/ adafruit_epd / ssd1675.py
ssd1675.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.ssd1675` - Adafruit SSD1675 - ePaper display driver
 24  ====================================================================================
 25  CircuitPython driver for Adafruit SSD1675 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  _SSD1675_DRIVER_CONTROL = const(0x01)
 38  _SSD1675_GATE_VOLTAGE = const(0x03)
 39  _SSD1675_SOURCE_VOLTAGE = const(0x04)
 40  _SSD1675_DEEP_SLEEP = const(0x10)
 41  _SSD1675_DATA_MODE = const(0x11)
 42  _SSD1675_SW_RESET = const(0x12)
 43  _SSD1675_HV_READY = const(0x14)
 44  _SSD1675_VCI_READY = const(0x15)
 45  _SSD1675_TEMP_WRITE = const(0x1A)
 46  _SSD1675_MASTER_ACTIVATE = const(0x20)
 47  _SSD1675_DISP_CTRL1 = const(0x21)
 48  _SSD1675_DISP_CTRL2 = const(0x22)
 49  _SSD1675_WRITE_RAM1 = const(0x24)
 50  _SSD1675_WRITE_RAM2 = const(0x26)
 51  _SSD1675_WRITE_VCOM = const(0x2C)
 52  _SSD1675_READ_OTP = const(0x2D)
 53  _SSD1675_WRITE_LUT = const(0x32)
 54  _SSD1675_WRITE_DUMMY = const(0x3A)
 55  _SSD1675_WRITE_GATELINE = const(0x3B)
 56  _SSD1675_WRITE_BORDER = const(0x3C)
 57  _SSD1675_SET_RAMXPOS = const(0x44)
 58  _SSD1675_SET_RAMYPOS = const(0x45)
 59  _SSD1675_SET_RAMXCOUNT = const(0x4E)
 60  _SSD1675_SET_RAMYCOUNT = const(0x4F)
 61  _SSD1675_SET_ANALOGBLOCK = const(0x74)
 62  _SSD1675_SET_DIGITALBLOCK = const(0x7E)
 63  _LUT_DATA = b"\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x02\t\t\x00\x00\x02\x03\x03\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa820\n"  # pylint: disable=line-too-long
 64  
 65  
 66  class Adafruit_SSD1675(Adafruit_EPD):
 67      """driver class for Adafruit SSD1675 ePaper display breakouts"""
 68  
 69      # pylint: disable=too-many-arguments
 70      def __init__(
 71          self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
 72      ):
 73          super(Adafruit_SSD1675, self).__init__(
 74              width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
 75          )
 76          stride = width
 77          if stride % 8 != 0:
 78              stride += 8 - stride % 8
 79  
 80          self._buffer1_size = int(stride * height / 8)
 81          self._buffer2_size = self._buffer1_size
 82  
 83          if sramcs_pin:
 84              self._buffer1 = self.sram.get_view(0)
 85              self._buffer2 = self.sram.get_view(self._buffer1_size)
 86          else:
 87              self._buffer1 = bytearray(self._buffer1_size)
 88              self._buffer2 = bytearray(self._buffer2_size)
 89          # since we have *two* framebuffers - one for red and one for black
 90          # we dont subclass but manage manually
 91          self._framebuf1 = adafruit_framebuf.FrameBuffer(
 92              self._buffer1,
 93              width,
 94              height,
 95              stride=stride,
 96              buf_format=adafruit_framebuf.MHMSB,
 97          )
 98          self._framebuf2 = adafruit_framebuf.FrameBuffer(
 99              self._buffer2,
100              width,
101              height,
102              stride=stride,
103              buf_format=adafruit_framebuf.MHMSB,
104          )
105          self.set_black_buffer(0, True)
106          self.set_color_buffer(0, True)
107          # pylint: enable=too-many-arguments
108  
109      def begin(self, reset=True):
110          """Begin communication with the display and set basic settings"""
111          if reset:
112              self.hardware_reset()
113          self.power_down()
114  
115      def busy_wait(self):
116          """Wait for display to be done with current task, either by polling the
117          busy pin, or pausing"""
118          if self._busy:
119              while self._busy.value:
120                  time.sleep(0.01)
121          else:
122              time.sleep(0.5)
123  
124      def power_up(self):
125          """Power up the display in preparation for writing RAM and updating"""
126          self.hardware_reset()
127          time.sleep(0.1)
128          self.busy_wait()
129  
130          self.command(_SSD1675_SW_RESET)
131          self.busy_wait()
132  
133          # set analog block control
134          self.command(_SSD1675_SET_ANALOGBLOCK, bytearray([0x54]))
135          # set digital block control
136          self.command(_SSD1675_SET_DIGITALBLOCK, bytearray([0x3B]))
137  
138          # driver output control
139          self.command(_SSD1675_DRIVER_CONTROL, bytearray([0xFA, 0x01, 0x00]))
140          # Data entry sequence
141          self.command(_SSD1675_DATA_MODE, bytearray([0x03]))
142          # Set ram X start/end postion
143          self.command(_SSD1675_SET_RAMXPOS, bytearray([0x00, 0x0F]))
144          # Set ram Y start/end postion
145          self.command(_SSD1675_SET_RAMYPOS, bytearray([0, 0, 0xF9, 0]))
146          # Border color
147          self.command(_SSD1675_WRITE_BORDER, bytearray([0x03]))
148          # Vcom Voltage
149          self.command(_SSD1675_WRITE_VCOM, bytearray([0x70]))
150          # Set gate voltage
151          self.command(_SSD1675_GATE_VOLTAGE, _LUT_DATA[70:71])
152          # Set gate voltage
153          self.command(_SSD1675_SOURCE_VOLTAGE, _LUT_DATA[71:74])
154          # Set dummy line period
155          self.command(_SSD1675_WRITE_DUMMY, _LUT_DATA[74:75])
156          # Set gate line width
157          self.command(_SSD1675_WRITE_GATELINE, _LUT_DATA[75:76])
158          # LUT
159          self.command(_SSD1675_WRITE_LUT, _LUT_DATA[0:70])
160  
161          self.command(_SSD1675_SET_RAMXCOUNT, bytearray([0]))
162          # Set RAM Y address counter
163          self.command(_SSD1675_SET_RAMYCOUNT, bytearray([0xF9, 0]))
164  
165          self.busy_wait()
166  
167      def power_down(self):
168          """Power down the display - required when not actively displaying!"""
169          self.command(_SSD1675_DEEP_SLEEP, bytearray([0x01]))
170          time.sleep(0.1)
171  
172      def update(self):
173          """Update the display from internal memory"""
174          self.command(_SSD1675_DISP_CTRL2, bytearray([0xC7]))
175          self.command(_SSD1675_MASTER_ACTIVATE)
176          self.busy_wait()
177          if not self._busy:
178              time.sleep(3)  # wait 3 seconds
179  
180      def write_ram(self, index):
181          """Send the one byte command for starting the RAM write process. Returns
182          the byte read at the same time over SPI. index is the RAM buffer, can be
183          0 or 1 for tri-color displays."""
184          if index == 0:
185              return self.command(_SSD1675_WRITE_RAM1, end=False)
186          if index == 1:
187              return self.command(_SSD1675_WRITE_RAM2, end=False)
188          raise RuntimeError("RAM index must be 0 or 1")
189  
190      def set_ram_address(self, x, y):  # pylint: disable=unused-argument, no-self-use
191          """Set the RAM address location, not used on this chipset but required by
192          the superclass"""
193          self.command(_SSD1675_SET_RAMXCOUNT, bytearray([x]))
194          self.command(_SSD1675_SET_RAMYCOUNT, bytearray([y, y >> 8]))