pull/3/head
Mike Causer 2018-02-24 02:38:02 +11:00
commit ca8a532054
22 zmienionych plików z 2412 dodań i 0 usunięć

22
LICENSE.txt 100644
Wyświetl plik

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2017 Waveshare
Copyright (c) 2018 Mike Causer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

32
README.md 100644
Wyświetl plik

@ -0,0 +1,32 @@
# MicroPython Waveshare e-Paper
MicroPython drivers for various Waveshare e-Paper displays, based on the original Waveshare Raspberry Pi examples found in the [wiki](https://www.waveshare.com/wiki/Main_Page).
![demo](docs/demo.jpg)
| Waveshare e-Paper Module | Colors | Grey Level | Resolution px | Display mm | Outline mm | Partial Refresh | Full Refresh | Interface | Pi Header | Controller | Display |
| ----------------------------------------------------------------------------------------- | -------------------- |:----------:|:-------------:|:--------------:|:-------------:|:---------------:|:------------:|:---------:|:---------:|:-----------|:----------------------------------------------------------------------------------------------------------------------------------------------------:|
| [1.54inch e-Paper Module](https://www.waveshare.com/wiki/1.54inch_e-Paper_Module) | Black, White | 2 | 200 × 200 | 27.60 × 27.60 | 48.0 × 33.0 | 0.3 | 2 | SPI | No | ? | [GDEH0154D27](http://www.eink-display.com/new-1-54-inch-partial-refresh-bi-stable-e0154a05-e-paper-display-electronic-paper-screen-gdeh0154d27.html) |
| [1.54inch e-Paper Module (B)](https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B)) | Black, White, Red | 2 | 200 × 200 | 27.60 × 27.60 | 48.0 × 33.0 | N/A | 8 | SPI | No | ? | [GDEW0154Z04](http://www.eink-display.com/1-54-inch-3-color-ultra-low-power-consumption-e-paper-display-screen-spi-interface-gdew0154z04.html) |
| [1.54inch e-Paper Module (C)](https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(C)) | Black, White, Yellow | 2 | 152 × 152 | 27.51 × 27.51 | 48.0 × 33.0 | N/A | 27 | SPI | No | ? | [GDEW0154C39](http://www.eink-display.com/new-1-54-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew0154c39.html) |
| [2.13inch e-Paper HAT](https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT) | Black, White | 2 | 250 × 122 | 48.55 × 23.71 | 65.0 × 30.2 | 0.3 | 2 | SPI | Yes | IL3895 | [GDEH0213B1](http://www.eink-display.com/new-2-13-inch-partial-refresh-e-paper-display-250x122-electronic-paper-screen-gdeh0213b1.html) |
| [2.13inch e-Paper HAT (B)](https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT_(B)) | Black, White, Red | 2 | 212 × 104 | 48.55 × 23.71 | 65.0 × 30.2 | N/A | 15 | SPI | Yes | ? | [GDEW0213Z16](http://www.eink-display.com/2-13-inch-three-color-low-power-e-paper-display-electronic-paper-screen-gdew0213z16.html) |
| [2.13inch e-Paper HAT (C)](https://www.waveshare.com/wiki/2.13inch_e-Paper_HAT_(C)) | Black, White, Yellow | 2 | 212 × 104 | 48.55 × 23.71 | 65.0 × 30.2 | N/A | 15 | SPI | Yes | ? | [GDEW0213C38](http://www.eink-display.com/new-2-13-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew0213c38.html) |
| [2.7inch e-Paper HAT](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT) | Black, White | 2 | 264 × 176 | 57.29 × 38.19 | 85.0 × 56.0 | N/A | 6 | SPI | Yes | ? | [GDEW027W3](http://www.eink-display.com/2-7-inch-ultra-low-power-consumption-high-contrast-small-size-electronic-paper-display-gdew027w3.html) |
| [2.7inch e-Paper HAT (B)](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT_(B)) | Black, White, Red | 2 | 264 × 176 | 57.29 × 38.19 | 85.0 × 56.0 | N/A | 15 | SPI | Yes | ? | [GDEW027C44](http://www.eink-display.com/2-7-inch-three-color-low-power-consumption-bi-stable-electronic-paper-screen-gdew027c44.html) |
| [2.9inch e-Paper Module](https://www.waveshare.com/wiki/2.9inch_e-Paper_Module) | Black, White | 2 | 296 × 128 | 66.89 × 29.05 | 89.5 × 38.0 | 0.3 | 2 | SPI | No | IL3820 | [GDEH029A1](http://www.eink-display.com/2-9-inch-partial-update-bi-stable-e-paper-display-electronic-paper-screen-gdeh029a1.html) |
| [2.9inch e-Paper Module (B)](https://www.waveshare.com/wiki/2.9inch_e-Paper_Module_(B)) | Black, White, Red | 2 | 296 × 128 | 66.89 × 29.05 | 89.5 × 38.0 | N/A | 15 | SPI | No | IL3820? | [GDEW029Z10](http://www.eink-display.com/2-9-inch-three-color-bi-stable-e-paper-display-electronic-paper-screen-gdew029z10.html) |
| [2.9inch e-Paper Module (C)](https://www.waveshare.com/wiki/2.9inch_e-Paper_Module_(C)) | Black, White, Yellow | 2 | 296 × 128 | 66.89 × 29.05 | 89.5 × 38.0 | N/A | 15 | SPI | No | IL3820? | [GDEW029C32](http://www.eink-display.com/new-2-9-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew029c32.html) |
| [4.2inch e-Paper Module](https://www.waveshare.com/wiki/4.2inch_e-Paper_Module) | Black, White | 2 | 400 × 300 | 84.80 × 63.60 | 103.0 × 78.5 | N/A | 4 | SPI | No | ? | [GDEW042T2](http://www.eink-display.com/4-2-inch-ultra-low-power-consumption-400x300-resolution-electronic-paper-screen-gdew042t2.html) |
| [4.2inch e-Paper Module (B)](https://www.waveshare.com/wiki/4.2inch_e-Paper_Module_(B)) | Black, White, Red | 2 | 400 × 300 | 84.80 × 63.60 | 103.0 × 78.5 | N/A | 15 | SPI | No | ? | [GDEW042Z15](http://www.eink-display.com/4-2-inch-three-color-bi-stable-electronic-paper-screen-gdew042z15.html) |
| [4.2inch e-Paper Module (C)](https://www.waveshare.com/wiki/4.2inch_e-Paper_Module_(C)) | Black, White, Yellow | 2 | 400 × 300 | 84.80 × 63.60 | 103.0 × 78.5 | N/A | 15 | SPI | No | ? | [GDEW042C37](http://www.eink-display.com/new-4-2-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew042c37.html) |
| [4.3inch e-Paper UART Module](https://www.waveshare.com/wiki/4.3inch_e-Paper_UART_Module) | Black, White | 4 | 800 × 600 | 88.00 × 66.00 | 118.0 × 75.0 | N/A | 1.5 | UART | No | ? | [GDE043A2](http://www.eink-display.com/4-3-inch-low-power-e-paper-display-electronic-paper-screen-gde043a2.html) |
| [7.5inch e-Paper HAT](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT) | Black, White | 2 | 600 × 384 | 163.20 × 97.92 | 170.2 × 111.2 | N/A | 6 | SPI | Yes | ? | [GDEW075T8](http://www.eink-display.com/7-5-inch-large-size-ultra-wide-viewing-angle-bi-stable-e-paper-display-e-paper-monitor-gdew075t8.html) |
| [7.5inch e-Paper HAT (B)](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT_(B)) | Black, White, Red | 2 | 170.2 × 111.2 | 163.20 × 97.92 | 170.2 × 111.2 | N/A | 31 | SPI | Yes | ? | [GDEW075Z09](http://www.eink-display.com/7-5-inch-large-size-three-color-bi-stable-e-paper-display-e-paper-monitor-gdew075z09.html) |
| [7.5inch e-Paper HAT (C)](https://www.waveshare.com/wiki/7.5inch_e-Paper_HAT_(C)) | Black, White, Yellow | 2 | 640 × 384 | 163.20 × 97.92 | 170.2 × 111.2 | N/A | 31 | SPI | Yes | ? | [GDEW075C21](http://www.eink-display.com/new-7-5-inch-bwy-three-colors-e-ink-e-paper-display-panel-black-write-and-yellow-gdew075c21.html) |
## Links
* [Waveshare Wiki](https://www.waveshare.com/wiki/Main_Page)
* [micropython.org](http://micropython.org)
* [Docs on framebuf](http://docs.micropython.org/en/latest/pyboard/library/framebuf.html)

BIN
docs/demo.jpg 100644

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 244 KiB

146
epaper1in54.py 100644
Wyświetl plik

@ -0,0 +1,146 @@
# MicroPython library for Waveshare 1.54" B/W e-paper display GDEH0154D27
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(200)
EPD_HEIGHT = const(200)
# Display commands
DRIVER_OUTPUT_CONTROL = const(0x01)
BOOSTER_SOFT_START_CONTROL = const(0x0C)
#GATE_SCAN_START_POSITION = const(0x0F)
DEEP_SLEEP_MODE = const(0x10)
DATA_ENTRY_MODE_SETTING = const(0x11)
#SW_RESET = const(0x12)
#TEMPERATURE_SENSOR_CONTROL = const(0x1A)
MASTER_ACTIVATION = const(0x20)
#DISPLAY_UPDATE_CONTROL_1 = const(0x21)
DISPLAY_UPDATE_CONTROL_2 = const(0x22)
WRITE_RAM = const(0x24)
WRITE_VCOM_REGISTER = const(0x2C)
WRITE_LUT_REGISTER = const(0x32)
SET_DUMMY_LINE_PERIOD = const(0x3A)
SET_GATE_TIME = const(0x3B) # not in datasheet
#BORDER_WAVEFORM_CONTROL = const(0x3C)
SET_RAM_X_ADDRESS_START_END_POSITION = const(0x44)
SET_RAM_Y_ADDRESS_START_END_POSITION = const(0x45)
SET_RAM_X_ADDRESS_COUNTER = const(0x4E)
SET_RAM_Y_ADDRESS_COUNTER = const(0x4F)
TERMINATE_FRAME_READ_WRITE = const(0xFF) # aka NOOP
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
LUT_FULL_UPDATE = bytearray(b'\x02\x02\x01\x11\x12\x12\x22\x22\x66\x69\x69\x59\x58\x99\x99\x88\x00\x00\x00\x00\xF8\xB4\x13\x51\x35\x51\x51\x19\x01\x00')
LUT_PARTIAL_UPDATE = bytearray(b'\x10\x18\x18\x08\x18\x18\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x14\x44\x12\x00\x00\x00\x00\x00\x00')
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(DRIVER_OUTPUT_CONTROL)
self._data(bytearray([(EPD_HEIGHT - 1) & 0xFF]))
self._data(bytearray([((EPD_HEIGHT - 1) >> 8) & 0xFF]))
self._data(bytearray([0x00])) # GD = 0 SM = 0 TB = 0
self._command(BOOSTER_SOFT_START_CONTROL, b'\xD7\xD6\x9D')
self._command(WRITE_VCOM_REGISTER, b'\xA8') # VCOM 7C
self._command(SET_DUMMY_LINE_PERIOD, b'\x1A') # 4 dummy lines per gate
self._command(SET_GATE_TIME, b'\x08') # 2us per line
self._command(DATA_ENTRY_MODE_SETTING, b'\x03') # X increment Y increment
self.set_lut(self.LUT_FULL_UPDATE)
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def set_lut(self, lut):
self._command(WRITE_LUT_REGISTER, lut)
# put an image in the frame memory
def set_frame_memory(self, image, x, y, w, h):
# x point must be the multiple of 8 or the last 3 bits will be ignored
x = x & 0xF8
w = w & 0xF8
if (x + w >= self.width):
x_end = self.width - 1
else:
x_end = x + w - 1
if (y + h >= self.height):
y_end = self.height - 1
else:
y_end = y + h - 1
self.set_memory_area(x, y, x_end, y_end)
self.set_memory_pointer(x, y)
self._command(WRITE_RAM, image)
# replace the frame memory with the specified color
def clear_frame_memory(self, color):
self.set_memory_area(0, 0, self.width - 1, self.height - 1)
self.set_memory_pointer(0, 0)
self._command(WRITE_RAM)
# send the color data
for i in range(0, self.width // 8 * self.height):
self._data(bytearray([color]))
# draw the current frame memory and switch to the next memory area
def display_frame(self):
self._command(DISPLAY_UPDATE_CONTROL_2, b'\xC4')
self._command(MASTER_ACTIVATION)
self._command(TERMINATE_FRAME_READ_WRITE)
self.wait_until_idle()
# specify the memory area for data R/W
def set_memory_area(self, x_start, y_start, x_end, y_end):
self._command(SET_RAM_X_ADDRESS_START_END_POSITION)
# x point must be the multiple of 8 or the last 3 bits will be ignored
self._data(bytearray([(x_start >> 3) & 0xFF]))
self._data(bytearray([(x_end >> 3) & 0xFF]))
self._command(SET_RAM_Y_ADDRESS_START_END_POSITION, ustruct.pack("<HH", y_start, y_end))
# specify the start point for data R/W
def set_memory_pointer(self, x, y):
self._command(SET_RAM_X_ADDRESS_COUNTER)
# x point must be the multiple of 8 or the last 3 bits will be ignored
self._data(bytearray([(x >> 3) & 0xFF]))
self._command(SET_RAM_Y_ADDRESS_COUNTER, ustruct.pack("<H", y))
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(DEEP_SLEEP_MODE, b'\x01') # enter deep sleep A0=1, A0=0 power on
self.wait_until_idle()

319
epaper1in54b.py 100644
Wyświetl plik

@ -0,0 +1,319 @@
# MicroPython library for Waveshare 1.54" B/W/R e-paper display GDEW0154Z04
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(200)
EPD_HEIGHT = const(200)
# Display commands
PANEL_SETTING = const(0x00) # in datasheet, but not in cmd table
POWER_SETTING = const(0x01)
POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03) # not in datasheet
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05) # not in datasheet
BOOSTER_SOFT_START = const(0x06)
#DEEP_SLEEP = const(0x07) # not in datasheet
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11) # not in datasheet
DISPLAY_REFRESH = const(0x12)
DATA_START_TRANSMISSION_2 = const(0x13)
VCOM_LUT = const(0x20) # VCOM LUT
W2W_LUT = const(0x21) # White LUT
B2W_LUT = const(0x22) # Black LUT
W2B_LUT = const(0x23) # not in datasheet
B2B_LUT = const(0x24) # not in datasheet
LUT_RED_0 = const(0x25) # Red VCOM LUT
LUT_RED_1 = const(0x26) # Red0 LUT
LUT_RED_2 = const(0x27) # RED1 LUT
#LUT_RED_3 = const(0x28) # not in datasheet
PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
#TEMPERATURE_SENSOR_CALIBRATION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51) # not in datasheet
#TCON_SETTING = const(0x60) # not in datasheet
TCON_RESOLUTION = const(0x61)
#SOURCE_AND_GATE_START_SETTING = const(0x62) # not in datasheet
#GET_STATUS = const(0x71) # in datasheet, but not in cmd table
#AUTO_MEASURE_VCOM = const(0x80) # not in datasheet
#VCOM_VALUE = const(0x81) # not in datasheet
VCM_DC_SETTING_REGISTER = const(0x82)
#PROGRAM_MODE = const(0xA0) # not in datasheet
#ACTIVE_PROGRAM = const(0xA1) # not in datasheet
#READ_OTP_DATA = const(0xA2) # not in datasheet
# Display orientation
ROTATE_0 = const(0)
ROTATE_90 = const(1)
ROTATE_180 = const(2)
ROTATE_270 = const(3)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.rotate = ROTATE_0
LUT_VCOM0 = bytearray(b'\x0E\x14\x01\x0A\x06\x04\x0A\x0A\x0F\x03\x03\x0C\x06\x0A\x00')
LUT_W = bytearray(b'\x0E\x14\x01\x0A\x46\x04\x8A\x4A\x0F\x83\x43\x0C\x86\x0A\x04')
LUT_B = bytearray(b'\x0E\x14\x01\x8A\x06\x04\x8A\x4A\x0F\x83\x43\x0C\x06\x4A\x04')
LUT_G1 = bytearray(b'\x8E\x94\x01\x8A\x06\x04\x8A\x4A\x0F\x83\x43\x0C\x06\x0A\x04')
LUT_G2 = LUT_G1
LUT_VCOM1 = bytearray(b'\x03\x1D\x01\x01\x08\x23\x37\x37\x01\x00\x00\x00\x00\x00\x00')
LUT_RED0 = bytearray(b'\x83\x5D\x01\x81\x48\x23\x77\x77\x01\x00\x00\x00\x00\x00\x00')
LUT_RED1 = LUT_VCOM1
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(POWER_SETTING, b'\x07\x00\x08\x00')
self._command(BOOSTER_SOFT_START, b'\x07\x07\x07')
self._command(POWER_ON)
self.wait_until_idle()
self._command(PANEL_SETTING, b'\xCF')
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x17') # for this panel, must be 0x17
self._command(PLL_CONTROL, b'\x39')
self._command(TCON_RESOLUTION, ustruct.pack(">BH", EPD_WIDTH, EPD_HEIGHT))
self._command(VCM_DC_SETTING_REGISTER, b'\x0E') # -1.4V
self.set_lut_bw()
self.set_lut_red()
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def set_lut_bw(self):
self._command(VCOM_LUT, self.LUT_VCOM0) # vcom
self._command(W2W_LUT, self.LUT_W) # ww --
self._command(B2W_LUT, self.LUT_B) # bw r
self._command(W2B_LUT, self.LUT_G1) # wb w
self._command(B2B_LUT, self.LUT_G2) # bb b
def set_lut_red(self):
self._command(LUT_RED_0, self.LUT_VCOM1)
self._command(LUT_RED_1, self.LUT_RED0)
self._command(LUT_RED_2, self.LUT_RED1)
def display_frame(self, frame_buffer_black, frame_buffer_red):
if (frame_buffer_black != None):
self._command(DATA_START_TRANSMISSION_1)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
temp = 0x00
for bit in range(0, 4):
if (frame_buffer_black[i] & (0x80 >> bit) != 0):
temp |= 0xC0 >> (bit * 2)
self._data(bytearray([temp]))
temp = 0x00
for bit in range(4, 8):
if (frame_buffer_black[i] & (0x80 >> bit) != 0):
temp |= 0xC0 >> ((bit - 4) * 2)
self._data(bytearray([temp]))
sleep_ms(2)
if (frame_buffer_red != None):
self._command(DATA_START_TRANSMISSION_2)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_red[i]]))
sleep_ms(2)
self._command(DISPLAY_REFRESH)
self.wait_until_idle()
def set_rotate(self, rotate):
if (rotate == ROTATE_0):
self.rotate = ROTATE_0
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
elif (rotate == ROTATE_90):
self.rotate = ROTATE_90
self.width = EPD_HEIGHT
self.height = EPD_WIDTH
elif (rotate == ROTATE_180):
self.rotate = ROTATE_180
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
elif (rotate == ROTATE_270):
self.rotate = ROTATE_270
self.width = EPD_HEIGHT
self.height = EPD_WIDTH
def set_pixel(self, frame_buffer, x, y, colored):
if (x < 0 or x >= self.width or y < 0 or y >= self.height):
return
if (self.rotate == ROTATE_0):
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_90):
point_temp = x
x = EPD_WIDTH - y
y = point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_180):
x = EPD_WIDTH - x
y = EPD_HEIGHT- y
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_270):
point_temp = x
x = y
y = EPD_HEIGHT - point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
def set_absolute_pixel(self, frame_buffer, x, y, colored):
# To avoid display orientation effects
# use EPD_WIDTH instead of self.width
# use EPD_HEIGHT instead of self.height
if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT):
return
if (colored):
frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8))
else:
frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8)
def display_string_at(self, frame_buffer, x, y, text, font, colored):
image = Image.new('1', (self.width, self.height))
draw = ImageDraw.Draw(image)
draw.text((x, y), text, font = font, fill = 255)
# Set buffer to value of Python Imaging Library image.
# Image must be in mode 1.
pixels = image.load()
for y in range(self.height):
for x in range(self.width):
# Set the bits for the column of pixels at the current position.
if pixels[x, y] != 0:
self.set_pixel(frame_buffer, x, y, colored)
def draw_line(self, frame_buffer, x0, y0, x1, y1, colored):
# Bresenham algorithm
dx = abs(x1 - x0)
sx = 1 if x0 < x1 else -1
dy = -abs(y1 - y0)
sy = 1 if y0 < y1 else -1
err = dx + dy
while((x0 != x1) and (y0 != y1)):
self.set_pixel(frame_buffer, x0, y0 , colored)
if (2 * err >= dy):
err += dy
x0 += sx
if (2 * err <= dx):
err += dx
y0 += sy
def draw_horizontal_line(self, frame_buffer, x, y, width, colored):
for i in range(x, x + width):
self.set_pixel(frame_buffer, i, y, colored)
def draw_vertical_line(self, frame_buffer, x, y, height, colored):
for i in range(y, y + height):
self.set_pixel(frame_buffer, x, i, colored)
def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored)
self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored)
self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored)
self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored)
def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
for i in range(min_x, max_x + 1):
self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored)
def draw_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
def draw_filled_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored)
self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored)
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
# to wake call reset() or init()
def sleep(self):
# TODO do we need to reset these here?
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x17') # for this panel, must be 0x17
self._command(VCM_DC_SETTING_REGISTER, b'\x00') # to solve Vcom drop
self._command(POWER_SETTING, b'\x02\x00\x00\x00') # gate switch to external
# /TODO
self.wait_until_idle()
self._command(POWER_OFF)

151
epaper2in13.py 100644
Wyświetl plik

@ -0,0 +1,151 @@
# MicroPython library for Waveshare 2.13" B/W e-paper display GDEH0213B1
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(128)
EPD_HEIGHT = const(250)
# datasheet says 250x122 (increased to 128 to be multiples of 8)
# Display commands
DRIVER_OUTPUT_CONTROL = const(0x01)
# Gate Driving Voltage Control 0x03
# Source Driving voltage Control 0x04
BOOSTER_SOFT_START_CONTROL = const(0x0C) # not in datasheet
#GATE_SCAN_START_POSITION = const(0x0F) # not in datasheet
DEEP_SLEEP_MODE = const(0x10)
DATA_ENTRY_MODE_SETTING = const(0x11)
#SW_RESET = const(0x12)
#TEMPERATURE_SENSOR_CONTROL = const(0x1A)
MASTER_ACTIVATION = const(0x20)
#DISPLAY_UPDATE_CONTROL_1 = const(0x21)
DISPLAY_UPDATE_CONTROL_2 = const(0x22)
# Panel Break Detection 0x23
WRITE_RAM = const(0x24)
WRITE_VCOM_REGISTER = const(0x2C)
# Status Bit Read 0x2F
WRITE_LUT_REGISTER = const(0x32)
SET_DUMMY_LINE_PERIOD = const(0x3A)
SET_GATE_TIME = const(0x3B)
#BORDER_WAVEFORM_CONTROL = const(0x3C)
SET_RAM_X_ADDRESS_START_END_POSITION = const(0x44)
SET_RAM_Y_ADDRESS_START_END_POSITION = const(0x45)
SET_RAM_X_ADDRESS_COUNTER = const(0x4E)
SET_RAM_Y_ADDRESS_COUNTER = const(0x4F)
TERMINATE_FRAME_READ_WRITE = const(0xFF) # not in datasheet, aka NOOP
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
LUT_FULL_UPDATE = bytearray(b'\x22\x55\xAA\x55\xAA\x55\xAA\x11\x00\x00\x00\x00\x00\x00\x00\x00\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x1E\x01\x00\x00\x00\x00\x00')
LUT_PARTIAL_UPDATE = bytearray(b'\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0F\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(DRIVER_OUTPUT_CONTROL)
self._data(bytearray([(EPD_HEIGHT - 1) & 0xFF]))
self._data(bytearray([((EPD_HEIGHT - 1) >> 8) & 0xFF]))
self._data(bytearray([0x00])) # GD = 0 SM = 0 TB = 0
self._command(BOOSTER_SOFT_START_CONTROL, b'\xD7\xD6\x9D')
self._command(WRITE_VCOM_REGISTER, b'\xA8') # VCOM 7C
self._command(SET_DUMMY_LINE_PERIOD, b'\x1A') # 4 dummy lines per gate
self._command(SET_GATE_TIME, b'\x08') # 2us per line
self._command(DATA_ENTRY_MODE_SETTING, b'\x03') # X increment Y increment
self.set_lut(self.LUT_FULL_UPDATE)
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def set_lut(self, lut):
self._command(WRITE_LUT_REGISTER, lut)
# put an image in the frame memory
def set_frame_memory(self, image, x, y, w, h):
# x point must be the multiple of 8 or the last 3 bits will be ignored
x = x & 0xF8
w = w & 0xF8
if (x + w >= self.width):
x_end = self.width - 1
else:
x_end = x + w - 1
if (y + h >= self.height):
y_end = self.height - 1
else:
y_end = y + h - 1
self.set_memory_area(x, y, x_end, y_end)
self.set_memory_pointer(x, y)
self._command(WRITE_RAM, image)
# replace the frame memory with the specified color
def clear_frame_memory(self, color):
self.set_memory_area(0, 0, self.width - 1, self.height - 1)
self.set_memory_pointer(0, 0)
self._command(WRITE_RAM)
# send the color data
for i in range(0, self.width // 8 * self.height):
self._data(bytearray([color]))
# draw the current frame memory and switch to the next memory area
def display_frame(self):
self._command(DISPLAY_UPDATE_CONTROL_2, b'\xC4')
self._command(MASTER_ACTIVATION)
self._command(TERMINATE_FRAME_READ_WRITE)
self.wait_until_idle()
# specify the memory area for data R/W
def set_memory_area(self, x_start, y_start, x_end, y_end):
self._command(SET_RAM_X_ADDRESS_START_END_POSITION)
# x point must be the multiple of 8 or the last 3 bits will be ignored
self._data(bytearray([(x_start >> 3) & 0xFF]))
self._data(bytearray([(x_end >> 3) & 0xFF]))
self._command(SET_RAM_Y_ADDRESS_START_END_POSITION, ustruct.pack("<HH", y_start, y_end))
# specify the start point for data R/W
def set_memory_pointer(self, x, y):
self._command(SET_RAM_X_ADDRESS_COUNTER)
# x point must be the multiple of 8 or the last 3 bits will be ignored
self._data(bytearray([(x >> 3) & 0xFF]))
self._command(SET_RAM_Y_ADDRESS_COUNTER, ustruct.pack("<H", y))
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(DEEP_SLEEP_MODE)
self.wait_until_idle()

281
epaper2in13b.py 100644
Wyświetl plik

@ -0,0 +1,281 @@
# MicroPython library for Waveshare 2.13" B/W/R e-paper display GDEW0213Z16
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(104)
EPD_HEIGHT = const(212)
# Display commands
PANEL_SETTING = const(0x00)
POWER_SETTING = const(0x01)
POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
#DEEP_SLEEP = const(0x07)
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
DATA_START_TRANSMISSION_2 = const(0x13)
#VCOM_LUT = const(0x20) # VCOM LUT(LUTC) (45-byte command, structure of bytes 2~7 repeated)
#W2W_LUT = const(0x21) # W2W LUT (LUTWW) (43-byte command, structure of bytes 2~7 repeated 7 times)
#B2W_LUT = const(0x22) # B2W LUT (LUTBW / LUTR) (43-byte command, structure of bytes 2~7 repeated 7 times)
#W2B_LUT = const(0x23) # W2B LUT (LUTWB / LUTW) (43-byte command, structure of bytes 2~7 repeated 7 times)
#B2B_LUT = const(0x24) # B2B LUT (LUTBB / LUTB) (43-byte command, sturcture of bytes 2~7 repeated 7 times)
#PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_CALIBRATION = const(0x40)
#TEMPERATURE_SENSOR_SELECTION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
#TCON_SETTING = const(0x60)
RESOLUTION_SETTING = const(0x61)
#GET_STATUS = const(0x71) # partial update status, i2c status, data received, power status, busy
#AUTO_MEASURE_VCOM = const(0x80)
#VCOM_VALUE = const(0x81)
VCM_DC_SETTING = const(0x82)
#PARTIAL_WINDOW = const(0x90)
#PARTIAL_IN = const(0x91)
#PARTIAL_OUT = const(0x92)
#PROGRAM_MODE = const(0xA0)
#ACTIVE_PROGRAM = const(0xA1)
#READ_OTP_DATA = const(0xA2)
#POWER_SAVING = const(0xE3)
# Display orientation
ROTATE_0 = const(0)
ROTATE_90 = const(1)
ROTATE_180 = const(2)
ROTATE_270 = const(3)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.rotate = ROTATE_0
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(BOOSTER_SOFT_START, b'\x17\x17\x17')
self._command(POWER_ON)
self.wait_until_idle()
self._command(PANEL_SETTING, b'\x8F') # (128x296, LUT from OTP, B/W/R, scan up, shift right, booster on)
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x37')
self._command(RESOLUTION_SETTING, ustruct.pack(">BH", EPD_WIDTH, EPD_HEIGHT))
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def display_frame(self, frame_buffer_black, frame_buffer_red):
if (frame_buffer_black != None):
self._command(DATA_START_TRANSMISSION_1)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_black[i]]))
sleep_ms(2)
if (frame_buffer_red != None):
self._command(DATA_START_TRANSMISSION_2)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_red[i]]))
sleep_ms(2)
self._command(DISPLAY_REFRESH)
self.wait_until_idle()
def set_rotate(self, rotate):
if (rotate == ROTATE_0):
self.rotate = ROTATE_0
self.width = epdif.EPD_WIDTH
self.height = epdif.EPD_HEIGHT
elif (rotate == ROTATE_90):
self.rotate = ROTATE_90
self.width = epdif.EPD_HEIGHT
self.height = epdif.EPD_WIDTH
elif (rotate == ROTATE_180):
self.rotate = ROTATE_180
self.width = epdif.EPD_WIDTH
self.height = epdif.EPD_HEIGHT
elif (rotate == ROTATE_270):
self.rotate = ROTATE_270
self.width = epdif.EPD_HEIGHT
self.height = epdif.EPD_WIDTH
def set_pixel(self, frame_buffer, x, y, colored):
if (x < 0 or x >= self.width or y < 0 or y >= self.height):
return
if (self.rotate == ROTATE_0):
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_90):
point_temp = x
x = epdif.EPD_WIDTH - y
y = point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_180):
x = epdif.EPD_WIDTH - x
y = epdif.EPD_HEIGHT- y
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_270):
point_temp = x
x = y
y = epdif.EPD_HEIGHT - point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
def set_absolute_pixel(self, frame_buffer, x, y, colored):
# To avoid display orientation effects
# use EPD_WIDTH instead of self.width
# use EPD_HEIGHT instead of self.height
if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT):
return
if (colored):
frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8))
else:
frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8)
def draw_string_at(self, frame_buffer, x, y, text, font, colored):
image = Image.new('1', (self.width, self.height))
draw = ImageDraw.Draw(image)
draw.text((x, y), text, font = font, fill = 255)
# Set buffer to value of Python Imaging Library image.
# Image must be in mode 1.
pixels = image.load()
for y in range(self.height):
for x in range(self.width):
# Set the bits for the column of pixels at the current position.
if pixels[x, y] != 0:
self.set_pixel(frame_buffer, x, y, colored)
def draw_line(self, frame_buffer, x0, y0, x1, y1, colored):
# Bresenham algorithm
dx = abs(x1 - x0)
sx = 1 if x0 < x1 else -1
dy = -abs(y1 - y0)
sy = 1 if y0 < y1 else -1
err = dx + dy
while((x0 != x1) and (y0 != y1)):
self.set_pixel(frame_buffer, x0, y0 , colored)
if (2 * err >= dy):
err += dy
x0 += sx
if (2 * err <= dx):
err += dx
y0 += sy
def draw_horizontal_line(self, frame_buffer, x, y, width, colored):
for i in range(x, x + width):
self.set_pixel(frame_buffer, i, y, colored)
def draw_vertical_line(self, frame_buffer, x, y, height, colored):
for i in range(y, y + height):
self.set_pixel(frame_buffer, x, i, colored)
def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored)
self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored)
self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored)
self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored)
def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
for i in range(min_x, max_x + 1):
self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored)
def draw_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
def draw_filled_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored)
self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored)
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
# to wake call reset() or init()
def sleep(self):
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x37')
self._command(VCM_DC_SETTING_REGISTER, b'\x00') # to solve Vcom drop
self._command(POWER_SETTING, b'\x02\x00\x00\x00') # gate switch to external
self.wait_until_idle()
self._command(POWER_OFF)

