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.
19 # pylint: disable=unused-import
20 import adafruit_platformdetect.constants.boards as ap_board
21 import adafruit_platformdetect.constants.chips as ap_chip
22 from adafruit_blinka import Enum, Lockable, agnostic
23 from adafruit_blinka.agnostic import board_id, detector
25 # pylint: disable=import-outside-toplevel,too-many-branches,too-many-statements
26 # pylint: disable=too-many-arguments,too-many-function-args,too-many-return-statements
31 Busio I2C Class for CircuitPython Compatibility. Used
32 for both MicroPython and Linux.
34 NOTE: Frequency has no effect on Linux systems. The argument is only there for compatibility.
37 def __init__(self, scl, sda, frequency=100000):
38 self.init(scl, sda, frequency)
40 def init(self, scl, sda, frequency):
43 if detector.board.ftdi_ft232h:
44 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
46 self._i2c = _I2C(frequency=frequency)
48 if detector.board.binho_nova:
49 from adafruit_blinka.microcontroller.nova.i2c import I2C as _I2C
51 self._i2c = _I2C(frequency=frequency)
53 if detector.board.microchip_mcp2221:
55 "BLINKA_FORCECHIP" in os.environ
56 and os.environ["BLINKA_FORCEBOARD"] == "MICROCHIP_MCP2221"
58 from adafruit_blinka.microcontroller.fake_mcp2221.i2c import I2C as _I2C
60 from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C
61 self._i2c = _I2C(frequency=frequency)
63 if detector.board.greatfet_one:
64 from adafruit_blinka.microcontroller.nxp_lpc4330.i2c import I2C as _I2C
66 self._i2c = _I2C(frequency=frequency)
68 if detector.board.pico_u2if:
69 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_Pico as _I2C
71 self._i2c = _I2C(scl, sda, frequency=frequency)
73 if detector.board.feather_u2if:
74 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
78 self._i2c = _I2C(scl, sda, frequency=frequency)
80 if detector.board.feather_can_u2if:
81 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
82 I2C_Feather_CAN as _I2C,
85 self._i2c = _I2C(scl, sda, frequency=frequency)
87 if detector.board.feather_epd_u2if:
88 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
89 I2C_Feather_EPD as _I2C,
92 self._i2c = _I2C(scl, sda, frequency=frequency)
94 if detector.board.feather_rfm_u2if:
95 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
96 I2C_Feather_RFM as _I2C,
99 self._i2c = _I2C(scl, sda, frequency=frequency)
101 if detector.board.qtpy_u2if:
102 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_QTPY as _I2C
104 self._i2c = _I2C(scl, sda, frequency=frequency)
106 if detector.board.itsybitsy_u2if:
107 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
108 I2C_ItsyBitsy as _I2C,
111 self._i2c = _I2C(scl, sda, frequency=frequency)
113 if detector.board.macropad_u2if:
114 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
115 I2C_MacroPad as _I2C,
118 self._i2c = _I2C(scl, sda, frequency=frequency)
120 if detector.board.qt2040_trinkey_u2if:
121 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
122 I2C_QT2040_Trinkey as _I2C,
125 self._i2c = _I2C(scl, sda, frequency=frequency)
127 if detector.board.kb2040_u2if:
128 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
132 self._i2c = _I2C(scl, sda, frequency=frequency)
134 if detector.chip.id == ap_chip.RP2040:
135 from adafruit_blinka.microcontroller.rp2040.i2c import I2C as _I2C
137 self._i2c = _I2C(scl, sda, frequency=frequency)
139 if detector.board.any_siemens_iot2000:
140 from adafruit_blinka.microcontroller.am65xx.i2c import I2C as _I2C
142 self._i2c = _I2C(frequency=frequency)
145 if detector.board.any_embedded_linux:
146 from adafruit_blinka.microcontroller.generic_linux.i2c import I2C as _I2C
148 if frequency == 100000:
149 frequency = None # Set to None if default to avoid triggering warning
150 elif detector.board.ftdi_ft2232h:
151 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
153 from adafruit_blinka.microcontroller.generic_micropython.i2c import (
156 from microcontroller.pin import i2cPorts
158 for portId, portScl, portSda in i2cPorts:
160 # pylint: disable=unexpected-keyword-arg
161 if scl == portScl and sda == portSda:
162 self._i2c = _I2C(portId, mode=_I2C.MASTER, baudrate=frequency)
164 # pylint: enable=unexpected-keyword-arg
169 "No Hardware I2C on (scl,sda)={}\nValid I2C ports: {}".format(
173 if threading is not None:
174 self._lock = threading.RLock()
177 """Deinitialization"""
180 except AttributeError:
184 if threading is not None:
188 def __exit__(self, exc_type, exc_value, traceback):
189 if threading is not None:
194 """Scan for attached devices"""
195 return self._i2c.scan()
197 def readfrom_into(self, address, buffer, *, start=0, end=None):
198 """Read from a device at specified address into a buffer"""
199 if start != 0 or end is not None:
202 buffer = memoryview(buffer)[start:end]
203 return self._i2c.readfrom_into(address, buffer, stop=True)
205 def writeto(self, address, buffer, *, start=0, end=None):
206 """Write to a device at specified address from a buffer"""
207 if isinstance(buffer, str):
208 buffer = bytes([ord(x) for x in buffer])
209 if start != 0 or end is not None:
211 return self._i2c.writeto(address, memoryview(buffer)[start:], stop=True)
212 return self._i2c.writeto(address, memoryview(buffer)[start:end], stop=True)
213 return self._i2c.writeto(address, buffer, stop=True)
215 def writeto_then_readfrom(
227 """ "Write to a device at specified address from a buffer then read
228 from a device at specified address into a buffer
230 return self._i2c.writeto_then_readfrom(
244 Busio SPI Class for CircuitPython Compatibility. Used
245 for both MicroPython and Linux.
248 def __init__(self, clock, MOSI=None, MISO=None):
250 if detector.board.ftdi_ft232h:
251 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
252 from adafruit_blinka.microcontroller.ftdi_mpsse.ft232h.pin import (
259 self._pins = (SCK, MOSI, MISO)
261 if detector.board.binho_nova:
262 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
263 from adafruit_blinka.microcontroller.nova.pin import SCK, MOSI, MISO
265 self._spi = _SPI(clock)
266 self._pins = (SCK, MOSI, MISO)
268 if detector.board.greatfet_one:
269 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
270 from adafruit_blinka.microcontroller.nxp_lpc4330.pin import SCK, MOSI, MISO
273 self._pins = (SCK, MOSI, MISO)
275 if detector.board.pico_u2if:
276 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
278 self._spi = _SPI(clock) # this is really all that's needed
279 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
281 if detector.board.feather_u2if:
282 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
286 self._spi = _SPI(clock) # this is really all that's needed
287 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
289 if detector.board.feather_can_u2if:
290 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
291 SPI_Feather_CAN as _SPI,
294 self._spi = _SPI(clock) # this is really all that's needed
295 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
297 if detector.board.feather_epd_u2if:
298 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
299 SPI_Feather_EPD as _SPI,
302 self._spi = _SPI(clock) # this is really all that's needed
303 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
305 if detector.board.feather_rfm_u2if:
306 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
307 SPI_Feather_RFM as _SPI,
310 self._spi = _SPI(clock) # this is really all that's needed
311 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
313 if detector.board.itsybitsy_u2if:
314 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
315 SPI_ItsyBitsy as _SPI,
318 self._spi = _SPI(clock) # this is really all that's needed
319 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
321 if detector.board.macropad_u2if:
322 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
323 SPI_MacroPad as _SPI,
326 self._spi = _SPI(clock) # this is really all that's needed
327 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
329 if detector.board.qtpy_u2if:
330 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
332 self._spi = _SPI(clock) # this is really all that's needed
333 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
335 if detector.board.kb2040_u2if:
336 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
340 self._spi = _SPI(clock) # this is really all that's needed
341 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
343 if detector.chip.id == ap_chip.RP2040:
344 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
346 self._spi = _SPI(clock, MOSI, MISO) # Pins configured on instantiation
347 self._pins = (clock, clock, clock) # These don't matter, they're discarded
349 if detector.board.any_siemens_iot2000:
350 from adafruit_blinka.microcontroller.am65xx.spi import SPI as _SPI
352 self._spi = _SPI(clock) # this is really all that's needed
353 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
355 if detector.board.any_embedded_linux:
356 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
357 elif detector.board.ftdi_ft2232h:
358 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
360 from adafruit_blinka.microcontroller.generic_micropython.spi import (
363 from microcontroller.pin import spiPorts
365 for portId, portSck, portMosi, portMiso in spiPorts:
368 and MOSI in (portMosi, None) # Clock is required!
369 and MISO in (portMiso, None) # But can do with just output
371 self._spi = _SPI(portId)
372 self._pins = (portSck, portMosi, portMiso)
376 "No Hardware SPI on (SCLK, MOSI, MISO)={}\nValid SPI ports:{}".format(
377 (clock, MOSI, MISO), spiPorts
381 def configure(self, baudrate=100000, polarity=0, phase=0, bits=8):
382 """Update the configuration"""
383 if detector.board.any_nanopi and detector.chip.id == ap_chip.SUN8I:
384 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
385 elif detector.board.ftdi_ft232h:
386 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
389 elif detector.board.ftdi_ft2232h:
390 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
393 elif detector.board.binho_nova:
394 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
395 elif detector.board.greatfet_one:
396 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
397 elif detector.board.any_lubancat and detector.chip.id == ap_chip.IMX6ULL:
398 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
399 elif detector.board.pico_u2if:
400 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
401 elif detector.board.feather_u2if:
402 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
405 elif detector.board.feather_can_u2if:
406 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
407 SPI_Feather_CAN as _SPI,
409 elif detector.board.feather_epd_u2if:
410 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
411 SPI_Feather_EPD as _SPI,
413 elif detector.board.feather_rfm_u2if:
414 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
415 SPI_Feather_RFM as _SPI,
417 elif detector.board.itsybitsy_u2if:
418 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
419 SPI_ItsyBitsy as _SPI,
421 elif detector.board.macropad_u2if:
422 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
423 SPI_MacroPad as _SPI,
425 elif detector.board.kb2040_u2if:
426 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
429 elif detector.board.qtpy_u2if:
430 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
431 elif detector.chip.id == ap_chip.RP2040:
432 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
433 elif detector.board.any_siemens_iot2000:
434 from adafruit_blinka.microcontroller.am65xx.spi import SPI as _SPI
435 from adafruit_blinka.microcontroller.am65xx.pin import Pin
436 elif detector.board.any_embedded_linux:
437 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
439 from adafruit_blinka.microcontroller.generic_micropython.spi import (
444 # TODO check if #init ignores MOSI=None rather than unsetting, to save _pinIds attribute
453 raise RuntimeError("First call try_lock()")
456 """Deinitialization"""
462 """Return the baud rate if implemented"""
464 return self._spi.frequency
465 except AttributeError as error:
466 raise NotImplementedError(
467 "Frequency attribute not implemented for this platform"
470 def write(self, buf, start=0, end=None):
471 """Write to the SPI device"""
472 return self._spi.write(buf, start, end)
474 def readinto(self, buf, start=0, end=None, write_value=0):
475 """Read from the SPI device into a buffer"""
476 return self._spi.readinto(buf, start, end, write_value=write_value)
479 self, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None
481 """Write to the SPI device and read from the SPI device into a buffer"""
482 return self._spi.write_readinto(
483 buffer_out, buffer_in, out_start, out_end, in_start, in_end
487 class UART(Lockable):
489 Busio UART Class for CircuitPython Compatibility. Used
490 for MicroPython and a few other non-Linux boards.
494 """Parity Enumeration"""
496 pass # pylint: disable=unnecessary-pass
498 Parity.ODD = Parity()
499 Parity.EVEN = Parity()
510 receiver_buffer_size=64,
513 if detector.board.any_embedded_linux:
515 "busio.UART not supported on this platform. Please use pyserial instead."
517 if detector.board.binho_nova:
518 from adafruit_blinka.microcontroller.nova.uart import UART as _UART
519 elif detector.board.greatfet_one:
520 from adafruit_blinka.microcontroller.nxp_lpc4330.uart import UART as _UART
521 elif detector.chip.id == ap_chip.RP2040:
522 from adafruit_blinka.microcontroller.rp2040.uart import UART as _UART
524 from machine import UART as _UART
526 from microcontroller.pin import uartPorts
528 self.baudrate = baudrate
530 if flow is not None: # default 0
531 raise NotImplementedError(
532 "Parameter '{}' unsupported on {}".format("flow", agnostic.board_id)
535 # translate parity flag for Micropython
536 if parity is UART.Parity.ODD:
538 elif parity is UART.Parity.EVEN:
543 raise ValueError("Invalid parity")
545 if detector.chip.id == ap_chip.RP2040:
555 # check tx and rx have hardware support
556 for portId, portTx, portRx in uartPorts: #
557 if portTx == tx and portRx == rx:
565 read_buf_len=receiver_buffer_size,
570 "No Hardware UART on (tx,rx)={}\nValid UART ports: {}".format(
576 """Deinitialization"""
577 if detector.board.binho_nova:
581 def read(self, nbytes=None):
582 """Read from the UART"""
583 return self._uart.read(nbytes)
585 def readinto(self, buf, nbytes=None):
586 """Read from the UART into a buffer"""
587 return self._uart.readinto(buf, nbytes)
590 """Read a line of characters up to a newline character from the UART"""
591 return self._uart.readline()
593 def write(self, buf):
594 """Write to the UART from a buffer"""
595 return self._uart.write(buf)