/ 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]))