├── .gitignore ├── LICENSE ├── README.md ├── demo.py ├── eink.py └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Doug Hall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # MicroPython e-Ink library for Waveshare 4.3inch display. 3 | 4 | This is a simple library for displaying information on a Waveshare 4.3 e-ink display from a device running Micropython. These are boards like the Pyboard, WiPy, or those based around the ESP8266 chip such as the Adafruit Feather Huzzah. As an alternative if you are running this on a full CPython implementation such as a Odroid or Raspberry Pi, see https://github.com/yy502/ePaperDisplay as that library has many more functions. 5 | 6 | ### Conversion 7 | It takes as its base a pure conversion from the Waveshare code. I used a few things to start the conversion from C code into Python: 8 | 9 | - a utility called cpp2python from https://github.com/hlamer/cpp2python 10 | - a demo script h2py.py in the Python demo/scripts directory to convert the header file 11 | - seasnake from the excellent BeeWare project at http://pybee.org/, but now abandoned - BeeWare itself is still very alive! 12 | - ctopy from http://www.catb.org/~esr/ctopy/ 13 | 14 | ...but mostly just hand-cranked the Python code whilst browsing the C routines. 15 | 16 | ### Adaption to MicroPython and embedded devices 17 | The original (and derivations) used excessive string concatenation which consumes memory space. In the constrained memory environment of the embedded systems on which MicroPython runs, memory is at a premium so I adapted the library for the following: 18 | 19 | - no extraneous operations, just the raw commands 20 | - constant binary strings for complete commands (eg. clear, update) where possible so not to use string concatenation 21 | - precalculated parity bytes 22 | -------------------------------------------------------------------------------- /demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from eink import * 3 | from time import sleep 4 | 5 | def base_draw(): 6 | 7 | eink_clear() 8 | for j in range(0, 600, 50): 9 | for i in range (0, 800, 50): 10 | eink_draw_pixel(i, j) 11 | eink_draw_pixel(i, j + 1) 12 | eink_draw_pixel(i + 1, j) 13 | eink_draw_pixel(i + 1, j + 1) 14 | eink_update() 15 | sleep(3) 16 | 17 | eink_clear() 18 | for i in range(0, 800, 100): 19 | eink_draw_line(0, 0, i, 599) 20 | eink_draw_line(799, 0, i, 599) 21 | eink_update() 22 | sleep(3) 23 | 24 | eink_clear() 25 | eink_set_color(BLACK, WHITE) 26 | eink_fill_rect(10, 10, 100, 100) 27 | eink_set_color(DARK_GRAY, WHITE) 28 | eink_fill_rect(110, 10, 200, 100) 29 | eink_set_color(GRAY, WHITE) 30 | eink_fill_rect(210, 10, 300, 100) 31 | eink_update() 32 | sleep(3) 33 | 34 | eink_set_color(BLACK, WHITE) 35 | eink_clear() 36 | 37 | for i in range(0, 300, 40): 38 | eink_draw_circle(399, 299, i) 39 | eink_update() 40 | sleep(3) 41 | 42 | eink_clear() 43 | for j in range(0, 6): 44 | for i in range(0, 8): 45 | eink_fill_circle(50 + i * 100, 50 + j * 100, 50) 46 | eink_update() 47 | sleep(3) 48 | 49 | eink_clear() 50 | for i in range(1, 5): 51 | eink_draw_triangle(399, 249 - i * 50, 349 - i * 50, 349 + i * 50, 449 + i * 50, 349 + i * 50) 52 | eink_update() 53 | sleep(3) 54 | 55 | def draw_text_demo(): 56 | buff = bytearray('G', 'B', 'K', '3', '2', ':', ' ', 0xc4, 0xe3, 0xba, 0xc3, 0xca, 0xc0, 0xbd, 0xe7, 0) 57 | eink_set_color(BLACK, WHITE) 58 | eink_clear() 59 | eink_set_ch_font(GBK32) 60 | eink_set_en_font(ASCII32) 61 | eink_disp_string(buff, 0, 50) 62 | eink_disp_string("ASCII32: Hello, World! ", 0, 300) 63 | eink_set_ch_font(GBK48) 64 | eink_set_en_font(ASCII48) 65 | buff[3] = '4' 66 | buff[4] = '8' 67 | eink_disp_string(buff, 0, 100) 68 | eink_disp_string("ASCII48: Hello, World! ", 0, 350) 69 | eink_set_ch_font(GBK64) 70 | eink_set_en_font(ASCII64) 71 | buff[3] = '6' 72 | buff[4] = '4' 73 | eink_disp_string(buff, 0, 160) 74 | eink_disp_string("ASCII64: Hello, World! ", 0, 450) 75 | eink_update() 76 | sleep(3) 77 | 78 | def draw_bitmap_demo(): 79 | eink_clear() 80 | eink_disp_bitmap("PIC4.BMP", 0, 0) 81 | eink_update() 82 | sleep(3) 83 | 84 | eink_clear() 85 | eink_disp_bitmap("PIC2.BMP", 0, 100) 86 | eink_disp_bitmap("PIC3.BMP", 400, 100) 87 | eink_update() 88 | sleep(3) 89 | 90 | eink_clear() 91 | eink_disp_bitmap("PIC7.BMP", 0, 0) 92 | eink_update() 93 | 94 | Tx = 'G12' 95 | Rx = 'G13' 96 | uartnum = 1 97 | eink_init() 98 | base_draw() 99 | # draw_text_demo() 100 | # draw_bitmap_demo() 101 | -------------------------------------------------------------------------------- /eink.py: -------------------------------------------------------------------------------- 1 | # MicroPython library for Waveshare 4.3 e-ink display 2 | # Converted from the file epd.cpp released by Waveshare 3 | # Doug Hall, 2016 4 | # 5 | # TBC: 6 | # - eink_init (add pins wakeup and reset to high)? 7 | # - eink_wakeup 8 | # - eink_reset 9 | # 10 | 11 | from machine import UART 12 | from ustruct import pack_into 13 | from ustruct import pack 14 | 15 | # commands 16 | _cmd_handshake = b"\xA5\x00\x09\x00\xCC\x33\xC3\x3C\xAC" 17 | _cmd_set_baud = b"\xA5\x00\x0D\x01\x00\x00\x00\x00\xCC\x33\xC3\x3C" 18 | _cmd_read_baud = b"\xA5\x00\x09\x02\xCC\x33\xC3\x3C\xAE" 19 | _cmd_set_memory = b"\xA5\x00\x0A\x07\x00\xCC\x33\xC3\x3C" 20 | _cmd_stopmode = b"\xA5\x00\x09\x08\xCC\x33\xC3\x3C\xA4" 21 | _cmd_update = b"\xA5\x00\x09\x0A\xCC\x33\xC3\x3C\xA6" 22 | _cmd_screen_rotation = b"\xA5\x00\x0A\x0D\x00\xCC\x33\xC3\x3C" 23 | _cmd_load_font = b"\xA5\x00\x09\x0E\xCC\x33\xC3\x3C\xA2" 24 | _cmd_load_pic = b"\xA5\x00\x09\x0F\xCC\x33\xC3\x3C\xA3" 25 | _cmd_set_colour = b"\xA5\x00\x0B\x10\x00\x00\xCC\x33\xC3\x3C" 26 | _cmd_set_en_font = b"\xA5\x00\x0A\x1E\x00\xCC\x33\xC3\x3C" 27 | _cmd_set_ch_font = b"\xA5\x00\x0A\x1F\x00\xCC\x33\xC3\x3C" 28 | _cmd_draw_pixel = b"\xA5\x00\x0D\x20\x00\x00\x00\x00\xCC\x33\xC3\x3C" 29 | _cmd_draw_line = b"\xA5\x00\x11\x22\x00\x00\x00\x00\x00\x00\x00\x00\xCC\x33\xC3\x3C" 30 | _cmd_fill_rect = b"\xA5\x00\x11\x24\x00\x00\x00\x00\x00\x00\x00\x00\xCC\x33\xC3\x3C" 31 | _cmd_draw_rect = b"\xA5\x00\x11\x25\x00\x00\x00\x00\x00\x00\x00\x00\xCC\x33\xC3\x3C" 32 | _cmd_draw_circle = b"\xA5\x00\x0F\x26\x00\x00\x00\x00\x00\x00\xCC\x33\xC3\x3C" 33 | _cmd_fill_circle = b"\xA5\x00\x0F\x27\x00\x00\x00\x00\x00\x00\xCC\x33\xC3\x3C" 34 | _cmd_draw_triangle = b"\xA5\x00\x15\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xCC\x33\xC3\x3C" 35 | _cmd_fill_triangle = b"\xA5\x00\x15\x29\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xCC\x33\xC3\x3C" 36 | _cmd_clear = b"\xA5\x00\x09\x2E\xCC\x33\xC3\x3C\x82" 37 | _cmd_draw_string = b"\xA5\x00\x00\x30\x00\x00\x00\x00" 38 | _cmd_draw_bitmap = b"\xA5\x00\x00\x70\x00\x00\x00\x00" 39 | 40 | # colours 41 | WHITE = 0x03 42 | GRAY = 0x02 43 | DARK_GRAY = 0x01 44 | BLACK = 0x00 45 | 46 | # fonts 47 | GBK32 = 0x01 48 | GBK48 = 0x02 49 | GBK64 = 0x03 50 | ASCII32 = 0x01 51 | ASCII48 = 0x02 52 | ASCII64 = 0x03 53 | 54 | # memory 55 | MEM_NAND = 0 56 | MEM_TF = 1 57 | 58 | # display 59 | EPD_NORMAL = 0 60 | EPD_INVERSION = 1 61 | 62 | # pins 63 | uartnum = 1 64 | Tx = 'G12' 65 | Rx = 'G13' 66 | wake_up = 2 67 | reset = 3 68 | 69 | def printhex(s): 70 | print(type(s),len(s),":".join("{:02x}".format(c) for c in s)) 71 | 72 | def send(cmd): 73 | # if __debug__: 74 | # printhex(cmd) 75 | uart.write(cmd) 76 | 77 | def addparity(packet): 78 | parity = 0 79 | if type(packet) == bytes: 80 | for b in packet: 81 | parity ^= b 82 | return(b''.join((packet,pack('!B',parity)))) 83 | elif type(packet) == bytearray: 84 | for b in packet: 85 | parity ^= b 86 | packet.append(parity) 87 | return(packet) 88 | elif type(packet) == str: 89 | for i in packet: 90 | parity ^= ord(i) 91 | return(''.join((packet, chr(parity)))) 92 | else: 93 | return None 94 | 95 | def eink_init(): 96 | global uart 97 | uart = UART(uartnum, baudrate=115200, pins=(Tx, Rx)) 98 | 99 | def eink_reset(): 100 | pass 101 | 102 | def eink_wakeup(): 103 | pass 104 | 105 | def eink_handshake(): 106 | send(_cmd_handshake) 107 | 108 | def eink_set_baud(baud): 109 | bcmd = bytearray(_cmd_set_baud) 110 | pack_into('!i',bcmd,4,baud) 111 | send(addparity(bcmd)) 112 | 113 | def eink_read_baud(): 114 | send(_cmd_read_baud) 115 | 116 | def eink_set_memory(mode): 117 | bcmd = bytearray(_cmd_set_memory) 118 | pack_into('!B',bcmd,4,mode) 119 | send(addparity(bcmd)) 120 | 121 | def eink_enter_stopmode(): 122 | send(_cmd_stopmode) 123 | 124 | def eink_update(): 125 | send(_cmd_update) 126 | 127 | def eink_screen_rotation(mode): 128 | bcmd = bytearray(_cmd_set_memory) 129 | pack_into('!B',bcmd,4,mode) 130 | send(addparity(bcmd)) 131 | 132 | def eink_load_font(): 133 | send(_cmd_load_font) 134 | 135 | def eink_load_pic(): 136 | send(_cmd_load_pic) 137 | 138 | def eink_set_color(colour, bkcolour): 139 | bcmd = bytearray(_cmd_set_colour) 140 | pack_into('!BB',bcmd,4,colour,bkcolour) 141 | send(addparity(bcmd)) 142 | 143 | def eink_set_en_font(font): 144 | bcmd = bytearray(_cmd_set_en_font) 145 | pack_into('!B',bcmd,4,font) 146 | send(addparity(bcmd)) 147 | 148 | def eink_set_ch_font(font): 149 | bcmd = bytearray(_cmd_set_ch_font) 150 | pack_into('!B',bcmd,4,font) 151 | send(addparity(bcmd)) 152 | 153 | def eink_draw_pixel(x, y): 154 | bcmd = bytearray(_cmd_draw_pixel) 155 | pack_into('!hh',bcmd,4,x,y) 156 | send(addparity(bcmd)) 157 | 158 | def eink_draw_line(x0, y0, x1, y1): 159 | bcmd = bytearray(_cmd_draw_line) 160 | pack_into('!hhhh',bcmd,4,x0,y0,x1,y1) 161 | send(addparity(bcmd)) 162 | 163 | def eink_draw_rect(x0, y0, x1, y1): 164 | bcmd = bytearray(_cmd_draw_rect) 165 | pack_into('!hhhh',bcmd,4,x0,y0,x1,y1) 166 | send(addparity(bcmd)) 167 | 168 | def eink_fill_rect(x0, y0, x1, y1): 169 | bcmd = bytearray(_cmd_fill_rect) 170 | pack_into('!hhhh',bcmd,4,x0,y0,x1,y1) 171 | send(addparity(bcmd)) 172 | 173 | def eink_draw_circle(x, y, r): 174 | bcmd = bytearray(_cmd_draw_circle) 175 | pack_into('!hhh',bcmd,4,x,y,r) 176 | send(addparity(bcmd)) 177 | 178 | def eink_fill_circle(x, y, r): 179 | bcmd = bytearray(_cmd_fill_circle) 180 | pack_into('!hhh',bcmd,4,x,y,r) 181 | send(addparity(bcmd)) 182 | 183 | def eink_draw_triangle(x0, y0, x1, y1, x2, y2): 184 | bcmd = bytearray(_cmd_draw_triangle) 185 | pack_into('!hhhhhh',bcmd,4,x0,y0,x1,y1,x2,y2) 186 | send(addparity(bcmd)) 187 | 188 | def eink_fill_triangle(x0, y0, x1, y1, x2, y2): 189 | bcmd = bytearray(_cmd_fill_triangle) 190 | pack_into('!hhhhhh',bcmd,4,x0,y0,x1,y1,x2,y2) 191 | send(addparity(bcmd)) 192 | 193 | def eink_clear(): 194 | send(_cmd_clear) 195 | send(_cmd_update) 196 | 197 | def eink_disp_char(ch, x, y): 198 | eink_disp_string(ch, x, y) 199 | 200 | def eink_disp_string(s, x, y): 201 | bcmd = bytearray(_cmd_draw_string) 202 | pack_into('!hh',bcmd,4,x,y) 203 | bcmd.extend(s.encode('hex')) 204 | bcmd.extend(b'\x00\xCC\x33\xC3\x3C') 205 | bcmd[2] = len(bcmd)+1 206 | send(addparity(bcmd)) 207 | 208 | def eink_disp_bitmap(bm, x, y): 209 | bcmd = bytearray(_cmd_draw_bitmap) 210 | pack_into('!hh',bcmd,4,x,y) 211 | bcmd.extend(bm.encode()) 212 | bcmd.extend(b'\x00\xCC\x33\xC3\x3C') 213 | bcmd[2] = len(bcmd)+1 214 | send(addparity(bcmd)) 215 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "urls": [ 3 | ["eink.py", "github:dhallgb/eInk-micropython/eink.py"] 4 | ], 5 | "version": "1.0.0", 6 | "deps": [] 7 | } --------------------------------------------------------------------------------