mirror of
https://github.com/antirez/uc8151_micropython.git
synced 2025-12-06 06:12:49 +08:00
Badged 2040 UC8151 display driver: setup & refresh test.
This commit is contained in:
244
uc8151.py
Normal file
244
uc8151.py
Normal file
@@ -0,0 +1,244 @@
|
||||
# MicroPython driver for the UC8151 e-paper display used in the
|
||||
# Badger 2040.
|
||||
#
|
||||
# Copyright(C) 2024 Salvatore Sanfilippo <antirez@gmail.com>
|
||||
# MIT license.
|
||||
|
||||
from machine import Pin
|
||||
import time, framebuf
|
||||
|
||||
### Commands list.
|
||||
# Commands are executed putting the DC line in command mode
|
||||
# and sending the command as first byte, followed if needed by
|
||||
# the data arguments (but with DC in data mode).
|
||||
|
||||
CMD_PSR = const(0x00)
|
||||
CMD_PWR = const(0x01)
|
||||
CMD_POF = const(0x02)
|
||||
CMD_PFS = const(0x03)
|
||||
CMD_PON = const(0x04)
|
||||
CMD_PMES = const(0x05)
|
||||
CMD_BTST = const(0x06)
|
||||
CMD_DSLP = const(0x07)
|
||||
CMD_DTM1 = const(0x10)
|
||||
CMD_DSP = const(0x11)
|
||||
CMD_DRF = const(0x12)
|
||||
CMD_DTM2 = const(0x13)
|
||||
CMD_LUT_VCOM = const(0x20)
|
||||
CMD_LUT_WW = const(0x21)
|
||||
CMD_LUT_BW = const(0x22)
|
||||
CMD_LUT_WB = const(0x23)
|
||||
CMD_LUT_BB = const(0x24)
|
||||
CMD_PLL = const(0x30)
|
||||
CMD_TSC = const(0x40)
|
||||
CMD_TSE = const(0x41)
|
||||
CMD_TSR = const(0x43)
|
||||
CMD_TSW = const(0x42)
|
||||
CMD_CDI = const(0x50)
|
||||
CMD_LPD = const(0x51)
|
||||
CMD_TCON = const(0x60)
|
||||
CMD_TRES = const(0x61)
|
||||
CMD_REV = const(0x70)
|
||||
CMD_FLG = const(0x71)
|
||||
CMD_AMV = const(0x80)
|
||||
CMD_VV = const(0x81)
|
||||
CMD_VDCS = const(0x82)
|
||||
CMD_PTL = const(0x90)
|
||||
CMD_PTIN = const(0x91)
|
||||
CMD_PTOU = const(0x92)
|
||||
CMD_PGM = const(0xa0)
|
||||
CMD_APG = const(0xa1)
|
||||
CMD_ROTP = const(0xa2)
|
||||
CMD_CCSET = const(0xe0)
|
||||
CMD_PWS = const(0xe3)
|
||||
CMD_TSSET = const(0xe5)
|
||||
|
||||
### Register values
|
||||
|
||||
# PSR
|
||||
RES_96x230 = const(0b00000000)
|
||||
RES_96x252 = const(0b01000000)
|
||||
RES_128x296 = const(0b10000000)
|
||||
RES_160x296 = const(0b11000000)
|
||||
LUT_OTP = const(0b00000000)
|
||||
LUT_REG = const(0b00100000)
|
||||
FORMAT_BWR = const(0b00000000)
|
||||
FORMAT_BW = const(0b00010000)
|
||||
SCAN_DOWN = const(0b00000000)
|
||||
SCAN_UP = const(0b00001000)
|
||||
SHIFT_LEFT = const(0b00000000)
|
||||
SHIFT_RIGHT = const(0b00000100)
|
||||
BOOSTER_OFF = const(0b00000000)
|
||||
BOOSTER_ON = const(0b00000010)
|
||||
RESET_SOFT = const(0b00000000)
|
||||
RESET_NONE = const(0b00000001)
|
||||
|
||||
# PWR
|
||||
VDS_EXTERNAL = const(0b00000000)
|
||||
VDS_INTERNAL = const(0b00000010)
|
||||
VDG_EXTERNAL = const(0b00000000)
|
||||
VDG_INTERNAL = const(0b00000001)
|
||||
VCOM_VD = const(0b00000000)
|
||||
VCOM_VG = const(0b00000100)
|
||||
VGHL_16V = const(0b00000000)
|
||||
VGHL_15V = const(0b00000001)
|
||||
VGHL_14V = const(0b00000010)
|
||||
VGHL_13V = const(0b00000011)
|
||||
|
||||
# BOOSTER
|
||||
START_10MS = const(0b00000000)
|
||||
START_20MS = const(0b01000000)
|
||||
START_30MS = const(0b10000000)
|
||||
START_40MS = const(0b11000000)
|
||||
STRENGTH_1 = const(0b00000000)
|
||||
STRENGTH_2 = const(0b00001000)
|
||||
STRENGTH_3 = const(0b00010000)
|
||||
STRENGTH_4 = const(0b00011000)
|
||||
STRENGTH_5 = const(0b00100000)
|
||||
STRENGTH_6 = const(0b00101000)
|
||||
STRENGTH_7 = const(0b00110000)
|
||||
STRENGTH_8 = const(0b00111000)
|
||||
OFF_0_27US = const(0b00000000)
|
||||
OFF_0_34US = const(0b00000001)
|
||||
OFF_0_40US = const(0b00000010)
|
||||
OFF_0_54US = const(0b00000011)
|
||||
OFF_0_80US = const(0b00000100)
|
||||
OFF_1_54US = const(0b00000101)
|
||||
OFF_3_34US = const(0b00000110)
|
||||
OFF_6_58US = const(0b00000111)
|
||||
|
||||
# PFS
|
||||
FRAMES_1 = const(0b00000000)
|
||||
FRAMES_2 = const(0b00010000)
|
||||
FRAMES_3 = const(0b00100000)
|
||||
FRAMES_4 = const(0b00110000)
|
||||
|
||||
# TSE
|
||||
TEMP_INTERNAL = const(0b00000000)
|
||||
TEMP_EXTERNAL = const(0b10000000)
|
||||
OFFSET_0 = const(0b00000000)
|
||||
OFFSET_1 = const(0b00000001)
|
||||
OFFSET_2 = const(0b00000010)
|
||||
OFFSET_3 = const(0b00000011)
|
||||
OFFSET_4 = const(0b00000100)
|
||||
OFFSET_5 = const(0b00000101)
|
||||
OFFSET_6 = const(0b00000110)
|
||||
OFFSET_7 = const(0b00000111)
|
||||
OFFSET_MIN_8 = const(0b00001000)
|
||||
OFFSET_MIN_7 = const(0b00001001)
|
||||
OFFSET_MIN_6 = const(0b00001010)
|
||||
OFFSET_MIN_5 = const(0b00001011)
|
||||
OFFSET_MIN_4 = const(0b00001100)
|
||||
OFFSET_MIN_3 = const(0b00001101)
|
||||
OFFSET_MIN_2 = const(0b00001110)
|
||||
OFFSET_MIN_1 = const(0b00001111)
|
||||
|
||||
# PLL flags
|
||||
HZ_29 = const(0b00111111)
|
||||
HZ_33 = const(0b00111110)
|
||||
HZ_40 = const(0b00111101)
|
||||
HZ_50 = const(0b00111100)
|
||||
HZ_67 = const(0b00111011)
|
||||
HZ_100 = const(0b00111010)
|
||||
HZ_200 = const(0b00111001)
|
||||
|
||||
class UC8151:
|
||||
UPDATE_SPEED_DEFAULT=const(0)
|
||||
UPDATE_SPEED_MEDIUM=const(1)
|
||||
UPDATE_SPEED_FAST=const(2)
|
||||
UPDATE_SPEED_TURBO=const(3)
|
||||
|
||||
def __init__(self,spi,*,cs,dc,rst,busy,speed=UPDATE_SPEED_DEFAULT,mirror_x=False,mirror_y=False,inverted=False):
|
||||
self.spi = spi
|
||||
self.cs = Pin(cs,Pin.OUT) if cs != None else None
|
||||
self.dc = Pin(dc,Pin.OUT) if dc != None else None
|
||||
self.rst = Pin(rst,Pin.OUT) if rst != None else None
|
||||
self.busy = Pin(busy,Pin.IN) if busy != None else None
|
||||
self.speed = speed
|
||||
self.inverted = inverted
|
||||
self.mirror_x = mirror_x
|
||||
self.mirror_y = mirror_y
|
||||
self.initialize_display()
|
||||
self.raw_fb = bytearray(128*296//8)
|
||||
self.fb = framebuf.FrameBuffer(self.raw_fb,128,296,framebuf.MONO_HLSB)
|
||||
|
||||
# While till the BUSY pin is high (chip no longer busy), and
|
||||
# the chip completed its operation.
|
||||
def wait_ready(self):
|
||||
if self.busy == None: return
|
||||
while not self.busy.value(): pass
|
||||
|
||||
# Perform hardware reset.
|
||||
def reset(self):
|
||||
self.rst.off()
|
||||
time.sleep_ms(10)
|
||||
self.rst.on()
|
||||
time.sleep_ms(10)
|
||||
self.wait_ready()
|
||||
|
||||
# Send just a command, just data, or a command + data, depending
|
||||
# on cmd or data being both bytes() / bytearrays() or None.
|
||||
def write(self,cmd=None,data=None):
|
||||
self.cs.off()
|
||||
self.dc.off() # Command mode
|
||||
self.spi.write(bytes([cmd]))
|
||||
if data:
|
||||
if isinstance(data,int): data = bytes([data])
|
||||
if isinstance(data,list): data = bytes(data)
|
||||
self.dc.on() # Data mode
|
||||
self.spi.write(data)
|
||||
self.cs.on()
|
||||
|
||||
def initialize_display(self):
|
||||
self.reset()
|
||||
psr_settings = RES_128x296 | FORMAT_BW | BOOSTER_ON | RESET_NONE
|
||||
# If we select the default update speed, we will use the
|
||||
# lookup tables defined by the device. Otherwise the values for
|
||||
# the lookup tables must be read from the registers we set.
|
||||
if self.speed == UPDATE_SPEED_DEFAULT:
|
||||
psr_settings |= LUT_OTP
|
||||
else:
|
||||
psr_settings |= LUT_REG
|
||||
|
||||
psr_settings |= SHIFT_LEFT if self.mirror_x else SHIFT_RIGHT
|
||||
psr_settings |= SCAN_DOWN if self.mirror_y else SCAN_UP
|
||||
|
||||
self.write(CMD_PSR,psr_settings)
|
||||
self.write(CMD_PWR, \
|
||||
[VDS_INTERNAL|VDG_INTERNAL,
|
||||
VCOM_VD|VGHL_16V,
|
||||
0b101011,
|
||||
0b101011,
|
||||
0b101011])
|
||||
self.write(CMD_PON)
|
||||
self.wait_ready()
|
||||
|
||||
# Booster soft start configuration.
|
||||
self.write(CMD_BTST, \
|
||||
[START_10MS | STRENGTH_3 | OFF_6_58US,
|
||||
START_10MS | STRENGTH_3 | OFF_6_58US,
|
||||
START_10MS | STRENGTH_3 | OFF_6_58US])
|
||||
|
||||
self.write(CMD_PFS,FRAMES_1)
|
||||
self.write(CMD_TSE,TEMP_INTERNAL | OFFSET_0)
|
||||
self.write(CMD_TCON,0x22)
|
||||
self.write(CMD_CDI,0b10_01_1100 if self.inverted else 0b01_00_1100)
|
||||
self.write(CMD_PLL,HZ_100)
|
||||
self.write(CMD_PON)
|
||||
self.wait_ready()
|
||||
|
||||
def update(self):
|
||||
self.write(CMD_PON)
|
||||
self.write(CMD_PTOU)
|
||||
self.write(CMD_DTM2,self.raw_fb)
|
||||
self.write(CMD_DSP)
|
||||
self.write(CMD_DRF) # Refresh
|
||||
|
||||
if __name__ == "__main__":
|
||||
from machine import SPI
|
||||
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.fb.ellipse(10,10,10,10,1)
|
||||
eink.fb.ellipse(50,50,10,10,1)
|
||||
eink.fb.text("SUKA",80,80,1)
|
||||
eink.update()
|
||||
Reference in New Issue
Block a user