/ adafruit_epd / ssd1608.py
ssd1608.py
1 # The MIT License (MIT) 2 # 3 # Copyright (c) 2018 Dean Miller for Adafruit Industries 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 13 # all 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 21 # THE SOFTWARE. 22 """ 23 `adafruit_epd.ssd1608` - Adafruit SSD1608 - ePaper display driver 24 ==================================================================================== 25 CircuitPython driver for Adafruit SSD1608 display breakouts 26 * Author(s): Dean Miller, Ladyada 27 """ 28 29 import time 30 from micropython import const 31 import adafruit_framebuf 32 from adafruit_epd.epd import Adafruit_EPD 33 34 __version__ = "0.0.0-auto.0" 35 __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git" 36 37 _SSD1608_DRIVER_CONTROL = const(0x01) 38 _SSD1608_GATE_VOLTAGE = const(0x03) 39 _SSD1608_SOURCE_VOLTAGE = const(0x04) 40 _SSD1608_DISPLAY_CONTROL = const(0x07) 41 _SSD1608_NON_OVERLAP = const(0x0B) 42 _SSD1608_BOOSTER_SOFT_START = const(0x0C) 43 _SSD1608_GATE_SCAN_START = const(0x0F) 44 _SSD1608_DEEP_SLEEP = const(0x10) 45 _SSD1608_DATA_MODE = const(0x11) 46 _SSD1608_SW_RESET = const(0x12) 47 _SSD1608_TEMP_WRITE = const(0x1A) 48 _SSD1608_TEMP_READ = const(0x1B) 49 _SSD1608_TEMP_CONTROL = const(0x1C) 50 _SSD1608_TEMP_LOAD = const(0x1D) 51 _SSD1608_MASTER_ACTIVATE = const(0x20) 52 _SSD1608_DISP_CTRL1 = const(0x21) 53 _SSD1608_DISP_CTRL2 = const(0x22) 54 _SSD1608_WRITE_RAM = const(0x24) 55 _SSD1608_READ_RAM = const(0x25) 56 _SSD1608_VCOM_SENSE = const(0x28) 57 _SSD1608_VCOM_DURATION = const(0x29) 58 _SSD1608_WRITE_VCOM = const(0x2C) 59 _SSD1608_READ_OTP = const(0x2D) 60 _SSD1608_WRITE_LUT = const(0x32) 61 _SSD1608_WRITE_DUMMY = const(0x3A) 62 _SSD1608_WRITE_GATELINE = const(0x3B) 63 _SSD1608_WRITE_BORDER = const(0x3C) 64 _SSD1608_SET_RAMXPOS = const(0x44) 65 _SSD1608_SET_RAMYPOS = const(0x45) 66 _SSD1608_SET_RAMXCOUNT = const(0x4E) 67 _SSD1608_SET_RAMYCOUNT = const(0x4F) 68 _SSD1608_NOP = const(0xFF) 69 _LUT_DATA = b'\x02\x02\x01\x11\x12\x12""fiiYX\x99\x99\x88\x00\x00\x00\x00\xf8\xb4\x13Q5QQ\x19\x01\x00' # pylint: disable=line-too-long 70 71 72 class Adafruit_SSD1608(Adafruit_EPD): 73 """driver class for Adafruit SSD1608 ePaper display breakouts""" 74 75 # pylint: disable=too-many-arguments 76 def __init__( 77 self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin 78 ): 79 super(Adafruit_SSD1608, self).__init__( 80 width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin 81 ) 82 83 if height % 8 != 0: 84 height += 8 - height % 8 85 self._height = height 86 87 self._buffer1_size = int(width * height / 8) 88 89 if sramcs_pin: 90 self._buffer1 = self.sram.get_view(0) 91 else: 92 self._buffer1 = bytearray((width * height) // 8) 93 self._framebuf1 = adafruit_framebuf.FrameBuffer( 94 self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB 95 ) 96 self.set_black_buffer(0, True) 97 self.set_color_buffer(0, True) 98 # pylint: enable=too-many-arguments 99 100 def begin(self, reset=True): 101 """Begin communication with the display and set basic settings""" 102 if reset: 103 self.hardware_reset() 104 self.power_down() 105 106 def busy_wait(self): 107 """Wait for display to be done with current task, either by polling the 108 busy pin, or pausing""" 109 if self._busy: 110 while self._busy.value: 111 time.sleep(0.01) 112 else: 113 time.sleep(0.5) 114 115 def power_up(self): 116 """Power up the display in preparation for writing RAM and updating""" 117 self.hardware_reset() 118 self.busy_wait() 119 self.command(_SSD1608_SW_RESET) 120 self.busy_wait() 121 # driver output control 122 self.command( 123 _SSD1608_DRIVER_CONTROL, 124 bytearray([self._width - 1, (self._width - 1) >> 8, 0x00]), 125 ) 126 # Set dummy line period 127 self.command(_SSD1608_WRITE_DUMMY, bytearray([0x1B])) 128 # Set gate line width 129 self.command(_SSD1608_WRITE_GATELINE, bytearray([0x0B])) 130 # Data entry sequence 131 self.command(_SSD1608_DATA_MODE, bytearray([0x03])) 132 # Set ram X start/end postion 133 self.command(_SSD1608_SET_RAMXPOS, bytearray([0x00, self._height // 8 - 1])) 134 # Set ram Y start/end postion 135 self.command( 136 _SSD1608_SET_RAMYPOS, 137 bytearray([0, 0, self._height - 1, (self._height - 1) >> 8]), 138 ) 139 # Vcom Voltage 140 self.command(_SSD1608_WRITE_VCOM, bytearray([0x70])) 141 # LUT 142 self.command(_SSD1608_WRITE_LUT, _LUT_DATA) 143 self.busy_wait() 144 145 def power_down(self): 146 """Power down the display - required when not actively displaying!""" 147 self.command(_SSD1608_DEEP_SLEEP, bytearray([0x01])) 148 time.sleep(0.1) 149 150 def update(self): 151 """Update the display from internal memory""" 152 self.command(_SSD1608_DISP_CTRL2, bytearray([0xC7])) 153 self.command(_SSD1608_MASTER_ACTIVATE) 154 self.busy_wait() 155 if not self._busy: 156 time.sleep(3) # wait 3 seconds 157 158 def write_ram(self, index): 159 """Send the one byte command for starting the RAM write process. Returns 160 the byte read at the same time over SPI. index is the RAM buffer, can be 161 0 or 1 for tri-color displays.""" 162 if index == 0: 163 return self.command(_SSD1608_WRITE_RAM, end=False) 164 raise RuntimeError("RAM index must be 0") 165 166 def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use 167 """Set the RAM address location, not used on this chipset but required by 168 the superclass""" 169 # Set RAM X address counter 170 self.command(_SSD1608_SET_RAMXCOUNT, bytearray([x])) 171 # Set RAM Y address counter 172 self.command(_SSD1608_SET_RAMYCOUNT, bytearray([y >> 8, y]))