1

I bought a 2.9inch ePaper display for RPi Pico (296 × 128 Pixels, Black / White / Red, SPI Interface) from WaveShare.

I found several MicroPython drivers for 2.9" ePaper on Waveshare's GitHub: https://github.com/waveshareteam/Pico_ePaper_Code

Unfortunately, there are no explanations / comments / doc.strings in the source code whatsoever! I tested all drivers for 2.9" displays, some of them did not work. I have no experience with C, only with Python.

What I did:

I took one of scripts that worked and cleaned it and annotated it to the best of my ability, trying to understand the logic behind it to the best of my ability. Please, see the script below (it works in Portrait mode).

What I need:

  1. I want to make this display to work in Landscape mode. I tried swapping width and height. I also tried changing buffer mode from framebuf.MONO_HLSB to framebuf.MONO_VLSB Nothing worked. Could you suggest what else can I do?
  2. When I run this script, the ePaper display flickers. I do not understand why! How can I reduce flickering / flashing?

import gc
import time
import framebuf
from machine import Pin, SPI
from micropython import const

def profile(func): def wrapper(args, kwargs): gc.collect() start_mem = gc.mem_free() start_t = time.ticks_ms() func(args, **kwargs) fin_t = time.ticks_ms() fin_mem = gc.mem_free() print(f'{func.name} took: {time.ticks_diff(fin_t, start_t)} ms to finish') print(f'{func.name} used around {start_mem - fin_mem} B of memory')

return wrapper

! Display Dimentions:

EPD_HEIGHT = const(296) # * screen height 296 pixels; type integer. EPD_WIDTH = const(128) # * screen width 128 pixels; type integer. BUF_FORMAT = framebuf.MONO_HLSB

! COLORS:

BLACK = 0x00 WHITE = 0xff

! Pins:

CS_PIN = 9 # * chip select (CS) pin (and start it high) RST_PIN = 12 # * Reset DC_PIN = 8 # * data/command control pin, write command when DC=0; write data when DC=1. BUSY_PIN = 13 FULL_UPDATE = 0 PART_UPDATE = 1

! Display Commands:

PANEL_SETTING = const(0x00) POWER_SETTING = const(0x01) POWER_OFF = const(0x02) POWER_OFF_SEQUENCE_SETTING = const(0x03) POWER_ON = const(0x04) POWER_ON_MEASURE = const(0x05) BOOSTER_SOFT_START = const(0x06) DEEP_SLEEP = const(0x07) DATA_START_TRANSMISSION_1 = const(0x10) DATA_STOP = const(0x11) DISPLAY_REFRESH = const(0x12) DATA_START_TRANSMISSION_2 = const(0x13) SET_MEM_ADDR = const(0x20) SET_COL_ADDR = const(0x21) SET_PAGE_ADDR = const(0x22) SET_DISP_START_LINE = const(0x40) VCOM_AND_DATA_INTERVAL_SETTING = const(0x50) TCON_RESOLUTION = const(0x61) GET_STATUS = const(0x71) AUTO_MEASURE_VCOM = const(0x80)

class EPD_2in9_B: # ? This Class inherits from MicroPython class FrameBuffer. def init(self): self.width = EPD_WIDTH self.height = EPD_HEIGHT self.dc_pin = Pin(DC_PIN, Pin.OUT, value=0) self.cs_pin = Pin(CS_PIN, Pin.OUT) self.busy_pin = Pin(BUSY_PIN, Pin.IN, Pin.PULL_UP) self.reset_pin = Pin(RST_PIN, Pin.OUT, value=0) # ? The default pins for SPI(1) are: sck=Pin(6), mosi=Pin(8), miso=Pin(7) # ? when increased the baudrate=20_000_000, no text appered on the screen. self.spi = SPI(1) self.spi.init(baudrate = 100_000) # * The display is stored as a list of bytes where each byte is eight consecutive pixels, either set to 1 to display a dark pixel or 0 for white (or clear). # * heihtwidth // 8 = (296128) / 8 = 4736 self.buffer_black = bytearray(self.height * self.width // 8) self.buffer_red = bytearray(self.height * self.width // 8) # * The first argument is the byte array, with and height are self explanatory, and framebuf.MONO_HLSB means that this framebuffer is a mono (1-bit) image, with horizontal bits stored as a byte. self.imageblack = framebuf.FrameBuffer(self.buffer_black, self.width, self.height, BUF_FORMAT) self.imagered = framebuf.FrameBuffer(self.buffer_red, self.width, self.height, BUF_FORMAT) self.init()

def digital_write(self, pin, value):
    '''
    Pin.value([x])
    If the argument is supplied then this method sets the digital logic level of the pin. 
    The argument x can be anything that converts to a boolean. 
    If it converts to True, the pin is set to state 1, otherwise it is set to state 0.
    '''
    pin.value(value)

def digital_read(self, pin):
    '''
    Use the value() method to check the present value on a pin set up to be in input mode. 
    With polling, you can use MicroPython code to monitor the value of a pin. 
    During polling, the system constantly checks the value of the pin.
    '''
    return pin.value()

