From a65d8d4305b542bfba8b6942c94c789f258fcf88 Mon Sep 17 00:00:00 2001 From: "adam_cummick:g9T51EHpC9gPQqG6sb9Q@gitlab.com" Date: Wed, 20 Oct 2021 14:18:08 -0400 Subject: [PATCH] Create separate BCM2711 structure. --- .../board/raspberrypi/raspi_4b.py | 55 ++++++ .../board/raspberrypi/raspi_cm4.py | 74 ++++++++ .../microcontroller/bcm2711/__init__.py | 0 .../microcontroller/bcm2711/neopixel.py | 123 ++++++++++++ .../microcontroller/bcm2711/pin.py | 161 ++++++++++++++++ .../microcontroller/bcm2711/pulseio/PWMOut.py | 162 ++++++++++++++++ .../bcm2711/pulseio/PulseIn.py | 178 ++++++++++++++++++ .../bcm2711/pulseio/__init__.py | 0 .../bcm2711/pulseio/libgpiod_pulsein | Bin 0 -> 20372 bytes .../bcm2711/pulseio/libgpiod_pulsein64 | Bin 0 -> 25832 bytes .../microcontroller/bcm283x/pin.py | 21 +-- src/board.py | 6 + src/microcontroller/__init__.py | 5 +- src/microcontroller/pin.py | 7 +- 14 files changed, 773 insertions(+), 19 deletions(-) create mode 100644 src/adafruit_blinka/board/raspberrypi/raspi_4b.py create mode 100644 src/adafruit_blinka/board/raspberrypi/raspi_cm4.py create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/__init__.py create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/neopixel.py create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/pin.py create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/pulseio/PWMOut.py create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/pulseio/PulseIn.py create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/pulseio/__init__.py create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/pulseio/libgpiod_pulsein create mode 100644 src/adafruit_blinka/microcontroller/bcm2711/pulseio/libgpiod_pulsein64 diff --git a/src/adafruit_blinka/board/raspberrypi/raspi_4b.py b/src/adafruit_blinka/board/raspberrypi/raspi_4b.py new file mode 100644 index 0000000..0b6187c --- /dev/null +++ b/src/adafruit_blinka/board/raspberrypi/raspi_4b.py @@ -0,0 +1,55 @@ +"""Pin definitions for 40-pin Raspberry Pi models.""" + +from adafruit_blinka.microcontroller.bcm2711 import pin + +D0 = pin.D0 +D1 = pin.D1 + +D2 = pin.D2 +SDA = pin.SDA +D3 = pin.D3 +SCL = pin.SCL + +D4 = pin.D4 +D5 = pin.D5 +D6 = pin.D6 + +D7 = pin.D7 +CE1 = pin.D7 +D8 = pin.D8 +CE0 = pin.D8 +D9 = pin.D9 +MISO = pin.D9 +D10 = pin.D10 +MOSI = pin.D10 +D11 = pin.D11 +SCLK = pin.D11 +SCK = pin.D11 + +D12 = pin.D12 +D13 = pin.D13 + +D14 = pin.D14 +TXD = pin.D14 +D15 = pin.D15 +RXD = pin.D15 +# create alias for most of the examples +TX = pin.D14 +RX = pin.D15 + +D16 = pin.D16 +D17 = pin.D17 +D18 = pin.D18 +D19 = pin.D19 +MISO_1 = pin.D19 +D20 = pin.D20 +MOSI_1 = pin.D20 +D21 = pin.D21 +SCLK_1 = pin.D21 +SCK_1 = pin.D21 +D22 = pin.D22 +D23 = pin.D23 +D24 = pin.D24 +D25 = pin.D25 +D26 = pin.D26 +D27 = pin.D27 diff --git a/src/adafruit_blinka/board/raspberrypi/raspi_cm4.py b/src/adafruit_blinka/board/raspberrypi/raspi_cm4.py new file mode 100644 index 0000000..bd0d4c7 --- /dev/null +++ b/src/adafruit_blinka/board/raspberrypi/raspi_cm4.py @@ -0,0 +1,74 @@ +"""Pin definitions for Raspberry Pi Compute Modules.""" + +from adafruit_blinka.microcontroller.bcm2711 import pin + +D2 = pin.D2 +SDA = pin.SDA +D3 = pin.D3 +SCL = pin.SCL + +D4 = pin.D4 +D5 = pin.D5 +D6 = pin.D6 + +D7 = pin.D7 +CE1 = pin.D7 +D8 = pin.D8 +CE0 = pin.D8 +D9 = pin.D9 +MISO = pin.D9 +D10 = pin.D10 +MOSI = pin.D10 +D11 = pin.D11 +SCLK = pin.D11 +SCK = pin.D11 + +D12 = pin.D12 +D13 = pin.D13 + +D14 = pin.D14 +TXD = pin.D14 +D15 = pin.D15 +RXD = pin.D15 +# create alias for most of the examples +TX = pin.D14 +RX = pin.D15 + +D16 = pin.D16 +D17 = pin.D17 +D18 = pin.D18 +D19 = pin.D19 +MISO_1 = pin.D19 +D20 = pin.D20 +MOSI_1 = pin.D20 +D21 = pin.D21 +SCLK_1 = pin.D21 +SCK_1 = pin.D21 +D22 = pin.D22 +D23 = pin.D23 +D24 = pin.D24 +D25 = pin.D25 +D26 = pin.D26 +D27 = pin.D27 +D28 = pin.D28 +D29 = pin.D29 +D30 = pin.D30 +D31 = pin.D31 +D32 = pin.D32 +D33 = pin.D33 +D34 = pin.D34 +D35 = pin.D35 +D36 = pin.D36 +D37 = pin.D37 +D38 = pin.D38 +D39 = pin.D39 +D40 = pin.D40 +MISO_2 = pin.D40 +D41 = pin.D41 +MOSI_2 = pin.D41 +D42 = pin.D42 +SCLK_2 = pin.D42 +SCK_2 = pin.D43 +D43 = pin.D43 +D44 = pin.D44 +D45 = pin.D45 diff --git a/src/adafruit_blinka/microcontroller/bcm2711/__init__.py b/src/adafruit_blinka/microcontroller/bcm2711/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/adafruit_blinka/microcontroller/bcm2711/neopixel.py b/src/adafruit_blinka/microcontroller/bcm2711/neopixel.py new file mode 100644 index 0000000..6235f3c --- /dev/null +++ b/src/adafruit_blinka/microcontroller/bcm2711/neopixel.py @@ -0,0 +1,123 @@ +"""BCM2711 NeoPixel Driver Class""" +import time +import atexit +import _rpi_ws281x as ws + +# LED configuration. +# pylint: disable=redefined-outer-name,too-many-branches,too-many-statements +# pylint: disable=global-statement,protected-access +LED_CHANNEL = 0 +LED_FREQ_HZ = 800000 # Frequency of the LED signal. We only support 800KHz +LED_DMA_NUM = 10 # DMA channel to use, can be 0-14. +LED_BRIGHTNESS = 255 # We manage the brightness in the neopixel library +LED_INVERT = 0 # We don't support inverted logic +LED_STRIP = None # We manage the color order within the neopixel library + +# a 'static' object that we will use to manage our PWM DMA channel +# we only support one LED strip per raspi +_led_strip = None +_buf = None + + +def neopixel_write(gpio, buf): + """NeoPixel Writing Function""" + global _led_strip # we'll have one strip we init if its not at first + global _buf # we save a reference to the buf, and if it changes we will cleanup and re-init. + + if _led_strip is None or buf is not _buf: + # This is safe to call since it doesn't do anything if _led_strip is None + neopixel_cleanup() + + # Create a ws2811_t structure from the LED configuration. + # Note that this structure will be created on the heap so you + # need to be careful that you delete its memory by calling + # delete_ws2811_t when it's not needed. + _led_strip = ws.new_ws2811_t() + _buf = buf + + # Initialize all channels to off + for channum in range(2): + channel = ws.ws2811_channel_get(_led_strip, channum) + ws.ws2811_channel_t_count_set(channel, 0) + ws.ws2811_channel_t_gpionum_set(channel, 0) + ws.ws2811_channel_t_invert_set(channel, 0) + ws.ws2811_channel_t_brightness_set(channel, 0) + + channel = ws.ws2811_channel_get(_led_strip, LED_CHANNEL) + + # Initialize the channel in use + count = 0 + if len(buf) % 3 == 0: + # most common, divisible by 3 is likely RGB + LED_STRIP = ws.WS2811_STRIP_RGB + count = len(buf) // 3 + elif len(buf) % 4 == 0: + LED_STRIP = ws.SK6812_STRIP_RGBW + count = len(buf) // 4 + else: + raise RuntimeError("We only support 3 or 4 bytes-per-pixel") + + ws.ws2811_channel_t_count_set( + channel, count + ) # we manage 4 vs 3 bytes in the library + ws.ws2811_channel_t_gpionum_set(channel, gpio._pin.id) + ws.ws2811_channel_t_invert_set(channel, LED_INVERT) + ws.ws2811_channel_t_brightness_set(channel, LED_BRIGHTNESS) + ws.ws2811_channel_t_strip_type_set(channel, LED_STRIP) + + # Initialize the controller + ws.ws2811_t_freq_set(_led_strip, LED_FREQ_HZ) + ws.ws2811_t_dmanum_set(_led_strip, LED_DMA_NUM) + + resp = ws.ws2811_init(_led_strip) + if resp != ws.WS2811_SUCCESS: + if resp == -5: + raise RuntimeError( + "NeoPixel support requires running with sudo, please try again!" + ) + message = ws.ws2811_get_return_t_str(resp) + raise RuntimeError( + "ws2811_init failed with code {0} ({1})".format(resp, message) + ) + atexit.register(neopixel_cleanup) + + channel = ws.ws2811_channel_get(_led_strip, LED_CHANNEL) + if gpio._pin.id != ws.ws2811_channel_t_gpionum_get(channel): + raise RuntimeError("Raspberry Pi neopixel support is for one strip only!") + + if ws.ws2811_channel_t_strip_type_get(channel) == ws.WS2811_STRIP_RGB: + bpp = 3 + else: + bpp = 4 + # assign all colors! + for i in range(len(buf) // bpp): + r = buf[bpp * i] + g = buf[bpp * i + 1] + b = buf[bpp * i + 2] + if bpp == 3: + pixel = (r << 16) | (g << 8) | b + else: + w = buf[bpp * i + 3] + pixel = (w << 24) | (r << 16) | (g << 8) | b + ws.ws2811_led_set(channel, i, pixel) + + resp = ws.ws2811_render(_led_strip) + if resp != ws.WS2811_SUCCESS: + message = ws.ws2811_get_return_t_str(resp) + raise RuntimeError( + "ws2811_render failed with code {0} ({1})".format(resp, message) + ) + time.sleep(0.001 * ((len(buf) // 100) + 1)) # about 1ms per 100 bytes + + +def neopixel_cleanup(): + """Cleanup when we're done""" + global _led_strip + + if _led_strip is not None: + # Ensure ws2811_fini is called before the program quits. + ws.ws2811_fini(_led_strip) + # Example of calling delete function to clean up structure memory. Isn't + # strictly necessary at the end of the program execution here, but is good practice. + ws.delete_ws2811_t(_led_strip) + _led_strip = None diff --git a/src/adafruit_blinka/microcontroller/bcm2711/pin.py b/src/adafruit_blinka/microcontroller/bcm2711/pin.py new file mode 100644 index 0000000..7fe5996 --- /dev/null +++ b/src/adafruit_blinka/microcontroller/bcm2711/pin.py @@ -0,0 +1,161 @@ +"""Broadcom BCM283x pin names""" +import RPi.GPIO as GPIO +from adafruit_blinka.agnostic import detector + +GPIO.setmode(GPIO.BCM) # Use BCM pins D4 = GPIO #4 +GPIO.setwarnings(False) # shh! + + +class Pin: + """Pins dont exist in CPython so...lets make our own!""" + + IN = 0 + OUT = 1 + LOW = 0 + HIGH = 1 + PULL_NONE = 0 + PULL_UP = 1 + PULL_DOWN = 2 + + id = None + _value = LOW + _mode = IN + + def __init__(self, bcm_number): + self.id = bcm_number + + def __repr__(self): + return str(self.id) + + def __eq__(self, other): + return self.id == other + + def init(self, mode=IN, pull=None): + """Initialize the Pin""" + if mode is not None: + if mode == self.IN: + self._mode = self.IN + GPIO.setup(self.id, GPIO.IN) + elif mode == self.OUT: + self._mode = self.OUT + GPIO.setup(self.id, GPIO.OUT) + else: + raise RuntimeError("Invalid mode for pin: %s" % self.id) + if pull is not None: + if self._mode != self.IN: + raise RuntimeError("Cannot set pull resistor on output") + if pull == self.PULL_UP: + GPIO.setup(self.id, GPIO.IN, pull_up_down=GPIO.PUD_UP) + elif pull == self.PULL_DOWN: + GPIO.setup(self.id, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) + else: + raise RuntimeError("Invalid pull for pin: %s" % self.id) + + def value(self, val=None): + """Set or return the Pin Value""" + if val is not None: + if val == self.LOW: + self._value = val + GPIO.output(self.id, val) + elif val == self.HIGH: + self._value = val + GPIO.output(self.id, val) + else: + raise RuntimeError("Invalid value for pin") + return None + return GPIO.input(self.id) + + +# Pi 1B rev1 only? +D0 = Pin(0) +D1 = Pin(1) + +D2 = Pin(2) +SDA = Pin(2) +D3 = Pin(3) +SCL = Pin(3) + +D4 = Pin(4) +D5 = Pin(5) +D6 = Pin(6) + +D7 = Pin(7) +CE1 = Pin(7) +D8 = Pin(8) +CE0 = Pin(8) +D9 = Pin(9) +MISO = Pin(9) +D10 = Pin(10) +MOSI = Pin(10) +D11 = Pin(11) +SCLK = Pin(11) # Raspberry Pi naming +SCK = Pin(11) # CircuitPython naming + +D12 = Pin(12) +D13 = Pin(13) + +D14 = Pin(14) +TXD = Pin(14) +D15 = Pin(15) +RXD = Pin(15) + +D16 = Pin(16) +D17 = Pin(17) +D18 = Pin(18) +D19 = Pin(19) +MISO_1 = Pin(19) +D20 = Pin(20) +MOSI_1 = Pin(20) +D21 = Pin(21) +SCLK_1 = Pin(21) +SCK_1 = Pin(21) +D22 = Pin(22) +D23 = Pin(23) +D24 = Pin(24) +D25 = Pin(25) +D26 = Pin(26) +D27 = Pin(27) +D28 = Pin(28) +D29 = Pin(29) +D30 = Pin(30) +D31 = Pin(31) +D32 = Pin(32) +D33 = Pin(33) +D34 = Pin(34) +D35 = Pin(35) +D36 = Pin(36) +D37 = Pin(37) +D38 = Pin(38) +D39 = Pin(39) +D40 = Pin(40) +MISO_2 = Pin(40) +D41 = Pin(41) +MOSI_2 = Pin(41) +D42 = Pin(42) +SCLK_2 = Pin(42) +SCK_2 = Pin(43) +D43 = Pin(43) +D44 = Pin(44) +D45 = Pin(45) + +# ordered as spiId, sckId, mosiId, misoId +spiPorts = ( + (0, SCLK, MOSI, MISO), + (6, SCLK_1, MOSI_1, MISO_1), + (2, SCLK_2, MOSI_2, MISO_2), + (3, D3, D2, D1), + (4, D7, D6, D5), + (5, D15, D14, D13), +) + +# ordered as uartId, txId, rxId +uartPorts = ((1, TXD, RXD),) + +# These are the known hardware I2C ports / pins. +# For software I2C ports created with the i2c-gpio overlay, see: +# https://github.com/adafruit/Adafruit_Python_Extended_Bus +i2cPorts = ( + (1, SCL, SDA), + (0, D1, D0), # both pi 1 and pi 2 i2c ports! + (10, D45, D44), # internal i2c bus for the CM4 +) diff --git a/src/adafruit_blinka/microcontroller/bcm2711/pulseio/PWMOut.py b/src/adafruit_blinka/microcontroller/bcm2711/pulseio/PWMOut.py new file mode 100644 index 0000000..65f269f --- /dev/null +++ b/src/adafruit_blinka/microcontroller/bcm2711/pulseio/PWMOut.py @@ -0,0 +1,162 @@ +"""Custom PWMOut Wrapper for Rpi.GPIO PWM Class""" +import RPi.GPIO as GPIO + +GPIO.setmode(GPIO.BCM) # Use BCM pins D4 = GPIO #4 +GPIO.setwarnings(False) # shh! + + +# pylint: disable=unnecessary-pass +class PWMError(IOError): + """Base class for PWM errors.""" + + pass + + +# pylint: enable=unnecessary-pass + + +class PWMOut: + """Pulse Width Modulation Output Class""" + + def __init__(self, pin, *, frequency=500, duty_cycle=0, variable_frequency=False): + self._pwmpin = None + self._period = 0 + self._open(pin, duty_cycle, frequency, variable_frequency) + + def __del__(self): + self.deinit() + + def __enter__(self): + return self + + def __exit__(self, t, value, traceback): + self.deinit() + + def _open(self, pin, duty=0, freq=500, variable_frequency=False): + self._pin = pin + GPIO.setup(pin.id, GPIO.OUT) + self._pwmpin = GPIO.PWM(pin.id, freq) + + if variable_frequency: + print("Variable Frequency is not supported, continuing without it...") + + # set frequency + self.frequency = freq + # set duty + self.duty_cycle = duty + + self.enabled = True + + def deinit(self): + """Deinit the PWM.""" + if self._pwmpin is not None: + self._pwmpin.stop() + GPIO.cleanup(self._pin.id) + self._pwmpin = None + + def _is_deinited(self): + if self._pwmpin is None: + raise ValueError( + "Object has been deinitialize and can no longer " + "be used. Create a new object." + ) + + @property + def period(self): + """Get or set the PWM's output period in seconds. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + + :type: int, float + """ + return 1.0 / self.frequency + + @period.setter + def period(self, period): + if not isinstance(period, (int, float)): + raise TypeError("Invalid period type, should be int or float.") + + self.frequency = 1.0 / period + + @property + def duty_cycle(self): + """Get or set the PWM's output duty cycle which is the fraction of + each pulse which is high. 16-bit + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + ValueError: if value is out of bounds of 0.0 to 1.0. + + :type: int, float + """ + return int(self._duty_cycle * 65535) + + @duty_cycle.setter + def duty_cycle(self, duty_cycle): + if not isinstance(duty_cycle, (int, float)): + raise TypeError("Invalid duty cycle type, should be int or float.") + + if not 0 <= duty_cycle <= 65535: + raise ValueError("Invalid duty cycle value, should be between 0 and 65535") + + # convert from 16-bit + duty_cycle /= 65535.0 + + self._duty_cycle = duty_cycle + self._pwmpin.ChangeDutyCycle(round(self._duty_cycle * 100)) + + @property + def frequency(self): + """Get or set the PWM's output frequency in Hertz. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not int or float. + + :type: int, float + """ + + return self._frequency + + @frequency.setter + def frequency(self, frequency): + if not isinstance(frequency, (int, float)): + raise TypeError("Invalid frequency type, should be int or float.") + + self._pwmpin.ChangeFrequency(round(frequency)) + self._frequency = frequency + + @property + def enabled(self): + """Get or set the PWM's output enabled state. + + Raises: + PWMError: if an I/O or OS error occurs. + TypeError: if value type is not bool. + + :type: bool + """ + return self._enabled + + @enabled.setter + def enabled(self, value): + if not isinstance(value, bool): + raise TypeError("Invalid enabled type, should be string.") + + if value: + self._pwmpin.start(round(self._duty_cycle * 100)) + else: + self._pwmpin.stop() + + self._enabled = value + + # String representation + def __str__(self): + return "pin %s (freq=%f Hz, duty_cycle=%f%%)" % ( + self._pin, + self.frequency, + self.duty_cycle, + ) diff --git a/src/adafruit_blinka/microcontroller/bcm2711/pulseio/PulseIn.py b/src/adafruit_blinka/microcontroller/bcm2711/pulseio/PulseIn.py new file mode 100644 index 0000000..700d8de --- /dev/null +++ b/src/adafruit_blinka/microcontroller/bcm2711/pulseio/PulseIn.py @@ -0,0 +1,178 @@ +"""Custom PulseIn Class to read PWM signals""" +import time +import subprocess +import os +import atexit +import random +import struct +import sysv_ipc + +DEBUG = False +queues = [] +procs = [] + +# The message queues live outside of python space, and must be formally cleaned! +def final(): + """In case the program is cancelled or quit, we need to clean up the PulseIn + helper process and also the message queue, this is called at exit to do so""" + if DEBUG: + print("Cleaning up message queues", queues) + print("Cleaning up processes", procs) + for q in queues: + q.remove() + for proc in procs: + proc.terminate() + + +atexit.register(final) + +# pylint: disable=c-extension-no-member +class PulseIn: + """PulseIn Class to read PWM signals""" + + def __init__(self, pin, maxlen=2, idle_state=False): + """Create a PulseIn object associated with the given pin. + The object acts as a read-only sequence of pulse lengths with + a given max length. When it is active, new pulse lengths are + added to the end of the list. When there is no more room + (len() == maxlen) the oldest pulse length is removed to make room.""" + self._pin = pin + self._maxlen = maxlen + self._idle_state = idle_state + self._queue_key = random.randint(1, 9999) + try: + self._mq = sysv_ipc.MessageQueue(None, flags=sysv_ipc.IPC_CREX) + if DEBUG: + print("Message Queue Key: ", self._mq.key) + queues.append(self._mq) + except sysv_ipc.ExistentialError: + raise RuntimeError( + "Message queue creation failed" + ) from sysv_ipc.ExistentialError + + # Check if OS is 64-bit + if struct.calcsize("P") * 8 == 64: + libgpiod_filename = "libgpiod_pulsein64" + else: + libgpiod_filename = "libgpiod_pulsein" + + dir_path = os.path.dirname(os.path.realpath(__file__)) + cmd = [ + dir_path + "/" + libgpiod_filename, + "--pulses", + str(maxlen), + "--queue", + str(self._mq.key), + ] + if idle_state: + cmd.append("-i") + cmd.append("gpiochip0") + cmd.append(str(pin)) + if DEBUG: + print(cmd) + + self._process = subprocess.Popen(cmd) + procs.append(self._process) + + # wait for it to start up + if DEBUG: + print("Waiting for startup success message from subprocess") + message = self._wait_receive_msg(timeout=0.25) + if message[0] != b"!": + raise RuntimeError("Could not establish message queue with subprocess") + self._paused = False + + # pylint: disable=redefined-builtin + def _wait_receive_msg(self, timeout=0, type=2): + """Internal helper that will wait for new messages of a given type, + and throw an exception on timeout""" + if timeout > 0: + stamp = time.monotonic() + while (time.monotonic() - stamp) < timeout: + try: + message = self._mq.receive(block=False, type=type) + return message + except sysv_ipc.BusyError: + time.sleep(0.001) # wait a bit then retry! + # uh-oh timed out + raise RuntimeError( + "Timed out waiting for PulseIn message. Make sure libgpiod is installed." + ) + message = self._mq.receive(block=True, type=type) + return message + + # pylint: enable=redefined-builtin + + def deinit(self): + """Deinitialises the PulseIn and releases any hardware and software + resources for reuse.""" + # Clean up after ourselves + self._process.terminate() + procs.remove(self._process) + self._mq.remove() + queues.remove(self._mq) + + def __enter__(self): + """No-op used by Context Managers.""" + return self + + def __exit__(self, exc_type, exc_value, tb): + """Automatically deinitializes the hardware when exiting a context.""" + self.deinit() + + def resume(self, trigger_duration=0): + """Resumes pulse capture after an optional trigger pulse.""" + if trigger_duration != 0: + self._mq.send("t%d" % trigger_duration, True, type=1) + else: + self._mq.send("r", True, type=1) + self._paused = False + + def pause(self): + """Pause pulse capture""" + self._mq.send("p", True, type=1) + self._paused = True + + @property + def paused(self): + """True when pulse capture is paused as a result of pause() or + an error during capture such as a signal that is too fast.""" + return self._paused + + @property + def maxlen(self): + """The maximum length of the PulseIn. When len() is equal to maxlen, + it is unclear which pulses are active and which are idle.""" + return self._maxlen + + def clear(self): + """Clears all captured pulses""" + self._mq.send("c", True, type=1) + + def popleft(self): + """Removes and returns the oldest read pulse.""" + self._mq.send("^", True, type=1) + message = self._wait_receive_msg() + reply = int(message[0].decode("utf-8")) + # print(reply) + if reply == -1: + raise IndexError("pop from empty list") + return reply + + def __len__(self): + """Returns the current pulse length""" + self._mq.send("l", True, type=1) + message = self._wait_receive_msg() + return int(message[0].decode("utf-8")) + + # pylint: disable=redefined-builtin + def __getitem__(self, index, type=None): + """Returns the value at the given index or values in slice.""" + self._mq.send("i%d" % index, True, type=1) + message = self._wait_receive_msg() + ret = int(message[0].decode("utf-8")) + if ret == -1: + raise IndexError("list index out of range") + return ret + + # pylint: enable=redefined-builtin diff --git a/src/adafruit_blinka/microcontroller/bcm2711/pulseio/__init__.py b/src/adafruit_blinka/microcontroller/bcm2711/pulseio/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/adafruit_blinka/microcontroller/bcm2711/pulseio/libgpiod_pulsein b/src/adafruit_blinka/microcontroller/bcm2711/pulseio/libgpiod_pulsein new file mode 100644 index 0000000000000000000000000000000000000000..0291c1b4669cd98f02f2d1c9d489ed13f1d9ca2f GIT binary patch literal 20372 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�O|)DrlPuXwM2n1up|g9<)CN!WRJZ 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 literal 0 HcmV?d00001 diff --git a/src/adafruit_blinka/microcontroller/bcm283x/pin.py b/src/adafruit_blinka/microcontroller/bcm283x/pin.py index dd8abe6..423435e 100644 --- a/src/adafruit_blinka/microcontroller/bcm283x/pin.py +++ b/src/adafruit_blinka/microcontroller/bcm283x/pin.py @@ -139,21 +139,11 @@ D44 = Pin(44) D45 = Pin(45) # ordered as spiId, sckId, mosiId, misoId -if detector.board.id in ["RASPBERRY_PI_4B", "RASPBERRY_PI_CM4"]: - spiPorts = ( - (0, SCLK, MOSI, MISO), - (6, SCLK_1, MOSI_1, MISO_1), - (2, SCLK_2, MOSI_2, MISO_2), - (3, D3, D2, D1), - (4, D7, D6, D5), - (5, D15, D14, D13), - ) -else: - spiPorts = ( - (0, SCLK, MOSI, MISO), - (1, SCLK_1, MOSI_1, MISO_1), - (2, SCLK_2, MOSI_2, MISO_2), - ) +spiPorts = ( + (0, SCLK, MOSI, MISO), + (1, SCLK_1, MOSI_1, MISO_1), + (2, SCLK_2, MOSI_2, MISO_2), +) # ordered as uartId, txId, rxId uartPorts = ((1, TXD, RXD),) @@ -164,5 +154,4 @@ uartPorts = ((1, TXD, RXD),) i2cPorts = ( (1, SCL, SDA), (0, D1, D0), # both pi 1 and pi 2 i2c ports! - (10, D45, D44), # internal i2c bus for the CM4 ) diff --git a/src/board.py b/src/board.py index 304daf5..36a248d 100755 --- a/src/board.py +++ b/src/board.py @@ -54,6 +54,12 @@ elif board_id == ap_board.PYBOARD: elif board_id == ap_board.RASPBERRY_PI_PICO: from adafruit_blinka.board.raspberrypi.pico import * +elif detector.board.RASPBERRY_PI_4B or detector.board.RASPBERRY_PI_400: + from adafruit_blinka.board.raspberrypi.raspi_4b import * + +elif detector.board.RASPBERRY_PI_CM4: + from adafruit_blinka.board.raspberrypi.raspi_cm4 import * + elif detector.board.any_raspberry_pi_40_pin: from adafruit_blinka.board.raspberrypi.raspi_40pin import * diff --git a/src/microcontroller/__init__.py b/src/microcontroller/__init__.py index 82bc1a9..d9ca071 100755 --- a/src/microcontroller/__init__.py +++ b/src/microcontroller/__init__.py @@ -57,7 +57,10 @@ elif chip_id == ap_chip.STM32F405: elif chip_id == ap_chip.RP2040: from adafruit_blinka.microcontroller.rp2040 import * elif chip_id == ap_chip.BCM2XXX: - from adafruit_blinka.microcontroller.bcm283x import * + if board_id in ["RASPBERRY_PI_4B", "RASPBERRY_PI_400", "RASPBERRY_PI_CM4",]: + from adafruit_blinka.microcontroller.bcm2711.pin import * + else: + from adafruit_blinka.microcontroller.bcm283x.pin import * elif chip_id == ap_chip.DRA74X: from adafruit_blinka.microcontroller.dra74x.pin import * elif chip_id == ap_chip.AM33XX: diff --git a/src/microcontroller/pin.py b/src/microcontroller/pin.py index c46a335..15e0152 100755 --- a/src/microcontroller/pin.py +++ b/src/microcontroller/pin.py @@ -1,7 +1,7 @@ """Pins named after their chip name.""" from adafruit_platformdetect.constants import chips as ap_chip -from adafruit_blinka.agnostic import chip_id +from adafruit_blinka.agnostic import board_id, chip_id # We intentionally are patching into this namespace so skip the wildcard check. # pylint: disable=unused-wildcard-import,wildcard-import,ungrouped-imports @@ -13,7 +13,10 @@ elif chip_id == ap_chip.STM32F405: elif chip_id == ap_chip.RP2040: from adafruit_blinka.microcontroller.rp2040.pin import * elif chip_id == ap_chip.BCM2XXX: - from adafruit_blinka.microcontroller.bcm283x.pin import * + if board_id in ["RASPBERRY_PI_4B", "RASPBERRY_PI_400", "RASPBERRY_PI_CM4",]: + from adafruit_blinka.microcontroller.bcm2711.pin import * + else: + from adafruit_blinka.microcontroller.bcm283x.pin import * elif chip_id == ap_chip.DRA74X: from adafruit_blinka.microcontroller.dra74x.pin import * elif chip_id == ap_chip.AM33XX: -- 2.49.0