Skip to content

Commit 275eff1

Browse files
committed
save data in bytearray prior to send (speed up factor >5)
1 parent 86759f4 commit 275eff1

File tree

1 file changed

+150
-131
lines changed

1 file changed

+150
-131
lines changed

epaper4in2.py

Lines changed: 150 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2424
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2525
SOFTWARE.
26+
27+
28+
Edit Schnoog:
29+
Data is collected into a bytearray and sent at once.
30+
Suitable for ESP32 with SPIRAM. Speed up
31+
2632
"""
2733

2834
from micropython import const
@@ -34,140 +40,153 @@
3440
EPD_HEIGHT = const(300)
3541

3642
# Display commands
37-
PANEL_SETTING = const(0x00)
38-
POWER_SETTING = const(0x01)
39-
POWER_OFF = const(0x02)
40-
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
41-
POWER_ON = const(0x04)
42-
#POWER_ON_MEASURE = const(0x05)
43-
BOOSTER_SOFT_START = const(0x06)
44-
DEEP_SLEEP = const(0x07)
45-
DATA_START_TRANSMISSION_1 = const(0x10)
46-
#DATA_STOP = const(0x11)
47-
DISPLAY_REFRESH = const(0x12)
48-
DATA_START_TRANSMISSION_2 = const(0x13)
49-
LUT_FOR_VCOM = const(0x20)
50-
LUT_WHITE_TO_WHITE = const(0x21)
51-
LUT_BLACK_TO_WHITE = const(0x22)
52-
LUT_WHITE_TO_BLACK = const(0x23)
53-
LUT_BLACK_TO_BLACK = const(0x24)
54-
PLL_CONTROL = const(0x30)
55-
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
43+
PANEL_SETTING = const(0x00)
44+
POWER_SETTING = const(0x01)
45+
POWER_OFF = const(0x02)
46+
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
47+
POWER_ON = const(0x04)
48+
#POWER_ON_MEASURE = const(0x05)
49+
BOOSTER_SOFT_START = const(0x06)
50+
DEEP_SLEEP = const(0x07)
51+
DATA_START_TRANSMISSION_1 = const(0x10)
52+
#DATA_STOP = const(0x11)
53+
DISPLAY_REFRESH = const(0x12)
54+
DATA_START_TRANSMISSION_2 = const(0x13)
55+
LUT_FOR_VCOM = const(0x20)
56+
LUT_WHITE_TO_WHITE = const(0x21)
57+
LUT_BLACK_TO_WHITE = const(0x22)
58+
LUT_WHITE_TO_BLACK = const(0x23)
59+
LUT_BLACK_TO_BLACK = const(0x24)
60+
PLL_CONTROL = const(0x30)
61+
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
5662
#TEMPERATURE_SENSOR_SELECTION = const(0x41)
57-
#TEMPERATURE_SENSOR_WRITE = const(0x42)
58-
#TEMPERATURE_SENSOR_READ = const(0x43)
63+
#TEMPERATURE_SENSOR_WRITE = const(0x42)
64+
#TEMPERATURE_SENSOR_READ = const(0x43)
5965
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
60-
#LOW_POWER_DETECTION = const(0x51)
61-
#TCON_SETTING = const(0x60)
62-
RESOLUTION_SETTING = const(0x61)
63-
#GSST_SETTING = const(0x65)
64-
#GET_STATUS = const(0x71)
65-
#AUTO_MEASUREMENT_VCOM = const(0x80)
66-
#READ_VCOM_VALUE = const(0x81)
67-
VCM_DC_SETTING = const(0x82)
68-
#PARTIAL_WINDOW = const(0x90)
69-
#PARTIAL_IN = const(0x91)
70-
#PARTIAL_OUT = const(0x92)
71-
72-
#PROGRAM_MODE = const(0xA0)
73-
#ACTIVE_PROGRAMMING = const(0xA1)
74-
#READ_OTP = const(0xA2)
75-
#POWER_SAVING = const(0xE3)
66+
#LOW_POWER_DETECTION = const(0x51)
67+
#TCON_SETTING = const(0x60)
68+
RESOLUTION_SETTING = const(0x61)
69+
#GSST_SETTING = const(0x65)
70+
#GET_STATUS = const(0x71)
71+
#AUTO_MEASUREMENT_VCOM = const(0x80)
72+
#READ_VCOM_VALUE = const(0x81)
73+
VCM_DC_SETTING = const(0x82)
74+
#PARTIAL_WINDOW = const(0x90)
75+
#PARTIAL_IN = const(0x91)
76+
#PARTIAL_OUT = const(0x92)
77+
78+
#PROGRAM_MODE = const(0xA0)
79+
#ACTIVE_PROGRAMMING = const(0xA1)
80+
#READ_OTP = const(0xA2)
81+
#POWER_SAVING = const(0xE3)
7682

7783
BUSY = const(0) # 0=busy, 1=idle
7884

7985
class EPD:
80-
def __init__(self, spi, cs, dc, rst, busy):
81-
self.spi = spi
82-
self.cs = cs
83-
self.dc = dc
84-
self.rst = rst
85-
self.busy = busy
86-
self.cs.init(self.cs.OUT, value=1)
87-
self.dc.init(self.dc.OUT, value=0)
88-
self.rst.init(self.rst.OUT, value=0)
89-
self.busy.init(self.busy.IN)
90-
self.width = EPD_WIDTH
91-
self.height = EPD_HEIGHT
92-
93-
# 44/42 bytes (look up tables)
94-
LUT_VCOM0 = bytearray(b'\x00\x17\x00\x00\x00\x02\x00\x17\x17\x00\x00\x02\x00\x0A\x01\x00\x00\x01\x00\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
95-
LUT_WW = bytearray(b'\x40\x17\x00\x00\x00\x02\x90\x17\x17\x00\x00\x02\x40\x0A\x01\x00\x00\x01\xA0\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
96-
LUT_BW = LUT_WW
97-
LUT_BB = bytearray(b'\x80\x17\x00\x00\x00\x02\x90\x17\x17\x00\x00\x02\x80\x0A\x01\x00\x00\x01\x50\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
98-
LUT_WB = LUT_BB
99-
100-
def _command(self, command, data=None):
101-
self.dc(0)
102-
self.cs(0)
103-
self.spi.write(bytearray([command]))
104-
self.cs(1)
105-
if data is not None:
106-
self._data(data)
107-
108-
def _data(self, data):
109-
self.dc(1)
110-
self.cs(0)
111-
self.spi.write(data)
112-
self.cs(1)
113-
114-
def init(self):
115-
self.reset()
116-
self._command(POWER_SETTING, b'\x03\x00\x2B\x2B\xFF') # VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR
117-
self._command(BOOSTER_SOFT_START, b'\x17\x17\x17') # 07 0f 17 1f 27 2F 37 2f
118-
self._command(POWER_ON)
119-
self.wait_until_idle()
120-
self._command(PANEL_SETTING, b'\xBF\x0B') # KW-BF KWR-AF BWROTP 0f
121-
self._command(PLL_CONTROL, b'\x3C') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
122-
123-
def wait_until_idle(self):
124-
while self.busy.value() == BUSY:
125-
sleep_ms(100)
126-
127-
def reset(self):
128-
self.rst(0)
129-
sleep_ms(200)
130-
self.rst(1)
131-
sleep_ms(200)
132-
133-
def set_lut(self):
134-
self._command(LUT_FOR_VCOM, self.LUT_VCOM0) # vcom
135-
self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww --
136-
self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r
137-
self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w
138-
self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b
139-
140-
# draw the current frame memory
141-
def display_frame(self, frame_buffer):
142-
self._command(RESOLUTION_SETTING, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT))
143-
self._command(VCM_DC_SETTING, b'\x12')
144-
self._command(VCOM_AND_DATA_INTERVAL_SETTING)
145-
self._command(0x97) # VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7
146-
# TODO should ^ this be _data(0x97), not sure what it does
147-
148-
if (frame_buffer != None):
149-
self._command(DATA_START_TRANSMISSION_1)
150-
for i in range(0, self.width * self.height // 8):
151-
self._data(bytearray([0xFF])) # bit set: white, bit reset: black
152-
sleep_ms(2)
153-
self._command(DATA_START_TRANSMISSION_2)
154-
for i in range(0, self.width * self.height // 8):
155-
self._data(bytearray([frame_buffer[i]]))
156-
sleep_ms(2)
157-
158-
self.set_lut()
159-
self._command(DISPLAY_REFRESH)
160-
sleep_ms(100)
161-
self.wait_until_idle()
162-
163-
# to wake call reset() or init()
164-
def sleep(self):
165-
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x17') # border floating
166-
self._command(VCM_DC_SETTING) # VCOM to 0V
167-
self._command(PANEL_SETTING)
168-
sleep_ms(100)
169-
self._command(POWER_SETTING, b'\x00\x00\x00\x00\x00') # VG&VS to 0V fast
170-
sleep_ms(100)
171-
self._command(POWER_OFF)
172-
self.wait_until_idle()
173-
self._command(DEEP_SLEEP, b'\xA5')
86+
def __init__(self, spi, cs, dc, rst, busy):
87+
self.spi = spi
88+
self.cs = cs
89+
self.dc = dc
90+
self.rst = rst
91+
self.busy = busy
92+
self.cs.init(self.cs.OUT, value=1)
93+
self.dc.init(self.dc.OUT, value=0)
94+
self.rst.init(self.rst.OUT, value=0)
95+
self.busy.init(self.busy.IN)
96+
self.width = EPD_WIDTH
97+
self.height = EPD_HEIGHT
98+
99+
# 44/42 bytes (look up tables)
100+
LUT_VCOM0 = bytearray(b'\x00\x17\x00\x00\x00\x02\x00\x17\x17\x00\x00\x02\x00\x0A\x01\x00\x00\x01\x00\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
101+
LUT_WW = bytearray(b'\x40\x17\x00\x00\x00\x02\x90\x17\x17\x00\x00\x02\x40\x0A\x01\x00\x00\x01\xA0\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
102+
LUT_BW = LUT_WW
103+
LUT_BB = bytearray(b'\x80\x17\x00\x00\x00\x02\x90\x17\x17\x00\x00\x02\x80\x0A\x01\x00\x00\x01\x50\x0E\x0E\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
104+
LUT_WB = LUT_BB
105+
106+
def _command(self, command, data=None):
107+
self.dc(0)
108+
self.cs(0)
109+
self.spi.write(bytearray([command]))
110+
self.cs(1)
111+
if data is not None:
112+
self._data(data)
113+
114+
def _data(self, data):
115+
116+
self.spi.write(data)
117+
#self.cs(1)
118+
119+
def init(self):
120+
self.reset()
121+
self._command(POWER_SETTING, b'\x03\x00\x2B\x2B\xFF') # VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR
122+
self._command(BOOSTER_SOFT_START, b'\x17\x17\x17') # 07 0f 17 1f 27 2F 37 2f
123+
self._command(POWER_ON)
124+
self.wait_until_idle()
125+
self._command(PANEL_SETTING, b'\xBF\x0B') # KW-BF KWR-AF BWROTP 0f
126+
self._command(PLL_CONTROL, b'\x3C') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
127+
128+
def wait_until_idle(self):
129+
while self.busy.value() == BUSY:
130+
sleep_ms(10)
131+
132+
def reset(self):
133+
self.rst(0)
134+
sleep_ms(20)
135+
self.rst(1)
136+
sleep_ms(20)
137+
138+
def set_lut(self):
139+
self._command(LUT_FOR_VCOM, self.LUT_VCOM0) # vcom
140+
self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww --
141+
self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r
142+
self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w
143+
self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b
144+
145+
# draw the current frame memory
146+
def display_frame(self, frame_buffer):
147+
self._command(RESOLUTION_SETTING, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT))
148+
self._command(VCM_DC_SETTING, b'\x12')
149+
self._command(VCOM_AND_DATA_INTERVAL_SETTING)
150+
self._command(0x97) # VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7
151+
# TODO should ^ this be _data(0x97), not sure what it does
152+
153+
if (frame_buffer != None):
154+
self._command(DATA_START_TRANSMISSION_1)
155+
self.dc(1)
156+
self.cs(0)
157+
msg = bytearray()
158+
print("PrepareBlank")
159+
for i in range(0, self.width * self.height // 8):
160+
msg.extend(bytearray([0xFF]))
161+
print("Send blank")
162+
self._data(msg)
163+
self.cs(1)
164+
sleep_ms(20)
165+
self._command(DATA_START_TRANSMISSION_2)
166+
self.dc(1)
167+
self.cs(0)
168+
print("Prepare data")
169+
msg = bytearray()
170+
for i in range(0, self.width * self.height // 8):
171+
msg.extend(bytearray([frame_buffer[i]]))
172+
print("Send data")
173+
self._data(msg)
174+
self.cs(1)
175+
sleep_ms(20)
176+
177+
self.set_lut()
178+
self._command(DISPLAY_REFRESH)
179+
sleep_ms(10)
180+
self.wait_until_idle()
181+
182+
# to wake call reset() or init()
183+
def sleep(self):
184+
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x17') # border floating
185+
self._command(VCM_DC_SETTING) # VCOM to 0V
186+
self._command(PANEL_SETTING)
187+
sleep_ms(100)
188+
self._command(POWER_SETTING, b'\x00\x00\x00\x00\x00') # VG&VS to 0V fast
189+
sleep_ms(100)
190+
self._command(POWER_OFF)
191+
self.wait_until_idle()
192+
self._command(DEEP_SLEEP, b'\xA5')

0 commit comments

Comments
 (0)