1 # SPDX-FileCopyrightText: 2021 Melissa LeBlanc-Williams for Adafruit Industries
3 # SPDX-License-Identifier: MIT
5 `busio` - Bus protocol support like I2C and SPI
6 =================================================
8 See `CircuitPython:busio` in CircuitPython for more details.
17 # pylint: disable=unused-import
18 import adafruit_platformdetect.constants.boards as ap_board
19 import adafruit_platformdetect.constants.chips as ap_chip
20 from adafruit_blinka import Enum, Lockable, agnostic
21 from adafruit_blinka.agnostic import board_id, detector
23 # pylint: disable=import-outside-toplevel,too-many-branches,too-many-statements
24 # pylint: disable=too-many-arguments,too-many-function-args,too-many-return-statements
29 Busio I2C Class for CircuitPython Compatibility. Used
30 for both MicroPython and Linux.
32 NOTE: Frequency has no effect on Linux systems. The argument is only there for compatibility.
35 def __init__(self, scl, sda, frequency=100000):
36 self.init(scl, sda, frequency)
38 def init(self, scl, sda, frequency):
41 if detector.board.ftdi_ft232h:
42 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
44 self._i2c = _I2C(frequency=frequency)
46 if detector.board.binho_nova:
47 from adafruit_blinka.microcontroller.nova.i2c import I2C as _I2C
49 self._i2c = _I2C(frequency=frequency)
51 if detector.board.microchip_mcp2221:
52 from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C
54 self._i2c = _I2C(frequency=frequency)
56 if detector.board.greatfet_one:
57 from adafruit_blinka.microcontroller.nxp_lpc4330.i2c import I2C as _I2C
59 self._i2c = _I2C(frequency=frequency)
61 if detector.board.pico_u2if:
62 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_Pico as _I2C
64 self._i2c = _I2C(scl, sda, frequency=frequency)
66 if detector.board.feather_u2if:
67 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
71 self._i2c = _I2C(scl, sda, frequency=frequency)
73 if detector.board.feather_can_u2if:
74 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
75 I2C_Feather_CAN as _I2C,
78 self._i2c = _I2C(scl, sda, frequency=frequency)
80 if detector.board.feather_epd_u2if:
81 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
82 I2C_Feather_EPD as _I2C,
85 self._i2c = _I2C(scl, sda, frequency=frequency)
87 if detector.board.feather_rfm_u2if:
88 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
89 I2C_Feather_RFM as _I2C,
92 self._i2c = _I2C(scl, sda, frequency=frequency)
94 if detector.board.qtpy_u2if:
95 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_QTPY as _I2C
97 self._i2c = _I2C(scl, sda, frequency=frequency)
99 if detector.board.itsybitsy_u2if:
100 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
101 I2C_ItsyBitsy as _I2C,
104 self._i2c = _I2C(scl, sda, frequency=frequency)
106 if detector.board.macropad_u2if:
107 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
108 I2C_MacroPad as _I2C,
111 self._i2c = _I2C(scl, sda, frequency=frequency)
113 if detector.board.qt2040_trinkey_u2if:
114 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
115 I2C_QT2040_Trinkey as _I2C,
118 self._i2c = _I2C(scl, sda, frequency=frequency)
120 if detector.board.kb2040_u2if:
121 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
125 self._i2c = _I2C(scl, sda, frequency=frequency)
127 if detector.chip.id == ap_chip.RP2040:
128 from adafruit_blinka.microcontroller.rp2040.i2c import I2C as _I2C
130 self._i2c = _I2C(scl, sda, frequency=frequency)
132 if detector.board.any_siemens_iot2000:
133 from adafruit_blinka.microcontroller.am65xx.i2c import I2C as _I2C
135 self._i2c = _I2C(frequency=frequency)
138 if detector.board.any_embedded_linux:
139 from adafruit_blinka.microcontroller.generic_linux.i2c import I2C as _I2C
141 if frequency == 100000:
142 frequency = None # Set to None if default to avoid triggering warning
143 elif detector.board.ftdi_ft2232h:
144 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
146 from adafruit_blinka.microcontroller.generic_micropython.i2c import (
149 from microcontroller.pin import i2cPorts
151 for portId, portScl, portSda in i2cPorts:
153 # pylint: disable=unexpected-keyword-arg
154 if scl == portScl and sda == portSda:
155 self._i2c = _I2C(portId, mode=_I2C.MASTER, baudrate=frequency)
157 # pylint: enable=unexpected-keyword-arg
162 "No Hardware I2C on (scl,sda)={}\nValid I2C ports: {}".format(
166 if threading is not None:
167 self._lock = threading.RLock()
170 """Deinitialization"""
173 except AttributeError:
177 if threading is not None:
181 def __exit__(self, exc_type, exc_value, traceback):
182 if threading is not None:
187 """Scan for attached devices"""
188 return self._i2c.scan()
190 def readfrom_into(self, address, buffer, *, start=0, end=None):
191 """Read from a device at specified address into a buffer"""
192 if start != 0 or end is not None:
195 buffer = memoryview(buffer)[start:end]
196 return self._i2c.readfrom_into(address, buffer, stop=True)
198 def writeto(self, address, buffer, *, start=0, end=None):
199 """Write to a device at specified address from a buffer"""
200 if isinstance(buffer, str):
201 buffer = bytes([ord(x) for x in buffer])
202 if start != 0 or end is not None:
204 return self._i2c.writeto(address, memoryview(buffer)[start:], stop=True)
205 return self._i2c.writeto(address, memoryview(buffer)[start:end], stop=True)
206 return self._i2c.writeto(address, buffer, stop=True)
208 def writeto_then_readfrom(
220 """ "Write to a device at specified address from a buffer then read
221 from a device at specified address into a buffer
223 return self._i2c.writeto_then_readfrom(
237 Busio SPI Class for CircuitPython Compatibility. Used
238 for both MicroPython and Linux.
241 def __init__(self, clock, MOSI=None, MISO=None):
243 if detector.board.ftdi_ft232h:
244 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
245 from adafruit_blinka.microcontroller.ftdi_mpsse.ft232h.pin import (
252 self._pins = (SCK, MOSI, MISO)
254 if detector.board.binho_nova:
255 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
256 from adafruit_blinka.microcontroller.nova.pin import SCK, MOSI, MISO
258 self._spi = _SPI(clock)
259 self._pins = (SCK, MOSI, MISO)
261 if detector.board.greatfet_one:
262 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
263 from adafruit_blinka.microcontroller.nxp_lpc4330.pin import SCK, MOSI, MISO
266 self._pins = (SCK, MOSI, MISO)
268 if detector.board.pico_u2if:
269 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
271 self._spi = _SPI(clock) # this is really all that's needed
272 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
274 if detector.board.feather_u2if:
275 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
279 self._spi = _SPI(clock) # this is really all that's needed
280 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
282 if detector.board.feather_can_u2if:
283 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
284 SPI_Feather_CAN as _SPI,
287 self._spi = _SPI(clock) # this is really all that's needed
288 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
290 if detector.board.feather_epd_u2if:
291 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
292 SPI_Feather_EPD as _SPI,
295 self._spi = _SPI(clock) # this is really all that's needed
296 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
298 if detector.board.feather_rfm_u2if:
299 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
300 SPI_Feather_RFM as _SPI,
303 self._spi = _SPI(clock) # this is really all that's needed
304 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
306 if detector.board.itsybitsy_u2if:
307 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
308 SPI_ItsyBitsy as _SPI,
311 self._spi = _SPI(clock) # this is really all that's needed
312 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
314 if detector.board.macropad_u2if:
315 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
316 SPI_MacroPad as _SPI,
319 self._spi = _SPI(clock) # this is really all that's needed
320 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
322 if detector.board.qtpy_u2if:
323 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
325 self._spi = _SPI(clock) # this is really all that's needed
326 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
328 if detector.board.kb2040_u2if:
329 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
333 self._spi = _SPI(clock) # this is really all that's needed
334 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
336 if detector.chip.id == ap_chip.RP2040:
337 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
339 self._spi = _SPI(clock, MOSI, MISO) # Pins configured on instantiation
340 self._pins = (clock, clock, clock) # These don't matter, they're discarded
342 if detector.board.any_siemens_iot2000:
343 from adafruit_blinka.microcontroller.am65xx.spi import SPI as _SPI
345 self._spi = _SPI(clock) # this is really all that's needed
346 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
348 if detector.board.any_embedded_linux:
349 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
350 elif detector.board.ftdi_ft2232h:
351 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
353 from adafruit_blinka.microcontroller.generic_micropython.spi import (
356 from microcontroller.pin import spiPorts
358 for portId, portSck, portMosi, portMiso in spiPorts:
361 and MOSI in (portMosi, None) # Clock is required!
362 and MISO in (portMiso, None) # But can do with just output
364 self._spi = _SPI(portId)
365 self._pins = (portSck, portMosi, portMiso)
369 "No Hardware SPI on (SCLK, MOSI, MISO)={}\nValid SPI ports:{}".format(
370 (clock, MOSI, MISO), spiPorts
374 def configure(self, baudrate=100000, polarity=0, phase=0, bits=8):
375 """Update the configuration"""
376 if detector.board.any_nanopi and detector.chip.id == ap_chip.SUN8I:
377 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
378 elif detector.board.ftdi_ft232h:
379 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
382 elif detector.board.ftdi_ft2232h:
383 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
386 elif detector.board.binho_nova:
387 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
388 elif detector.board.greatfet_one:
389 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
390 elif detector.board.any_lubancat and detector.chip.id == ap_chip.IMX6ULL:
391 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
392 elif detector.board.pico_u2if:
393 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
394 elif detector.board.feather_u2if:
395 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
398 elif detector.board.feather_can_u2if:
399 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
400 SPI_Feather_CAN as _SPI,
402 elif detector.board.feather_epd_u2if:
403 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
404 SPI_Feather_EPD as _SPI,
406 elif detector.board.feather_rfm_u2if:
407 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
408 SPI_Feather_RFM as _SPI,
410 elif detector.board.itsybitsy_u2if:
411 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
412 SPI_ItsyBitsy as _SPI,
414 elif detector.board.macropad_u2if:
415 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
416 SPI_MacroPad as _SPI,
418 elif detector.board.kb2040_u2if:
419 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
422 elif detector.board.qtpy_u2if:
423 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
424 elif detector.chip.id == ap_chip.RP2040:
425 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
426 elif detector.board.any_siemens_iot2000:
427 from adafruit_blinka.microcontroller.am65xx.spi import SPI as _SPI
428 from adafruit_blinka.microcontroller.am65xx.pin import Pin
429 elif detector.board.any_embedded_linux:
430 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
432 from adafruit_blinka.microcontroller.generic_micropython.spi import (
437 # TODO check if #init ignores MOSI=None rather than unsetting, to save _pinIds attribute
446 raise RuntimeError("First call try_lock()")
449 """Deinitialization"""
455 """Return the baud rate if implemented"""
457 return self._spi.frequency
458 except AttributeError as error:
459 raise NotImplementedError(
460 "Frequency attribute not implemented for this platform"
463 def write(self, buf, start=0, end=None):
464 """Write to the SPI device"""
465 return self._spi.write(buf, start, end)
467 def readinto(self, buf, start=0, end=None, write_value=0):
468 """Read from the SPI device into a buffer"""
469 return self._spi.readinto(buf, start, end, write_value=write_value)
472 self, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None
474 """Write to the SPI device and read from the SPI device into a buffer"""
475 return self._spi.write_readinto(
476 buffer_out, buffer_in, out_start, out_end, in_start, in_end
480 class UART(Lockable):
482 Busio UART Class for CircuitPython Compatibility. Used
483 for MicroPython and a few other non-Linux boards.
487 """Parity Enumeration"""
489 pass # pylint: disable=unnecessary-pass
491 Parity.ODD = Parity()
492 Parity.EVEN = Parity()
503 receiver_buffer_size=64,
506 if detector.board.any_embedded_linux:
508 "busio.UART not supported on this platform. Please use pyserial instead."
510 if detector.board.binho_nova:
511 from adafruit_blinka.microcontroller.nova.uart import UART as _UART
512 elif detector.board.greatfet_one:
513 from adafruit_blinka.microcontroller.nxp_lpc4330.uart import UART as _UART
514 elif detector.chip.id == ap_chip.RP2040:
515 from adafruit_blinka.microcontroller.rp2040.uart import UART as _UART
517 from machine import UART as _UART
519 from microcontroller.pin import uartPorts
521 self.baudrate = baudrate
523 if flow is not None: # default 0
524 raise NotImplementedError(
525 "Parameter '{}' unsupported on {}".format("flow", agnostic.board_id)
528 # translate parity flag for Micropython
529 if parity is UART.Parity.ODD:
531 elif parity is UART.Parity.EVEN:
536 raise ValueError("Invalid parity")
538 if detector.chip.id == ap_chip.RP2040:
548 # check tx and rx have hardware support
549 for portId, portTx, portRx in uartPorts: #
550 if portTx == tx and portRx == rx:
558 read_buf_len=receiver_buffer_size,
563 "No Hardware UART on (tx,rx)={}\nValid UART ports: {}".format(
569 """Deinitialization"""
570 if detector.board.binho_nova:
574 def read(self, nbytes=None):
575 """Read from the UART"""
576 return self._uart.read(nbytes)
578 def readinto(self, buf, nbytes=None):
579 """Read from the UART into a buffer"""
580 return self._uart.readinto(buf, nbytes)
583 """Read a line of characters up to a newline character from the UART"""
584 return self._uart.readline()
586 def write(self, buf):
587 """Write to the UART from a buffer"""
588 return self._uart.write(buf)