I have purchases a Raspberry Pi Pico W and have wired it to the Waveshare 1.54 inch e-Paper display module V2 I have used the code available at the github page, specifically the epd1in54b.py and the epconfig.py,
The specific errors that I have got are some missing libraries, including logging, spidev, ctypes, subprocess. I have tried to work around this as best as I can by replacing these modules with modules supported by Micropython & the Raspberry Pi Pico W.
This is the modified version of epd1in54b_V2.py file
import epdconfig
# Display resolution
EPD_WIDTH = 200
EPD_HEIGHT = 200
class EPD:
def __init__(self, cs, dc, rst, busy):
self.reset_pin = rst
self.dc_pin = dc
self.busy_pin = busy
self.cs_pin = cs
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
# Hardware reset
def reset(self):
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0) # module reset
epdconfig.delay_ms(5)
epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200)
def send_command(self, command):
epdconfig.digital_write(self.dc_pin, 0)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([command]) # Ensure this sends a list
epdconfig.digital_write(self.cs_pin, 1)
def send_data(self, data):
epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte([data]) # Ensure this sends a list
epdconfig.digital_write(self.cs_pin, 1)
# Send a lot of data
def send_data2(self, data):
epdconfig.digital_write(self.dc_pin, 1)
epdconfig.digital_write(self.cs_pin, 0)
epdconfig.spi_writebyte2(data) # Pass the data array directly
epdconfig.digital_write(self.cs_pin, 1)
def ReadBusy(self):
print("e-Paper busy")
while epdconfig.digital_read(self.busy_pin) == 1:
epdconfig.delay_ms(100)
print("e-Paper busy release")
def init(self):
if epdconfig.module_init() != 0:
return -1
# EPD hardware init start
self.reset()
self.ReadBusy()
self.send_command(0x12) # SWRESET
self.ReadBusy()
self.send_command(0x01) # Driver output control
self.send_data(0xC7)
self.send_data(0x00)
self.send_data(0x01)
self.send_command(0x11) # Data entry mode
self.send_data(0x01)
self.send_command(0x44) # Set RAM-X address start/end position
self.send_data(0x00)
self.send_data(0x18) # 0x18 --> (24+1)*8=200
self.send_command(0x45) # Set RAM-Y address start/end position
self.send_data(0xC7) # 0xC7 --> (199+1)=200
self.send_data(0x00)
self.send_data(0x00)
self.send_data(0x00)
self.send_command(0x3C) # BorderWaveform
self.send_data(0x05)
self.send_command(0x18) # Read built-in temperature sensor
self.send_data(0x80)
self.send_command(0x4E) # Set RAM x address count to 0
self.send_data(0x00)
self.send_command(0x4F) # Set RAM y address count to 0X199
self.send_data(0xC7)
self.send_data(0x00)
self.ReadBusy()
return 0
def getbuffer(self, image):
buf = [0xFF] * int(self.width * self.height / 8)
image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size
if imwidth != self.width or imheight != self.height:
raise ValueError('Image must be same dimensions as display ({0}x{1}).'.format(self.width, self.height))
pixels = image_monocolor.load()
for y in range(self.height):
for x in range(self.width):
if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
return buf
def display(self, blackimage, redimage):
if self.width % 8 == 0:
linewidth = int(self.width / 8)
else:
linewidth = int(self.width / 8) + 1
buf = [0x00] * self.height * linewidth
# Send black data
if blackimage is not None:
self.send_command(0x24) # DATA_START_TRANSMISSION_1
self.send_data2(blackimage)
# Send red data
if redimage is not None:
self.send_command(0x26) # DATA_START_TRANSMISSION_2
for i in range(int(self.width * self.height / 8)):
buf[i] = ~redimage[i]
self.send_data2(buf)
self.send_command(0x22) # DISPLAY_REFRESH
self.send_data(0xF7)
self.send_command(0x20) # DISPLAY_REFRESH
self.ReadBusy()
def Clear(self):
if self.width % 8 == 0:
linewidth = int(self.width / 8)
else:
linewidth = int(self.width / 8) + 1
self.send_command(0x24) # DATA_START_TRANSMISSION_1
self.send_data2([0xff] * int(self.height * linewidth))
self.send_command(0x26) # DATA_START_TRANSMISSION_2
self.send_data2([0x00] * int(self.height * linewidth))
self.send_command(0x22) # DISPLAY_REFRESH
self.send_data(0xF7)
self.send_command(0x20) # DISPLAY_REFRESH
self.ReadBusy()
def sleep(self):
self.send_command(0x10) # Enter deep sleep
self.send_data(0x01)
epdconfig.delay_ms(2000)
epdconfig.module_exit()
The modified epdconfig.py file is here:
import os
import sys
import time
# logger = logging.getLogger(__name__)
import machine
import time
class RaspberryPi:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
PWR_PIN = 18
def __init__(self):
self.spi = machine.SPI(0, baudrate=4000000, polarity=0, phase=0, sck=machine.Pin(18), mosi=machine.Pin(19))
self.rst = machine.Pin(self.RST_PIN, machine.Pin.OUT)
self.dc = machine.Pin(self.DC_PIN, machine.Pin.OUT)
self.cs = machine.Pin(self.CS_PIN, machine.Pin.OUT)
self.busy = machine.Pin(self.BUSY_PIN, machine.Pin.IN)
self.pwr = machine.Pin(self.PWR_PIN, machine.Pin.OUT)
self.cs(1) # Disable the chip select
def digital_write(self, pin, value):
pin_obj = getattr(self, pin.lower())
pin_obj.value(value)
def digital_read(self, pin):
pin_obj = getattr(self, pin.lower())
return pin_obj.value()
def delay_ms(self, delaytime):
time.sleep_ms(delaytime)
def spi_writebyte(self, data):
self.cs(0) # Enable chip select
self.spi.write(bytearray(data))
self.cs(1) # Disable chip select
def module_init(self):
self.pwr.on()
return 0
def module_exit(self):
self.spi.deinit()
self.rst.off()
self.dc.off()
self.pwr.off()
print("SPI end, Module enters 0 power consumption ...")
# Assuming we are using the RaspberryPi configuration for the Pico
implementation = RaspberryPi()
# Export functions to the module level
for func in [x for x in dir(implementation) if not x.startswith('_')]:
setattr(sys.modules[__name__], func, getattr(implementation, func))
class JetsonNano:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
PWR_PIN = 18
def __init__(self):
import Jetson.GPIO
self.GPIO = Jetson.GPIO
def digital_write(self, pin, value):
self.GPIO.output(pin, value)
def digital_read(self, pin):
return self.GPIO.input(self.BUSY_PIN)
def delay_ms(self, delaytime):
time.sleep(delaytime / 1000.0)
def spi_writebyte(self, data):
self.SPI.SYSFS_software_spi_transfer(data[0])
def spi_writebyte2(self, data):
for i in range(len(data)):
self.SPI.SYSFS_software_spi_transfer(data[i])
def module_init(self):
self.GPIO.setmode(self.GPIO.BCM)
self.GPIO.setwarnings(False)
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
self.GPIO.setup(self.CS_PIN, self.GPIO.OUT)
self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT)
self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
self.GPIO.output(self.PWR_PIN, 1)
self.SPI.SYSFS_software_spi_begin()
return 0
def module_exit(self):
print("spi end")
self.SPI.SYSFS_software_spi_end()
print("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.output(self.PWR_PIN, 0)
self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN, self.PWR_PIN])
class SunriseX3:
# Pin definition
RST_PIN = 17
DC_PIN = 25
CS_PIN = 8
BUSY_PIN = 24
PWR_PIN = 18
Flag = 0
def __init__(self):
import spidev
import Hobot.GPIO
self.GPIO = Hobot.GPIO
self.SPI = spidev.SpiDev()
def digital_write(self, pin, value):
self.GPIO.output(pin, value)
def digital_read(self, pin):
return self.GPIO.input(pin)
def delay_ms(self, delaytime):
time.sleep(delaytime / 1000.0)
def spi_writebyte(self, data):
self.SPI.writebytes(data)
def spi_writebyte2(self, data):
self.SPI.xfer3(data)
def module_init(self):
if self.Flag == 0:
self.Flag = 1
self.GPIO.setmode(self.GPIO.BCM)
self.GPIO.setwarnings(False)
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
self.GPIO.setup(self.CS_PIN, self.GPIO.OUT)
self.GPIO.setup(self.PWR_PIN, self.GPIO.OUT)
self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
self.GPIO.output(self.PWR_PIN, 1)
self.SPI.open(2, 0)
self.SPI.max_speed_hz = 4000000
self.SPI.mode = 0b00
return 0
else:
return 0
def module_exit(self):
print("spi end")
self.SPI.close()
print("close 5V, Module enters 0 power consumption ...")
self.Flag = 0
self.GPIO.output(self.RST_PIN, 0)
self.GPIO.output(self.DC_PIN, 0)
self.GPIO.output(self.PWR_PIN, 0)
self.GPIO.cleanup([self.RST_PIN, self.DC_PIN, self.CS_PIN, self.BUSY_PIN], self.PWR_PIN)
output = "Raspberry Pi Pico"
if "Raspberry" in output:
implementation = RaspberryPi()
elif os.path.exists('/sys/bus/platform/drivers/gpio-x3'):
implementation = SunriseX3()
else:
implementation = JetsonNano()
for func in [x for x in dir(implementation) if not x.startswith('_')]:
setattr(sys.modules[__name__], func, getattr(implementation, func))
### END OF FILE ###
The code I am using to generate the image is here:
import framebuf
import utime
from machine import Pin, SPI
import epd1in54b_V2
# Initialize the SPI communication
spi = SPI(1, baudrate=2000000, polarity=0, phase=0, sck=Pin(10), mosi=Pin(11), miso=Pin(12))
# Initialize the e-paper display
epd = epd1in54b_V2.EPD(spi, cs=Pin(13), dc=Pin(14), rst=Pin(15), busy=Pin(16))
# Clear the display
epd.init()
epd.clear_frame_memory(0xFF)
epd.display_frame()
# Create a black and white image (10x10 pixels)
image_width = 10
image_height = 10
image = bytearray(image_width * image_height // 8)
framebuf_image = framebuf.FrameBuffer(image, image_width, image_height, framebuf.MONO_HLSB)
# Draw a 10x10 pixel black square
for y in range(image_height):
for x in range(image_width):
framebuf_image.pixel(x, y, 0) # 0 means black in MONO_HLSB mode
# Calculate the position to place the image in the center of the display
display_width = epd.width
display_height = epd.height
x_pos = (display_width - image_width) // 2
y_pos = (display_height - image_height) // 2
# Display the image
epd.set_frame_memory(image, x_pos, y_pos, image_width, image_height)
epd.display_frame()
# Put the display to sleep
epd.sleep()
Can someone please advise me on how to do this.
user26708930 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.