Play with different LUTs for different refesh times.

This commit is contained in:
antirez
2024-03-14 23:50:27 +01:00
parent 6f5b01b6aa
commit 0aaf4c6bab

161
uc8151.py
View File

@@ -211,9 +211,15 @@ class UC8151:
self.write(CMD_PSR,psr_settings)
# Set the lookup tables depending on the speed.
self.set_waveform_lut()
# Here we set the voltage levels that are used for the low-high
# transitions states, driven by the waveforms provided in the
# lookup tables for refresh.
#
# The VCOM_DC is left to the default of -0.10v, since
# CMD_VDCS is not given.
self.write(CMD_PWR, \
[VDS_INTERNAL|VDG_INTERNAL,
VCOM_VD|VGHL_16V,
@@ -256,6 +262,150 @@ class UC8151:
self.write(CMD_POF)
self.wait_ready()
# Set the lookup tables used during the display refresh.
# We have a table for each transition possibile:
# white -> white
# white -> black
# black -> black
# black -> white
# and a final table that controls the VCOM voltage.
#
# The update process happens in phases, each 6 rows of each
# table tells the display how to set each pixel based on the
# transition (WW, WB, BB, BW) and VCOM in each phase.
# VCOM is different and explained later, but for the first four
# tables, this is how to interpret them. For instance the
# lookup for WW in turbo speed has the first phase set to:
#
# 0x54, 0x01, 0x01, 0x02, 0x00, 0x01
#
# The first byte must be read as four two bits integers:
#
# 0x54 is: 01|01|01|00
#
# Where each 2 bit number menas:
# 00 - Put to ground
# 01 - Put to VDH voltage (11v in our config)
# 10 - Put to VDL voltage (-11v in our config)
# 11 - Not used.
#
# Then the next four bytes in the row mean how many
# "frames" (the refresh tick time, less than 1ms) we
# hold a given state.
# So in the above case: hold pixel at VDH for 1 frame, then
# again VDH for 1 frame, and again, the last entry says 0 frames
# so it's not used. The final number in the row, 0x01, means
# that this sequence must be repeated just once. If it was 2
# the sequence would repeat 2 times and so forth.
#
# The VCOM table is similar, but the bits meaning is different:
# 00 - Put VCOM to VCM_DC voltage
# 01 - Put VCOM to VDH+VCM_DC voltage (see PWR register config)
# 10 - Put VCOM to VDL+VCM_DC voltage
# 11 - Floating
#
# The meaning of the additional two bytes in the VCOM table
# apparently is the following (but I'm not sure what it means):
# first additional byte: ST_XON, if a (1<<phase) bit is set, for the
# that phase all gates are on. Second byte: ST_CHV. Like ST_XON
# but if a bit is set VCOM voltage is set to high for this phase.
def set_waveform_lut(self):
if self.speed == UPDATE_SPEED_DEFAULT: return
if self.speed == UPDATE_SPEED_MEDIUM:
VCOM = bytes([
0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x23, 0x23, 0x00, 0x00, 0x02,
0x00, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
])
WHITE = bytes([
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
])
BLACK = bytes([
0xa8, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x60, 0x23, 0x23, 0x00, 0x00, 0x02,
0x54, 0x16, 0x16, 0x0d, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
])
elif self.speed == UPDATE_SPEED_FAST:
VCOM = bytes([
0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
0x00, 0x17, 0x17, 0x00, 0x00, 0x02,
0x00, 0x0A, 0x01, 0x00, 0x00, 0x01,
0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
])
WHITE = bytes([
0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
0x40, 0x0A, 0x01, 0x00, 0x00, 0x01,
0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
])
BLACK = bytes([
0x80, 0x17, 0x00, 0x00, 0x00, 0x02,
0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
0x80, 0x0A, 0x01, 0x00, 0x00, 0x01,
0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
])
elif self.speed == UPDATE_SPEED_TURBO:
VCOM = bytes([
0x00, 0x01, 0x01, 0x02, 0x00, 0x01,
0x00, 0x02, 0x02, 0x00, 0x00, 0x02,
0x00, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00
])
WHITE = bytes([
0x54, 0x01, 0x01, 0x02, 0x00, 0x01,
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
0xa8, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
])
BLACK = bytes([
0xa8, 0x01, 0x01, 0x02, 0x00, 0x01,
0x60, 0x02, 0x02, 0x00, 0x00, 0x02,
0x54, 0x02, 0x02, 0x03, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
])
self.write(CMD_LUT_VCOM,VCOM)
self.write(CMD_LUT_WW,WHITE)
self.write(CMD_LUT_BW,WHITE)
self.write(CMD_LUT_BB,BLACK)
self.write(CMD_LUT_WB,BLACK)
# Wait for the display to return back able to accept commands
# (if it is updating the display it remains busy), and switch
# it off once it is possible.
@@ -284,9 +434,16 @@ class UC8151:
if __name__ == "__main__":
from machine import SPI
import random
spi = SPI(0, baudrate=12000000, phase=0, polarity=0, sck=Pin(18), mosi=Pin(19), miso=Pin(16))
eink = UC8151(spi,cs=17,dc=20,rst=21,busy=26)
eink = UC8151(spi,cs=17,dc=20,rst=21,busy=26,speed=UPDATE_SPEED_TURBO)
eink.fb.ellipse(10,10,10,10,1)
eink.fb.ellipse(50,50,10,10,1)
eink.fb.text("SUKA",80,80,1)
x = random.randrange(100)
y = random.randrange(100)
eink.fb.text("TEST",x,y,1)
start = time.ticks_ms()
eink.update(blocking=True)
print("Update time:",time.ticks_ms() - start)