/ adafruit_bus_device / spi_device.py
spi_device.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2016 Scott Shawcroft 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  # pylint: disable=too-few-public-methods
 23  
 24  """
 25  `adafruit_bus_device.spi_device` - SPI Bus Device
 26  ====================================================
 27  """
 28  
 29  __version__ = "0.0.0-auto.0"
 30  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BusDevice.git"
 31  
 32  
 33  class SPIDevice:
 34      """
 35      Represents a single SPI device and manages locking the bus and the device
 36      address.
 37  
 38      :param ~busio.SPI spi: The SPI bus the device is on
 39      :param ~digitalio.DigitalInOut chip_select: The chip select pin object that implements the
 40          DigitalInOut API.
 41      :param int extra_clocks: The minimum number of clock cycles to cycle the bus after CS is high.
 42          (Used for SD cards.)
 43  
 44      .. note:: This class is **NOT** built into CircuitPython. See
 45        :ref:`here for install instructions <bus_device_installation>`.
 46  
 47      Example:
 48  
 49      .. code-block:: python
 50  
 51          import busio
 52          import digitalio
 53          from board import *
 54          from adafruit_bus_device.spi_device import SPIDevice
 55  
 56          with busio.SPI(SCK, MOSI, MISO) as spi_bus:
 57              cs = digitalio.DigitalInOut(D10)
 58              device = SPIDevice(spi_bus, cs)
 59              bytes_read = bytearray(4)
 60              # The object assigned to spi in the with statements below
 61              # is the original spi_bus object. We are using the busio.SPI
 62              # operations busio.SPI.readinto() and busio.SPI.write().
 63              with device as spi:
 64                  spi.readinto(bytes_read)
 65              # A second transaction
 66              with device as spi:
 67                  spi.write(bytes_read)
 68      """
 69  
 70      def __init__(
 71          self,
 72          spi,
 73          chip_select=None,
 74          *,
 75          baudrate=100000,
 76          polarity=0,
 77          phase=0,
 78          extra_clocks=0
 79      ):
 80          self.spi = spi
 81          self.baudrate = baudrate
 82          self.polarity = polarity
 83          self.phase = phase
 84          self.extra_clocks = extra_clocks
 85          self.chip_select = chip_select
 86          if self.chip_select:
 87              self.chip_select.switch_to_output(value=True)
 88  
 89      def __enter__(self):
 90          while not self.spi.try_lock():
 91              pass
 92          self.spi.configure(
 93              baudrate=self.baudrate, polarity=self.polarity, phase=self.phase
 94          )
 95          if self.chip_select:
 96              self.chip_select.value = False
 97          return self.spi
 98  
 99      def __exit__(self, exc_type, exc_val, exc_tb):
100          if self.chip_select:
101              self.chip_select.value = True
102          if self.extra_clocks > 0:
103              buf = bytearray(1)
104              buf[0] = 0xFF
105              clocks = self.extra_clocks // 8
106              if self.extra_clocks % 8 != 0:
107                  clocks += 1
108              for _ in range(clocks):
109                  self.spi.write(buf)
110          self.spi.unlock()
111          return False