├── .gitignore ├── LICENSE ├── README.md ├── badgyRev2C.py ├── badgy_python.jpg ├── epaper2in9.py ├── image.py ├── main.py └── text.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 SQFMI 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 | ## Instructions 2 | 1. Follow this guide to install MicroPython on Badgy [Getting started with MicroPython on the ESP8266](https://docs.micropython.org/en/latest/esp8266/tutorial/intro.html) 3 | 2. Install [ampy](https://learn.adafruit.com/micropython-basics-load-files-and-run-code/install-ampy) or use the [WebREPL](https://micropython.org/webrepl/) for uploading files 4 | 3. Upload [main.py](main.py), [image.py](image.py), and [epaper2in9.py](epaper2in9.py) 5 | 4. Reset Badgy and see the image! 6 | 7 | 8 | 9 | ## Next Steps 10 | * Check out this [library](https://github.com/mcauser/micropython-waveshare-epaper) by [@mcauser](https://github.com/mcauser) for more examples and function calls 11 | * We'll be adding more examples shortly! 12 | -------------------------------------------------------------------------------- /badgyRev2C.py: -------------------------------------------------------------------------------- 1 | from micropython import const 2 | from time import sleep_ms 3 | 4 | # Display resolution 5 | EPD_WIDTH = const(128) 6 | EPD_HEIGHT = const(296) 7 | 8 | BUSY = const(1) # 1=busy\=idle 9 | 10 | class EPD: 11 | def __init__(self, spi, cs, dc, rst, busy): 12 | self.spi = spi 13 | self.cs = cs 14 | self.dc = dc 15 | self.rst = rst 16 | self.busy = busy 17 | self.cs.init(self.cs.OUT, value=1) 18 | self.dc.init(self.dc.OUT, value=0) 19 | self.rst.init(self.rst.OUT, value=0) 20 | self.busy.init(self.busy.IN) 21 | self.width = EPD_WIDTH 22 | self.height = EPD_HEIGHT 23 | 24 | LUT_20_VCOMDC = bytearray(b'\x00\x08\x00\x00\x00\x02\x60\x28\x28\x00\x00\x01\x00\x14\x00\x00\x00\x01\x00\x12\x12\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 25 | LUT_21_WW = bytearray(b'\x40\x08\x00\x00\x00\x02\x90\x28\x28\x00\x00\x01\x40\x14\x00\x00\x00\x01\xA0\x12\x12\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 26 | LUT_22_BW = bytearray(b'\x40\x08\x00\x00\x00\x02\x90\x28\x28\x00\x00\x01\x40\x14\x00\x00\x00\x01\xA0\x12\x12\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 27 | LUT_23_WB = bytearray(b'\x80\x08\x00\x00\x00\x02\x90\x28\x28\x00\x00\x01\x80\x14\x00\x00\x00\x01\x50\x12\x12\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 28 | LUT_24_BB = bytearray(b'\x80\x08\x00\x00\x00\x02\x90\x28\x28\x00\x00\x01\x80\x14\x00\x00\x00\x01\x50\x12\x12\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 29 | 30 | def _command(self, command, data=None): 31 | self.dc(0) 32 | self.cs(0) 33 | self.spi.write(bytearray([command])) 34 | self.cs(1) 35 | if data is not None: 36 | self._data(data) 37 | 38 | def _data(self, data): 39 | self.dc(1) 40 | self.cs(0) 41 | self.spi.write(data) 42 | self.cs(1) 43 | 44 | def init(self): 45 | self.reset() 46 | 47 | def wait_until_idle(self): 48 | while self.busy.value() == BUSY: 49 | sleep_ms(100) 50 | 51 | def reset(self): 52 | self.rst(0) 53 | sleep_ms(200) 54 | self.rst(1) 55 | sleep_ms(200) 56 | 57 | # put an image in the frame memory 58 | def set_frame_memory(self, image, x, y, w, h): 59 | self.clear_frame_memory(0xFF) 60 | self._command(0x13, image) 61 | 62 | # replace the frame memory with the specified color 63 | def clear_frame_memory(self, color): 64 | self._wake_up() 65 | self._command(0x10) 66 | # send the color data 67 | for i in range(0, self.width // 8 * self.height): 68 | self._data(bytearray([color])) 69 | 70 | # draw the current frame memory and switch to the next memory area 71 | def display_frame(self): 72 | self._command(0x12) 73 | self.wait_until_idle() 74 | self._sleep() 75 | 76 | def _init_full_update(self): 77 | self._command(0x82,b'\x08') 78 | self._command(0X50,b'\x97') 79 | 80 | self._command(0x20) 81 | self._data(self.LUT_20_VCOMDC) 82 | self._command(0x21) 83 | self._data(self.LUT_21_WW) 84 | self._command(0x22) 85 | self._data(self.LUT_22_BW) 86 | self._command(0x23) 87 | self._data(self.LUT_23_WB) 88 | self._command(0x24) 89 | self._data(self.LUT_24_BB) 90 | 91 | def _wake_up(self): 92 | self.reset() 93 | self._command(0x01,b'\x03\x00\x2B\x2B\x03') 94 | self._command(0x06,b'\x17\x17\x17') 95 | self._command(0x04); 96 | self.wait_until_idle() 97 | 98 | self._command(0x00,b'\xBF\x0D') 99 | self._command(0x30,b'\x3A') 100 | 101 | self._command(0x61) 102 | self._data(bytearray([EPD_WIDTH])) 103 | self._data(bytearray([EPD_HEIGHT >> 8])) 104 | self._data(bytearray([EPD_HEIGHT & 0xFF])) 105 | self._init_full_update() 106 | 107 | def _sleep(self): 108 | self._command(0x02) 109 | self._command(0x07, b'\xA5') 110 | self.wait_until_idle() 111 | -------------------------------------------------------------------------------- /badgy_python.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqfmi/badgy-python/e68aadcf3167fdf8d7015b67a0d6bda2e525a2b1/badgy_python.jpg -------------------------------------------------------------------------------- /epaper2in9.py: -------------------------------------------------------------------------------- 1 | """ 2 | MicroPython Waveshare 2.9" Black/White GDEH029A1 e-paper display driver 3 | https://github.com/mcauser/micropython-waveshare-epaper 4 | 5 | MIT License 6 | Copyright (c) 2017 Waveshare 7 | Copyright (c) 2018 Mike Causer 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | """ 27 | 28 | from micropython import const 29 | from time import sleep_ms 30 | import ustruct 31 | 32 | # Display resolution 33 | EPD_WIDTH = const(128) 34 | EPD_HEIGHT = const(296) 35 | 36 | # Display commands 37 | DRIVER_OUTPUT_CONTROL = const(0x01) 38 | BOOSTER_SOFT_START_CONTROL = const(0x0C) 39 | #GATE_SCAN_START_POSITION = const(0x0F) 40 | DEEP_SLEEP_MODE = const(0x10) 41 | DATA_ENTRY_MODE_SETTING = const(0x11) 42 | #SW_RESET = const(0x12) 43 | #TEMPERATURE_SENSOR_CONTROL = const(0x1A) 44 | MASTER_ACTIVATION = const(0x20) 45 | #DISPLAY_UPDATE_CONTROL_1 = const(0x21) 46 | DISPLAY_UPDATE_CONTROL_2 = const(0x22) 47 | WRITE_RAM = const(0x24) 48 | WRITE_VCOM_REGISTER = const(0x2C) 49 | WRITE_LUT_REGISTER = const(0x32) 50 | SET_DUMMY_LINE_PERIOD = const(0x3A) 51 | SET_GATE_TIME = const(0x3B) 52 | #BORDER_WAVEFORM_CONTROL = const(0x3C) 53 | SET_RAM_X_ADDRESS_START_END_POSITION = const(0x44) 54 | SET_RAM_Y_ADDRESS_START_END_POSITION = const(0x45) 55 | SET_RAM_X_ADDRESS_COUNTER = const(0x4E) 56 | SET_RAM_Y_ADDRESS_COUNTER = const(0x4F) 57 | TERMINATE_FRAME_READ_WRITE = const(0xFF) 58 | 59 | BUSY = const(1) # 1=busy, 0=idle 60 | 61 | class EPD: 62 | def __init__(self, spi, cs, dc, rst, busy): 63 | self.spi = spi 64 | self.cs = cs 65 | self.dc = dc 66 | self.rst = rst 67 | self.busy = busy 68 | self.cs.init(self.cs.OUT, value=1) 69 | self.dc.init(self.dc.OUT, value=0) 70 | self.rst.init(self.rst.OUT, value=0) 71 | self.busy.init(self.busy.IN) 72 | self.width = EPD_WIDTH 73 | self.height = EPD_HEIGHT 74 | 75 | # 30 bytes (look up tables) 76 | # original waveshare example 77 | 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') 78 | 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') 79 | 80 | # https://github.com/ZinggJM/GxEPD/blob/master/GxGDEH029A1/GxGDEH029A1.cpp 81 | #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') 82 | #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') 83 | 84 | def _command(self, command, data=None): 85 | self.dc(0) 86 | self.cs(0) 87 | self.spi.write(bytearray([command])) 88 | self.cs(1) 89 | if data is not None: 90 | self._data(data) 91 | 92 | def _data(self, data): 93 | self.dc(1) 94 | self.cs(0) 95 | self.spi.write(data) 96 | self.cs(1) 97 | 98 | def init(self): 99 | self.reset() 100 | self._command(DRIVER_OUTPUT_CONTROL, ustruct.pack("= self.width): 128 | x_end = self.width - 1 129 | else: 130 | x_end = x + w - 1 131 | 132 | if (y + h >= self.height): 133 | y_end = self.height - 1 134 | else: 135 | y_end = y + h - 1 136 | 137 | self.set_memory_area(x, y, x_end, y_end) 138 | self.set_memory_pointer(x, y) 139 | self._command(WRITE_RAM, image) 140 | 141 | # replace the frame memory with the specified color 142 | def clear_frame_memory(self, color): 143 | self.set_memory_area(0, 0, self.width - 1, self.height - 1) 144 | self.set_memory_pointer(0, 0) 145 | self._command(WRITE_RAM) 146 | # send the color data 147 | for i in range(0, self.width // 8 * self.height): 148 | self._data(bytearray([color])) 149 | 150 | # draw the current frame memory and switch to the next memory area 151 | def display_frame(self): 152 | self._command(DISPLAY_UPDATE_CONTROL_2, b'\xC4') 153 | self._command(MASTER_ACTIVATION) 154 | self._command(TERMINATE_FRAME_READ_WRITE) 155 | self.wait_until_idle() 156 | 157 | # specify the memory area for data R/W 158 | def set_memory_area(self, x_start, y_start, x_end, y_end): 159 | self._command(SET_RAM_X_ADDRESS_START_END_POSITION) 160 | # x point must be the multiple of 8 or the last 3 bits will be ignored 161 | self._data(bytearray([(x_start >> 3) & 0xFF])) 162 | self._data(bytearray([(x_end >> 3) & 0xFF])) 163 | self._command(SET_RAM_Y_ADDRESS_START_END_POSITION, ustruct.pack("> 3) & 0xFF])) 170 | self._command(SET_RAM_Y_ADDRESS_COUNTER, ustruct.pack("