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.
18 # pylint: disable=unused-import
19 import adafruit_platformdetect.constants.boards as ap_board
20 import adafruit_platformdetect.constants.chips as ap_chip
21 from adafruit_blinka import Enum, Lockable, agnostic
22 from adafruit_blinka.agnostic import board_id, detector
24 # pylint: disable=import-outside-toplevel,too-many-branches,too-many-statements
25 # pylint: disable=too-many-arguments,too-many-function-args,too-many-return-statements
30 Busio I2C Class for CircuitPython Compatibility. Used
31 for both MicroPython and Linux.
34 def __init__(self, scl, sda, frequency=100000):
35 self.init(scl, sda, frequency)
37 def init(self, scl, sda, frequency):
40 if detector.board.ftdi_ft232h:
41 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
43 self._i2c = _I2C(frequency=frequency)
45 if detector.board.binho_nova:
46 from adafruit_blinka.microcontroller.nova.i2c import I2C as _I2C
48 self._i2c = _I2C(frequency=frequency)
50 if detector.board.microchip_mcp2221:
51 from adafruit_blinka.microcontroller.mcp2221.i2c import I2C as _I2C
53 self._i2c = _I2C(frequency=frequency)
55 if detector.board.greatfet_one:
56 from adafruit_blinka.microcontroller.nxp_lpc4330.i2c import I2C as _I2C
58 self._i2c = _I2C(frequency=frequency)
60 if detector.board.pico_u2if:
61 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_Pico as _I2C
63 self._i2c = _I2C(scl, sda, frequency=frequency)
65 if detector.board.feather_u2if:
66 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
70 self._i2c = _I2C(scl, sda, frequency=frequency)
72 if detector.board.qtpy_u2if:
73 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import I2C_QTPY as _I2C
75 self._i2c = _I2C(scl, sda, frequency=frequency)
77 if detector.board.itsybitsy_u2if:
78 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
79 I2C_ItsyBitsy as _I2C,
82 self._i2c = _I2C(scl, sda, frequency=frequency)
84 if detector.board.macropad_u2if:
85 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
89 self._i2c = _I2C(scl, sda, frequency=frequency)
91 if detector.board.qt2040_trinkey_u2if:
92 from adafruit_blinka.microcontroller.rp2040_u2if.i2c import (
93 I2C_QT2040_Trinkey as _I2C,
96 self._i2c = _I2C(scl, sda, frequency=frequency)
98 if detector.chip.id == ap_chip.RP2040:
99 from adafruit_blinka.microcontroller.rp2040.i2c import I2C as _I2C
101 self._i2c = _I2C(scl, sda, frequency=frequency)
103 if detector.board.any_embedded_linux:
104 from adafruit_blinka.microcontroller.generic_linux.i2c import I2C as _I2C
105 elif detector.board.ftdi_ft2232h:
106 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.i2c import I2C as _I2C
108 from adafruit_blinka.microcontroller.generic_micropython.i2c import (
111 from microcontroller.pin import i2cPorts
113 for portId, portScl, portSda in i2cPorts:
115 # pylint: disable=unexpected-keyword-arg
116 if scl == portScl and sda == portSda:
117 self._i2c = _I2C(portId, mode=_I2C.MASTER, baudrate=frequency)
119 # pylint: enable=unexpected-keyword-arg
124 "No Hardware I2C on (scl,sda)={}\nValid I2C ports: {}".format(
128 if threading is not None:
129 self._lock = threading.RLock()
132 """Deinitialization"""
135 except AttributeError:
139 if threading is not None:
143 def __exit__(self, exc_type, exc_value, traceback):
144 if threading is not None:
149 """Scan for attached devices"""
150 return self._i2c.scan()
152 def readfrom_into(self, address, buffer, *, start=0, end=None):
153 """Read from a device at specified address into a buffer"""
154 if start != 0 or end is not None:
157 buffer = memoryview(buffer)[start:end]
158 stop = True # remove for efficiency later
159 return self._i2c.readfrom_into(address, buffer, stop=stop)
161 def writeto(self, address, buffer, *, start=0, end=None, stop=True):
162 """Write to a device at specified address from a buffer"""
163 if isinstance(buffer, str):
164 buffer = bytes([ord(x) for x in buffer])
165 if start != 0 or end is not None:
167 return self._i2c.writeto(address, memoryview(buffer)[start:], stop=stop)
168 return self._i2c.writeto(address, memoryview(buffer)[start:end], stop=stop)
169 return self._i2c.writeto(address, buffer, stop=stop)
171 def writeto_then_readfrom(
183 """ "Write to a device at specified address from a buffer then read
184 from a device at specified address into a buffer
186 return self._i2c.writeto_then_readfrom(
200 Busio SPI Class for CircuitPython Compatibility. Used
201 for both MicroPython and Linux.
204 def __init__(self, clock, MOSI=None, MISO=None):
206 if detector.board.ftdi_ft232h:
207 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
208 from adafruit_blinka.microcontroller.ftdi_mpsse.ft232h.pin import (
215 self._pins = (SCK, MOSI, MISO)
217 if detector.board.binho_nova:
218 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
219 from adafruit_blinka.microcontroller.nova.pin import SCK, MOSI, MISO
221 self._spi = _SPI(clock)
222 self._pins = (SCK, MOSI, MISO)
224 if detector.board.greatfet_one:
225 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
226 from adafruit_blinka.microcontroller.nxp_lpc4330.pin import SCK, MOSI, MISO
229 self._pins = (SCK, MOSI, MISO)
231 if detector.board.pico_u2if:
232 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
234 self._spi = _SPI(clock) # this is really all that's needed
235 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
237 if detector.board.feather_u2if:
238 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
242 self._spi = _SPI(clock) # this is really all that's needed
243 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
245 if detector.board.itsybitsy_u2if:
246 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
247 SPI_ItsyBitsy as _SPI,
250 self._spi = _SPI(clock) # this is really all that's needed
251 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
253 if detector.board.macropad_u2if:
254 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
255 SPI_MacroPad as _SPI,
258 self._spi = _SPI(clock) # this is really all that's needed
259 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
261 if detector.board.qtpy_u2if:
262 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
264 self._spi = _SPI(clock) # this is really all that's needed
265 self._pins = (clock, clock, clock) # will determine MOSI/MISO from clock
267 if detector.chip.id == ap_chip.RP2040:
268 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
270 self._spi = _SPI(clock, MOSI, MISO) # Pins configured on instantiation
271 self._pins = (clock, clock, clock) # These don't matter, they're discarded
273 if detector.board.any_embedded_linux:
274 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
275 elif detector.board.ftdi_ft2232h:
276 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import SPI as _SPI
278 from adafruit_blinka.microcontroller.generic_micropython.spi import (
281 from microcontroller.pin import spiPorts
283 for portId, portSck, portMosi, portMiso in spiPorts:
286 and MOSI in (portMosi, None) # Clock is required!
287 and MISO in (portMiso, None) # But can do with just output
289 self._spi = _SPI(portId)
290 self._pins = (portSck, portMosi, portMiso)
294 "No Hardware SPI on (SCLK, MOSI, MISO)={}\nValid SPI ports:{}".format(
295 (clock, MOSI, MISO), spiPorts
299 def configure(self, baudrate=100000, polarity=0, phase=0, bits=8):
300 """Update the configuration"""
301 if detector.board.any_nanopi and detector.chip.id == ap_chip.SUN8I:
302 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
303 elif detector.board.ftdi_ft232h:
304 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
307 elif detector.board.ftdi_ft2232h:
308 from adafruit_blinka.microcontroller.ftdi_mpsse.mpsse.spi import (
311 elif detector.board.binho_nova:
312 from adafruit_blinka.microcontroller.nova.spi import SPI as _SPI
313 elif detector.board.greatfet_one:
314 from adafruit_blinka.microcontroller.nxp_lpc4330.spi import SPI as _SPI
315 elif detector.board.any_lubancat and detector.chip.id == ap_chip.IMX6ULL:
316 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
317 elif detector.board.pico_u2if:
318 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_Pico as _SPI
319 elif detector.board.feather_u2if:
320 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
323 elif detector.board.itsybitsy_u2if:
324 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
325 SPI_ItsyBitsy as _SPI,
327 elif detector.board.macropad_u2if:
328 from adafruit_blinka.microcontroller.rp2040_u2if.spi import (
329 SPI_MacroPad as _SPI,
331 elif detector.board.qtpy_u2if:
332 from adafruit_blinka.microcontroller.rp2040_u2if.spi import SPI_QTPY as _SPI
333 elif detector.chip.id == ap_chip.RP2040:
334 from adafruit_blinka.microcontroller.rp2040.spi import SPI as _SPI
335 elif detector.board.any_embedded_linux:
336 from adafruit_blinka.microcontroller.generic_linux.spi import SPI as _SPI
338 from adafruit_blinka.microcontroller.generic_micropython.spi import (
343 # TODO check if #init ignores MOSI=None rather than unsetting, to save _pinIds attribute
352 raise RuntimeError("First call try_lock()")
355 """Deinitialization"""
361 """Return the baud rate if implemented"""
363 return self._spi.frequency
364 except AttributeError as error:
365 raise NotImplementedError(
366 "Frequency attribute not implemented for this platform"
369 def write(self, buf, start=0, end=None):
370 """Write to the SPI device"""
371 return self._spi.write(buf, start, end)
373 def readinto(self, buf, start=0, end=None, write_value=0):
374 """Read from the SPI device into a buffer"""
375 return self._spi.readinto(buf, start, end, write_value=write_value)
378 self, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None
380 """Write to the SPI device and read from the SPI device into a buffer"""
381 return self._spi.write_readinto(
382 buffer_out, buffer_in, out_start, out_end, in_start, in_end
386 class UART(Lockable):
388 Busio UART Class for CircuitPython Compatibility. Used
389 for MicroPython and a few other non-Linux boards.
393 """Parity Enumeration"""
395 pass # pylint: disable=unnecessary-pass
397 Parity.ODD = Parity()
398 Parity.EVEN = Parity()
409 receiver_buffer_size=64,
412 if detector.board.any_embedded_linux:
414 "busio.UART not supported on this platform. Please use pyserial instead."
416 if detector.board.binho_nova:
417 from adafruit_blinka.microcontroller.nova.uart import UART as _UART
418 elif detector.board.greatfet_one:
419 from adafruit_blinka.microcontroller.nxp_lpc4330.uart import UART as _UART
420 elif detector.chip.id == ap_chip.RP2040:
421 from adafruit_blinka.microcontroller.rp2040.uart import UART as _UART
423 from machine import UART as _UART
425 from microcontroller.pin import uartPorts
427 self.baudrate = baudrate
429 if flow is not None: # default 0
430 raise NotImplementedError(
431 "Parameter '{}' unsupported on {}".format("flow", agnostic.board_id)
434 # translate parity flag for Micropython
435 if parity is UART.Parity.ODD:
437 elif parity is UART.Parity.EVEN:
442 raise ValueError("Invalid parity")
444 if detector.chip.id == ap_chip.RP2040:
454 # check tx and rx have hardware support
455 for portId, portTx, portRx in uartPorts: #
456 if portTx == tx and portRx == rx:
464 read_buf_len=receiver_buffer_size,
469 "No Hardware UART on (tx,rx)={}\nValid UART ports: {}".format(
475 """Deinitialization"""
476 if detector.board.binho_nova:
480 def read(self, nbytes=None):
481 """Read from the UART"""
482 return self._uart.read(nbytes)
484 def readinto(self, buf, nbytes=None):
485 """Read from the UART into a buffer"""
486 return self._uart.readinto(buf, nbytes)
489 """Read a line of characters up to a newline charater from the UART"""
490 return self._uart.readline()
492 def write(self, buf):
493 """Write to the UART from a buffer"""
494 return self._uart.write(buf)
499 Stub class for OneWire, which is currently not implemented
502 def __init__(self, pin):
503 raise NotImplementedError("OneWire has not been implemented")
507 Deinitialize the OneWire bus and release any hardware resources for reuse.
509 raise NotImplementedError("OneWire has not been implemented")
513 Reset the OneWire bus and read presence
515 raise NotImplementedError("OneWire has not been implemented")
521 raise NotImplementedError("OneWire has not been implemented")
523 def write_bit(self, value):
525 Write out a bit based on value.
527 raise NotImplementedError("OneWire has not been implemented")