2

I got a 5.8" eink display from Pervasive Displays and cannot get it to work, I feel that only a little bit is missing. After a lot of struggle I managed to run it via their sample C code, but the ported code to Python doesn't work. First the hardware details:

I connected it as described here: https://embeddedcomputing.weebly.com/connecting-the-ext3-to-the-raspberry-pi.html then simplified the example code to a bare minimum here this works fine, it displays the sample image. Its a bit tricky stuff, since it instructs to run the code in a Arduino emulator (RasPiArduino).

Here is my code for the bare minimum code that should work (it should trigger a display refresh), but nothing happens:

import spidev # SPI library
import time
import RPi.GPIO as GPIO 
from images import BW_0x00Buffer, BW_monoBuffer # just arrays with hex numbers, see repo
class board_EXT3:
 # EXT3 pin 1 Black -> +3.3V
 # EXT3 pin 2 Brown -> GPIO 11 SPI0 SCLK
 panelBusy = 7 # EXT3 pin 3 Red -> GPIO7 pin 26 (SPI chip select 1 / CE1)
 panelDC = 8 # EXT3 pin 4 Orange -> GPIO8 pin 24 (SPI chip select 0 / CE0)
 panelReset = 25 # EXT3 pin 5 Yellow -> GPIO25 pin 22
 panelCS = 27 # EXT3 pin 9 Grey -> GPIO27 pin 13
 # EXT3 pin 6 Green -> GPIO9 SPI0 MISO
 # EXT3 pin 7 Blue -> GPIO10 SPI0 MOSI
 flashCS = 22 # EXT3 pin 8 Violet -> GPIO22 pin 15
 # EXT3 pin 10 White -> GROUND
def COG_initial():
 GPIO.setup(board_EXT3.panelBusy, GPIO.IN) # all pins 0
 GPIO.setup(board_EXT3.panelDC, GPIO.OUT)
 GPIO.output(board_EXT3.panelDC, GPIO.HIGH)
 GPIO.setup(board_EXT3.panelReset, GPIO.OUT)
 GPIO.output(board_EXT3.panelReset, GPIO.HIGH)
 GPIO.setup(board_EXT3.panelCS, GPIO.OUT)
 GPIO.output(board_EXT3.panelCS,GPIO.HIGH)
 global spi
 spi = spidev.SpiDev()
 spi.close()
 spi.open(0, 0) # device 0 (SPI_CE0_N)
 spi.max_speed_hz = 122000 # bit rate, was 8000000 should be OK too
 spi.lsbfirst = False
 spi.mode = 0b00 # polarity CPOL=0 CPHA=0, bits
 spi.bits_per_word = 8 # read only on the Pi
def globalUpdate(data1s, data2s):
 print("reset")
 _reset() # needed for min
 print("soft start")
 _DCDC_softStart_Mid() # needed for min
 print("refresh")
 _displayRefresh() # needed for min
 print("shutdown")
 _DCDC_softShutdown_Mid()
def _reset():
 time.sleep(0.2)
 GPIO.output(board_EXT3.panelReset, GPIO.HIGH) # RES = 1
 time.sleep(0.02)
 GPIO.output(board_EXT3.panelReset, GPIO.LOW)
 time.sleep(0.2)
 GPIO.output(board_EXT3.panelReset, GPIO.HIGH)
 time.sleep(0.05)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH)
 time.sleep(0.005)