139
epaper2in7.py 100644
Wyświetl plik

@ -0,0 +1,139 @@
# MicroPython library for Waveshare 2.7" B/W e-paper display GDEW027W3
from micropython import const
from time import sleep_ms
# Display resolution
EPD_WIDTH = const(176)
EPD_HEIGHT = const(264)
# Display commands
PANEL_SETTING = const(0x00)
POWER_SETTING = const(0x01)
#POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
DEEP_SLEEP = const(0x07)
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
DATA_START_TRANSMISSION_2 = const(0x13) # not in datasheet
#PARTIAL_DATA_START_TRANSMISSION_1 = const(0x14)
#PARTIAL_DATA_START_TRANSMISSION_2 = const(0x15)
PARTIAL_DISPLAY_REFRESH = const(0x16)
LUT_FOR_VCOM = const(0x20) # LUT for VCOM(LUT1)
LUT_WHITE_TO_WHITE = const(0x21) # White to white LUT (LUTWW)
LUT_BLACK_TO_WHITE = const(0x22) # Black to white LUT (LUTBW/LUTR)
LUT_WHITE_TO_BLACK = const(0x23) # White to Black LUT (LUTWB/LUTW)
LUT_BLACK_TO_BLACK = const(0x24) # Black to Black LUT (LUTBB/LUTB)
PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
#TEMPERATURE_SENSOR_CALIBRATION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
#VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
#TCON_SETTING = const(0x60)
#TCON_RESOLUTION = const(0x61)
#SOURCE_AND_GATE_START_SETTING = const(0x62)
#GET_STATUS = const(0x71)
#AUTO_MEASURE_VCOM = const(0x80)
#VCOM_VALUE = const(0x81)
VCM_DC_SETTING_REGISTER = const(0x82)
#PROGRAM_MODE = const(0xA0)
#ACTIVE_PROGRAM = const(0xA1)
#READ_OTP_DATA = const(0xA2)
POWER_OPTIMIZATION = const(0xF8) # Power optimization in flow diagram
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
LUT_VCOM_DC = bytearray(b'\x00\x00\x00\x0F\x0F\x00\x00\x05\x00\x32\x32\x00\x00\x02\x00\x0F\x0F\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
LUT_WW = bytearray(b'\x50\x0F\x0F\x00\x00\x05\x60\x32\x32\x00\x00\x02\xA0\x0F\x0F\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # R21H
LUT_BW = LUT_BW # R22H r
LUT_BB = bytearray(b'\xA0\x0F\x0F\x00\x00\x05\x60\x32\x32\x00\x00\x02\x50\x0F\x0F\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') # R24H b
LUT_WB = LUT_BB # R23H w
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(POWER_SETTING, b'\x03\x00\x2B\x2B\x09') # VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR
self._command(BOOSTER_SOFT_START, b'\x07\x07\x17')
self._command(POWER_OPTIMIZATION, b'\x60\xA5')
self._command(POWER_OPTIMIZATION, b'\x89\xA5')
self._command(POWER_OPTIMIZATION, b'\x90\x00')
self._command(POWER_OPTIMIZATION, b'\x93\x2A')
self._command(POWER_OPTIMIZATION, b'\xA0\xA5')
self._command(POWER_OPTIMIZATION, b'\xA1\x00')
self._command(POWER_OPTIMIZATION, b'\x73\x41')
self._command(PARTIAL_DISPLAY_REFRESH, b'\x00')
self._command(POWER_ON)
self.wait_until_idle()
self._command(PANEL_SETTING, b'\xAF') # KW-BF KWR-AF BWROTP 0f
self._command(PLL_CONTROL, b'\x3A') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
self._command(VCM_DC_SETTING_REGISTER, b'\x12')
sleep_ms(2)
self.set_lut()
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def set_lut(self):
self._command(LUT_FOR_VCOM, self.LUT_VCOM_DC) # vcom
self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww --
self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r
self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w
self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b
# draw the current frame memory
def display_frame(self, frame_buffer):
if (frame_buffer != None):
self._command(DATA_START_TRANSMISSION_1)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([0xFF]))
sleep_ms(2)
self._command(DATA_START_TRANSMISSION_2)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer[i]]))
sleep_ms(2)
self._command(DISPLAY_REFRESH)
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(DEEP_SLEEP, b'\xA5')

