/ adafruit_pcd8544.py
adafruit_pcd8544.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2018 Tony DiCola, ladyada 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_pcd8544`
 24  ====================================================
 25  
 26  A display control library for Nokia 5110 PCD8544 monochrome displays
 27  
 28  * Author(s): ladyada
 29  
 30  Implementation Notes
 31  --------------------
 32  
 33  **Hardware:**
 34  
 35  * `Nokia 5110 PCD8544 Display <https://www.adafruit.com/product/338>`_
 36  
 37  **Software and Dependencies:**
 38  
 39  * Adafruit CircuitPython firmware for the supported boards:
 40    https://github.com/adafruit/circuitpython/releases
 41  
 42  * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
 43  
 44  """
 45  
 46  import time
 47  from micropython import const
 48  from adafruit_bus_device import spi_device
 49  
 50  try:
 51      import framebuf
 52  except ImportError:
 53      import adafruit_framebuf as framebuf
 54  
 55  __version__ = "0.0.0-auto.0"
 56  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PCD8544.git"
 57  
 58  _LCDWIDTH = const(84)
 59  _LCDHEIGHT = const(48)
 60  _PCD8544_POWERDOWN = const(0x04)
 61  _PCD8544_ENTRYMODE = const(0x02)
 62  _PCD8544_EXTENDEDINSTRUCTION = const(0x01)
 63  _PCD8544_DISPLAYBLANK = const(0x0)
 64  _PCD8544_DISPLAYNORMAL = const(0x4)
 65  _PCD8544_DISPLAYALLON = const(0x1)
 66  _PCD8544_DISPLAYINVERTED = const(0x5)
 67  _PCD8544_FUNCTIONSET = const(0x20)
 68  _PCD8544_DISPLAYCONTROL = const(0x08)
 69  _PCD8544_SETYADDR = const(0x40)
 70  _PCD8544_SETXADDR = const(0x80)
 71  _PCD8544_SETTEMP = const(0x04)
 72  _PCD8544_SETBIAS = const(0x10)
 73  _PCD8544_SETVOP = const(0x80)
 74  
 75  
 76  class PCD8544(framebuf.FrameBuffer):
 77      """Nokia 5110/3310 PCD8544-based LCD display."""
 78  
 79      # pylint: disable=too-many-instance-attributes
 80  
 81      def __init__(
 82          self,
 83          spi,
 84          dc_pin,
 85          cs_pin,
 86          reset_pin=None,
 87          *,
 88          contrast=80,
 89          bias=4,
 90          baudrate=1000000
 91      ):
 92          self._dc_pin = dc_pin
 93          dc_pin.switch_to_output(value=False)
 94  
 95          self.spi_device = spi_device.SPIDevice(spi, cs_pin, baudrate=baudrate)
 96  
 97          self._reset_pin = reset_pin
 98          if reset_pin:
 99              reset_pin.switch_to_output(value=True)
100  
101          self.buffer = bytearray((_LCDHEIGHT // 8) * _LCDWIDTH)
102          super().__init__(self.buffer, _LCDWIDTH, _LCDHEIGHT)
103  
104          self._contrast = None
105          self._bias = None
106          self._invert = False
107  
108          self.reset()
109          # Set LCD bias.
110          self.bias = bias
111          self.contrast = contrast
112  
113      def reset(self):
114          """Reset the display"""
115          if self._reset_pin:
116              # Toggle RST low to reset.
117              self._reset_pin.value = False
118              time.sleep(0.5)
119              self._reset_pin.value = True
120              time.sleep(0.5)
121  
122      def write_cmd(self, cmd):
123          """Send a command to the SPI device"""
124          self._dc_pin.value = 0
125          with self.spi_device as spi:
126              spi.write(bytearray([cmd]))  # pylint: disable=no-member
127  
128      def extended_command(self, cmd):
129          """Send a command in extended mode"""
130          # Set extended command mode
131          self.write_cmd(_PCD8544_FUNCTIONSET | _PCD8544_EXTENDEDINSTRUCTION)
132          self.write_cmd(cmd)
133          # Set normal display mode.
134          self.write_cmd(_PCD8544_FUNCTIONSET)
135          self.write_cmd(_PCD8544_DISPLAYCONTROL | _PCD8544_DISPLAYNORMAL)
136  
137      def show(self):
138          """write out the frame buffer via SPI"""
139          self.write_cmd(_PCD8544_SETYADDR)
140          self.write_cmd(_PCD8544_SETXADDR)
141          self._dc_pin.value = True
142          with self.spi_device as spi:
143              spi.write(self.buffer)  # pylint: disable=no-member
144  
145      @property
146      def invert(self):
147          """Whether the display is inverted, cached value"""
148          return self._invert
149  
150      @invert.setter
151      def invert(self, val):
152          """Set invert on or normal display on"""
153          self._invert = val
154          self.write_cmd(_PCD8544_FUNCTIONSET)
155          if val:
156              self.write_cmd(_PCD8544_DISPLAYCONTROL | _PCD8544_DISPLAYINVERTED)
157          else:
158              self.write_cmd(_PCD8544_DISPLAYCONTROL | _PCD8544_DISPLAYNORMAL)
159  
160      @property
161      def contrast(self):
162          """The cached contrast value"""
163          return self._contrast
164  
165      @contrast.setter
166      def contrast(self, val):
167          """Set contrast to specified value (should be 0-127)."""
168          self._contrast = max(0, min(val, 0x7F))  # Clamp to values 0-0x7f
169          self.extended_command(_PCD8544_SETVOP | self._contrast)
170  
171      @property
172      def bias(self):
173          """The cached bias value"""
174          return self._bias
175  
176      @bias.setter
177      def bias(self, val):
178          """Set display bias"""
179          self._bias = val
180          self.extended_command(_PCD8544_SETBIAS | self._bias)