def _DCDC_softStart_Mid():
 # Initialize COG Driver
 data4 = [0x7d]
 _sendIndexData(0x05, data4, 1)
 time.sleep(0.2)
 data5 = [0x00]
 _sendIndexData(0x05, data5, 1)
 time.sleep(0.01)
 data6 = [0x3f]
 _sendIndexData(0xc2, data6, 1)
 time.sleep(0.001)
 data7 = [0x00]
 _sendIndexData(0xd8, data7, 1) # MS_SYNC mtp_0x1d
 data8 = [0x00]
 _sendIndexData(0xd6, data8, 1) # BVSS mtp_0x1e
 data9 = [0x10]
 _sendIndexData(0xa7, data9, 1)
 time.sleep(0.1)
 _sendIndexData(0xa7, data5, 1)
 time.sleep(0.1)
 print("ss1")
 data10 = [0x00, 0x01] # OSC
 _sendIndexData(0x03, data10, 2) # OSC mtp_0x12
 _sendIndexData(0x44, data5, 1)
 data11 = [0x80]
 _sendIndexData(0x45, data11, 1)
 _sendIndexData(0xa7, data9, 1)
 time.sleep(0.1)
 _sendIndexData(0xa7, data7, 1)
 time.sleep(0.1)
 data12 = [0x06]
 _sendIndexData(0x44, data12, 1)
 data13 = [0x82]
 _sendIndexData(0x45, data13, 1) # Temperature 0x82@25C
 _sendIndexData(0xa7, data9, 1)
 time.sleep(0.1)
 _sendIndexData(0xa7, data7, 1)
 time.sleep(0.1)
 data14 = [0x25]
 _sendIndexData(0x60, data14, 1) # TCON mtp_0x0b
 data15 = [0x00] # STV_DIR
 _sendIndexData(0x61, data15, 1) # STV_DIR mtp_0x1c
 data16 = [0x00]
 _sendIndexData(0x01, data16, 1) # DCTL mtp_0x10 ?? this is not in the flowchart
 data17 = [0x00]
 _sendIndexData(0x02, data17, 1) # VCOM mtp_0x11
 print("ss2")
 # DC-DC soft start
 index51 = [0x50, 0x01, 0x0a, 0x01]
 _sendIndexData(0x51, index51, 2)
 index09 = [0x1f, 0x9f, 0x7f, 0xff]
 for value in range(1, 5): # 1,2,3,4
 _sendIndexData(0x09, index09, 1)
 index51[1] = value
 _sendIndexData(0x51, index51, 2)
 _sendIndexData(0x09, index09[1:], 1)
 time.sleep(0.002)
 for value in range(1, 11):
 _sendIndexData(0x09, index09, 1)
 index51[3] = value
 _sendIndexData(0x51, index51[2:], 2)
 _sendIndexData(0x09, index09[1:], 1)
 time.sleep(0.002)
 for value in range(3, 11):
 _sendIndexData(0x09, index09[2:], 1)
 index51[3] = value
 _sendIndexData(0x51, index51[2:], 2)
 _sendIndexData(0x09, index09[3:], 1)
 time.sleep(0.002)
 for value in range(9, 1, -1): # 9,8,7,...2
 _sendIndexData(0x09, index09[2:], 1)
 index51[2] = value
 _sendIndexData(0x51, index51[2:], 2)
 _sendIndexData(0x09, index09[3:], 1)
 time.sleep(0.002)
 _sendIndexData(0x09, index09[3:], 1)
 time.sleep(0.01)
def _displayRefresh():
 while GPIO.input(board_EXT3.panelBusy) != GPIO.HIGH:
 time.sleep(0.1)
 _sendIndexData(0x15, [0x3c], 1) # Display Refresh
 time.sleep(0.005)
def _DCDC_softShutdown_Mid():
 while GPIO.input(board_EXT3.panelBusy) != GPIO.HIGH:
 time.sleep(0.1)
 data19 = [0x7f]
 _sendIndexData(0x09, data19, 1)
 data20 = [0x7d]
 _sendIndexData(0x05, data20, 1)
 data55 = [0x00]
 _sendIndexData(0x09, data55, 1)
 time.sleep(0.2)
 while GPIO.input(board_EXT3.panelBusy) != GPIO.HIGH:
 time.sleep(0.1)
 GPIO.output(board_EXT3.panelDC, GPIO.LOW)
 GPIO.output(board_EXT3.panelCS, GPIO.LOW)
 GPIO.output(board_EXT3.panelReset, GPIO.LOW)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH) # CS# = 1
def _sendIndexData(index, data, size):
 GPIO.output(board_EXT3.panelDC, GPIO.LOW) # DC Low
 GPIO.output(board_EXT3.panelCS, GPIO.LOW) # (CS == CSB) Low
 time.sleep(0.05)
 spi.writebytes([index]) # SPI.transfer(index)
 time.sleep(0.05)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH) # CS High
 GPIO.output(board_EXT3.panelDC, GPIO.HIGH) # DC High
 GPIO.output(board_EXT3.panelCS, GPIO.LOW) # CS Low
 time.sleep(0.05)
 #for i in range(size):
 # spi.writebytes([data[i]])
 spi.writebytes(data[:size])
 time.sleep(0.05)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH) # CS High
