bitbangio.py
1 """ 2 `bitbangio` - Bitbanged bus protocols 3 ============================================================== 4 5 See `CircuitPython:bitbangio` in CircuitPython for more details. 6 7 * Author(s): cefn 8 """ 9 10 import adafruit_platformdetect.constants.boards as ap_board 11 from adafruit_blinka import Lockable, agnostic 12 13 # pylint: disable=import-outside-toplevel,too-many-arguments 14 15 16 class I2C(Lockable): 17 """Bitbang/Software I2C implementation""" 18 19 def __init__(self, scl, sda, frequency=400000): 20 # TODO: This one is a bit questionable: 21 if agnostic.board_id == ap_board.PYBOARD: 22 raise NotImplementedError("No software I2C on {}".format(agnostic.board_id)) 23 if agnostic.detector.board.any_embedded_linux: 24 # TODO: Attempt to load this library automatically 25 raise NotImplementedError( 26 "For bitbangio on Linux, please use Adafruit_CircuitPython_BitbangIO" 27 ) 28 self.init(scl, sda, frequency) 29 30 def init(self, scl, sda, frequency): 31 """Initialization""" 32 from machine import Pin 33 from machine import I2C as _I2C 34 35 self.deinit() 36 id = ( # pylint: disable=redefined-builtin 37 -1 38 ) # force bitbanging implementation - in future 39 # introspect platform if SDA/SCL matches hardware I2C 40 self._i2c = _I2C(id, Pin(scl.id), Pin(sda.id), freq=frequency) 41 42 def deinit(self): 43 """Deinitialization""" 44 try: 45 del self._i2c 46 except AttributeError: 47 pass 48 49 def __enter__(self): 50 return self 51 52 def __exit__(self, exc_type, exc_value, traceback): 53 self.deinit() 54 55 def scan(self): 56 """Scan for attached devices""" 57 return self._i2c.scan() 58 59 def readfrom_into(self, address, buffer, start=0, end=None): 60 """Read from a device at specified address into a buffer""" 61 if start != 0 or end is not None: 62 if end is None: 63 end = len(buffer) 64 buffer = memoryview(buffer)[start:end] 65 stop = True # remove for efficiency later 66 return self._i2c.readfrom_into(address, buffer, stop) 67 68 def writeto(self, address, buffer, start=0, end=None, stop=True): 69 """Write to a device at specified address from a buffer""" 70 if start != 0 or end is not None: 71 if end is None: 72 return self._i2c.writeto(address, memoryview(buffer)[start:], stop) 73 return self._i2c.writeto(address, memoryview(buffer)[start:end], stop) 74 return self._i2c.writeto(address, buffer, stop) 75 76 77 # TODO untested, as actually busio.SPI was on 78 # tasklist https://github.com/adafruit/Adafruit_Micropython_Blinka/issues/2 :( 79 class SPI(Lockable): 80 """Bitbang/Software SPI implementation""" 81 82 def __init__(self, clock, MOSI=None, MISO=None): 83 if agnostic.detector.board.any_embedded_linux: 84 # TODO: Attempt to load this library automatically 85 raise NotImplementedError( 86 "For bitbangio on Linux, please use Adafruit_CircuitPython_BitbangIO" 87 ) 88 from machine import SPI as _SPI 89 90 self._spi = _SPI(-1) 91 self._pins = (clock, MOSI, MISO) 92 93 def configure(self, baudrate=100000, polarity=0, phase=0, bits=8): 94 """Update the configuration""" 95 from machine import Pin 96 from machine import SPI as _SPI 97 98 if self._locked: 99 # TODO verify if _spi obj 'caches' sck, mosi, miso to 100 # avoid storing in _attributeIds (duplicated in busio) 101 # i.e. #init ignores MOSI=None rather than unsetting 102 self._spi.init( 103 baudrate=baudrate, 104 polarity=polarity, 105 phase=phase, 106 bits=bits, 107 firstbit=_SPI.MSB, 108 sck=Pin(self._pins[0].id), 109 mosi=Pin(self._pins[1].id), 110 miso=Pin(self._pins[2].id), 111 ) 112 else: 113 raise RuntimeError("First call try_lock()") 114 115 def write(self, buf): 116 """Write to the SPI device""" 117 return self._spi.write(buf) 118 119 def readinto(self, buf): 120 """Read from the SPI device into a buffer""" 121 return self.readinto(buf) 122 123 def write_readinto(self, buffer_out, buffer_in): 124 """Write to the SPI device and read from the SPI device into a buffer""" 125 return self.write_readinto(buffer_out, buffer_in)