/ adafruit_epd / ssd1681.py
ssd1681.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.ssd1681` - Adafruit SSD1681 - ePaper display driver
 24  ====================================================================================
 25  CircuitPython driver for Adafruit SSD1681 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  _SSD1681_DRIVER_CONTROL = const(0x01)
 38  _SSD1681_GATE_VOLTAGE = const(0x03)
 39  _SSD1681_SOURCE_VOLTAGE = const(0x04)
 40  _SSD1681_INIT_SETTING = const(0x08)
 41  _SSD1681_INIT_WRITE_REG = const(0x09)
 42  _SSD1681_INIT_READ_REG = const(0x0A)
 43  _SSD1681_BOOSTER_SOFT_START = const(0x0C)
 44  _SSD1681_DEEP_SLEEP = const(0x10)
 45  _SSD1681_DATA_MODE = const(0x11)
 46  _SSD1681_SW_RESET = const(0x12)
 47  _SSD1681_HV_DETECT = const(0x14)
 48  _SSD1681_VCI_DETECT = const(0x15)
 49  _SSD1681_TEMP_CONTROL = const(0x18)
 50  _SSD1681_TEMP_WRITE = const(0x1A)
 51  _SSD1681_TEMP_READ = const(0x1B)
 52  _SSD1681_EXTTEMP_WRITE = const(0x1C)
 53  _SSD1681_MASTER_ACTIVATE = const(0x20)
 54  _SSD1681_DISP_CTRL1 = const(0x21)
 55  _SSD1681_DISP_CTRL2 = const(0x22)
 56  _SSD1681_WRITE_BWRAM = const(0x24)
 57  _SSD1681_WRITE_REDRAM = const(0x26)
 58  _SSD1681_READ_RAM = const(0x27)
 59  _SSD1681_VCOM_SENSE = const(0x28)
 60  _SSD1681_VCOM_DURATION = const(0x29)
 61  _SSD1681_WRITE_VCOM_OTP = const(0x2A)
 62  _SSD1681_WRITE_VCOM_CTRL = const(0x2B)
 63  _SSD1681_WRITE_VCOM_REG = const(0x2C)
 64  _SSD1681_READ_OTP = const(0x2D)
 65  _SSD1681_READ_USERID = const(0x2E)
 66  _SSD1681_READ_STATUS = const(0x2F)
 67  _SSD1681_WRITE_WS_OTP = const(0x30)
 68  _SSD1681_LOAD_WS_OTP = const(0x31)
 69  _SSD1681_WRITE_LUT = const(0x32)
 70  _SSD1681_CRC_CALC = const(0x34)
 71  _SSD1681_CRC_READ = const(0x35)
 72  _SSD1681_PROG_OTP = const(0x36)
 73  _SSD1681_WRITE_DISPLAY_OPT = const(0x37)
 74  _SSD1681_WRITE_USERID = const(0x38)
 75  _SSD1681_OTP_PROGMODE = const(0x39)
 76  _SSD1681_WRITE_BORDER = const(0x3C)
 77  _SSD1681_END_OPTION = const(0x3F)
 78  _SSD1681_SET_RAMXPOS = const(0x44)
 79  _SSD1681_SET_RAMYPOS = const(0x45)
 80  _SSD1681_AUTOWRITE_RED = const(0x46)
 81  _SSD1681_AUTOWRITE_BW = const(0x47)
 82  _SSD1681_SET_RAMXCOUNT = const(0x4E)
 83  _SSD1681_SET_RAMYCOUNT = const(0x4F)
 84  _SSD1681_NOP = const(0xFF)
 85  
 86  _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
 87  
 88  
 89  class Adafruit_SSD1681(Adafruit_EPD):
 90      """driver class for Adafruit SSD1681 ePaper display breakouts"""
 91  
 92      # pylint: disable=too-many-arguments
 93      def __init__(
 94          self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
 95      ):
 96          super(Adafruit_SSD1681, self).__init__(
 97              width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
 98          )
 99  
100          if height % 8 != 0:
101              height += 8 - height % 8
102              self._height = height
103  
104          self._buffer1_size = int(width * height / 8)
105  
106          if sramcs_pin:
107              self._buffer1 = self.sram.get_view(0)
108          else:
109              self._buffer1 = bytearray((width * height) // 8)
110          self._framebuf1 = adafruit_framebuf.FrameBuffer(
111              self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
112          )
113          self.set_black_buffer(0, True)
114          self.set_color_buffer(0, True)
115          # pylint: enable=too-many-arguments
116  
117      def begin(self, reset=True):
118          """Begin communication with the display and set basic settings"""
119          if reset:
120              self.hardware_reset()
121          self.power_down()
122  
123      def busy_wait(self):
124          """Wait for display to be done with current task, either by polling the
125          busy pin, or pausing"""
126          if self._busy:
127              while self._busy.value:
128                  time.sleep(0.01)
129          else:
130              time.sleep(0.5)
131  
132      def power_up(self):
133          """Power up the display in preparation for writing RAM and updating"""
134          self.hardware_reset()
135          self.busy_wait()
136          self.command(_SSD1681_SW_RESET)
137          self.busy_wait()
138          # driver output control
139          self.command(
140              _SSD1681_DRIVER_CONTROL,
141              bytearray([self._width - 1, (self._width - 1) >> 8, 0x00]),
142          )
143          # data entry mode
144          self.command(_SSD1681_DATA_MODE, bytearray([0x03]))
145          # Set ram X start/end postion
146          self.command(_SSD1681_SET_RAMXPOS, bytearray([0x00, self._height // 8 - 1]))
147          # Set ram Y start/end postion
148          self.command(
149              _SSD1681_SET_RAMYPOS,
150              bytearray([0, 0, self._height - 1, (self._height - 1) >> 8]),
151          )
152          # Set border waveform
153          self.command(_SSD1681_WRITE_BORDER, bytearray([0x05]))
154          # Set temperature control
155          self.command(_SSD1681_TEMP_CONTROL, bytearray([0x80]))
156  
157          self.busy_wait()
158  
159      def power_down(self):
160          """Power down the display - required when not actively displaying!"""
161          self.command(_SSD1681_DEEP_SLEEP, bytearray([0x01]))
162          time.sleep(0.1)
163  
164      def update(self):
165          """Update the display from internal memory"""
166          self.command(_SSD1681_DISP_CTRL2, bytearray([0xF7]))
167          self.command(_SSD1681_MASTER_ACTIVATE)
168          self.busy_wait()
169          if not self._busy:
170              time.sleep(3)  # wait 3 seconds
171  
172      def write_ram(self, index):
173          """Send the one byte command for starting the RAM write process. Returns
174          the byte read at the same time over SPI. index is the RAM buffer, can be
175          0 or 1 for tri-color displays."""
176          if index == 0:
177              return self.command(_SSD1681_WRITE_BWRAM, end=False)
178          raise RuntimeError("RAM index must be 0")
179  
180      def set_ram_address(self, x, y):  # pylint: disable=unused-argument, no-self-use
181          """Set the RAM address location, not used on this chipset but required by
182          the superclass"""
183          # Set RAM X address counter
184          self.command(_SSD1681_SET_RAMXCOUNT, bytearray([x]))
185          # Set RAM Y address counter
186          self.command(_SSD1681_SET_RAMYCOUNT, bytearray([y >> 8, y]))