COG_initial()
print("update")
globalUpdate(BW_monoBuffer, BW_0x00Buffer)
print("power off")
COG_powerOff()
print("program end")

What could I be doing wrong? I have SPI enabled in raspi-config, tried to run it as root, the cabling is correct (since the C code linked above works fine), triple checked everything for typos. My guess it is something trivial, e.g. RasPiArduino's SPI.transfer does something different than spidev's spi.writebytes. The only thing I see that the display does nothing and that _DCDC_softStart_Mid takes longer to execute than the C++ code.

asked Mar 14, 2022 at 22:42
2
  • 1
    I can see no relationship between the C code and the Python code. If you want help please present working C code in the question so we can compare it line by line with the Python code. Commented Mar 14, 2022 at 22:50
  • @joan both are in the repo I linked above. The C code is here: github.com/matyasf/pi-radio/blob/main/workingCode/… (and in the other files in the same folder), the Python code is above Commented Mar 14, 2022 at 23:21

2 Answers 2

1

After some debugging with a logic analyzer I could fix the code, it had 2 issues:

  1. _sendIndexData had wrong sleep values, the original code had microseconds.
  2. And more importantly spidev sets the cs line to low on each transfer, Pervasive displays EXT kit needs it on low for transferring the index and on high when transferring the data. This is already in the code, just one needs to disable this functionality in spidev: spi.no_cs = True

So here is the working code:

import spidev # SPI library
import time
import RPi.GPIO as GPIO 
from images import BW_0x00Buffer, BW_monoBuffer
GPIO.setmode(GPIO.BCM) # use standard rpi pin numbering
print('starting in GPIO mode ' + str(GPIO.getmode()))
# Raspberry Pi Zero, 2B, 3B, 4B configuration
class board_EXT3:
 # EXT3 pin 1 Black -> +3.3V
 # EXT3 pin 2 Brown -> GPIO 11 SPI0 SCLK
 panelBusy = 7 # EXT3 pin 3 Red -> GPIO7 pin 26 (SPI chip select 1 / CE1)
 panelDC = 8 # EXT3 pin 4 Orange -> GPIO8 pin 24 (SPI chip select 0 / CE0)
 panelReset = 25 # EXT3 pin 5 Yellow -> GPIO25 pin 22
 # EXT3 pin 6 Green -> SPI MISO
 # EXT3 pin 7 Blue -> SPI MOSI
 panelCS = 27 # EXT3 pin 9 Grey -> GPIO27 pin 13
 # EXT3 pin 6 Green -> GPIO9 SPI0 MISO
 # EXT3 pin 7 Blue -> GPIO10 SPI0 MOSI
 # flashCS = 22 # EXT3 pin 8 Violet -> GPIO22 pin 15
 # EXT3 pin 10 White -> GROUND
def COG_initial():
 GPIO.setup(board_EXT3.panelBusy, GPIO.IN) # all pins 0
 GPIO.setup(board_EXT3.panelDC, GPIO.OUT)
 GPIO.output(board_EXT3.panelDC, GPIO.HIGH)
 GPIO.setup(board_EXT3.panelReset, GPIO.OUT)
 GPIO.output(board_EXT3.panelReset, GPIO.HIGH)
 GPIO.setup(board_EXT3.panelCS, GPIO.OUT)
 GPIO.output(board_EXT3.panelCS,GPIO.HIGH)
 global spi
 spi = spidev.SpiDev()
 spi.close()
 spi.open(0, 0) # device 0 (SPI_CE0_N)
 spi.max_speed_hz = 122000 # bit rate, was 8000000 should be OK too
 spi.lsbfirst = False
 spi.mode = 0b00 # polarity CPOL=0 CPHA=0, bits
 spi.bits_per_word = 8 # read only on the Pi
 spi.no_cs = True
