2 `busio` - Bus protocol support like I2C and SPI
3 =================================================
5 See `CircuitPython:busio` in CircuitPython for more details.
15 import adafruit_platformdetect.constants.boards as ap_board
16 import adafruit_platformdetect.constants.chips as ap_chip
17 from adafruit_blinka import Enum, Lockable, agnostic
18 from adafruit_blinka.agnostic import board_id, detector
20 # pylint: disable=import-outside-toplevel,too-many-branches,too-many-statements
21 # pylint: disable=too-many-arguments,too-many-function-args,consider-using-with
26 Busio I2C Class for CircuitPython Compatibility. Used
27 for both MicroPython and Linux.
30 def __init__(self, scl, sda, frequency=100000):
31 self.init(scl, sda, frequency)
33 def init(self, scl, sda, frequency):
36 if detector.board.ftdi_ft232h:
37 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
39 self._i2c = _I2C(frequency=frequency)
41 if detector.board.binho_nova:
42 from adafruit_blinka.microcontroller.nova.i2c import I2C as _I2C
44 self._i2c = _I2C(frequency=frequency)
46 if detector.board.microchip_mcp2221:
47 from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C
49 self._i2c = _I2C(frequency=frequency)
51 if detector.board.greatfet_one:
52 from adafruit_blinka.microcontroller.nxp_lpc4330.i2c import I2C as _I2C
54 self._i2c = _I2C(frequency=frequency)
56 if detector.board.pico_u2if:
57 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_Pico as _I2C
59 self._i2c = _I2C(scl, sda, frequency=frequency)
61 if detector.board.feather_u2if:
62 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_Feather as _I2C
64 self._i2c = _I2C(scl, sda, frequency=frequency)
66 if detector.board.qtpy_u2if:
67 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_QTPY as _I2C
69 self._i2c = _I2C(scl, sda, frequency=frequency)
71 if detector.board.itsybitsy_u2if:
72 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_ItsyBitsy as _I2C
74 self._i2c = _I2C(scl, sda, frequency=frequency)
76 if detector.board.qt2040_trinkey_u2if:
77 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_QT2040_Trinkey as _I2C
79 self._i2c = _I2C(scl, sda, frequency=frequency)
81 if detector.chip.id == ap_chip.RP2040:
82 from adafruit_blinka.microcontroller.rp2040.i2c import I2C as _I2C
84 self._i2c = _I2C(scl, sda, frequency=frequency)
86 if detector.board.any_embedded_linux:
87 from adafruit_blinka.microcontroller.generic_linux.i2c import I2C as _I2C
88 elif detector.board.ftdi_ft2232h:
89 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
91 from adafruit_blinka.microcontroller.generic_micropython.i2c import (
94 from microcontroller.pin import i2cPorts
96 for portId, portScl, portSda in i2cPorts:
98 # pylint: disable=unexpected-keyword-arg
99 if scl == portScl and sda == portSda:
100 self._i2c = _I2C(portId, mode=_I2C.MASTER, baudrate=frequency)
102 # pylint: enable=unexpected-keyword-arg
107 "No Hardware I2C on (scl,sda)={}\nValid I2C ports: {}".format(
111 if threading is not None:
112 self._lock = threading.RLock()
115 """Deinitialization"""
118 except AttributeError:
122 if threading is not None:
126 def __exit__(self, exc_type, exc_value, traceback):
127 if threading is not None:
132 """Scan for attached devices"""
133 return self._i2c.scan()
135 def readfrom_into(self, address, buffer, *, start=0, end=None):
136 """Read from a device at specified address into a buffer"""
137 if start != 0 or end is not None:
140 buffer = memoryview(buffer)[start:end]
141 stop = True # remove for efficiency later
142 return self._i2c.readfrom_into(address, buffer, stop=stop)
144 def writeto(self, address, buffer, *, start=0, end=None, stop=True):
145 """Write to a device at specified address from a buffer"""
146 if isinstance(buffer, str):
147 buffer = bytes([ord(x) for x in buffer])
148 if start != 0 or end is not None:
150 return self._i2c.writeto(address, memoryview(buffer)[start:], stop=stop)
151 return self._i2c.writeto(address, memoryview(buffer)[start:end], stop=stop)
152 return self._i2c.writeto(address, buffer, stop=stop)
154 def writeto_then_readfrom(
166 """ "Write to a device at specified address from a buffer then read
167 from a device at specified address into a buffer
169 return self._i2c.writeto_then_readfrom(
183 Busio SPI Class for CircuitPython Compatibility. Used
184 for both MicroPython and Linux.
187 def __init__(self, clock, MOSI=None, MISO=None):
189 if detector.board.ftdi_ft232h:
190 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
191 from adafruit_blinka.microcontroller.ftdi_mpsse.ft232h.pin import (
198 self._pins = (SCK, MOSI, MISO)
200 if detector.board.binho_nova:
201 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
202 from adafruit_blinka.microcontroller.nova.pin import SCK, MOSI, MISO
204 self._spi = _SPI(clock)
205 self._pins = (SCK, MOSI, MISO)
207 if detector.board.greatfet_one:
208 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
209 from adafruit_blinka.microcontroller.nxp_lpc4330.pin import SCK, MOSI, MISO
212 self._pins = (SCK, MOSI, MISO)
214 if detector.board.pico_u2if:
215 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
217 self._spi = _SPI(clock) # this is really all that's needed
218 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
220 if detector.board.feather_u2if:
221 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Feather as _SPI
223 self._spi = _SPI(clock) # this is really all that's needed
224 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
226 if detector.board.itsybitsy_u2if:
227 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_ItsyBitsy as _SPI
229 self._spi = _SPI(clock) # this is really all that's needed
230 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
232 if detector.board.qtpy_u2if:
233 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
235 self._spi = _SPI(clock) # this is really all that's needed
236 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
238 if detector.chip.id == ap_chip.RP2040:
239 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
241 self._spi = _SPI(clock, MOSI, MISO) # Pins configured on instantiation
242 self._pins = (clock, clock, clock) # These don't matter, they're discarded
244 if detector.board.any_embedded_linux:
245 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
246 elif detector.board.ftdi_ft2232h:
247 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
249 from adafruit_blinka.microcontroller.generic_micropython.spi import (
252 from microcontroller.pin import spiPorts
254 for portId, portSck, portMosi, portMiso in spiPorts:
257 and MOSI in (portMosi, None) # Clock is required!
258 and MISO in (portMiso, None) # But can do with just output
260 self._spi = _SPI(portId)
261 self._pins = (portSck, portMosi, portMiso)
265 "No Hardware SPI on (SCLK, MOSI, MISO)={}\nValid SPI ports:{}".format(
266 (clock, MOSI, MISO), spiPorts
270 def configure(self, baudrate=100000, polarity=0, phase=0, bits=8):
271 """Update the configuration"""
272 if detector.board.any_raspberry_pi or detector.board.any_raspberry_pi_40_pin:
273 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
274 elif detector.board.BEAGLEBONE_AI:
275 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
276 elif detector.board.any_beaglebone:
277 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
278 elif detector.board.any_orange_pi:
279 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
280 elif detector.board.any_nanopi and detector.chip.id == ap_chip.SUN8I:
281 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
282 elif board_id == ap_board.GIANT_BOARD:
283 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
284 elif board_id == ap_board.CORAL_EDGE_TPU_DEV:
285 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
286 elif board_id == ap_board.CORAL_EDGE_TPU_DEV_MINI:
287 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
288 elif board_id == ap_board.ODROID_C2:
289 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
290 elif board_id == ap_board.ODROID_C4:
291 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
292 elif board_id == ap_board.ODROID_XU4:
293 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
294 elif board_id == ap_board.DRAGONBOARD_410C:
295 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
296 elif board_id == ap_board.JETSON_NANO:
297 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
298 elif board_id == ap_board.JETSON_TX1:
299 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
300 elif board_id == ap_board.JETSON_TX2:
301 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
302 elif board_id == ap_board.JETSON_XAVIER:
303 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
304 elif board_id == ap_board.JETSON_NX:
305 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
306 elif detector.board.ROCK_PI_S:
307 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
308 elif detector.board.ROCK_PI_4:
309 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
310 elif detector.board.ROCK_PI_E:
311 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
312 elif detector.board.SIFIVE_UNLEASHED:
313 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
314 elif detector.board.ftdi_ft232h:
315 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
318 elif detector.board.ftdi_ft2232h:
319 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
322 elif detector.board.binho_nova:
323 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
324 elif detector.board.greatfet_one:
325 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
332 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
333 elif board_id == ap_board.PINEH64:
334 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
335 elif board_id == ap_board.CLOCKWORK_CPI3:
336 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
337 elif board_id == ap_board.ONION_OMEGA2:
338 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
339 elif detector.board.any_lubancat and detector.chip.id == ap_chip.IMX6ULL:
340 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
341 elif detector.board.pico_u2if:
342 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
343 elif detector.board.feather_u2if:
344 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Feather as _SPI
345 elif detector.board.itsybitsy_u2if:
346 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_ItsyBitsy as _SPI
347 elif detector.board.qtpy_u2if:
348 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
349 elif detector.chip.id == ap_chip.RP2040:
350 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
352 from adafruit_blinka.microcontroller.generic_micropython.spi import (
357 # TODO check if #init ignores MOSI=None rather than unsetting, to save _pinIds attribute
366 raise RuntimeError("First call try_lock()")
369 """Deinitialization"""
375 """Return the baud rate if implemented"""
377 return self._spi.frequency
378 except AttributeError:
379 raise NotImplementedError(
380 "Frequency attribute not implemented for this platform"
381 ) from AttributeError
383 def write(self, buf, start=0, end=None):
384 """Write to the SPI device"""
385 return self._spi.write(buf, start, end)
387 def readinto(self, buf, start=0, end=None, write_value=0):
388 """Read from the SPI device into a buffer"""
389 return self._spi.readinto(buf, start, end, write_value=write_value)
392 self, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None
394 """Write to the SPI device and read from the SPI device into a buffer"""
395 return self._spi.write_readinto(
396 buffer_out, buffer_in, out_start, out_end, in_start, in_end
400 class UART(Lockable):
402 Busio UART Class for CircuitPython Compatibility. Used
403 for MicroPython and a few other non-Linux boards.
407 """Parity Enumeration"""
409 pass # pylint: disable=unnecessary-pass
411 Parity.ODD = Parity()
412 Parity.EVEN = Parity()
423 receiver_buffer_size=64,
426 if detector.board.any_embedded_linux:
428 "busio.UART not supported on this platform. Please use pyserial instead."
430 if detector.board.binho_nova:
431 from adafruit_blinka.microcontroller.nova.uart import UART as _UART
432 elif detector.board.greatfet_one:
433 from adafruit_blinka.microcontroller.nxp_lpc4330.uart import UART as _UART
434 elif detector.chip.id == ap_chip.RP2040:
435 from adafruit_blinka.microcontroller.rp2040.uart import UART as _UART
437 from machine import UART as _UART
439 from microcontroller.pin import uartPorts
441 self.baudrate = baudrate
443 if flow is not None: # default 0
444 raise NotImplementedError(
445 "Parameter '{}' unsupported on {}".format("flow", agnostic.board_id)
448 # translate parity flag for Micropython
449 if parity is UART.Parity.ODD:
451 elif parity is UART.Parity.EVEN:
456 raise ValueError("Invalid parity")
458 if detector.chip.id == ap_chip.RP2040:
468 # check tx and rx have hardware support
469 for portId, portTx, portRx in uartPorts: #
470 if portTx == tx and portRx == rx:
478 read_buf_len=receiver_buffer_size,
483 "No Hardware UART on (tx,rx)={}\nValid UART ports: {}".format(
489 """Deinitialization"""
490 if detector.board.binho_nova:
494 def read(self, nbytes=None):
495 """Read from the UART"""
496 return self._uart.read(nbytes)
498 def readinto(self, buf, nbytes=None):
499 """Read from the UART into a buffer"""
500 return self._uart.readinto(buf, nbytes)
503 """Read a line of characters up to a newline charater from the UART"""
504 return self._uart.readline()
506 def write(self, buf):
507 """Write to the UART from a buffer"""
508 return self._uart.write(buf)
513 Stub class for OneWire, which is currently not implemented
516 def __init__(self, pin):
517 raise NotImplementedError("OneWire has not been implemented")
521 Deinitialize the OneWire bus and release any hardware resources for reuse.
523 raise NotImplementedError("OneWire has not been implemented")
527 Reset the OneWire bus and read presence
529 raise NotImplementedError("OneWire has not been implemented")
535 raise NotImplementedError("OneWire has not been implemented")
537 def write_bit(self, value):
539 Write out a bit based on value.
541 raise NotImplementedError("OneWire has not been implemented")