302
epaper2in7b.py 100644
Wyświetl plik

@ -0,0 +1,302 @@
# MicroPython library for Waveshare 2.7" B/W/R e-paper display GDEW027C44
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(176)
EPD_HEIGHT = const(264)
# Display commands
PANEL_SETTING = const(0x00)
POWER_SETTING = const(0x01)
#POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
DEEP_SLEEP = const(0x07)
#DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
DATA_START_TRANSMISSION_2 = const(0x13)
#PARTIAL_DATA_START_TRANSMISSION_1 = const(0x14)
#PARTIAL_DATA_START_TRANSMISSION_2 = const(0x15)
PARTIAL_DISPLAY_REFRESH = const(0x16)
LUT_FOR_VCOM = const(0x20)
LUT_WHITE_TO_WHITE = const(0x21)
LUT_BLACK_TO_WHITE = const(0x22)
LUT_WHITE_TO_BLACK = const(0x23)
LUT_BLACK_TO_BLACK = const(0x24)
PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
#TEMPERATURE_SENSOR_CALIBRATION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
#TCON_SETTING = const(0x60)
TCON_RESOLUTION = const(0x61)
#SOURCE_AND_GATE_START_SETTING = const(0x62)
#GET_STATUS = const(0x71)
#AUTO_MEASURE_VCOM = const(0x80)
#VCOM_VALUE = const(0x81)
VCM_DC_SETTING_REGISTER = const(0x82)
#PROGRAM_MODE = const(0xA0)
#ACTIVE_PROGRAM = const(0xA1)
#READ_OTP_DATA = const(0xA2)
POWER_OPTIMIZATION = const(0xF8) # Power optimization in flow diagram
# Display orientation
ROTATE_0 = const(0)
ROTATE_90 = const(1)
ROTATE_180 = const(2)
ROTATE_270 = const(3)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.rotate = ROTATE_0
LUT_VCOM_DC = bytearray(b'\x00\x00\x00\x1A\x1A\x00\x00\x01\x00\x0A\x0A\x00\x00\x08\x00\x0E\x01\x0E\x01\x10\x00\x0A\x0A\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0E\x00\x00\x0A\x00\x23\x00\x00\x00\x01')
LUT_WW = bytearray(b'\x90\x1A\x1A\x00\x00\x01\x40\x0A\x0A\x00\x00\x08\x84\x0E\x01\x0E\x01\x10\x80\x0A\x0A\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0E\x00\x00\x0A\x00\x23\x00\x00\x00\x01') # R21H
LUT_BW = bytearray(b'\xA0\x1A\x1A\x00\x00\x01\x00\x0A\x0A\x00\x00\x08\x84\x0E\x01\x0E\x01\x10\x90\x0A\x0A\x00\x00\x08\xB0\x04\x10\x00\x00\x05\xB0\x03\x0E\x00\x00\x0A\xC0\x23\x00\x00\x00\x01') # R22H r
LUT_BB = LUT_WW # R23H w
LUT_WB = bytearray(b'\x90\x1A\x1A\x00\x00\x01\x20\x0A\x0A\x00\x00\x08\x84\x0E\x01\x0E\x01\x10\x10\x0A\x0A\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0E\x00\x00\x0A\x00\x23\x00\x00\x00\x01') # R24H b
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(POWER_ON)
self.wait_until_idle()
self._command(PANEL_SETTING, b'\xAF') # (296x160, LUT from register, B/W/R run both LU1 LU2, scan up, shift right, bootster on) KW-BF KWR-AF BWROTP 0f
self._command(PLL_CONTROL, b'\x3A') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
self._command(POWER_SETTING, b'\x03\x00\x2b\x2b\x09') # VDS_EN VDG_EN, VCOM_HV VGHL_LV[1] VGHL_LV[0], VDH, VDL, VDHR
self._command(BOOSTER_SOFT_START, b'\x07\x07\x17')
self._command(POWER_OPTIMIZATION, b'\x60\xA5')
self._command(POWER_OPTIMIZATION, b'\x89\xA5')
self._command(POWER_OPTIMIZATION, b'\x90\x00')
self._command(POWER_OPTIMIZATION, b'\x93\x2A')
self._command(POWER_OPTIMIZATION, b'\x73\x41')
self._command(VCM_DC_SETTING_REGISTER, b'\x12')
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x87') # define by OTP
self.set_lut()
self._command(PARTIAL_DISPLAY_REFRESH, b'\x00')
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def set_lut(self):
self._command(LUT_FOR_VCOM, self.LUT_VCOM_DC) # vcom
self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww --
self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r
self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w
self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b
def display_frame(self, frame_buffer_black, frame_buffer_red):
self._command(TCON_RESOLUTION, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT))
if (frame_buffer_black != None):
self._command(DATA_START_TRANSMISSION_1)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_black[i]]))
sleep_ms(2)
if (frame_buffer_red != None):
self._command(DATA_START_TRANSMISSION_2)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_red[i]]))
sleep_ms(2)
self._command(DISPLAY_REFRESH)
self.wait_until_idle()
def set_rotate(self, rotate):
if (rotate == ROTATE_0):
self.rotate = ROTATE_0
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
elif (rotate == ROTATE_90):
self.rotate = ROTATE_90
self.width = EPD_HEIGHT
self.height = EPD_WIDTH
elif (rotate == ROTATE_180):
self.rotate = ROTATE_180
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
elif (rotate == ROTATE_270):
self.rotate = ROTATE_270
self.width = EPD_HEIGHT
self.height = EPD_WIDTH
def set_pixel(self, frame_buffer, x, y, colored):
if (x < 0 or x >= self.width or y < 0 or y >= self.height):
return
if (self.rotate == ROTATE_0):
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_90):
point_temp = x
x = EPD_WIDTH - y
y = point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_180):
x = EPD_WIDTH - x
y = EPD_HEIGHT- y
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_270):
point_temp = x
x = y
y = EPD_HEIGHT - point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
def set_absolute_pixel(self, frame_buffer, x, y, colored):
# To avoid display orientation effects
# use EPD_WIDTH instead of self.width
# use EPD_HEIGHT instead of self.height
if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT):
return
if (colored):
frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8)
else:
frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8))
def draw_string_at(self, frame_buffer, x, y, text, font, colored):
image = Image.new('1', (self.width, self.height))
draw = ImageDraw.Draw(image)
draw.text((x, y), text, font = font, fill = 255)
# Set buffer to value of Python Imaging Library image.
# Image must be in mode 1.
pixels = image.load()
for y in range(self.height):
for x in range(self.width):
# Set the bits for the column of pixels at the current position.
if pixels[x, y] != 0:
self.set_pixel(frame_buffer, x, y, colored)
def draw_line(self, frame_buffer, x0, y0, x1, y1, colored):
# Bresenham algorithm
dx = abs(x1 - x0)
sx = 1 if x0 < x1 else -1
dy = -abs(y1 - y0)
sy = 1 if y0 < y1 else -1
err = dx + dy
while((x0 != x1) and (y0 != y1)):
self.set_pixel(frame_buffer, x0, y0 , colored)
if (2 * err >= dy):
err += dy
x0 += sx
if (2 * err <= dx):
err += dx
y0 += sy
def draw_horizontal_line(self, frame_buffer, x, y, width, colored):
for i in range(x, x + width):
self.set_pixel(frame_buffer, i, y, colored)
def draw_vertical_line(self, frame_buffer, x, y, height, colored):
for i in range(y, y + height):
self.set_pixel(frame_buffer, x, i, colored)
def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored)
self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored)
self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored)
self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored)
def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
for i in range(min_x, max_x + 1):
self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored)
def draw_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
def draw_filled_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored);
self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored);
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
# to wake call reset() or init()
def sleep(self):
self._command(DEEP_SLEEP, b'\xA5')