def globalUpdate(data1s, data2s):
 print("reset")
 _reset() # needed for min
 
 dtcl = [0x08] # 0=IST7232, 8=IST7236
 _sendIndexData(0x01, dtcl, 1) #DCTL 0x10 of MTP
 
 # Send image data
 print("send image data")
 data1 = [0x00, 0x1f, 0x50, 0x00, 0x1f, 0x03] # DUW
 _sendIndexData(0x13, data1, 6) # DUW
 data2 = [0x00, 0x1f, 0x00, 0xc9] # DRFW
 _sendIndexData(0x90, data2, 4) # DRFW
 data3 = [0x1f, 0x50, 0x14] # RAM_RW
 _sendIndexData(0x12, data3, 3) # RAM_RW
 # send first frame
 print("send 1st frame")
 _sendIndexData(0x10, data1s, 23040) # First frame
 data33 = [0x1f, 0x50, 0x14] # RAM_RW
 _sendIndexData(0x12, data33, 3) # RAM_RW
 # send second frame
 print("send 2nd frame")
 _sendIndexData(0x11, data2s, 23040) # Second frame
 
 print("soft start")
 _DCDC_softStart_Mid() # needed for min
 print("refresh")
 _displayRefresh() # needed for min
 print("shutdown")
 _DCDC_softShutdown_Mid() # if left out it'll just darken
def _reset():
 time.sleep(0.2)
 GPIO.output(board_EXT3.panelReset, GPIO.HIGH) # RES = 1
 time.sleep(0.02)
 GPIO.output(board_EXT3.panelReset, GPIO.LOW)
 time.sleep(0.2)
 GPIO.output(board_EXT3.panelReset, GPIO.HIGH)
 time.sleep(0.05)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH) # CS# = 1 -- not in the manual
 time.sleep(0.005)
# DC-DC soft-start command
# - Implemented after image data are uploaded to CoG
# - Specific to mid-sized EPDs only
def _DCDC_softStart_Mid():
 # Initialize COG Driver
 data4 = [0x7d]
 _sendIndexData(0x05, data4, 1)
 time.sleep(0.2)
 data5 = [0x00]
 _sendIndexData(0x05, data5, 1)
 time.sleep(0.01)
 data6 = [0x3f]
 _sendIndexData(0xc2, data6, 1)
 time.sleep(0.001)
 data7 = [0x00]
 _sendIndexData(0xd8, data7, 1) # MS_SYNC mtp_0x1d
 data8 = [0x00]
 _sendIndexData(0xd6, data8, 1) # BVSS mtp_0x1e
 data9 = [0x10]
 _sendIndexData(0xa7, data9, 1)
 time.sleep(0.1)
 _sendIndexData(0xa7, data5, 1)
 time.sleep(0.1)
 print("ss1")
 data10 = [0x00, 0x01] # OSC
 _sendIndexData(0x03, data10, 2) # OSC mtp_0x12
 _sendIndexData(0x44, data5, 1)
 data11 = [0x80]
 _sendIndexData(0x45, data11, 1)
 _sendIndexData(0xa7, data9, 1)
 time.sleep(0.1)
 _sendIndexData(0xa7, data7, 1)
 time.sleep(0.1)
 data12 = [0x06]
 _sendIndexData(0x44, data12, 1)
 data13 = [0x82]
 _sendIndexData(0x45, data13, 1) # Temperature 0x82@25C
 _sendIndexData(0xa7, data9, 1)
 time.sleep(0.1)
 _sendIndexData(0xa7, data7, 1)
 time.sleep(0.1)
 data14 = [0x25]
 _sendIndexData(0x60, data14, 1) # TCON mtp_0x0b
 data15 = [0x00] # STV_DIR
 _sendIndexData(0x61, data15, 1) # STV_DIR mtp_0x1c
 data16 = [0x00]
 _sendIndexData(0x01, data16, 1) # DCTL mtp_0x10 ?? this is not in the flowchart
 data17 = [0x00]
 _sendIndexData(0x02, data17, 1) # VCOM mtp_0x11
 print("ss2")
 # DC-DC soft start
 index51 = [0x50, 0x01, 0x0a, 0x01]
 _sendIndexData(0x51, index51, 2)
 index09 = [0x1f, 0x9f, 0x7f, 0xff]
 for value in range(1, 5): # 1,2,3,4
 _sendIndexData(0x09, index09, 1)
 index51[1] = value
 _sendIndexData(0x51, index51, 2)
 _sendIndexData(0x09, index09[1:], 1)
 time.sleep(0.002)
 for value in range(1, 11):
 _sendIndexData(0x09, index09, 1)
 index51[3] = value
 _sendIndexData(0x51, index51[2:], 2)
 _sendIndexData(0x09, index09[1:], 1)
 time.sleep(0.002)
 for value in range(3, 11):
 _sendIndexData(0x09, index09[2:], 1)
 index51[3] = value
 _sendIndexData(0x51, index51[2:], 2)
 _sendIndexData(0x09, index09[3:], 1)
 time.sleep(0.002)
 for value in range(9, 1, -1): # 9,8,7,...2
 _sendIndexData(0x09, index09[2:], 1)
 index51[2] = value
 _sendIndexData(0x51, index51[2:], 2)
 _sendIndexData(0x09, index09[3:], 1)
 time.sleep(0.002)
 _sendIndexData(0x09, index09[3:], 1)
 time.sleep(0.01)