def spi_writebyte(self, data):
    '''
    SPI.write(buf): write the bytes contained in buffer.
    '''
    self.spi.write(bytearray(data))

# * Hardware reset
def reset(self):
# * If we have a reset pin, do a hardware reset by toggling it.
    if self.reset_pin:
        self.digital_write(self.reset_pin, False)
        time.sleep(0.1)
        self.digital_write(self.reset_pin, True)
        time.sleep(0.1)

def send_command(self, command):
    self.digital_write(self.dc_pin, 0)
    self.digital_write(self.cs_pin, 0)
    self.spi_writebyte([command])
    self.digital_write(self.cs_pin, 1)

def send_data(self, data):
    self.digital_write(self.dc_pin, 1)
    self.digital_write(self.cs_pin, 0)
    self.spi_writebyte([data])
    self.digital_write(self.cs_pin, 1)

@profile
def ReadBusy(self):
    print('ePaper is busy!')
    self.send_command(GET_STATUS)
    while (self.digital_read(self.busy_pin) == 0): 
        self.send_command(GET_STATUS)
        time.sleep_ms(10) 
    print('Busy release')

@profile
def init(self):
    print('Initializind the display!')
    self.reset()
    self.send_command(POWER_ON)
    self.ReadBusy()  # ? waiting for the electronic paper IC to release the idle signal
    self.send_command(PANEL_SETTING )  # panel setting
    self.send_data(0x0f)  # LUT from OTP,128x296
    self.send_data(0x89)  # Temperature sensor, boost and other related timing settings
    self.send_command(TCON_RESOLUTION)  #resolution setting
    self.send_data (AUTO_MEASURE_VCOM)
    self.send_data (POWER_SETTING)
    self.send_data (0x28)
    self.send_command(VCOM_AND_DATA_INTERVAL_SETTING)
    self.send_data(0x77)  # WBmode:VBDF 17|D7 VBDW 97 VBDB 57
    return 0

def TurnOnDisplay(self):
    self.send_command(DISPLAY_REFRESH)
    self.ReadBusy()

def display(self):
    self.send_command(0x10)
    self.send_data1(self.buffer_black)
    self.send_command(0x13)
    self.send_data1(self.buffer_red)   
    self.TurnOnDisplay()

def send_data1(self, buf):
    '''
    send_data1() is used only in Clear()
    '''
    self.digital_write(self.dc_pin, 1)
    self.digital_write(self.cs_pin, 0)
    self.spi.write(bytearray(buf))
    self.digital_write(self.cs_pin, 1)

@profile
def Clear(self, color_black, color_red):
    self.send_command(DATA_START_TRANSMISSION_1)
    self.send_data1([color_black] * self.height * int(self.width / 8))
    print([color_black] * self.height * int(self.width / 8))
    print(f"bytearray length: {self.height * int(self.width / 8)}")
    self.send_command(DATA_START_TRANSMISSION_2)
    self.send_data1([color_red] * self.height * int(self.width / 8))
    self.TurnOnDisplay()

    '''
    high = self.height
    if( self.width % 8 == 0) :
        wide =  self.width // 8
    else :
        wide =  self.width // 8 + 1
    self.send_command(0x10)
    self.send_data1([color] * high * wide)
    self.send_command(0x13)
    self.send_data1([~color] * high * wide)
    self.SetFullReg()
    self.TurnOnDisplay()'''

def sleep(self):
    self.send_command(POWER_OFF) # power off
    self.ReadBusy()
    self.send_command(DEEP_SLEEP) # deep sleep
    self.send_data(0xA5)
    time.sleep_ms(2000)
    self.digital_write(self.reset_pin, 0)

if name=='main': START_TIME = time.time() epd = EPD_2in9_B() # ! Clear the Screen (only white color): print("Clearing screen!") epd.Clear(WHITE, WHITE) epd.imageblack.fill(WHITE) epd.imagered.fill(WHITE) # ! Display text: print("Displaying text!") epd.imageblack.text("Waveshare", 0, 10, BLACK) epd.imagered.text("ePaper-2.9-B", 0, 25, BLACK) epd.imageblack.text("Raspberry_Pi_Pico W", 0, 40, BLACK) epd.imagered.text("Hello World", 0, 55, BLACK) epd.display() time.sleep_ms(2000) print("Drawing rectangles!") epd.imageblack.rect(10, 150, 40, 40, 0x00) epd.imagered.fill_rect(60, 150, 40, 40, 0x00) epd.display() time.sleep_ms(2000) print("Clearing screen!") epd.Clear(WHITE, WHITE) time.sleep_ms(2000) print("Sleeping!") epd.sleep() # ! Measure time: FINISH_TIME = time.time() duration = FINISH_TIME - START_TIME print(f"\nProcess duration is {duration:.3f} seconds.")

user136555
  • 111
  • 3

0 Answers0