149
epaper2in9.py 100644
Wyświetl plik

@ -0,0 +1,149 @@
# MicroPython library for Waveshare 2.9" B/W e-paper display GDEH029A1
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(128)
EPD_HEIGHT = const(296)
# Display commands
DRIVER_OUTPUT_CONTROL = const(0x01)
BOOSTER_SOFT_START_CONTROL = const(0x0C)
#GATE_SCAN_START_POSITION = const(0x0F)
DEEP_SLEEP_MODE = const(0x10)
DATA_ENTRY_MODE_SETTING = const(0x11)
#SW_RESET = const(0x12)
#TEMPERATURE_SENSOR_CONTROL = const(0x1A)
MASTER_ACTIVATION = const(0x20)
#DISPLAY_UPDATE_CONTROL_1 = const(0x21)
DISPLAY_UPDATE_CONTROL_2 = const(0x22)
WRITE_RAM = const(0x24)
WRITE_VCOM_REGISTER = const(0x2C)
WRITE_LUT_REGISTER = const(0x32)
SET_DUMMY_LINE_PERIOD = const(0x3A)
SET_GATE_TIME = const(0x3B)
#BORDER_WAVEFORM_CONTROL = const(0x3C)
SET_RAM_X_ADDRESS_START_END_POSITION = const(0x44)
SET_RAM_Y_ADDRESS_START_END_POSITION = const(0x45)
SET_RAM_X_ADDRESS_COUNTER = const(0x4E)
SET_RAM_Y_ADDRESS_COUNTER = const(0x4F)
TERMINATE_FRAME_READ_WRITE = const(0xFF)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
# 30 bytes (look up tables)
# original waveshare example
LUT_FULL_UPDATE = bytearray(b'\x02\x02\x01\x11\x12\x12\x22\x22\x66\x69\x69\x59\x58\x99\x99\x88\x00\x00\x00\x00\xF8\xB4\x13\x51\x35\x51\x51\x19\x01\x00')
LUT_PARTIAL_UPDATE = bytearray(b'\x10\x18\x18\x08\x18\x18\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x14\x44\x12\x00\x00\x00\x00\x00\x00')
# https://github.com/ZinggJM/GxEPD/blob/master/GxGDEH029A1/GxGDEH029A1.cpp
#LUT_FULL_UPDATE = bytearray(b'\x50\xAA\x55\xAA\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x1F\x00\x00\x00\x00\x00\x00\x00')
#LUT_PARTIAL_UPDATE = bytearray(b'\x10\x18\x18\x08\x18\x18\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x14\x44\x12\x00\x00\x00\x00\x00\x00')
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(DRIVER_OUTPUT_CONTROL, ustruct.pack("<HB", EPD_HEIGHT-1, 0x00))
self._command(BOOSTER_SOFT_START_CONTROL, b'\xD7\xD6\x9D')
self._command(WRITE_VCOM_REGISTER, b'\xA8') # VCOM 7C
self._command(SET_DUMMY_LINE_PERIOD, b'\x1A') # 4 dummy lines per gate
self._command(SET_GATE_TIME, b'\x08') # 2us per line
self._command(DATA_ENTRY_MODE_SETTING, b'\x03') # X increment Y increment
self.set_lut(self.LUT_FULL_UPDATE)
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def set_lut(self, lut):
self._command(WRITE_LUT_REGISTER, lut)
# put an image in the frame memory
def set_frame_memory(self, image, x, y, w, h):
# x point must be the multiple of 8 or the last 3 bits will be ignored
x = x & 0xF8
w = w & 0xF8
if (x + w >= self.width):
x_end = self.width - 1
else:
x_end = x + w - 1
if (y + h >= self.height):
y_end = self.height - 1
else:
y_end = y + h - 1
self.set_memory_area(x, y, x_end, y_end)
self.set_memory_pointer(x, y)
self._command(WRITE_RAM, image)
# replace the frame memory with the specified color
def clear_frame_memory(self, color):
self.set_memory_area(0, 0, self.width - 1, self.height - 1)
self.set_memory_pointer(0, 0)
self._command(WRITE_RAM)
# send the color data
for i in range(0, self.width // 8 * self.height):
self._data(bytearray([color]))
# draw the current frame memory and switch to the next memory area
def display_frame(self):
self._command(DISPLAY_UPDATE_CONTROL_2, b'\xC4')
self._command(MASTER_ACTIVATION)
self._command(TERMINATE_FRAME_READ_WRITE)
self.wait_until_idle()
# specify the memory area for data R/W
def set_memory_area(self, x_start, y_start, x_end, y_end):
self._command(SET_RAM_X_ADDRESS_START_END_POSITION)
# x point must be the multiple of 8 or the last 3 bits will be ignored
self._data(bytearray([(x_start >> 3) & 0xFF]))
self._data(bytearray([(x_end >> 3) & 0xFF]))
self._command(SET_RAM_Y_ADDRESS_START_END_POSITION, ustruct.pack("<HH", y_start, y_end))
# specify the start point for data R/W
def set_memory_pointer(self, x, y):
self._command(SET_RAM_X_ADDRESS_COUNTER)
# x point must be the multiple of 8 or the last 3 bits will be ignored
self._data(bytearray([(x >> 3) & 0xFF]))
self._command(SET_RAM_Y_ADDRESS_COUNTER, ustruct.pack("<H", y))
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(DEEP_SLEEP_MODE)
self.wait_until_idle()

277
epaper2in9b.py 100644
Wyświetl plik

@ -0,0 +1,277 @@
# MicroPython library for Waveshare 2.9" B/W/R e-paper display GDEW029Z10
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(128)
EPD_HEIGHT = const(296)
# Display commands
PANEL_SETTING = const(0x00)
POWER_SETTING = const(0x01)
POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
#DEEP_SLEEP = const(0x07)
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
DATA_START_TRANSMISSION_2 = const(0x13)
#PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
#TEMPERATURE_SENSOR_CALIBRATION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
#TCON_SETTING = const(0x60)
TCON_RESOLUTION = const(0x61)
#GET_STATUS = const(0x71)
#AUTO_MEASURE_VCOM = const(0x80)
#VCOM_VALUE = const(0x81)
VCM_DC_SETTING_REGISTER = const(0x82)
#PARTIAL_WINDOW = const(0x90)
#PARTIAL_IN = const(0x91)
#PARTIAL_OUT = const(0x92)
#PROGRAM_MODE = const(0xA0)
#ACTIVE_PROGRAM = const(0xA1)
#READ_OTP_DATA = const(0xA2)
#POWER_SAVING = const(0xE3)
# Display orientation
ROTATE_0 = const(0)
ROTATE_90 = const(1)
ROTATE_180 = const(2)
ROTATE_270 = const(3)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.rotate = ROTATE_0
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(BOOSTER_SOFT_START, b'\x17\x17\x17')
self._command(POWER_ON)
self.wait_until_idle()
self._command(PANEL_SETTING, b'\x8F')
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x77')
self._command(TCON_RESOLUTION, ustruct.pack(">BH", EPD_WIDTH, EPD_HEIGHT))
self._command(VCM_DC_SETTING_REGISTER, b'\x0A')
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def display_frame(self, frame_buffer_black, frame_buffer_red):
if (frame_buffer_black != None):
self._command(DATA_START_TRANSMISSION_1)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_black[i]]))
sleep_ms(2)
if (frame_buffer_red != None):
self._command(DATA_START_TRANSMISSION_2)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_red[i]]))
sleep_ms(2)
self._command(DISPLAY_REFRESH)
self.wait_until_idle()
def set_rotate(self, rotate):
if (rotate == ROTATE_0):
self.rotate = ROTATE_0
self.width = epdif.EPD_WIDTH
self.height = epdif.EPD_HEIGHT
elif (rotate == ROTATE_90):
self.rotate = ROTATE_90
self.width = epdif.EPD_HEIGHT
self.height = epdif.EPD_WIDTH
elif (rotate == ROTATE_180):
self.rotate = ROTATE_180
self.width = epdif.EPD_WIDTH
self.height = epdif.EPD_HEIGHT
elif (rotate == ROTATE_270):
self.rotate = ROTATE_270
self.width = epdif.EPD_HEIGHT
self.height = epdif.EPD_WIDTH
def set_pixel(self, frame_buffer, x, y, colored):
if (x < 0 or x >= self.width or y < 0 or y >= self.height):
return
if (self.rotate == ROTATE_0):
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_90):
point_temp = x
x = epdif.EPD_WIDTH - y
y = point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_180):
x = epdif.EPD_WIDTH - x
y = epdif.EPD_HEIGHT- y
self.set_absolute_pixel(frame_buffer, x, y, colored)
elif (self.rotate == ROTATE_270):
point_temp = x
x = y
y = epdif.EPD_HEIGHT - point_temp
self.set_absolute_pixel(frame_buffer, x, y, colored)
def set_absolute_pixel(self, frame_buffer, x, y, colored):
# To avoid display orientation effects
# use EPD_WIDTH instead of self.width
# use EPD_HEIGHT instead of self.height
if (x < 0 or x >= EPD_WIDTH or y < 0 or y >= EPD_HEIGHT):
return
if (colored):
frame_buffer[(x + y * EPD_WIDTH) // 8] &= ~(0x80 >> (x % 8))
else:
frame_buffer[(x + y * EPD_WIDTH) // 8] |= 0x80 >> (x % 8)
def draw_string_at(self, frame_buffer, x, y, text, font, colored):
image = Image.new('1', (self.width, self.height))
draw = ImageDraw.Draw(image)
draw.text((x, y), text, font = font, fill = 255)
# Set buffer to value of Python Imaging Library image.
# Image must be in mode 1.
pixels = image.load()
for y in range(self.height):
for x in range(self.width):
# Set the bits for the column of pixels at the current position.
if pixels[x, y] != 0:
self.set_pixel(frame_buffer, x, y, colored)
def draw_line(self, frame_buffer, x0, y0, x1, y1, colored):
# Bresenham algorithm
dx = abs(x1 - x0)
sx = 1 if x0 < x1 else -1
dy = -abs(y1 - y0)
sy = 1 if y0 < y1 else -1
err = dx + dy
while((x0 != x1) and (y0 != y1)):
self.set_pixel(frame_buffer, x0, y0 , colored)
if (2 * err >= dy):
err += dy
x0 += sx
if (2 * err <= dx):
err += dx
y0 += sy
def draw_horizontal_line(self, frame_buffer, x, y, width, colored):
for i in range(x, x + width):
self.set_pixel(frame_buffer, i, y, colored)
def draw_vertical_line(self, frame_buffer, x, y, height, colored):
for i in range(y, y + height):
self.set_pixel(frame_buffer, x, i, colored)
def draw_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
self.draw_horizontal_line(frame_buffer, min_x, min_y, max_x - min_x + 1, colored)
self.draw_horizontal_line(frame_buffer, min_x, max_y, max_x - min_x + 1, colored)
self.draw_vertical_line(frame_buffer, min_x, min_y, max_y - min_y + 1, colored)
self.draw_vertical_line(frame_buffer, max_x, min_y, max_y - min_y + 1, colored)
def draw_filled_rectangle(self, frame_buffer, x0, y0, x1, y1, colored):
min_x = x0 if x1 > x0 else x1
max_x = x1 if x1 > x0 else x0
min_y = y0 if y1 > y0 else y1
max_y = y1 if y1 > y0 else y0
for i in range(min_x, max_x + 1):
self.draw_vertical_line(frame_buffer, i, min_y, max_y - min_y + 1, colored)
def draw_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
def draw_filled_circle(self, frame_buffer, x, y, radius, colored):
# Bresenham algorithm
x_pos = -radius
y_pos = 0
err = 2 - 2 * radius
if (x >= self.width or y >= self.height):
return
while True:
self.set_pixel(frame_buffer, x - x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y + y_pos, colored)
self.set_pixel(frame_buffer, x + x_pos, y - y_pos, colored)
self.set_pixel(frame_buffer, x - x_pos, y - y_pos, colored)
self.draw_horizontal_line(frame_buffer, x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored)
self.draw_horizontal_line(frame_buffer, x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored)
e2 = err
if (e2 <= y_pos):
y_pos += 1
err += y_pos * 2 + 1
if(-x_pos == y_pos and e2 <= x_pos):
e2 = 0
if (e2 > x_pos):
x_pos += 1
err += x_pos * 2 + 1
if x_pos > 0:
break
# to wake call reset() or init()
def sleep(self):
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x37')
self._command(VCM_DC_SETTING_REGISTER, b'\x00') # to solve Vcom drop
self._command(POWER_SETTING, b'\x02\x00\x00\x00') # gate switch to external
self.wait_until_idle()
self._command(POWER_OFF)

146
epaper4in2.py 100644
Wyświetl plik

@ -0,0 +1,146 @@
# MicroPython library for Waveshare 4.2" B/W e-paper display GDEW042T2
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(400)
EPD_HEIGHT = const(300)
# Display commands
PANEL_SETTING = const(0x00)
POWER_SETTING = const(0x01)
POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
DEEP_SLEEP = const(0x07)
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
DATA_START_TRANSMISSION_2 = const(0x13)
LUT_FOR_VCOM = const(0x20)
LUT_WHITE_TO_WHITE = const(0x21)
LUT_BLACK_TO_WHITE = const(0x22)
LUT_WHITE_TO_BLACK = const(0x23)
LUT_BLACK_TO_BLACK = const(0x24)
PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
#TEMPERATURE_SENSOR_SELECTION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
#TCON_SETTING = const(0x60)
RESOLUTION_SETTING = const(0x61)
#GSST_SETTING = const(0x65)
#GET_STATUS = const(0x71)
#AUTO_MEASUREMENT_VCOM = const(0x80)
#READ_VCOM_VALUE = const(0x81)
VCM_DC_SETTING = const(0x82)
#PARTIAL_WINDOW = const(0x90)
#PARTIAL_IN = const(0x91)
#PARTIAL_OUT = const(0x92)
#PROGRAM_MODE = const(0xA0)
#ACTIVE_PROGRAMMING = const(0xA1)
#READ_OTP = const(0xA2)
#POWER_SAVING = const(0xE3)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
# 44/42 bytes (look up tables)
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')
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')
LUT_BW = LUT_WW
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')
LUT_WB = LUT_BB
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
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
self._command(BOOSTER_SOFT_START, b'\x17\x17\x17') # 07 0f 17 1f 27 2F 37 2f
self._command(POWER_ON)
self.wait_until_idle()
self._command(PANEL_SETTING, b'\xBF\x0B') # KW-BF KWR-AF BWROTP 0f
self._command(PLL_CONTROL, b'\x3C') # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
def set_lut(self):
self._command(LUT_FOR_VCOM, self.LUT_VCOM0) # vcom
self._command(LUT_WHITE_TO_WHITE, self.LUT_WW) # ww --
self._command(LUT_BLACK_TO_WHITE, self.LUT_BW) # bw r
self._command(LUT_WHITE_TO_BLACK, self.LUT_BB) # wb w
self._command(LUT_BLACK_TO_BLACK, self.LUT_WB) # bb b
# draw the current frame memory
def display_frame(self, frame_buffer):
self._command(RESOLUTION_SETTING, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT))
self._command(VCM_DC_SETTING, b'\x12')
self._command(VCOM_AND_DATA_INTERVAL_SETTING)
self._command(0x97) # VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7
# TODO should ^ this be _data(0x97), not sure what it does
if (frame_buffer != None):
self._command(DATA_START_TRANSMISSION_1)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([0xFF])) # bit set: white, bit reset: black
sleep_ms(2)
self._command(DATA_START_TRANSMISSION_2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer[i]]))
sleep_ms(2)
self.set_lut()
self._command(DISPLAY_REFRESH)
sleep_ms(100)
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x17') # border floating
self._command(VCM_DC_SETTING) # VCOM to 0V
self._command(PANEL_SETTING)
sleep_ms(100)
self._command(POWER_SETTING, b'\x00\x00\x00\x00\x00') # VG&VS to 0V fast
sleep_ms(100)
self._command(POWER_OFF)
self.wait_until_idle()
self._command(DEEP_SLEEP, b'\xA5')

