/ adafruit_epd / il91874.py
il91874.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.il91874` - Adafruit IL91874 - ePaper display driver
 24  ====================================================================================
 25  CircuitPython driver for Adafruit IL91874 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  _IL91874_PANEL_SETTING = const(0x00)
 38  _IL91874_POWER_SETTING = const(0x01)
 39  _IL91874_POWER_OFF = const(0x02)
 40  _IL91874_POWER_OFF_SEQUENCE = const(0x03)
 41  _IL91874_POWER_ON = const(0x04)
 42  _IL91874_POWER_ON_MEASURE = const(0x05)
 43  _IL91874_BOOSTER_SOFT_START = const(0x06)
 44  _IL91874_DEEP_SLEEP = const(0x07)
 45  _IL91874_DTM1 = const(0x10)
 46  _IL91874_DATA_STOP = const(0x11)
 47  _IL91874_DISPLAY_REFRESH = const(0x12)
 48  _IL91874_DTM2 = const(0x13)
 49  _IL91874_PDTM1 = const(0x14)
 50  _IL91874_PDTM2 = const(0x15)
 51  _IL91874_PDRF = const(0x16)
 52  _IL91874_LUT1 = const(0x20)
 53  _IL91874_LUTWW = const(0x21)
 54  _IL91874_LUTBW = const(0x22)
 55  _IL91874_LUTWB = const(0x23)
 56  _IL91874_LUTBB = const(0x24)
 57  _IL91874_PLL = const(0x30)
 58  _IL91874_CDI = const(0x50)
 59  _IL91874_RESOLUTION = const(0x61)
 60  _IL91874_VCM_DC_SETTING = const(0x82)
 61  
 62  # pylint: disable=line-too-long
 63  _LUT_VCOMDC = b"\x00\x00\x00\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x00\x0e\x01\x0e\x01\x10\x00\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
 64  _LUT_WW = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
 65  _LUT_BW = b"\xa0\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x90\n\n\x00\x00\x08\xb0\x04\x10\x00\x00\x05\xb0\x03\x0e\x00\x00\n\xc0#\x00\x00\x00\x01"
 66  _LUT_BB = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
 67  _LUT_WB = b"\x90\x1a\x1a\x00\x00\x01 \n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x10\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
 68  # pylint: enable=line-too-long
 69  
 70  
 71  class Adafruit_IL91874(Adafruit_EPD):
 72      """driver class for Adafruit IL91874 ePaper display breakouts"""
 73  
 74      # pylint: disable=too-many-arguments
 75      def __init__(
 76          self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
 77      ):
 78          super(Adafruit_IL91874, self).__init__(
 79              width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
 80          )
 81  
 82          self._buffer1_size = int(width * height / 8)
 83          self._buffer2_size = int(width * height / 8)
 84  
 85          if sramcs_pin:
 86              self._buffer1 = self.sram.get_view(0)
 87              self._buffer2 = self.sram.get_view(self._buffer1_size)
 88          else:
 89              self._buffer1 = bytearray((width * height) // 8)
 90              self._buffer2 = bytearray((width * height) // 8)
 91          # since we have *two* framebuffers - one for red and one for black
 92          # we dont subclass but manage manually
 93          self._framebuf1 = adafruit_framebuf.FrameBuffer(
 94              self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
 95          )
 96          self._framebuf2 = adafruit_framebuf.FrameBuffer(
 97              self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB
 98          )
 99          self.set_black_buffer(0, True)
100          self.set_color_buffer(1, False)
101          self._single_byte_tx = True
102  
103      def begin(self, reset=True):
104          """Begin communication with the display and set basic settings"""
105          if reset:
106              self.hardware_reset()
107  
108          self.power_down()
109  
110      def busy_wait(self):
111          """Wait for display to be done with current task, either by polling the
112          busy pin, or pausing"""
113          if self._busy:
114              while not self._busy.value:
115                  time.sleep(0.01)
116          else:
117              time.sleep(0.5)
118  
119      def power_up(self):
120          """Power up the display in preparation for writing RAM and updating"""
121          self.hardware_reset()
122          time.sleep(0.2)
123          self.command(_IL91874_POWER_ON)
124          self.busy_wait()
125  
126          self.command(_IL91874_PANEL_SETTING, bytearray([0xAF]))
127          self.command(_IL91874_PLL, bytearray([0x3A]))
128          self.command(_IL91874_POWER_SETTING, bytearray([0x03, 0x00, 0x2B, 0x2B, 0x09]))
129          self.command(_IL91874_BOOSTER_SOFT_START, bytearray([0x07, 0x07, 0x17]))
130  
131          self.command(0xF8, bytearray([0x60, 0xA5]))  # mystery command in example code
132          self.command(0xF8, bytearray([0x89, 0xA5]))  # mystery command in example code
133          self.command(0xF8, bytearray([0x90, 0x00]))  # mystery command in example code
134          self.command(0xF8, bytearray([0x93, 0xA2]))  # mystery command in example code
135          self.command(0xF8, bytearray([0x73, 0x41]))  # mystery command in example code
136  
137          self.command(_IL91874_VCM_DC_SETTING, bytearray([0x12]))
138          self.command(_IL91874_CDI, bytearray([0x87]))
139  
140          # Look Up Tables
141          self.command(_IL91874_LUT1, _LUT_VCOMDC)
142          self.command(_IL91874_LUTWW, _LUT_WW)
143          self.command(_IL91874_LUTBW, _LUT_BW)
144          self.command(_IL91874_LUTWB, _LUT_WB)
145          self.command(_IL91874_LUTBB, _LUT_BB)
146  
147          _b0 = (self._width >> 8) & 0xFF
148          _b1 = self._width & 0xFF
149          _b2 = (self._height >> 8) & 0xFF
150          _b3 = self._height & 0xFF
151          self.command(_IL91874_RESOLUTION, bytearray([_b0, _b1, _b2, _b3]))
152          self.command(_IL91874_PDRF, bytearray([0x00]))
153  
154      def power_down(self):
155          """Power down the display - required when not actively displaying!"""
156          self.command(_IL91874_POWER_OFF, bytearray([0x17]))
157          self.busy_wait()
158  
159          if self._rst:  # Only deep sleep if we can get out of it
160              self.command(_IL91874_DEEP_SLEEP, bytearray([0xA5]))
161  
162      def update(self):
163          """Update the display from internal memory"""
164          self.command(_IL91874_DISPLAY_REFRESH)
165          self.busy_wait()
166          if not self._busy:
167              time.sleep(16)  # wait 16 seconds
168  
169      def write_ram(self, index):
170          """Send the one byte command for starting the RAM write process. Returns
171          the byte read at the same time over SPI. index is the RAM buffer, can be
172          0 or 1 for tri-color displays."""
173          if index == 0:
174              return self.command(_IL91874_DTM1, end=False)
175          if index == 1:
176              return self.command(_IL91874_DTM2, end=False)
177          raise RuntimeError("RAM index must be 0 or 1")
178  
179      def set_ram_address(self, x, y):  # pylint: disable=unused-argument, no-self-use
180          """Set the RAM address location, not used on this chipset but required by
181          the superclass"""
182          return  # on this chip it does nothing