/ adafruit_74hc595.py
adafruit_74hc595.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2018 Kattni Rembor 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_74hc595`
 24  ====================================================
 25  
 26  CircuitPython driver for 74HC595 shift register.
 27  
 28  * Author(s): Kattni Rembor, Tony DiCola
 29  
 30  Implementation Notes
 31  --------------------
 32  
 33  **Hardware:**
 34  
 35  "* `74HC595 Shift Register - 3 pack <https://www.adafruit.com/product/450>`_"
 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  import digitalio
 46  import adafruit_bus_device.spi_device as spi_device
 47  
 48  __version__ = "0.0.0-auto.0"
 49  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_74HC595.git"
 50  
 51  
 52  class DigitalInOut:
 53      """Digital input/output of the 74HC595.  The interface is exactly the
 54      same as the ``digitalio.DigitalInOut`` class, however note that by design
 55      this device is OUTPUT ONLY!  Attempting to read inputs or set
 56      direction as input will raise an exception.
 57      """
 58  
 59      def __init__(self, pin_number, shift_register_74hc595):
 60          """Specify the pin number of the shift register (0...7) and
 61          ShiftRegister74HC595 instance.
 62          """
 63          self._pin = pin_number
 64          self._shift_register = shift_register_74hc595
 65  
 66      # kwargs in switch functions below are _necessary_ for compatibility
 67      # with DigitalInout class (which allows specifying pull, etc. which
 68      # is unused by this class).  Do not remove them, instead turn off pylint
 69      # in this case.
 70      # pylint: disable=unused-argument
 71      def switch_to_output(self, value=False, **kwargs):
 72          """``DigitalInOut switch_to_output``"""
 73          self.direction = digitalio.Direction.OUTPUT
 74          self.value = value
 75  
 76      def switch_to_input(self, **kwargs):  # pylint: disable=no-self-use
 77          """``switch_to_input`` is not supported."""
 78          raise RuntimeError("Digital input not supported.")
 79  
 80      # pylint: enable=unused-argument
 81  
 82      @property
 83      def value(self):
 84          """The value of the pin, either True for high or False for low."""
 85          return self._shift_register.gpio & (1 << self._pin) == (1 << self._pin)
 86  
 87      @value.setter
 88      def value(self, val):
 89          gpio = self._shift_register.gpio
 90          if val:
 91              gpio |= 1 << self._pin
 92          else:
 93              gpio &= ~(1 << self._pin)
 94          self._shift_register.gpio = gpio
 95  
 96      @property
 97      def direction(self):
 98          """``Direction`` can only be set to ``OUTPUT``."""
 99          return digitalio.Direction.OUTPUT
100  
101      @direction.setter
102      def direction(self, val):  # pylint: disable=no-self-use
103          """``Direction`` can only be set to ``OUTPUT``."""
104          if val != digitalio.Direction.OUTPUT:
105              raise RuntimeError("Digital input not supported.")
106  
107      @property
108      def pull(self):
109          """Pull-up/down not supported, return None for no pull-up/down."""
110          return None
111  
112      @pull.setter
113      def pull(self, val):  # pylint: disable=no-self-use
114          """Only supports null/no pull state."""
115          if val is not None:
116              raise RuntimeError("Pull-up and pull-down not supported.")
117  
118  
119  class ShiftRegister74HC595:
120      """Initialise the 74HC595 on specified SPI bus."""
121  
122      def __init__(self, spi, latch):
123          self._device = spi_device.SPIDevice(spi, latch, baudrate=1000000)
124          self._gpio = bytearray(1)
125          self._gpio[0] = 0x00
126  
127      @property
128      def gpio(self):
129          """The raw GPIO output register.  Each bit represents the
130          output value of the associated pin (0 = low, 1 = high).
131          """
132          return self._gpio[0]
133  
134      @gpio.setter
135      def gpio(self, val):
136          self._gpio[0] = val & 0xFF
137          with self._device as spi:
138              # pylint: disable=no-member
139              spi.write(self._gpio)
140  
141      def get_pin(self, pin):
142          """Convenience function to create an instance of the DigitalInOut class
143          pointing at the specified pin of this 74HC595 device .
144          """
145          assert 0 <= pin <= 7
146          return DigitalInOut(pin, self)