118
epaper4in2b.py 100644
Wyświetl plik

@ -0,0 +1,118 @@
# MicroPython library for Waveshare 4.2" B/W/R e-paper display GDEW042Z15
from micropython import const
from time import sleep_ms
# Display resolution
EPD_WIDTH = const(400)
EPD_HEIGHT = const(300)
# Display commands
PANEL_SETTING = const(0x00)
#POWER_SETTING = const(0x01)
POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
DEEP_SLEEP = const(0x07)
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
DATA_START_TRANSMISSION_2 = const(0x13)
#VCOM_LUT = const(0x20)
#W2W_LUT = const(0x21)
#B2W_LUT = const(0x22)
#W2B_LUT = const(0x23)
#B2B_LUT = const(0x24)
#PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_CALIBRATION = const(0x40)
#TEMPERATURE_SENSOR_SELECTION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
#TCON_SETTING = const(0x60)
#RESOLUTION_SETTING = const(0x61)
#GSST_SETTING = const(0x65)
#GET_STATUS = const(0x71)
#AUTO_MEASURE_VCOM = const(0x80)
#VCOM_VALUE = const(0x81)
#VCM_DC_SETTING = const(0x82)
#PARTIAL_WINDOW = const(0x90)
#PARTIAL_IN = const(0x91)
#PARTIAL_OUT = const(0x92)
#PROGRAM_MODE = const(0xA0)
#ACTIVE_PROGRAM = const(0xA1)
#READ_OTP_DATA = const(0xA2)
#POWER_SAVING = const(0xE3)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(BOOSTER_SOFT_START, b'\x17\x17\x17') # 07 0f 17 1f 27 2F 37 2f
self._command(POWER_ON)
self.wait_until_idle()
self._command(PANEL_SETTING, b'\x0F') # LUT from OTP
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
# draw the current frame memory
def display_frame(self, frame_buffer_black, frame_buffer_red):
if (frame_buffer_black != None):
self._command(DATA_START_TRANSMISSION_1)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_black[i]]))
sleep_ms(2)
if (frame_buffer_red != None):
self._command(DATA_START_TRANSMISSION_2)
sleep_ms(2)
for i in range(0, self.width * self.height // 8):
self._data(bytearray([frame_buffer_red[i]]))
sleep_ms(2)
self._command(DISPLAY_REFRESH)
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\xF7') # border floating
self._command(POWER_OFF)
self.wait_until_idle()
self._command(DEEP_SLEEP, b'\xA5') # check code

133
epaper7in5.py 100644
Wyświetl plik

@ -0,0 +1,133 @@
# MicroPython library for Waveshare 7.5" B/W e-paper display GDEW075T8
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(640)
EPD_HEIGHT = const(384)
# Display commands
PANEL_SETTING = const(0x00)
POWER_SETTING = const(0x01)
POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
DEEP_SLEEP = const(0x07)
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
#IMAGE_PROCESS = const(0x13)
#LUT_FOR_VCOM = const(0x20)
#LUT_BLUE = const(0x21)
#LUT_WHITE = const(0x22)
#LUT_GRAY_1 = const(0x23)
#LUT_GRAY_2 = const(0x24)
#LUT_RED_0 = const(0x25)
#LUT_RED_1 = const(0x26)
#LUT_RED_2 = const(0x27)
#LUT_RED_3 = const(0x28)
#LUT_XON = const(0x29)
PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
TEMPERATURE_CALIBRATION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
TCON_SETTING = const(0x60)
TCON_RESOLUTION = const(0x61)
#SPI_FLASH_CONTROL = const(0x65)
#REVISION = const(0x70)
#GET_STATUS = const(0x71)
#AUTO_MEASUREMENT_VCOM = const(0x80)
#READ_VCOM_VALUE = const(0x81)
VCM_DC_SETTING = const(0x82)
FLASH_MODE = const(0xE5)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(POWER_SETTING, b'\x37\x00')
self._command(PANEL_SETTING, b'\xCF\x08')
self._command(BOOSTER_SOFT_START, b'\xC7\xCC\x28')
self._command(POWER_ON)
self.wait_until_idle()
self._command(PLL_CONTROL, b'\x3C')
self._command(TEMPERATURE_CALIBRATION, b'\x00')
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x77')
self._command(TCON_SETTING, b'\x22')
self._command(TCON_RESOLUTION, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT))
self._command(VCM_DC_SETTING, b'\x1E') # decide by LUT file
self._command(FLASH_MODE, b'\x03')
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
# draw the current frame memory
def display_frame(self, frame_buffer):
self._command(DATA_START_TRANSMISSION_1)
for i in range(0, 30720):
temp1 = frame_buffer[i]
j = 0
while (j < 8):
if (temp1 & 0x80):
temp2 = 0x03
else:
temp2 = 0x00
temp2 = (temp2 << 4) & 0xFF
temp1 = (temp1 << 1) & 0xFF
j += 1
if (temp1 & 0x80):
temp2 |= 0x03
else:
temp2 |= 0x00
temp1 = (temp1 << 1) & 0xFF
self._data(bytearray([temp2]))
j += 1
self._command(DISPLAY_REFRESH)
sleep_ms(100)
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(POWER_OFF)
self.wait_until_idle()
self._command(DEEP_SLEEP, b'\xA5')