# EPD Screen refresh function
# INPUT: None but requires global variables on SPI pinout and config register data
def _displayRefresh():
 while GPIO.input(board_EXT3.panelBusy) != GPIO.HIGH:
 time.sleep(0.1)
 _sendIndexData(0x15, [0x3c], 1) # Display Refresh
 time.sleep(0.005)
# DC-DC soft-shutdown command
# - Implemented after image data are uploaded to CoG
# - Specific to mid-sized EPDs only
def _DCDC_softShutdown_Mid():
 while GPIO.input(board_EXT3.panelBusy) != GPIO.HIGH:
 time.sleep(0.1)
 data19 = [0x7f]
 _sendIndexData(0x09, data19, 1)
 data20 = [0x7d]
 _sendIndexData(0x05, data20, 1)
 data55 = [0x00]
 _sendIndexData(0x09, data55, 1)
 time.sleep(0.2)
 while GPIO.input(board_EXT3.panelBusy) != GPIO.HIGH:
 time.sleep(0.1)
 GPIO.output(board_EXT3.panelDC, GPIO.LOW)
 GPIO.output(board_EXT3.panelCS, GPIO.LOW)
 GPIO.output(board_EXT3.panelReset, GPIO.LOW)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH) # CS# = 1
# CoG shutdown function
# - Shuts down the CoG and DC/DC circuit after all update functions
# INPUT:
# - none but requires global variables on SPI pinout and config register data
def COG_powerOff():
 register_turnOff = [0x7f, 0x7d, 0x00]
 _sendIndexData(0x09, register_turnOff, 3)
 time.sleep(0.2)
 while GPIO.input(board_EXT3.panelBusy) != GPIO.HIGH:
 time.sleep(0.05)
 GPIO.output(board_EXT3.panelDC, GPIO.LOW)
 GPIO.output(board_EXT3.panelCS, GPIO.LOW)
 GPIO.output(board_EXT3.panelBusy, GPIO.LOW)
 time.sleep(0.15)
 GPIO.output(board_EXT3.panelReset, GPIO.LOW)
def _sendIndexData(index, data, size):
 GPIO.output(board_EXT3.panelDC, GPIO.LOW) # DC Low
 GPIO.output(board_EXT3.panelCS, GPIO.LOW) # (CS == CSB) Low
 time.sleep(0.00005)
 spi.writebytes2([index])
 time.sleep(0.00005)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH) # CS High
 GPIO.output(board_EXT3.panelDC, GPIO.HIGH) # DC High
 GPIO.output(board_EXT3.panelCS, GPIO.LOW) # CS Low
 time.sleep(0.00005)
 spi.writebytes2(data[:size])
 time.sleep(0.00005)
 GPIO.output(board_EXT3.panelCS, GPIO.HIGH) # CS High
COG_initial()
print("globalUpdate")
globalUpdate(BW_monoBuffer, BW_0x00Buffer)
print("power off")
COG_powerOff()
print("program end")

not that its still not perfect, the power off function gets stuck waiting for busy to be low.

answered Mar 29, 2022 at 8:28
0

I think the most effective way to debug this is to hook up a logic analyzer (a Pi running piscope or an actual analyzer/scope) on the SPI lines and look at the signals being transmitted. Remember to reduce the SPI clock frequency to a lower value (e.g. 100 kHz) if your logic analyzer fails to capture 8MHz signals properly.

The problem could be anything from the signal timing to unexpected extra clock transitions or wrong data being transmitted. Of course, you could always find the reason for wrong data by carefully analyzing your own code, the Python library and the SPI kernel driver, but it will be so much faster to simply look at what you transmit and check if those are the same bytes that Arduino is sending.

answered Mar 18, 2022 at 11:07
1
  • 1
    Yep, thats the plan B, I've already ordered a cheap logic analyzer. As I wrote above the connections are all right, the C code executes fine. Commented Mar 18, 2022 at 11:13

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.