137
epaper7in5b.py 100644
Wyświetl plik

@ -0,0 +1,137 @@
# MicroPython library for Waveshare 7.5" B/W/R e-paper display GDEW075Z09
from micropython import const
from time import sleep_ms
import ustruct
# Display resolution
EPD_WIDTH = const(640)
EPD_HEIGHT = const(384)
# Display commands
PANEL_SETTING = const(0x00)
POWER_SETTING = const(0x01)
POWER_OFF = const(0x02)
#POWER_OFF_SEQUENCE_SETTING = const(0x03)
POWER_ON = const(0x04)
#POWER_ON_MEASURE = const(0x05)
BOOSTER_SOFT_START = const(0x06)
DEEP_SLEEP = const(0x07)
DATA_START_TRANSMISSION_1 = const(0x10)
#DATA_STOP = const(0x11)
DISPLAY_REFRESH = const(0x12)
#IMAGE_PROCESS = const(0x13)
#LUT_FOR_VCOM = const(0x20)
#LUT_BLUE = const(0x21)
#LUT_WHITE = const(0x22)
#LUT_GRAY_1 = const(0x23)
#LUT_GRAY_2 = const(0x24)
#LUT_RED_0 = const(0x25)
#LUT_RED_1 = const(0x26)
#LUT_RED_2 = const(0x27)
#LUT_RED_3 = const(0x28)
#LUT_XON = const(0x29)
PLL_CONTROL = const(0x30)
#TEMPERATURE_SENSOR_COMMAND = const(0x40)
TEMPERATURE_CALIBRATION = const(0x41)
#TEMPERATURE_SENSOR_WRITE = const(0x42)
#TEMPERATURE_SENSOR_READ = const(0x43)
VCOM_AND_DATA_INTERVAL_SETTING = const(0x50)
#LOW_POWER_DETECTION = const(0x51)
TCON_SETTING = const(0x60)
TCON_RESOLUTION = const(0x61)
#SPI_FLASH_CONTROL = const(0x65)
#REVISION = const(0x70)
#GET_STATUS = const(0x71)
#AUTO_MEASUREMENT_VCOM = const(0x80)
#READ_VCOM_VALUE = const(0x81)
VCM_DC_SETTING = const(0x82)
FLASH_MODE = const(0xE5)
class EPD:
def __init__(self, spi, cs, dc, rst, busy):
self.spi = spi
self.cs = cs
self.dc = dc
self.rst = rst
self.busy = busy
self.cs.init(self.cs.OUT, value=1)
self.dc.init(self.dc.OUT, value=0)
self.rst.init(self.rst.OUT, value=0)
self.busy.init(self.busy.IN)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
def _command(self, command, data=None):
self.dc.low()
self.cs.low()
self.spi.write(bytearray([command]))
self.cs.high()
if data is not None:
self._data(data)
def _data(self, data):
self.dc.high()
self.cs.low()
self.spi.write(data)
self.cs.high()
def init(self):
self.reset()
self._command(POWER_SETTING, b'\x37\x00')
self._command(PANEL_SETTING, b'\xCF\x08')
self._command(BOOSTER_SOFT_START, b'\xC7\xCC\x28')
self._command(POWER_ON)
self.wait_until_idle()
self._command(PLL_CONTROL, b'\x3C')
self._command(TEMPERATURE_CALIBRATION, b'\x00')
self._command(VCOM_AND_DATA_INTERVAL_SETTING, b'\x77')
self._command(TCON_SETTING, b'\x22')
self._command(TCON_RESOLUTION, ustruct.pack(">HH", EPD_WIDTH, EPD_HEIGHT))
self._command(VCM_DC_SETTING, b'\x1E') # decide by LUT file
self._command(FLASH_MODE, b'\x03')
def wait_until_idle(self):
while self.busy.value() == 1:
sleep_ms(100)
def reset(self):
self.rst.low()
sleep_ms(200)
self.rst.high()
sleep_ms(200)
# draw the current frame memory
def display_frame(self, frame_buffer):
self._command(DATA_START_TRANSMISSION_1)
for i in range(0, self.width // 4 * self.height):
temp1 = frame_buffer[i]
j = 0
while (j < 4):
if ((temp1 & 0xC0) == 0xC0):
temp2 = 0x03
elif ((temp1 & 0xC0) == 0x00):
temp2 = 0x00
else:
temp2 = 0x04
temp2 = (temp2 << 4) & 0xFF
temp1 = (temp1 << 2) & 0xFF
j += 1
if ((temp1 & 0xC0) == 0xC0):
temp2 |= 0x03
elif ((temp1 & 0xC0) == 0x00):
temp2 |= 0x00
else:
temp2 |= 0x04
temp1 = (temp1 << 2) & 0xFF
self._data(bytearray([temp2]))
j += 1
self._command(DISPLAY_REFRESH)
sleep_ms(100)
self.wait_until_idle()
# to wake call reset() or init()
def sleep(self):
self._command(POWER_OFF)
self.wait_until_idle()
self._command(DEEP_SLEEP, b'\xA5')

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 111 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 148 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.4 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,54 @@
import epaper2in9
from pyb import SPI
# SPI3 on Black STM32F407VET6
spi = SPI(3, SPI.MASTER, baudrate=2000000, polarity=0, phase=0)
cs = pyb.Pin('PB6')
dc = pyb.Pin('PB7')
rst = pyb.Pin('PB8')
busy = pyb.Pin('PB9')
e = epaper2in9.EPD(spi, cs, dc, rst, busy)
e.init()
w = 128
h = 296
x = 0
y = 0
# write hello world with black bg and white text
from image_dark import hello_world_dark
e.clear_frame_memory(b'\xFF')
e.set_frame_memory(hello_world_dark, x, y, w, h)
e.display_frame()
# write hello world with white bg and black text
from image_light import hello_world_light
e.clear_frame_memory(b'\xFF')
e.set_frame_memory(hello_world_light, x, y, w, h)
e.display_frame()
# clear display
e.clear_frame_memory(b'\xFF')
e.display_frame()
# use a frame buffer
# 128 * 296 / 8 = 4736 - thats a lot of pixels
import framebuf
buf = bytearray(128 * 296 // 8)
fb = framebuf.FrameBuffer(buf, 128, 296, framebuf.MONO_HLSB)
black = 0
white = 1
fb.fill(white)
fb.text('Hello World',30,0,black)
fb.pixel(30, 10, black)
fb.hline(30, 30, 10, black)
fb.vline(30, 50, 10, black)
fb.line(30, 70, 40, 80, black)
fb.rect(30, 90, 10, 10, black)
fb.fill_rect(30, 110, 10, 10, black)
for row in range(0,37):
fb.text(str(row),0,row*8,black)
fb.text('Line 36',0,288,black)
e.set_frame_memory(buf, x, y, w, h)
e.display_frame()