From 5052177bcfdc5cf84a20ef51444737906ca084e5 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Thu, 26 Dec 2024 13:25:26 -0800 Subject: [PATCH 01/27] Setup files for busio --- ports/analog/common-hal/busio/I2C.c | 210 ++++++++++++++++++ ports/analog/common-hal/busio/I2C.h | 24 ++ ports/analog/common-hal/busio/SPI.c | 254 ++++++++++++++++++++++ ports/analog/common-hal/busio/SPI.h | 35 +++ ports/analog/common-hal/busio/UART.c | 76 +++++++ ports/analog/common-hal/busio/UART.h | 31 +++ ports/analog/common-hal/busio/__init__.c | 5 + ports/analog/peripherals/max32690/gpios.h | 2 + 8 files changed, 637 insertions(+) create mode 100644 ports/analog/common-hal/busio/I2C.c create mode 100644 ports/analog/common-hal/busio/I2C.h create mode 100644 ports/analog/common-hal/busio/SPI.c create mode 100644 ports/analog/common-hal/busio/SPI.h create mode 100644 ports/analog/common-hal/busio/UART.c create mode 100644 ports/analog/common-hal/busio/UART.h create mode 100644 ports/analog/common-hal/busio/__init__.c diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c new file mode 100644 index 0000000000000..ae18f561c502f --- /dev/null +++ b/ports/analog/common-hal/busio/I2C.c @@ -0,0 +1,210 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" + +static I2CSPM_Init_TypeDef i2cspm_init; +static bool in_used = false; + +// Construct I2C protocol, this function init i2c peripheral +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t *scl, + const mcu_pin_obj_t *sda, + uint32_t frequency, uint32_t timeout) { + + // Ensure the object starts in its deinit state. + common_hal_busio_i2c_mark_deinit(self); + + if ((scl != NULL) && (sda != NULL)) { + if (scl->function_list[ DEFAULT_I2C_PERIPHERAL == I2C1? + FN_I2C1_SCL : FN_I2C0_SCL] == 1 && + scl->function_list[DEFAULT_I2C_PERIPHERAL == I2C1? + FN_I2C1_SDA : FN_I2C0_SDA] == 1) { + self->scl = scl; + self->sda = sda; + self->has_lock = false; + i2cspm_init.sclPort = self->scl->port; + i2cspm_init.sclPin = self->scl->number; + i2cspm_init.sdaPort = self->sda->port; + i2cspm_init.sdaPin = self->sda->number; + i2cspm_init.port = DEFAULT_I2C_PERIPHERAL; + i2cspm_init.i2cRefFreq = 0; + i2cspm_init.i2cMaxFreq = I2C_FREQ_STANDARD_MAX; + i2cspm_init.i2cClhr = i2cClockHLRStandard; + + self->i2cspm = i2cspm_init.port; + I2CSPM_Init(&i2cspm_init); + common_hal_mcu_pin_claim(scl); + common_hal_mcu_pin_claim(sda); + in_used = true; + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); + } + } else { + raise_ValueError_invalid_pins(); + } +} + +// Never reset I2C obj when reload +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + common_hal_never_reset_pin(self->sda); + common_hal_never_reset_pin(self->scl); +} + +// Check I2C status, deinited or not +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + return self->sda == NULL; +} + +// Deinit i2c obj, reset I2C pin +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } + I2C_Reset(self->i2cspm); + common_hal_reset_pin(self->sda); + common_hal_reset_pin(self->scl); + self->i2cspm = NULL; + in_used = false; + common_hal_busio_i2c_mark_deinit(self); +} + +void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { + self->sda = NULL; +} + +// Probe device in I2C bus +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + uint8_t data = 0; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_READ; + + seq.buf[0].data = &data; + seq.buf[0].len = 1; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return false; + } + return true; +} + +// Lock I2C bus +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return false; + } + bool grabbed_lock = false; + + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + + return grabbed_lock; +} + +// Check I2C lock status +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { + return self->has_lock; +} + +// Unlock I2C bus +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; +} + +// Write data to the device selected by address +uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, + const uint8_t *data, size_t len) { + + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_WRITE; + + seq.buf[0].data = (uint8_t *)data; + seq.buf[0].len = len; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return MP_EIO; + } + return 0; +} + +// Read into buffer from the device selected by address +uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, + uint16_t addr, + uint8_t *data, size_t len) { + + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_READ; + + seq.buf[0].data = data; + seq.buf[0].len = len; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return MP_EIO; + } + return 0; +} + +// Write the bytes from out_data to the device selected by address, +uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, + uint8_t *out_data, size_t out_len, + uint8_t *in_data, size_t in_len) { + + I2C_TransferSeq_TypeDef seq; + I2C_TransferReturn_TypeDef ret; + + seq.addr = addr << 1; + seq.flags = I2C_FLAG_WRITE_READ; + // Select command to issue + seq.buf[0].data = out_data; + seq.buf[0].len = out_len; + // Select location/length of data to be read + seq.buf[1].data = in_data; + seq.buf[1].len = in_len; + + ret = I2CSPM_Transfer(self->i2cspm, &seq); + if (ret != i2cTransferDone) { + return MP_EIO; + } + return 0; +} diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h new file mode 100644 index 0000000000000..c92283d6c53b6 --- /dev/null +++ b/ports/analog/common-hal/busio/I2C.h @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " +#include "py/obj.h" + +// HAL-specific +#include "i2c.h" +#include "gpio.h" + +// Define a struct for what BUSIO.I2C should carry +typedef struct { + mp_obj_base_t base; + mxc_i2c_regs_t* i2c_regs; + bool has_lock; + const mcu_pin_obj_t *scl; + const mcu_pin_obj_t *sda; +} busio_i2c_obj_t; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c new file mode 100644 index 0000000000000..74cfc69bfb2a0 --- /dev/null +++ b/ports/analog/common-hal/busio/SPI.c @@ -0,0 +1,254 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/busio/SPI.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/board.h" +#include "shared-bindings/microcontroller/Pin.h" + +// Note that any bugs introduced in this file can cause crashes +// at startupfor chips using external SPI flash. + +static SPIDRV_HandleData_t spidrv_eusart_handle; +static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; +static bool in_used = false; +static bool never_reset = false; + +// Reset SPI when reload +void spi_reset(void) { + if (!never_reset && in_used) { + SPIDRV_DeInit(&spidrv_eusart_handle); + in_used = false; + } + return; +} + +// Construct SPI protocol, this function init SPI peripheral +void common_hal_busio_spi_construct(busio_spi_obj_t *self, + const mcu_pin_obj_t *sck, + const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, + bool half_duplex) { + Ecode_t sc = ECODE_OK; + + if (half_duplex) { + mp_raise_NotImplementedError( + MP_ERROR_TEXT("Half duplex SPI is not implemented")); + } + + if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) { + if (sck->function_list[FN_EUSART1_SCLK] == 1 + && miso->function_list[FN_EUSART1_RX] == 1 + && mosi->function_list[FN_EUSART1_TX] == 1) { + + self->sck = sck; + self->mosi = mosi; + self->miso = miso; + self->handle = &spidrv_eusart_handle; + self->polarity = 0; + self->phase = 0; + self->bits = 8; + + spidrv_eusart_init.portTx = mosi->port; + spidrv_eusart_init.portRx = miso->port; + spidrv_eusart_init.portClk = sck->port; + spidrv_eusart_init.pinTx = mosi->number; + spidrv_eusart_init.pinRx = miso->number; + spidrv_eusart_init.pinClk = sck->number; + spidrv_eusart_init.bitRate = 1000000; + spidrv_eusart_init.frameLength = 8; + spidrv_eusart_init.dummyTxValue = 0; + spidrv_eusart_init.type = spidrvMaster; + spidrv_eusart_init.bitOrder = spidrvBitOrderMsbFirst; + spidrv_eusart_init.clockMode = spidrvClockMode0; + spidrv_eusart_init.csControl = spidrvCsControlApplication; + spidrv_eusart_init.slaveStartMode = spidrvSlaveStartImmediate; + + sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("SPI init error")); + } + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); + } + } else { + raise_ValueError_invalid_pins(); + } + + in_used = true; + common_hal_mcu_pin_claim(sck); + common_hal_mcu_pin_claim(mosi); + common_hal_mcu_pin_claim(miso); +} + +// Never reset SPI when reload +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + never_reset = true; + common_hal_never_reset_pin(self->mosi); + common_hal_never_reset_pin(self->miso); + common_hal_never_reset_pin(self->sck); +} + +// Check SPI status, deinited or not +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + return self->sck == NULL; +} + +// Deinit SPI obj +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + + if (common_hal_busio_spi_deinited(self)) { + return; + } + + Ecode_t sc = SPIDRV_DeInit(self->handle); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); + } + + in_used = false; + self->sck = NULL; + self->mosi = NULL; + self->miso = NULL; + self->handle = NULL; + common_hal_reset_pin(self->mosi); + common_hal_reset_pin(self->miso); + common_hal_reset_pin(self->sck); +} + +// Configures the SPI bus. The SPI object must be locked. +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, + uint32_t baudrate, + uint8_t polarity, + uint8_t phase, + uint8_t bits) { + Ecode_t sc; + // This resets the SPI, so check before updating it redundantly + if (baudrate == self->baudrate && polarity == self->polarity + && phase == self->phase && bits == self->bits) { + return true; + } + + sc = SPIDRV_DeInit(self->handle); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); + } + in_used = false; + self->baudrate = baudrate; + self->phase = phase; + self->bits = bits; + self->polarity = polarity; + + spidrv_eusart_init.bitRate = baudrate; + spidrv_eusart_init.frameLength = 8; + if (polarity == 0 && phase == 0) { + spidrv_eusart_init.clockMode = spidrvClockMode0; + } else if (polarity == 0 && phase == 1) { + spidrv_eusart_init.clockMode = spidrvClockMode1; + } else if (polarity == 1 && phase == 0) { + spidrv_eusart_init.clockMode = spidrvClockMode2; + } else if (polarity == 1 && phase == 1) { + spidrv_eusart_init.clockMode = spidrvClockMode3; + } + + sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); + if (sc != ECODE_EMDRV_SPIDRV_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); + } + in_used = true; + return true; +} + +// Lock SPI bus +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + + return grabbed_lock; +} + +// Check SPI lock status +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +// Unlock SPI bus +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; +} + +// Write the data contained in buffer +bool common_hal_busio_spi_write(busio_spi_obj_t *self, + const uint8_t *data, + size_t len) { + + Ecode_t result = SPIDRV_MTransmitB(self->handle, data, len); + return result == ECODE_EMDRV_SPIDRV_OK; +} + +// Read data into buffer +bool common_hal_busio_spi_read(busio_spi_obj_t *self, + uint8_t *data, size_t len, + uint8_t write_value) { + + self->handle->initData.dummyTxValue = write_value; + Ecode_t result = SPIDRV_MReceiveB(self->handle, data, len); + return result == ECODE_EMDRV_SPIDRV_OK; +} + +// Write out the data in data_out +// while simultaneously reading data into data_in +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, + const uint8_t *data_out, + uint8_t *data_in, + size_t len) { + + Ecode_t result = SPIDRV_MTransferB(self->handle, data_out, data_in, len); + return result == ECODE_EMDRV_SPIDRV_OK; +} + +// Get SPI baudrate +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { + return self->baudrate; +} + +// Get SPI phase +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { + return self->phase; +} + +// Get SPI polarity +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { + return self->polarity; +} diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h new file mode 100644 index 0000000000000..8c48147ff6c77 --- /dev/null +++ b/ports/analog/common-hal/busio/SPI.h @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H +#define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H + +#include "common-hal/microcontroller/Pin.h" +// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " +#include "py/obj.h" + +// HAL-specific +#include "spi.h" + +// Define a struct for what BUSIO.SPI should carry +typedef struct { + mp_obj_base_t base; + mxc_spi_regs_t* spi_regs; + bool has_lock; + const mcu_pin_obj_t *sck; + const mcu_pin_obj_t *mosi; + const mcu_pin_obj_t *miso; + const mcu_pin_obj_t *nss; + uint32_t baudrate; + uint16_t prescaler; + uint8_t polarity; + uint8_t phase; + uint8_t bits; +} busio_spi_obj_t; + +void spi_reset(void); + +#endif // MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c new file mode 100644 index 0000000000000..6d1507b78c696 --- /dev/null +++ b/ports/analog/common-hal/busio/UART.c @@ -0,0 +1,76 @@ +/* + * This file is part of Adafruit for EFR32 project + * + * The MIT License (MIT) + * + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/UART.h" + +#include "mpconfigport.h" +#include "shared/readline/readline.h" +#include "shared/runtime/interrupt_char.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "uart.h" +#include "UART.h" + +typedef enum { + BUSIO_UART_PARITY_NONE, + BUSIO_UART_PARITY_EVEN, + BUSIO_UART_PARITY_ODD +} busio_uart_parity_t; + +// Construct an underlying UART object. +extern void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, + const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, + const mcu_pin_obj_t *rs485_dir, bool rs485_invert, + uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, + mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, + bool sigint_enabled); + +extern void common_hal_busio_uart_deinit(busio_uart_obj_t *self); +extern bool common_hal_busio_uart_deinited(busio_uart_obj_t *self); + +// Read characters. len is in characters NOT bytes! +extern size_t common_hal_busio_uart_read(busio_uart_obj_t *self, + uint8_t *data, size_t len, int *errcode); + +// Write characters. len is in characters NOT bytes! +extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode); + +extern uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self); +extern void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate); +extern mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self); +extern void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout); + +extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self); +extern void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self); +extern bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self); + +extern void common_hal_busio_uart_never_reset(busio_uart_obj_t *self); diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h new file mode 100644 index 0000000000000..a8d294de222d3 --- /dev/null +++ b/ports/analog/common-hal/busio/UART.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H + +#include "common-hal/microcontroller/Pin.h" +#include "peripherals/periph.h" +#include "py/obj.h" +#include "py/ringbuf.h" + +#include "uart.h" + +// Define a struct for what BUSIO.UART should contain +typedef struct { + mp_obj_base_t base; + mxc_uart_regs_t* uart_regs; + const mcu_pin_obj_t *rx; + const mcu_pin_obj_t *tx; + uint32_t baudrate; + bool parity; + uint8_t stop_bits; + uint8_t bits; +} busio_uart_obj_t; + +void uart_reset(void); + +#endif // MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H diff --git a/ports/analog/common-hal/busio/__init__.c b/ports/analog/common-hal/busio/__init__.c new file mode 100644 index 0000000000000..ff05be051bb25 --- /dev/null +++ b/ports/analog/common-hal/busio/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT diff --git a/ports/analog/peripherals/max32690/gpios.h b/ports/analog/peripherals/max32690/gpios.h index 4677bf8f33dbe..fe91227728291 100644 --- a/ports/analog/peripherals/max32690/gpios.h +++ b/ports/analog/peripherals/max32690/gpios.h @@ -4,6 +4,8 @@ // // SPDX-License-Identifier: MIT +#pragma once + #include "py/obj.h" #include "py/mphal.h" From 0220236715f6459d0d4b11d76c6c63e0d6d176cd Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 14 Jan 2025 15:19:04 -0800 Subject: [PATCH 02/27] Add default build for analog ports for apard32690 board. --- Makefile | 3 +++ ports/analog/Makefile | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 554945691b459..d14c047a5b8a5 100644 --- a/Makefile +++ b/Makefile @@ -304,6 +304,9 @@ update-frozen-libraries: one-of-each: samd21 litex mimxrt10xx nordic stm +analog: + $(MAKE) -C ports/analog/ BOARD=apard32690 + samd21: $(MAKE) -C ports/atmel-samd BOARD=trinket_m0 diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 08b245c5897e3..7e11f1cc7e2ec 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -5,12 +5,13 @@ # # SPDX-License-Identifier: MIT +BOARD ?= apard32690 +CROSS_COMPILE = arm-none-eabi- + # Includes mpconfigboard.mk & mpconfigport.mk, # along with numerous other shared environment makefiles. include ../../py/circuitpy_mkenv.mk -CROSS_COMPILE = arm-none-eabi- - # MCU_SERIES e.g. "max32" # MCU_VARIANT e.g. "max32690" # defined in mpconfigboard.mk @@ -19,6 +20,7 @@ MCU_SERIES_UPPER := $(shell echo $(MCU_SERIES) | tr '[:lower:]' '[:upper:]') MCU_VARIANT_LOWER := $(shell echo $(MCU_VARIANT) | tr '[:upper:]' '[:lower:]') MCU_VARIANT_UPPER := $(shell echo $(MCU_VARIANT) | tr '[:lower:]' '[:upper:]') + # ******************************************************************************* #### MSDK INCLUDES #### # Necessary for msdk makefiles @@ -58,6 +60,7 @@ DIE_TYPE=me18 endif PERIPH_SRC = $(ADI_PERIPH)/Source +PERIPH_INC = $(ADI_PERIPH)/Include/$(MCU_VARIANT_UPPER) INC += -I. INC += -I../.. @@ -74,7 +77,7 @@ INC += \ -I$(TOP)/lib/cmsis/inc \ -I$(CMSIS_ROOT)/Include \ -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Include \ - -I$(ADI_PERIPH)/Include/$(MCU_VARIANT_UPPER) \ + -I$(PERIPH_INC) \ -I$(PERIPH_SRC)/SYS \ -I$(PERIPH_SRC)/CTB \ -I$(PERIPH_SRC)/DMA \ @@ -122,7 +125,8 @@ SRC_C += $(SRC_MAX32) \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/pins.c \ - peripherals/$(MCU_VARIANT_LOWER)/gpios.c + peripherals/$(MCU_VARIANT_LOWER)/gpios.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c # ******************************************************************************* ### Compiler & Linker Flags ### From 3ce7bdd5b8d387d73cd30a03785ba07dd4dbbcfb Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 14 Jan 2025 15:22:10 -0800 Subject: [PATCH 03/27] Add preliminary busio.UART support - Enabled BUSIO in mpconfigport.mk - Stubs added for busio.I2C & busio.SPI - Implemented busio.UART to basic working functionality - Added MCU-specific UART data in peripherals//max32_uart.c & max32_uart.h - Still have a couple issues where UART generates garbage characters or does not respond to timeouts / generate asynchronous IRQs --- ports/analog/common-hal/busio/I2C.c | 116 +---- ports/analog/common-hal/busio/SPI.c | 147 +------ ports/analog/common-hal/busio/UART.c | 406 +++++++++++++++++- ports/analog/common-hal/busio/UART.h | 33 +- ports/analog/max32_port.h | 52 +-- ports/analog/mpconfigport.mk | 4 +- .../analog/peripherals/max32690/max32_uart.c | 47 ++ .../analog/peripherals/max32690/max32_uart.h | 16 + 8 files changed, 529 insertions(+), 292 deletions(-) create mode 100644 ports/analog/peripherals/max32690/max32_uart.c create mode 100644 ports/analog/peripherals/max32690/max32_uart.h diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index ae18f561c502f..a8080fa5bc10d 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -30,7 +30,6 @@ #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -static I2CSPM_Init_TypeDef i2cspm_init; static bool in_used = false; // Construct I2C protocol, this function init i2c peripheral @@ -39,37 +38,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - // Ensure the object starts in its deinit state. - common_hal_busio_i2c_mark_deinit(self); - - if ((scl != NULL) && (sda != NULL)) { - if (scl->function_list[ DEFAULT_I2C_PERIPHERAL == I2C1? - FN_I2C1_SCL : FN_I2C0_SCL] == 1 && - scl->function_list[DEFAULT_I2C_PERIPHERAL == I2C1? - FN_I2C1_SDA : FN_I2C0_SDA] == 1) { - self->scl = scl; - self->sda = sda; - self->has_lock = false; - i2cspm_init.sclPort = self->scl->port; - i2cspm_init.sclPin = self->scl->number; - i2cspm_init.sdaPort = self->sda->port; - i2cspm_init.sdaPin = self->sda->number; - i2cspm_init.port = DEFAULT_I2C_PERIPHERAL; - i2cspm_init.i2cRefFreq = 0; - i2cspm_init.i2cMaxFreq = I2C_FREQ_STANDARD_MAX; - i2cspm_init.i2cClhr = i2cClockHLRStandard; - - self->i2cspm = i2cspm_init.port; - I2CSPM_Init(&i2cspm_init); - common_hal_mcu_pin_claim(scl); - common_hal_mcu_pin_claim(sda); - in_used = true; - } else { - mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); - } - } else { - raise_ValueError_invalid_pins(); - } + } // Never reset I2C obj when reload @@ -85,53 +54,26 @@ bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { // Deinit i2c obj, reset I2C pin void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { - return; - } - I2C_Reset(self->i2cspm); - common_hal_reset_pin(self->sda); - common_hal_reset_pin(self->scl); - self->i2cspm = NULL; - in_used = false; - common_hal_busio_i2c_mark_deinit(self); + // FIXME: Implement } void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { - self->sda = NULL; + // FIXME: Implement } // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - uint8_t data = 0; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_READ; - - seq.buf[0].data = &data; - seq.buf[0].len = 1; + // FIXME: Implement - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return false; - } return true; } // Lock I2C bus bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { - return false; - } - bool grabbed_lock = false; - if (!self->has_lock) { - grabbed_lock = true; - self->has_lock = true; - } + // FIXME: Implement - return grabbed_lock; + return false; } // Check I2C lock status @@ -148,19 +90,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_WRITE; - - seq.buf[0].data = (uint8_t *)data; - seq.buf[0].len = len; - - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return MP_EIO; - } + // FIXME: Implement return 0; } @@ -169,19 +99,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_READ; - - seq.buf[0].data = data; - seq.buf[0].len = len; - - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return MP_EIO; - } + // FIXME: Implement return 0; } @@ -190,21 +108,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - I2C_TransferSeq_TypeDef seq; - I2C_TransferReturn_TypeDef ret; - - seq.addr = addr << 1; - seq.flags = I2C_FLAG_WRITE_READ; - // Select command to issue - seq.buf[0].data = out_data; - seq.buf[0].len = out_len; - // Select location/length of data to be read - seq.buf[1].data = in_data; - seq.buf[1].len = in_len; - - ret = I2CSPM_Transfer(self->i2cspm, &seq); - if (ret != i2cTransferDone) { - return MP_EIO; - } + // FIXME: Implement + return 0; } diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 74cfc69bfb2a0..083403b12bbe3 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -34,17 +34,9 @@ // Note that any bugs introduced in this file can cause crashes // at startupfor chips using external SPI flash. -static SPIDRV_HandleData_t spidrv_eusart_handle; -static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; -static bool in_used = false; -static bool never_reset = false; - // Reset SPI when reload void spi_reset(void) { - if (!never_reset && in_used) { - SPIDRV_DeInit(&spidrv_eusart_handle); - in_used = false; - } + // FIXME: Implement return; } @@ -54,64 +46,14 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { - Ecode_t sc = ECODE_OK; - - if (half_duplex) { - mp_raise_NotImplementedError( - MP_ERROR_TEXT("Half duplex SPI is not implemented")); - } - - if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) { - if (sck->function_list[FN_EUSART1_SCLK] == 1 - && miso->function_list[FN_EUSART1_RX] == 1 - && mosi->function_list[FN_EUSART1_TX] == 1) { - - self->sck = sck; - self->mosi = mosi; - self->miso = miso; - self->handle = &spidrv_eusart_handle; - self->polarity = 0; - self->phase = 0; - self->bits = 8; - - spidrv_eusart_init.portTx = mosi->port; - spidrv_eusart_init.portRx = miso->port; - spidrv_eusart_init.portClk = sck->port; - spidrv_eusart_init.pinTx = mosi->number; - spidrv_eusart_init.pinRx = miso->number; - spidrv_eusart_init.pinClk = sck->number; - spidrv_eusart_init.bitRate = 1000000; - spidrv_eusart_init.frameLength = 8; - spidrv_eusart_init.dummyTxValue = 0; - spidrv_eusart_init.type = spidrvMaster; - spidrv_eusart_init.bitOrder = spidrvBitOrderMsbFirst; - spidrv_eusart_init.clockMode = spidrvClockMode0; - spidrv_eusart_init.csControl = spidrvCsControlApplication; - spidrv_eusart_init.slaveStartMode = spidrvSlaveStartImmediate; - - sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_ValueError(MP_ERROR_TEXT("SPI init error")); - } - } else { - mp_raise_ValueError(MP_ERROR_TEXT("Hardware in use, try alternative pins")); - } - } else { - raise_ValueError_invalid_pins(); - } - - in_used = true; - common_hal_mcu_pin_claim(sck); - common_hal_mcu_pin_claim(mosi); - common_hal_mcu_pin_claim(miso); + + + // FIXME: Implement } // Never reset SPI when reload void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset = true; - common_hal_never_reset_pin(self->mosi); - common_hal_never_reset_pin(self->miso); - common_hal_never_reset_pin(self->sck); + // FIXME: Implement } // Check SPI status, deinited or not @@ -122,23 +64,7 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return; - } - - Ecode_t sc = SPIDRV_DeInit(self->handle); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); - } - - in_used = false; - self->sck = NULL; - self->mosi = NULL; - self->miso = NULL; - self->handle = NULL; - common_hal_reset_pin(self->mosi); - common_hal_reset_pin(self->miso); - common_hal_reset_pin(self->sck); + // FIXME: Implement } // Configures the SPI bus. The SPI object must be locked. @@ -147,55 +73,15 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint8_t polarity, uint8_t phase, uint8_t bits) { - Ecode_t sc; - // This resets the SPI, so check before updating it redundantly - if (baudrate == self->baudrate && polarity == self->polarity - && phase == self->phase && bits == self->bits) { - return true; - } - - sc = SPIDRV_DeInit(self->handle); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); - } - in_used = false; - self->baudrate = baudrate; - self->phase = phase; - self->bits = bits; - self->polarity = polarity; - - spidrv_eusart_init.bitRate = baudrate; - spidrv_eusart_init.frameLength = 8; - if (polarity == 0 && phase == 0) { - spidrv_eusart_init.clockMode = spidrvClockMode0; - } else if (polarity == 0 && phase == 1) { - spidrv_eusart_init.clockMode = spidrvClockMode1; - } else if (polarity == 1 && phase == 0) { - spidrv_eusart_init.clockMode = spidrvClockMode2; - } else if (polarity == 1 && phase == 1) { - spidrv_eusart_init.clockMode = spidrvClockMode3; - } - - sc = SPIDRV_Init(self->handle, &spidrv_eusart_init); - if (sc != ECODE_EMDRV_SPIDRV_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("SPI re-init")); - } - in_used = true; + + // FIXME: Implement return true; } // Lock SPI bus bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return false; - } - bool grabbed_lock = false; - if (!self->has_lock) { - grabbed_lock = true; - self->has_lock = true; - } - - return grabbed_lock; + // FIXME: Implement + return false; } // Check SPI lock status @@ -213,8 +99,8 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { - Ecode_t result = SPIDRV_MTransmitB(self->handle, data, len); - return result == ECODE_EMDRV_SPIDRV_OK; + // FIXME: Implement + return false; } // Read data into buffer @@ -222,9 +108,8 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { - self->handle->initData.dummyTxValue = write_value; - Ecode_t result = SPIDRV_MReceiveB(self->handle, data, len); - return result == ECODE_EMDRV_SPIDRV_OK; + // FIXME: Implement + return false; } // Write out the data in data_out @@ -234,8 +119,8 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_in, size_t len) { - Ecode_t result = SPIDRV_MTransferB(self->handle, data_out, data_in, len); - return result == ECODE_EMDRV_SPIDRV_OK; + // FIXME: Implement + return false; } // Get SPI baudrate diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 6d1507b78c696..ddffc8f55b9c3 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -26,8 +26,11 @@ #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/shared/tick.h" #include "shared-bindings/busio/UART.h" +#include "shared-bindings/microcontroller/Pin.h" + #include "mpconfigport.h" #include "shared/readline/readline.h" #include "shared/runtime/interrupt_char.h" @@ -35,42 +38,403 @@ #include "py/mperrno.h" #include "py/runtime.h" -#include "uart.h" +#include "max32_port.h" #include "UART.h" +#include "nvic_table.h" + +// UART IRQ Priority +#define UART_PRIORITY 1 + +/** + * +// Define a struct for what BUSIO.UART should contain +typedef struct { + mp_obj_base_t base; + int uart_id; + mxc_uart_regs_t* uart_regs; + + const mcu_pin_obj_t *rx_pin; + const mcu_pin_obj_t *tx_pin; + const mcu_pin_obj_t *rts_pin; + const mcu_pin_obj_t *cts_pin; + + uint8_t bits; + uint32_t baudrate; + bool parity; + uint8_t stop_bits; + + uint32_t timeout_ms; + bool error; +} busio_uart_obj_t; + */ + +typedef enum { + UART_9600 = 9600, + UART_14400 = 14400, + UART_19200 = 19200, + UART_38400 = 38400, + UART_57600 = 57600, + UART_115200 = 115200, + UART_230400 = 230400, + UART_460800 = 460800, + UART_921600 = 921600, +} uart_valid_baudrates; + typedef enum { - BUSIO_UART_PARITY_NONE, - BUSIO_UART_PARITY_EVEN, - BUSIO_UART_PARITY_ODD -} busio_uart_parity_t; + UART_FREE = 0, + UART_BUSY, + UART_NEVER_RESET, +} uart_status_t; + +static uint32_t timeout_ms=0; + +// Set each bit to indicate an active UART +// will be checked by ISR Handler for which ones to call +static uint8_t uarts_active = 0; +static uart_status_t uart_status[NUM_UARTS]; +// static uint8_t uart_never_reset_mask = 0; + +static int isValidBaudrate(uint32_t baudrate) { + switch(baudrate) { + case UART_9600: + return 1; + break; + case UART_14400: + return 1; + break; + case UART_19200: + return 1; + break; + case UART_38400: + return 1; + break; + case UART_57600: + return 1; + break; + case UART_115200: + return 1; + break; + case UART_230400: + return 1; + break; + case UART_460800: + return 1; + break; + case UART_921600: + return 1; + break; + default: + return 0; + break; + } +} + +static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) +{ + switch(busio_parity) { + case BUSIO_UART_PARITY_NONE: + return MXC_UART_PARITY_DISABLE; + case BUSIO_UART_PARITY_EVEN: + return MXC_UART_PARITY_EVEN_0; + case BUSIO_UART_PARITY_ODD: + return MXC_UART_PARITY_ODD_0; + default: + mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); + } +} + +// FIXME: Find a better way of doing t his without a for loop +void UartISR(void) { + for (int i=0; i< NUM_UARTS; i++) { + if (uarts_active & (1 << i) ) { + MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); + uart_status[i] = UART_FREE; + } + } +} + +void uartCallback(mxc_uart_req_t *req, int error) { + +} // Construct an underlying UART object. -extern void common_hal_busio_uart_construct(busio_uart_obj_t *self, +void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, - bool sigint_enabled); + bool sigint_enabled) +{ + int err, temp; + + // Check for NULL Pointers && valid UART settings + assert( self ); + + // Assign UART ID based on pins + temp = pinsToUart(tx, rx); + if (temp == -1) { + // Error will be indicated by pinsToUart(tx, rx) function + return; + } + else { + self->uart_id = temp; + self->uart_regs = MXC_UART_GET_UART(temp); + } + + assert( (self->uart_id >= 0) && (self->uart_id < NUM_UARTS) ); + + // Indicate RS485 not implemented + if ( (rs485_dir != NULL) || (rs485_invert) ) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("RS485")); + } + + if ((rx != NULL) && (tx != NULL)) { + err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); + if (err != E_NO_ERROR) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to initialize UART.\n")); + } + + // attach & configure pins + self->tx_pin = tx; + self->rx_pin = rx; + common_hal_mcu_pin_claim(self->tx_pin); + common_hal_mcu_pin_claim(self->rx_pin); + } + else if (tx != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); + } + else if (rx != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); + } + else { + // Should not get here, as shared-bindings API should not call this way + } + + if ((cts) && (rts)) { + MXC_UART_SetFlowCtrl(self->uart_regs, MXC_UART_FLOW_EN, 8); + self->cts_pin = cts; + self->rts_pin = rts; + common_hal_mcu_pin_claim(self->cts_pin); + common_hal_mcu_pin_claim(self->rts_pin); + } + else if (cts || rts) { + mp_raise_ValueError(MP_ERROR_TEXT("Flow Ctrl needs both CTS & RTS")); + } + + // Set stop bits & data size + assert( (stop == 1) || (stop == 2) ); + mp_arg_validate_int(bits, 8, MP_QSTR_bits); + MXC_UART_SetDataSize(self->uart_regs, bits); + MXC_UART_SetStopBits(self->uart_regs, stop); + + // Set parity + MXC_UART_SetParity(self->uart_regs, convertParity(parity)); + + // attach UART parameters + self->stop_bits = stop; // must be 1 or 2 + self->bits = bits; + self->parity = parity; + self->baudrate = baudrate; + self->error = E_NO_ERROR; -extern void common_hal_busio_uart_deinit(busio_uart_obj_t *self); -extern bool common_hal_busio_uart_deinited(busio_uart_obj_t *self); + // Initialize ringbuffer for receiving data + if (self->rx_pin) { + // if given a ringbuff, use that + if (receiver_buffer) { + ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size); + } + // else create one and attach it + else { + if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size)) { + m_malloc_fail(receiver_buffer_size); + } + } + } + // Indicate to this module that the UART is active + uarts_active |= (1 << self->uart_id); + + MXC_UART_ClearFlags(self->uart_regs, self->uart_regs->int_fl); + + /* Enable UART interrupt */ + NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); + NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)UartISR); + + // FIXME: UART ISRs are NOT WORKING! + // MXC_UART_EnableInt(self->uart_regs, ???) + // NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + + return; +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) +{ + assert(self); + + if (!common_hal_busio_uart_deinited(self)) { + // First disable the ISR to avoid pre-emption + NVIC_DisableIRQ(UART0_IRQn); + + MXC_UART_Shutdown(self->uart_regs); + self->error = E_UNINITIALIZED; + + assert(self->rx_pin && self->tx_pin); + reset_pin_number(self->rx_pin->port, self->rx_pin->mask); + reset_pin_number(self->tx_pin->port, self->tx_pin->mask); + + if (self->cts_pin && self->rts_pin) { + reset_pin_number(self->cts_pin->port, self->cts_pin->mask); + reset_pin_number(self->rts_pin->port, self->rts_pin->mask); + } + + self->tx_pin = NULL; + self->rx_pin = NULL; + self->cts_pin = NULL; + self->rts_pin = NULL; + + // Indicate to this module that the UART is not active + uarts_active &= ~(1 << self->uart_id); + } +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) +{ + if (uarts_active & (1 << self->uart_id)) { + return false; + } + else { + return true; + }; +} + +// todo: test // Read characters. len is in characters NOT bytes! -extern size_t common_hal_busio_uart_read(busio_uart_obj_t *self, - uint8_t *data, size_t len, int *errcode); +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, + uint8_t *data, size_t len, int *errcode) +{ + int err; + static size_t bytes_remaining; + + bytes_remaining = len * 4; + while(bytes_remaining > 0) { + mxc_uart_req_t uart_wr_req; + uart_wr_req.rxCnt = 0; + uart_wr_req.txCnt = 0; + uart_wr_req.rxData = data; + uart_wr_req.txData = NULL; + uart_wr_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_wr_req.txLen = 0; + uart_wr_req.uart = self->uart_regs; + + err = MXC_UART_Transaction(&uart_wr_req); + if (err != E_NO_ERROR) { + *errcode = err; + return ((len * 4) - bytes_remaining); + } + bytes_remaining -= uart_wr_req.rxLen; + } + return len; +} + +//todo: test // Write characters. len is in characters NOT bytes! -extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self, - const uint8_t *data, size_t len, int *errcode); + size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode) +{ + int err; + uint32_t start_time=0; + static size_t bytes_remaining; + + bytes_remaining = len * 4; + + while(bytes_remaining > 0) { + mxc_uart_req_t uart_wr_req; + uart_wr_req.rxCnt = 0; + uart_wr_req.txCnt = 0; + uart_wr_req.rxData = NULL; + uart_wr_req.txData = data; + uart_wr_req.txLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_wr_req.rxLen = 0; + uart_wr_req.uart = self->uart_regs; + + uart_status[self->uart_id] = UART_BUSY; + start_time = supervisor_ticks_ms64(); + err = MXC_UART_Transaction(&uart_wr_req); + if (err != E_NO_ERROR) { + *errcode = err; + return ((len * 4) - bytes_remaining); + } + + // FIXME: NOT ENTERING ISR, NOT HANDLING TIMEOUT + // Wait for transaction completion + // FIXME: Test timeout & status flags + while ( (supervisor_ticks_ms64() - start_time < 500) + && (uart_status[self->uart_id] != UART_FREE) + ) {}; + + bytes_remaining -= uart_wr_req.txLen; + } + return len; +} + + uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) +{ + return self->baudrate; +} + +// Validate baudrate +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) +{ + if ( isValidBaudrate(baudrate) ) { + self->baudrate = baudrate; + } + else { + mp_raise_ValueError(MP_ERROR_TEXT("Baudrate invalid. Must be a standard UART baudrate.\n")); + } +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) +{ + return self->timeout; +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) +{ + if (timeout > 100.0) { + mp_raise_ValueError(MP_ERROR_TEXT("Timeout must be < 100 seconds")); + } + + timeout_ms = 1000 * (uint32_t)timeout; + self->timeout = (uint32_t)timeout; + + return; +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) +{ + return MXC_UART_GetRXFIFOAvailable(self->uart_regs); +} -extern uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self); -extern void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate); -extern mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self); -extern void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout); +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) +{ + MXC_UART_ClearRXFIFO(self->uart_regs); +} -extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self); -extern void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self); -extern bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self); +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) +{ + return !(MXC_UART_GetStatus(self->uart_regs) & (MXC_F_UART_STATUS_TX_BUSY)); +} -extern void common_hal_busio_uart_never_reset(busio_uart_obj_t *self); +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) +{ + common_hal_never_reset_pin(self->tx_pin); + common_hal_never_reset_pin(self->rx_pin); + common_hal_never_reset_pin(self->cts_pin); + common_hal_never_reset_pin(self->rts_pin); + // uart_never_reset_mask |= ( 1 << (self->uart_id) ); +} diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index a8d294de222d3..3c76efc720e78 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -4,28 +4,43 @@ // // SPDX-License-Identifier: MIT -#ifndef MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H -#define MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H +#ifndef MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H +#define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H #include "common-hal/microcontroller/Pin.h" -#include "peripherals/periph.h" #include "py/obj.h" #include "py/ringbuf.h" -#include "uart.h" +// #include "uart.h" +// #include "uart_regs.h" +// #include "mxc_sys.h" + +#include "max32_port.h" // Define a struct for what BUSIO.UART should contain typedef struct { mp_obj_base_t base; + + int uart_id; + int uart_map; mxc_uart_regs_t* uart_regs; - const mcu_pin_obj_t *rx; - const mcu_pin_obj_t *tx; - uint32_t baudrate; + bool parity; - uint8_t stop_bits; uint8_t bits; + uint8_t stop_bits; + uint32_t baudrate; + + int error; + float timeout; + + ringbuf_t ringbuf; + + const mcu_pin_obj_t *rx_pin; + const mcu_pin_obj_t *tx_pin; + const mcu_pin_obj_t *rts_pin; + const mcu_pin_obj_t *cts_pin; } busio_uart_obj_t; void uart_reset(void); -#endif // MICROPY_INCLUDED_EFR32_COMMON_HAL_BUSIO_UART_H +#endif // MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_UART_H diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index 5d92fcfe6d3ee..5c3811b651554 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -22,31 +22,35 @@ #include "system_max32690.h" #include "max32690.h" +// UART Ports & pins +#include "peripherals/max32690/max32_uart.h" +#define NUM_UARTS 4 + /** START: GPIO4 Handling specific to MAX32690 */ -#define GPIO4_PIN_MASK 0x00000003 -#define GPIO4_RESET_MASK 0xFFFFFF77 -#define GPIO4_OUTEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) -#define GPIO4_PULLDIS_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) -#define GPIO4_DATAOUT_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) -#define GPIO4_DATAOUT_GET_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ - mask) -#define GPIO4_DATAIN_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ - mask) -#define GPIO4_AFEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ - ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) + #define GPIO4_PIN_MASK 0x00000003 + #define GPIO4_RESET_MASK 0xFFFFFF77 + #define GPIO4_OUTEN_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) + #define GPIO4_PULLDIS_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) + #define GPIO4_DATAOUT_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) + #define GPIO4_DATAOUT_GET_MASK(mask) \ + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ + mask) + #define GPIO4_DATAIN_MASK(mask) \ + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ + mask) + #define GPIO4_AFEN_MASK(mask) \ + (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ + ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) /** END: GPIO4 Handling specific to MAX32690 */ #endif diff --git a/ports/analog/mpconfigport.mk b/ports/analog/mpconfigport.mk index 1729a284a3f47..c9b392e58062e 100644 --- a/ports/analog/mpconfigport.mk +++ b/ports/analog/mpconfigport.mk @@ -21,8 +21,10 @@ INTERNAL_FLASH_FILESYSTEM = 1 #################################################################################### # These modules are implemented in ports//common-hal: +# Actively implementing (some functions may be stubbed out) +CIRCUITPY_BUSIO ?= 1 + # Plan to implement -CIRCUITPY_BUSIO ?= 0 CIRCUITPY_RTC ?= 0 # Other modules (may or may not implement): diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c new file mode 100644 index 0000000000000..f8c53dc63218e --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/UART.h" +#include "max32_uart.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +// FIXME: Remove upon test! +// mxc_uart_regs_t max32_uarts[NUM_UARTS] = { +// MXC_UART0, +// MXC_UART1, +// MXC_UART2, +// MXC_UART3, +// }; + +const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { + { MXC_GPIO2, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } +}; + +int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { + for (int i = 0; i < NUM_UARTS; i++) { + if ( (uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) + && (uart_maps[i].mask == (( tx->mask) | (rx->mask))) ) { + return i; + } + } + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find a uart matching pins...\nTX: port %d mask %d\nRX: port %d mask %d\n"), + tx->port, tx->mask, rx->port, rx->mask); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_uart.h b/ports/analog/peripherals/max32690/max32_uart.h new file mode 100644 index 0000000000000..f03b500a3c507 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_uart.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "uart_regs.h" +#include "mxc_sys.h" +#include "uart.h" +#include "peripherals/pins.h" + +#define NUM_UARTS 4 + +int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx); From 3608b8c7641bd9a903adfc35987b8754ec07ad67 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 14 Jan 2025 15:26:49 -0800 Subject: [PATCH 04/27] Add tools files for debugging - Add debug-dap.sh to spawn OpenOCD process & gdb-multiarch process for debugging. Requires MaximSDK install & path settings inside this script. Also depends on gdb-multiarch and connected CMSIS-DAP probe over USB. - debug-dap.gdb simply holds the gdb commands for this script + small style fix on common-hal/microcontroller/Pin.c --- ports/analog/common-hal/microcontroller/Pin.c | 2 +- ports/analog/tools/debug-dap.gdb | 3 +++ ports/analog/tools/debug-dap.sh | 23 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 ports/analog/tools/debug-dap.gdb create mode 100644 ports/analog/tools/debug-dap.sh diff --git a/ports/analog/common-hal/microcontroller/Pin.c b/ports/analog/common-hal/microcontroller/Pin.c index 4545aa039c2fa..6816054153e72 100644 --- a/ports/analog/common-hal/microcontroller/Pin.c +++ b/ports/analog/common-hal/microcontroller/Pin.c @@ -37,7 +37,7 @@ void reset_all_pins(void) { } void reset_pin_number(uint8_t pin_port, uint8_t pin_pad) { - if (pin_port == INVALID_PIN || pin_port > NUM_GPIO_PORTS) { + if ( (pin_port == INVALID_PIN) || (pin_port > NUM_GPIO_PORTS) ) { return; } diff --git a/ports/analog/tools/debug-dap.gdb b/ports/analog/tools/debug-dap.gdb new file mode 100644 index 0000000000000..d0aa7e2b13fa0 --- /dev/null +++ b/ports/analog/tools/debug-dap.gdb @@ -0,0 +1,3 @@ +target remote :3333 +break main +continue diff --git a/ports/analog/tools/debug-dap.sh b/ports/analog/tools/debug-dap.sh new file mode 100644 index 0000000000000..df2964fcb122a --- /dev/null +++ b/ports/analog/tools/debug-dap.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Primer on taking cmd line args in Linux shell scripts +# $0 is the script itself +# $1 $2 $3 are arg1, arg2, arg3, etc + +# Export OCD Path +### USER ACTION: Replace with your path to OpenOCD ### +OCD_PATH="~/MaximSDK/Tools/OpenOCD" + +# Call openocd to setup the debug server, storing the PID for OpenOCD +sh -c "openocd -s $OCD_PATH/scripts -f interface/cmsis-dap.cfg -f target/$1.cfg -c \"init; reset halt\" " & + +# Allow enough time for OCD server to set up +# + wait for the sleep to finish +sleep 3 & +wait $! + +# spawn the gdb process and store the gdb_pid +gdb-multiarch build-apard32690/firmware.elf -x "tools/debug-dap.gdb" + +# when gdb exits, kill all openocd processes +killall openocd From 8848d432cb8e387b91d281b7afaf44c4c30f7176 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Fri, 24 Jan 2025 13:42:42 -0800 Subject: [PATCH 05/27] Fixed most UART write issues. - Graceful recovery from timeouts added - Remaining issue still exists where a timeout occurs after a while --- ports/analog/common-hal/busio/UART.c | 86 +++++++++++++++++----------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index ddffc8f55b9c3..4b0c8bfba6a81 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#if CIRCUITPY_BUSIO_UART + #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "supervisor/shared/tick.h" @@ -144,18 +146,21 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) } } -// FIXME: Find a better way of doing t his without a for loop -void UartISR(void) { - for (int i=0; i< NUM_UARTS; i++) { +// FIXME: Find a better way of doing this without a for loop +// FIXME: Fixed @ UART0 for TESTING BUGFIXES!!! +void UART0_IRQHandler(void) { + // MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); + for (int i=0; i < NUM_UARTS; i++) { if (uarts_active & (1 << i) ) { MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); - uart_status[i] = UART_FREE; } } } -void uartCallback(mxc_uart_req_t *req, int error) { - +// Callback gets called when AsyncRequest is COMPLETE +// (e.g. txLen == txCnt) +static volatile void uartCallback(mxc_uart_req_t *req, int error) { + uart_status[MXC_UART_GET_IDX(req->uart)] = UART_FREE; } // Construct an underlying UART object. @@ -256,17 +261,12 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Indicate to this module that the UART is active uarts_active |= (1 << self->uart_id); - MXC_UART_ClearFlags(self->uart_regs, self->uart_regs->int_fl); /* Enable UART interrupt */ NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); - NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)UartISR); - - // FIXME: UART ISRs are NOT WORKING! - // MXC_UART_EnableInt(self->uart_regs, ???) - // NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)&UART0_IRQHandler); return; } @@ -321,23 +321,30 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, bytes_remaining = len * 4; - while(bytes_remaining > 0) { - mxc_uart_req_t uart_wr_req; - uart_wr_req.rxCnt = 0; - uart_wr_req.txCnt = 0; - uart_wr_req.rxData = data; - uart_wr_req.txData = NULL; - uart_wr_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); - uart_wr_req.txLen = 0; - uart_wr_req.uart = self->uart_regs; + MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); + NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - err = MXC_UART_Transaction(&uart_wr_req); + while(bytes_remaining > 0) { + mxc_uart_req_t uart_rd_req; + uart_rd_req.rxCnt = 0; + uart_rd_req.txCnt = 0; + uart_rd_req.rxData = data; + uart_rd_req.txData = NULL; + uart_rd_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_rd_req.txLen = 0; + uart_rd_req.uart = self->uart_regs; + uart_rd_req.callback = (void *)uartCallback; + + err = MXC_UART_TransactionAsync(&uart_rd_req); if (err != E_NO_ERROR) { *errcode = err; + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); return ((len * 4) - bytes_remaining); } - bytes_remaining -= uart_wr_req.rxLen; + bytes_remaining -= uart_rd_req.rxLen; } + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + return len; } @@ -350,7 +357,10 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint32_t start_time=0; static size_t bytes_remaining; - bytes_remaining = len * 4; + bytes_remaining = len; + + MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); + NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); while(bytes_remaining > 0) { mxc_uart_req_t uart_wr_req; @@ -358,28 +368,38 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uart_wr_req.txCnt = 0; uart_wr_req.rxData = NULL; uart_wr_req.txData = data; - uart_wr_req.txLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); + uart_wr_req.txLen = bytes_remaining; uart_wr_req.rxLen = 0; uart_wr_req.uart = self->uart_regs; + uart_wr_req.callback = (void *)uartCallback; uart_status[self->uart_id] = UART_BUSY; start_time = supervisor_ticks_ms64(); - err = MXC_UART_Transaction(&uart_wr_req); + err = MXC_UART_TransactionAsync(&uart_wr_req); if (err != E_NO_ERROR) { *errcode = err; - return ((len * 4) - bytes_remaining); + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); } - // FIXME: NOT ENTERING ISR, NOT HANDLING TIMEOUT // Wait for transaction completion - // FIXME: Test timeout & status flags - while ( (supervisor_ticks_ms64() - start_time < 500) - && (uart_status[self->uart_id] != UART_FREE) + while ( (uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000)) ) {}; - bytes_remaining -= uart_wr_req.txLen; + // If the timeout gets hit, abort and error out + if (uart_status[self->uart_id] != UART_FREE) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + } + + bytes_remaining -= uart_wr_req.txCnt; } + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); return len; + } uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) @@ -438,3 +458,5 @@ void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) common_hal_never_reset_pin(self->rts_pin); // uart_never_reset_mask |= ( 1 << (self->uart_id) ); } + +#endif // CIRCUITPY_BUSIO_UART From 872e81ce5ecb4949cdcdb7abd717418ba589d4e8 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Fri, 24 Jan 2025 17:08:32 -0800 Subject: [PATCH 06/27] Fix issues with UART reads and unreliable UART writes. - No ISR for UART writes, but uses timeouts - Reads use ISRs, but also incorporate timeouts --- ports/analog/common-hal/busio/UART.c | 162 ++++++++++++++++----------- 1 file changed, 98 insertions(+), 64 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 4b0c8bfba6a81..ad5425d62ea31 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -95,6 +95,7 @@ static uint32_t timeout_ms=0; // will be checked by ISR Handler for which ones to call static uint8_t uarts_active = 0; static uart_status_t uart_status[NUM_UARTS]; +static volatile int uart_err; // static uint8_t uart_never_reset_mask = 0; static int isValidBaudrate(uint32_t baudrate) { @@ -146,12 +147,9 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) } } -// FIXME: Find a better way of doing this without a for loop -// FIXME: Fixed @ UART0 for TESTING BUGFIXES!!! void UART0_IRQHandler(void) { - // MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); - for (int i=0; i < NUM_UARTS; i++) { - if (uarts_active & (1 << i) ) { + for (int i = 0; i < NUM_UARTS; i++) { + if (uarts_active & (1 << i)) { MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); } } @@ -161,6 +159,7 @@ void UART0_IRQHandler(void) { // (e.g. txLen == txCnt) static volatile void uartCallback(mxc_uart_req_t *req, int error) { uart_status[MXC_UART_GET_IDX(req->uart)] = UART_FREE; + uart_err = error; } // Construct an underlying UART object. @@ -262,7 +261,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, uarts_active |= (1 << self->uart_id); - /* Enable UART interrupt */ + /* Setup UART interrupt */ NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); @@ -311,45 +310,67 @@ bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) }; } -// todo: test // Read characters. len is in characters NOT bytes! size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { int err; + uint32_t start_time=0; static size_t bytes_remaining; - bytes_remaining = len * 4; + // Setup globals & status tracking + uart_err = E_NO_ERROR; + uarts_active |= (1 << self->uart_id); + uart_status[self->uart_id] = UART_BUSY; + bytes_remaining = len; - MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - while(bytes_remaining > 0) { - mxc_uart_req_t uart_rd_req; - uart_rd_req.rxCnt = 0; - uart_rd_req.txCnt = 0; - uart_rd_req.rxData = data; - uart_rd_req.txData = NULL; - uart_rd_req.rxLen = (uint32_t)( (bytes_remaining >= 255) ? 255 : bytes_remaining ); - uart_rd_req.txLen = 0; - uart_rd_req.uart = self->uart_regs; - uart_rd_req.callback = (void *)uartCallback; - - err = MXC_UART_TransactionAsync(&uart_rd_req); - if (err != E_NO_ERROR) { - *errcode = err; - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - return ((len * 4) - bytes_remaining); - } - bytes_remaining -= uart_rd_req.rxLen; + mxc_uart_req_t uart_rd_req; + uart_rd_req.rxCnt = 0; + uart_rd_req.txCnt = 0; + uart_rd_req.rxData = data; + uart_rd_req.txData = NULL; + uart_rd_req.rxLen = bytes_remaining; + uart_rd_req.txLen = 0; + uart_rd_req.uart = self->uart_regs; + uart_rd_req.callback = (void *)uartCallback; + + // Initiate the read transaction + start_time = supervisor_ticks_ms64(); + err = MXC_UART_TransactionAsync(&uart_rd_req); + if (err != E_NO_ERROR) { + *errcode = err; + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting trasaction: %d\n"), err); } - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + // Wait for transaction completion or timeout + while ( (uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { + } + + // If the timeout gets hit, abort and error out + if (uart_status[self->uart_id] != UART_FREE) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + } + + // Check for errors from the callback + else if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); + } + + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); return len; } -//todo: test // Write characters. len is in characters NOT bytes! +// This function blocks until the timeout finishes size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { @@ -357,49 +378,62 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint32_t start_time=0; static size_t bytes_remaining; + // Setup globals & status tracking + uart_err = E_NO_ERROR; + uarts_active |= (1 << self->uart_id); + uart_status[self->uart_id] = UART_BUSY; bytes_remaining = len; - MXC_UART_ClearFlags(self->uart_regs, 0xFFFFFFFF); - NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - - while(bytes_remaining > 0) { - mxc_uart_req_t uart_wr_req; - uart_wr_req.rxCnt = 0; - uart_wr_req.txCnt = 0; - uart_wr_req.rxData = NULL; - uart_wr_req.txData = data; - uart_wr_req.txLen = bytes_remaining; - uart_wr_req.rxLen = 0; - uart_wr_req.uart = self->uart_regs; - uart_wr_req.callback = (void *)uartCallback; - - uart_status[self->uart_id] = UART_BUSY; - start_time = supervisor_ticks_ms64(); - err = MXC_UART_TransactionAsync(&uart_wr_req); - if (err != E_NO_ERROR) { - *errcode = err; - MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); - } + mxc_uart_req_t uart_wr_req = {}; + + // Setup transaction + uart_wr_req.rxCnt = 0; + uart_wr_req.txCnt = 0; + uart_wr_req.rxData = NULL; + uart_wr_req.txData = data; + uart_wr_req.txLen = bytes_remaining; + uart_wr_req.rxLen = 0; + uart_wr_req.uart = self->uart_regs; + uart_wr_req.callback = (void *)uartCallback; + + // Start the transaction + start_time = supervisor_ticks_ms64(); + err = MXC_UART_TransactionAsync(&uart_wr_req); + if (err != E_NO_ERROR) { + *errcode = err; + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); + } - // Wait for transaction completion - while ( (uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000)) - ) {}; + // Wait for transaction completion or timeout + while ( (uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { - // If the timeout gets hit, abort and error out - if (uart_status[self->uart_id] != UART_FREE) { - MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + // Call the handler and abort if errors + uart_err = MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); + if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(MXC_UART_GET_UART(0)); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(0)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); } + } - bytes_remaining -= uart_wr_req.txCnt; + // If the timeout gets hit, abort and error out + if (uart_status[self->uart_id] != UART_FREE) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); } - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - return len; + // Check for errors from the callback + else if (uart_err != E_NO_ERROR) { + MXC_UART_AbortAsync(self->uart_regs); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); + } + + return len; } uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) From d47b882b8584c5475ee7a695f1b2b3590d49bb00 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 27 Jan 2025 13:50:52 -0800 Subject: [PATCH 07/27] Add pre-commit changes to UART - Formatting & codespell fixes from pre-commit --- ports/analog/common-hal/busio/I2C.h | 2 +- ports/analog/common-hal/busio/SPI.h | 2 +- ports/analog/common-hal/busio/UART.c | 115 +++++++----------- ports/analog/common-hal/busio/UART.h | 2 +- ports/analog/common-hal/microcontroller/Pin.c | 2 +- ports/analog/max32_port.h | 32 ++--- .../analog/peripherals/max32690/max32_uart.c | 16 +-- 7 files changed, 74 insertions(+), 97 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h index c92283d6c53b6..9571a8ab694f4 100644 --- a/ports/analog/common-hal/busio/I2C.h +++ b/ports/analog/common-hal/busio/I2C.h @@ -17,7 +17,7 @@ // Define a struct for what BUSIO.I2C should carry typedef struct { mp_obj_base_t base; - mxc_i2c_regs_t* i2c_regs; + mxc_i2c_regs_t *i2c_regs; bool has_lock; const mcu_pin_obj_t *scl; const mcu_pin_obj_t *sda; diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h index 8c48147ff6c77..d90f55da111a0 100644 --- a/ports/analog/common-hal/busio/SPI.h +++ b/ports/analog/common-hal/busio/SPI.h @@ -17,7 +17,7 @@ // Define a struct for what BUSIO.SPI should carry typedef struct { mp_obj_base_t base; - mxc_spi_regs_t* spi_regs; + mxc_spi_regs_t *spi_regs; bool has_lock; const mcu_pin_obj_t *sck; const mcu_pin_obj_t *mosi; diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index ad5425d62ea31..b4b17126e60e9 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -89,7 +89,7 @@ typedef enum { UART_NEVER_RESET, } uart_status_t; -static uint32_t timeout_ms=0; +static uint32_t timeout_ms = 0; // Set each bit to indicate an active UART // will be checked by ISR Handler for which ones to call @@ -99,7 +99,7 @@ static volatile int uart_err; // static uint8_t uart_never_reset_mask = 0; static int isValidBaudrate(uint32_t baudrate) { - switch(baudrate) { + switch (baudrate) { case UART_9600: return 1; break; @@ -133,17 +133,16 @@ static int isValidBaudrate(uint32_t baudrate) { } } -static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) -{ - switch(busio_parity) { - case BUSIO_UART_PARITY_NONE: - return MXC_UART_PARITY_DISABLE; - case BUSIO_UART_PARITY_EVEN: - return MXC_UART_PARITY_EVEN_0; - case BUSIO_UART_PARITY_ODD: - return MXC_UART_PARITY_ODD_0; - default: - mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); +static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) { + switch (busio_parity) { + case BUSIO_UART_PARITY_NONE: + return MXC_UART_PARITY_DISABLE; + case BUSIO_UART_PARITY_EVEN: + return MXC_UART_PARITY_EVEN_0; + case BUSIO_UART_PARITY_ODD: + return MXC_UART_PARITY_ODD_0; + default: + mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); } } @@ -169,33 +168,31 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, - bool sigint_enabled) -{ + bool sigint_enabled) { int err, temp; // Check for NULL Pointers && valid UART settings - assert( self ); + assert(self); // Assign UART ID based on pins temp = pinsToUart(tx, rx); if (temp == -1) { // Error will be indicated by pinsToUart(tx, rx) function return; - } - else { + } else { self->uart_id = temp; self->uart_regs = MXC_UART_GET_UART(temp); } - assert( (self->uart_id >= 0) && (self->uart_id < NUM_UARTS) ); + assert((self->uart_id >= 0) && (self->uart_id < NUM_UARTS)); // Indicate RS485 not implemented - if ( (rs485_dir != NULL) || (rs485_invert) ) { + if ((rs485_dir != NULL) || (rs485_invert)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("RS485")); } if ((rx != NULL) && (tx != NULL)) { - err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); + err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); if (err != E_NO_ERROR) { mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to initialize UART.\n")); } @@ -205,14 +202,11 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->rx_pin = rx; common_hal_mcu_pin_claim(self->tx_pin); common_hal_mcu_pin_claim(self->rx_pin); - } - else if (tx != NULL) { + } else if (tx != NULL) { mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); - } - else if (rx != NULL) { + } else if (rx != NULL) { mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); - } - else { + } else { // Should not get here, as shared-bindings API should not call this way } @@ -222,13 +216,12 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->rts_pin = rts; common_hal_mcu_pin_claim(self->cts_pin); common_hal_mcu_pin_claim(self->rts_pin); - } - else if (cts || rts) { + } else if (cts || rts) { mp_raise_ValueError(MP_ERROR_TEXT("Flow Ctrl needs both CTS & RTS")); } // Set stop bits & data size - assert( (stop == 1) || (stop == 2) ); + assert((stop == 1) || (stop == 2)); mp_arg_validate_int(bits, 8, MP_QSTR_bits); MXC_UART_SetDataSize(self->uart_regs, bits); MXC_UART_SetStopBits(self->uart_regs, stop); @@ -270,8 +263,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, return; } -void common_hal_busio_uart_deinit(busio_uart_obj_t *self) -{ +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { assert(self); if (!common_hal_busio_uart_deinited(self)) { @@ -300,22 +292,19 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) } } -bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) -{ +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { if (uarts_active & (1 << self->uart_id)) { return false; - } - else { + } else { return true; }; } // Read characters. len is in characters NOT bytes! size_t common_hal_busio_uart_read(busio_uart_obj_t *self, - uint8_t *data, size_t len, int *errcode) -{ + uint8_t *data, size_t len, int *errcode) { int err; - uint32_t start_time=0; + uint32_t start_time = 0; static size_t bytes_remaining; // Setup globals & status tracking @@ -343,12 +332,12 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, *errcode = err; MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting trasaction: %d\n"), err); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting transaction: %d\n"), err); } // Wait for transaction completion or timeout - while ( (uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { + while ((uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { } // If the timeout gets hit, abort and error out @@ -357,7 +346,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); mp_raise_RuntimeError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); } - // Check for errors from the callback else if (uart_err != E_NO_ERROR) { MXC_UART_AbortAsync(self->uart_regs); @@ -371,11 +359,10 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, // Write characters. len is in characters NOT bytes! // This function blocks until the timeout finishes - size_t common_hal_busio_uart_write(busio_uart_obj_t *self, - const uint8_t *data, size_t len, int *errcode) -{ +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode) { int err; - uint32_t start_time=0; + uint32_t start_time = 0; static size_t bytes_remaining; // Setup globals & status tracking @@ -407,8 +394,8 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, } // Wait for transaction completion or timeout - while ( (uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { + while ((uart_status[self->uart_id] != UART_FREE) && + (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { // Call the handler and abort if errors uart_err = MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); @@ -425,7 +412,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); } - // Check for errors from the callback else if (uart_err != E_NO_ERROR) { MXC_UART_AbortAsync(self->uart_regs); @@ -436,29 +422,24 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, return len; } - uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) -{ +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { return self->baudrate; } // Validate baudrate -void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) -{ - if ( isValidBaudrate(baudrate) ) { +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + if (isValidBaudrate(baudrate)) { self->baudrate = baudrate; - } - else { + } else { mp_raise_ValueError(MP_ERROR_TEXT("Baudrate invalid. Must be a standard UART baudrate.\n")); } } -mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) -{ +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { return self->timeout; } -void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) -{ +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { if (timeout > 100.0) { mp_raise_ValueError(MP_ERROR_TEXT("Timeout must be < 100 seconds")); } @@ -469,23 +450,19 @@ void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeou return; } -uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) -{ +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { return MXC_UART_GetRXFIFOAvailable(self->uart_regs); } -void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) -{ +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { MXC_UART_ClearRXFIFO(self->uart_regs); } -bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) -{ +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { return !(MXC_UART_GetStatus(self->uart_regs) & (MXC_F_UART_STATUS_TX_BUSY)); } -void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) -{ +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { common_hal_never_reset_pin(self->tx_pin); common_hal_never_reset_pin(self->rx_pin); common_hal_never_reset_pin(self->cts_pin); diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index 3c76efc720e78..f24f310fe3a52 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -23,7 +23,7 @@ typedef struct { int uart_id; int uart_map; - mxc_uart_regs_t* uart_regs; + mxc_uart_regs_t *uart_regs; bool parity; uint8_t bits; diff --git a/ports/analog/common-hal/microcontroller/Pin.c b/ports/analog/common-hal/microcontroller/Pin.c index 6816054153e72..83e2f3b9c3a76 100644 --- a/ports/analog/common-hal/microcontroller/Pin.c +++ b/ports/analog/common-hal/microcontroller/Pin.c @@ -37,7 +37,7 @@ void reset_all_pins(void) { } void reset_pin_number(uint8_t pin_port, uint8_t pin_pad) { - if ( (pin_port == INVALID_PIN) || (pin_port > NUM_GPIO_PORTS) ) { + if ((pin_port == INVALID_PIN) || (pin_port > NUM_GPIO_PORTS)) { return; } diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index 5c3811b651554..3b4fe7bc87d90 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -30,27 +30,27 @@ #define GPIO4_PIN_MASK 0x00000003 #define GPIO4_RESET_MASK 0xFFFFFF77 #define GPIO4_OUTEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_OE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_OE_POS - 1))) #define GPIO4_PULLDIS_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_PE_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_PE_POS - 1))) #define GPIO4_DATAOUT_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) + (((mask & (1 << 0)) << MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((mask & (1 << 1)) << (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) #define GPIO4_DATAOUT_GET_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ - mask) + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_DO) >> MXC_F_MCR_GPIO4_CTRL_P40_DO_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_DO) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_DO_POS - 1))) & \ + mask) #define GPIO4_DATAIN_MASK(mask) \ - ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ - ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ - (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ - mask) + ((((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P40_IN) >> MXC_F_MCR_GPIO4_CTRL_P40_IN_POS) | \ + ((MXC_MCR->gpio4_ctrl & MXC_F_MCR_GPIO4_CTRL_P41_IN) >> \ + (MXC_F_MCR_GPIO4_CTRL_P41_IN_POS - 1))) & \ + mask) #define GPIO4_AFEN_MASK(mask) \ - (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ - ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) + (((mask & (1 << 0)) << MXC_F_MCR_OUTEN_PDOWN_OUT_EN_POS) | \ + ((mask & (1 << 1)) >> (MXC_F_MCR_OUTEN_SQWOUT_EN_POS + 1))) /** END: GPIO4 Handling specific to MAX32690 */ #endif diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index f8c53dc63218e..3ccb930d85c14 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -23,21 +23,21 @@ const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { { MXC_GPIO2, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), - MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), - MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, + MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } }; int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { for (int i = 0; i < NUM_UARTS; i++) { - if ( (uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) - && (uart_maps[i].mask == (( tx->mask) | (rx->mask))) ) { + if ((uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) + && (uart_maps[i].mask == ((tx->mask) | (rx->mask)))) { return i; } } From 68d8daa3399e14d130a689bd390d30ab68c935d8 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Fri, 31 Jan 2025 16:45:13 -0800 Subject: [PATCH 08/27] Resolve UART ISR naming issues - Call NVIC_SetRAM in supervisor/port.c to move NVIC table to RAM, enabling ISR RAM remapping. - Rename UART ISR to be generic for any UART IRQn. - Remove background led writes from background.c. --- ports/analog/background.c | 10 ++-------- ports/analog/common-hal/busio/UART.c | 11 +++++++++-- ports/analog/supervisor/port.c | 8 ++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/ports/analog/background.c b/ports/analog/background.c index ffad007ffa51c..ad840c6dcdabc 100644 --- a/ports/analog/background.c +++ b/ports/analog/background.c @@ -19,19 +19,13 @@ extern const mxc_gpio_cfg_t led_pin[]; extern const int num_leds; /** NOTE: ALL "ticks" refer to a 1/1024 s period */ -static int status_led_ticks = 0; +static int status_ticks = 0; // This function is where port-specific background // tasks should be performed // Execute port specific actions during background tick. Only if ticks are enabled. void port_background_tick(void) { - status_led_ticks++; - - // Set an LED approx. 1/s - if (status_led_ticks > 1024) { - MXC_GPIO_OutToggle(led_pin[2].port, led_pin[2].mask); - status_led_ticks = 0; - } + status_ticks++; } // Execute port specific actions during background tasks. This is before the diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index b4b17126e60e9..310965e34609b 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -146,7 +146,7 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) { } } -void UART0_IRQHandler(void) { +void uart_isr(void) { for (int i = 0; i < NUM_UARTS; i++) { if (uarts_active & (1 << i)) { MXC_UART_AsyncHandler(MXC_UART_GET_UART(i)); @@ -237,6 +237,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->error = E_NO_ERROR; // Initialize ringbuffer for receiving data + // FIXME: Either the use the ringbuf or get rid of it! if (self->rx_pin) { // if given a ringbuff, use that if (receiver_buffer) { @@ -253,12 +254,18 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Indicate to this module that the UART is active uarts_active |= (1 << self->uart_id); + // Set the timeout to a default value + if (((timeout < 0.0) || (timeout > 100.0))) { + self->timeout = 1.0; + } else { + self->timeout = timeout; + } /* Setup UART interrupt */ NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); - NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)&UART0_IRQHandler); + NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)uart_isr); return; } diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index ad003c12ed9e0..a919a747d50f5 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -39,6 +39,7 @@ // Sys includes #include "max32_port.h" +#include "nvic_table.h" // Timers #include "mxc_delay.h" @@ -75,6 +76,13 @@ void SysTick_Handler(void) { safe_mode_t port_init(void) { int err = E_NO_ERROR; + // Set Vector Table to RAM & configure ARM core to use RAM-based ISRs + // This allows definition of ISRs with custom names + // + // Useful for mapping ISRs with names not related to a specific IRQn. + // Source: https://arm-software.github.io/CMSIS_5/Core/html/using_VTOR_pg.html + NVIC_SetRAM(); + // 1ms tick timer SysTick_Config(SystemCoreClock / 1000); NVIC_EnableIRQ(SysTick_IRQn); From edf069d0e775c267136cdb29bf40240d30561de2 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Thu, 6 Mar 2025 23:57:59 -0800 Subject: [PATCH 09/27] Add BUSIO.I2C and MAX32690 I2C structure - Data structure and constructor for I2C (tested) - Lock and probing functions complete and tested TODO: Implement I2C Write, Read, Wr/Rd Signed-off-by: Brandon-Hurst --- ports/analog/Makefile | 16 ++- ports/analog/common-hal/busio/I2C.c | 131 ++++++++++++++++-- ports/analog/common-hal/busio/I2C.h | 7 +- ports/analog/max32_port.h | 2 +- ports/analog/peripherals/max32690/max32_i2c.c | 35 +++++ ports/analog/peripherals/max32690/max32_i2c.h | 16 +++ 6 files changed, 193 insertions(+), 14 deletions(-) create mode 100644 ports/analog/peripherals/max32690/max32_i2c.c create mode 100644 ports/analog/peripherals/max32690/max32_i2c.h diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 7e11f1cc7e2ec..39ead2adf7e3f 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -86,7 +86,8 @@ INC += \ -I$(PERIPH_SRC)/ICC \ -I$(PERIPH_SRC)/TMR \ -I$(PERIPH_SRC)/RTC \ - -I$(PERIPH_SRC)/UART + -I$(PERIPH_SRC)/UART \ + -I$(PERIPH_SRC)/I2C INC += -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Source/GCC @@ -119,14 +120,18 @@ SRC_MAX32 += \ $(PERIPH_SRC)/TMR/tmr_$(DIE_TYPE).c \ $(PERIPH_SRC)/UART/uart_common.c \ $(PERIPH_SRC)/UART/uart_$(DIE_TYPE).c \ - $(PERIPH_SRC)/UART/uart_revb.c + $(PERIPH_SRC)/UART/uart_revb.c \ + $(PERIPH_SRC)/I2C/i2c_$(DIE_TYPE).c \ + $(PERIPH_SRC)/I2C/i2c_reva.c SRC_C += $(SRC_MAX32) \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/gpios.c \ - peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c + peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_i2c.c + # ******************************************************************************* ### Compiler & Linker Flags ### @@ -267,6 +272,11 @@ flash-msdk: -f interface/cmsis-dap.cfg -f target/$(MCU_VARIANT_LOWER).cfg \ -c "program $(BUILD)/firmware.elf verify; init; reset; exit" +flash-openocd-jlink: + $(OPENOCD) -s $(OPENOCD_SCRIPTS) \ + -f interface/jlink.cfg -f target/$(MCU_VARIANT_LOWER).cfg \ + -c "program $(BUILD)/firmware.elf verify; init; reset; exit" + # flash target using JLink JLINK_DEVICE = $(MCU_VARIANT_LOWER) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index a8080fa5bc10d..306b4bc8f4ab1 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -30,7 +30,38 @@ #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -static bool in_used = false; +#include "max32_port.h" + +#define I2C_PRIORITY 1 + +typedef enum { + I2C_FREE = 0, + I2C_BUSY, + I2C_NEVER_RESET, +} i2c_status_t; + +// Set each bit to indicate an active UART +// will be checked by ISR Handler for which ones to call +static uint8_t i2c_active = 0; +static i2c_status_t i2c_status[NUM_I2C]; +static volatile int i2c_err; + +// I2C Interrupt Handler +void i2c_isr(void) { + for (int i = 0; i < NUM_I2C; i++) { + if (i2c_active & (1 << i)) { + // NOTE: I2C_GET_TMR actually returns the I2C registers + MXC_I2C_AsyncHandler(MXC_I2C_GET_I2C(i)); + } + } +} + +// Callback gets called when AsyncRequest is COMPLETE +// (e.g. txLen == txCnt) +// static volatile void i2cCallback(mxc_i2c_req_t *req, int error) { +// i2c_status[MXC_I2C_GET_IDX(req->i2c)] = I2C_FREE; +// i2c_err = error; +// } // Construct I2C protocol, this function init i2c peripheral void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, @@ -38,7 +69,64 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - + int temp, err = 0; + + // Check for NULL Pointers && valid I2C settings + assert(self); + + // Assign I2C ID based on pins + temp = pinsToI2c(sda, scl); + if (temp == -1) { + // Error will be indicated by pinsToUart(tx, rx) function + return; + } else { + self->i2c_id = temp; + self->i2c_regs = MXC_I2C_GET_I2C(temp); + } + + assert((self->i2c_id >= 0) && (self->i2c_id < NUM_I2C)); + + // Init I2C as main / controller node (0x00 is ignored) + if ((scl != NULL) && (sda != NULL)) { + err = MXC_I2C_Init(self->i2c_regs, 1, 0x00); + if (err) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init I2C.\n")); + } + err = MXC_I2C_SetFrequency(self->i2c_regs, frequency); + if (err < 0) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to set I2C frequency\n")); + } + } else if (scl != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); + } else if (sda != NULL) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); + } else { + // Should not get here, as shared-bindings API should not call this way + } + + // Attach I2C pins + self->sda = sda; + self->scl = scl; + common_hal_mcu_pin_claim(self->sda); + common_hal_mcu_pin_claim(self->scl); + + // Indicate to this module that the I2C is active + i2c_active |= (1 << self->i2c_id); + + // Set the timeout to a default value + if (((timeout < 0.0) || (timeout > 100.0))) { + self->timeout = 1.0; + } else { + self->timeout = timeout; + } + + /* Setup I2C interrupt */ + NVIC_ClearPendingIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); + NVIC_DisableIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); + NVIC_SetPriority(MXC_I2C_GET_IRQ(self->i2c_id), I2C_PRIORITY); + NVIC_SetVector(MXC_I2C_GET_IRQ(self->i2c_id), (uint32_t)i2c_isr); + + return; } // Never reset I2C obj when reload @@ -54,7 +142,13 @@ bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { // Deinit i2c obj, reset I2C pin void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { - // FIXME: Implement + MXC_I2C_Shutdown(self->i2c_regs); + + common_hal_reset_pin(self->sda); + common_hal_reset_pin(self->scl); + + self->sda = NULL; + self->scl = NULL; } void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { @@ -63,17 +157,36 @@ void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - // FIXME: Implement - - return true; + int nack = 0; + + mxc_i2c_req_t addr_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_len = 0, + .tx_buf = NULL, + .rx_len = 0, + .rx_buf = NULL, + .callback = NULL + }; + + // Probe the address + nack = MXC_I2C_MasterTransaction(&addr_req); + if (nack) { + return false; + } else { + return true; + } } // Lock I2C bus bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { - // FIXME: Implement - - return false; + if (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { + return false; + } else { + self->has_lock = true; + return true; + } } // Check I2C lock status diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h index 9571a8ab694f4..2c7ffec20785e 100644 --- a/ports/analog/common-hal/busio/I2C.h +++ b/ports/analog/common-hal/busio/I2C.h @@ -17,8 +17,13 @@ // Define a struct for what BUSIO.I2C should carry typedef struct { mp_obj_base_t base; + + int i2c_id; mxc_i2c_regs_t *i2c_regs; - bool has_lock; const mcu_pin_obj_t *scl; const mcu_pin_obj_t *sda; + const int frequency; + + uint32_t timeout; + bool has_lock; } busio_i2c_obj_t; diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index 3b4fe7bc87d90..fcab5b5976238 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -24,7 +24,7 @@ // UART Ports & pins #include "peripherals/max32690/max32_uart.h" -#define NUM_UARTS 4 +#include "peripherals/max32690/max32_i2c.h" /** START: GPIO4 Handling specific to MAX32690 */ #define GPIO4_PIN_MASK 0x00000003 diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c new file mode 100644 index 0000000000000..8a13cf7a9a5a3 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/I2C.h" +#include "max32_i2c.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { + // I2C0A + { MXC_GPIO0, (MXC_GPIO_PIN_30 | MXC_GPIO_PIN_31), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // I2C1A + { MXC_GPIO2, (MXC_GPIO_PIN_17 | MXC_GPIO_PIN_18), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, +}; + +int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { + for (int i = 0; i < NUM_I2C; i++) { + if ((i2c_maps[i].port == (MXC_GPIO_GET_GPIO(sda->port))) + && (i2c_maps[i].mask == ((sda->mask) | (scl->mask)))) { + return i; + } + } + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an I2C matching pins...\nSCL: port %d mask %d\nSDA: port %d mask %d\n"), + sda->port, sda->mask, scl->port, scl->mask); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_i2c.h b/ports/analog/peripherals/max32690/max32_i2c.h new file mode 100644 index 0000000000000..3e554da5abcde --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_i2c.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "i2c_regs.h" +#include "mxc_sys.h" +#include "i2c.h" +#include "peripherals/pins.h" + +#define NUM_I2C 2 + +int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl); From 696794993965d20dc6e4d512eba4fdc1b2da0643 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 00:37:46 -0800 Subject: [PATCH 10/27] Add hardware mapping for BUSIO.SPI for MAX32690 Currently coupled a bit to APARD32690-SL board. Will refactor after testing BUSIO.SPI Signed-off-by: Brandon-Hurst --- ports/analog/Makefile | 11 +++-- ports/analog/peripherals/max32690/max32_spi.c | 49 +++++++++++++++++++ ports/analog/peripherals/max32690/max32_spi.h | 17 +++++++ 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 ports/analog/peripherals/max32690/max32_spi.c create mode 100644 ports/analog/peripherals/max32690/max32_spi.h diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 39ead2adf7e3f..e2e2a24b33e51 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -87,7 +87,8 @@ INC += \ -I$(PERIPH_SRC)/TMR \ -I$(PERIPH_SRC)/RTC \ -I$(PERIPH_SRC)/UART \ - -I$(PERIPH_SRC)/I2C + -I$(PERIPH_SRC)/I2C \ + -I$(PERIPH_SRC)/SPI INC += -I$(CMSIS_ROOT)/Device/Maxim/$(MCU_VARIANT_UPPER)/Source/GCC @@ -122,7 +123,9 @@ SRC_MAX32 += \ $(PERIPH_SRC)/UART/uart_$(DIE_TYPE).c \ $(PERIPH_SRC)/UART/uart_revb.c \ $(PERIPH_SRC)/I2C/i2c_$(DIE_TYPE).c \ - $(PERIPH_SRC)/I2C/i2c_reva.c + $(PERIPH_SRC)/I2C/i2c_reva.c \ + $(PERIPH_SRC)/SPI/spi_$(DIE_TYPE).c \ + $(PERIPH_SRC)/SPI/spi_reva1.c SRC_C += $(SRC_MAX32) \ boards/$(BOARD)/board.c \ @@ -130,8 +133,8 @@ SRC_C += $(SRC_MAX32) \ peripherals/$(MCU_VARIANT_LOWER)/pins.c \ peripherals/$(MCU_VARIANT_LOWER)/gpios.c \ peripherals/$(MCU_VARIANT_LOWER)/max32_uart.c \ - peripherals/$(MCU_VARIANT_LOWER)/max32_i2c.c - + peripherals/$(MCU_VARIANT_LOWER)/max32_i2c.c \ + peripherals/$(MCU_VARIANT_LOWER)/max32_spi.c # ******************************************************************************* ### Compiler & Linker Flags ### diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c new file mode 100644 index 0000000000000..587349b7e2140 --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -0,0 +1,49 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +#include "common-hal/busio/SPI.h" +#include "max32_spi.h" +#include "max32690.h" + +#include "py/runtime.h" +#include "py/mperrno.h" + +// TODO Decouple from APARD board +const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { + // DUMMY entry for SPI0 (not on APARD board) + { MXC_GPIO0, 0xFFFFFFFF, 0, 0, 0, 0}, + + // SPI1A + { MXC_GPIO1, (MXC_GPIO_PIN_23 | MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI2A + { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4 | MXC_GPIO_PIN_5), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI3A + { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_19 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + // SPI4A + { MXC_GPIO1, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), + MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, +}; + +int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, + const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs) { + for (int i = 0; i < NUM_SPI; i++) { + if ((spi_maps[i].port == (MXC_GPIO_GET_GPIO(mosi->port))) + && (spi_maps[i].mask == ((cs->mask) | (mosi->mask) | (miso->mask) | (sck->mask)))) { + return i; + } + } + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an SPI matching pins... \ + \nMOSI: port %d mask %d\nMISO: port %d mask %d\n \ + \nSCK: port %d mask %d\nCS: port %d mask%d\n"), + mosi->port, mosi->mask, miso->port, miso->mask, + sck->port, sck->mask, cs->port, cs->mask); + return -1; +} diff --git a/ports/analog/peripherals/max32690/max32_spi.h b/ports/analog/peripherals/max32690/max32_spi.h new file mode 100644 index 0000000000000..d0b9c83201c2b --- /dev/null +++ b/ports/analog/peripherals/max32690/max32_spi.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Brandon Hurst, Analog Devices, Inc. +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "spi_regs.h" +#include "mxc_sys.h" +#include "spi.h" +#include "peripherals/pins.h" + +#define NUM_SPI 5 + +int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, + const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs); From a81ea5e7509ec4f20c3a18d2eaafad34eb972308 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 02:16:40 -0800 Subject: [PATCH 11/27] Add complete BUSIO driver structure for SPI & I2C. TODO: - Figure out assigning CS Pins for SPI - Test & Debug SPI / I2C Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/I2C.c | 50 +++- ports/analog/common-hal/busio/SPI.c | 214 +++++++++++++++++- ports/analog/common-hal/busio/SPI.h | 9 +- ports/analog/max32_port.h | 1 + ports/analog/peripherals/max32690/max32_spi.c | 17 +- ports/analog/peripherals/max32690/max32_spi.h | 2 +- 6 files changed, 267 insertions(+), 26 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 306b4bc8f4ab1..1834db0e4a3d4 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -200,28 +200,72 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address +// todo test uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { - // FIXME: Implement + int ret; + mxc_i2c_req_t wr_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = (uint8_t *)data, + .tx_len = len, + .rx_buf = NULL, + .rx_len = 0, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&wr_req); + if (ret) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + } + return 0; } // Read into buffer from the device selected by address +// todo test uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - // FIXME: Implement + int ret; + mxc_i2c_req_t rd_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = NULL, + .tx_len = 0, + .rx_buf = data, + .rx_len = len, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&rd_req); + if (ret) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + } + return 0; } // Write the bytes from out_data to the device selected by address, +// todo test uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - // FIXME: Implement + int ret; + mxc_i2c_req_t wr_rd_req = { + .addr = addr, + .i2c = self->i2c_regs, + .tx_buf = out_data, + .tx_len = out_len, + .rx_buf = in_data, + .rx_len = in_len, + .callback = NULL + }; + ret = MXC_I2C_MasterTransaction(&wr_rd_req); + if (ret) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + } return 0; } diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 083403b12bbe3..0c882d3ecc991 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -31,9 +31,35 @@ #include "supervisor/board.h" #include "shared-bindings/microcontroller/Pin.h" +#include "max32_port.h" +#include "spi_reva1.h" + // Note that any bugs introduced in this file can cause crashes // at startupfor chips using external SPI flash. +#define SPI_PRIORITY 1 + +typedef enum { + SPI_FREE = 0, + SPI_BUSY, + SPI_NEVER_RESET, +} spi_status_t; + +// Set each bit to indicate an active SPI +// will be checked by ISR Handler for which ones to call +static uint8_t spi_active = 0; +static spi_status_t spi_status[NUM_SPI]; +static volatile int spi_err; + +// SPI Interrupt Handler +void spi_isr(void) { + for (int i = 0; i < NUM_SPI; i++) { + if (spi_active & (1 << i)) { + MXC_SPI_AsyncHandler(MXC_SPI_GET_SPI(i)); + } + } +} + // Reset SPI when reload void spi_reset(void) { // FIXME: Implement @@ -41,19 +67,69 @@ void spi_reset(void) { } // Construct SPI protocol, this function init SPI peripheral +// todo: figure out Chip select behavior void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + int temp, err = 0; + // Check for NULL Pointers && valid I2C settings + assert(self); - // FIXME: Implement + // Assign I2C ID based on pins + temp = pinsToSpi(mosi, miso, sck); + if (temp == -1) { + // Error will be indicated by pinsToUart(tx, rx) function + return; + } else { + self->spi_id = temp; + self->spi_regs = MXC_SPI_GET_SPI(temp); + } + + assert((self->spi_id >= 0) && (self->spi_id < NUM_SPI)); + + // Init I2C as main / controller node (0x00 is ignored) + // FIXME: MUST map the SPI pins to a spi_pins_t struct + if ((mosi != NULL) && (miso != NULL) && (sck != NULL)) { + // spi, mastermode, quadModeUsed, numSubs, ssPolarity, frequency + err = MXC_SPI_RevA1_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000); + if (err) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init SPI.\n")); + } + } else { + mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); + } + + // Attach SPI pins + self->mosi = mosi; + self->miso = miso; + self->sck = sck; + common_hal_mcu_pin_claim(self->mosi); + common_hal_mcu_pin_claim(self->miso); + common_hal_mcu_pin_claim(self->sck); + + // Indicate to this module that the SPI is active + spi_active |= (1 << self->spi_id); + + /* Setup I2C interrupt */ + NVIC_ClearPendingIRQ(MXC_SPI_GET_IRQ(self->spi_id)); + NVIC_DisableIRQ(MXC_SPI_GET_IRQ(self->spi_id)); + NVIC_SetPriority(MXC_SPI_GET_IRQ(self->spi_id), SPI_PRIORITY); + NVIC_SetVector(MXC_SPI_GET_IRQ(self->spi_id), (uint32_t)spi_isr); + + return; } // Never reset SPI when reload void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - // FIXME: Implement + common_hal_never_reset_pin(self->mosi); + common_hal_never_reset_pin(self->miso); + common_hal_never_reset_pin(self->sck); + common_hal_never_reset_pin(self->nss); + + spi_status[self->spi_id] = SPI_NEVER_RESET; } // Check SPI status, deinited or not @@ -64,7 +140,16 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { - // FIXME: Implement + MXC_SPI_Shutdown(self->spi_regs); + common_hal_reset_pin(self->mosi); + common_hal_reset_pin(self->miso); + common_hal_reset_pin(self->sck); + common_hal_reset_pin(self->nss); + + self->mosi = NULL; + self->miso = NULL; + self->sck = NULL; + self->nss = NULL; } // Configures the SPI bus. The SPI object must be locked. @@ -74,14 +159,58 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint8_t phase, uint8_t bits) { - // FIXME: Implement + mxc_spi_clkmode_t clk_mode; + int ret; + + self->baudrate = baudrate; + self->polarity = polarity; + self->phase = phase; + self->bits = bits; + + switch ((polarity << 1) | (phase)) { + case 0b00: + clk_mode = MXC_SPI_CLKMODE_0; + break; + case 0b01: + clk_mode = MXC_SPI_CLKMODE_1; + break; + case 0b10: + clk_mode = MXC_SPI_CLKMODE_2; + break; + case 0b11: + clk_mode = MXC_SPI_CLKMODE_3; + break; + default: + mp_raise_ValueError(MP_ERROR_TEXT("CPOL / CPHA must both be either 0 or 1\n")); + return false; + } + + ret = MXC_SPI_SetFrequency(self->spi_regs, baudrate); + if (ret) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frequency\n")); + return false; + } + ret = MXC_SPI_SetDataSize(self->spi_regs, bits); + if (ret) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frame Size\n")); + return false; + } + ret = MXC_SPI_SetMode(self->spi_regs, clk_mode); + if (ret) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Clock Mode\n")); + return false; + } return true; } // Lock SPI bus bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { - // FIXME: Implement - return false; + if (spi_status[self->spi_id] != SPI_BUSY) { + self->has_lock = true; + return true; + } else { + return false; + } } // Check SPI lock status @@ -98,9 +227,27 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { + int ret = 0; - // FIXME: Implement - return false; + mxc_spi_req_t wr_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = (uint8_t *)data, + .txLen = len, + .rxData = NULL, + .rxLen = 0, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = 0xFF, + }; + ret = MXC_SPI_MasterTransaction(&wr_req); + if (ret) { + return false; + } else { + return true; + } } // Read data into buffer @@ -108,8 +255,32 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { - // FIXME: Implement - return false; + int ret = 0; + // uint8_t tx_buffer[len] = {0x0}; + + // for (int i = 0; i < len; i++) { + // tx_buffer[i] = write_value; + // } + + mxc_spi_req_t rd_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = NULL, + .txLen = len, + .rxData = data, + .rxLen = len, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = write_value, + }; + ret = MXC_SPI_MasterTransaction(&rd_req); + if (ret) { + return false; + } else { + return true; + } } // Write out the data in data_out @@ -119,8 +290,27 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_in, size_t len) { - // FIXME: Implement - return false; + int ret = 0; + + mxc_spi_req_t rd_req = { + .spi = self->spi_regs, + .ssIdx = 0, + .txCnt = 0, + .rxCnt = 0, + .txData = (uint8_t *)data_out, + .txLen = len, + .rxData = data_in, + .rxLen = len, + .ssDeassert = 1, + .completeCB = NULL, + .txDummyValue = 0xFF, + }; + ret = MXC_SPI_MasterTransaction(&rd_req); + if (ret) { + return false; + } else { + return true; + } } // Get SPI baudrate diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h index d90f55da111a0..e70d4234d9407 100644 --- a/ports/analog/common-hal/busio/SPI.h +++ b/ports/analog/common-hal/busio/SPI.h @@ -17,17 +17,24 @@ // Define a struct for what BUSIO.SPI should carry typedef struct { mp_obj_base_t base; + + // Spi regs & pins + int spi_id; mxc_spi_regs_t *spi_regs; - bool has_lock; const mcu_pin_obj_t *sck; const mcu_pin_obj_t *mosi; const mcu_pin_obj_t *miso; const mcu_pin_obj_t *nss; + + // Configuration uint32_t baudrate; uint16_t prescaler; uint8_t polarity; uint8_t phase; uint8_t bits; + + // Synch data + bool has_lock; } busio_spi_obj_t; void spi_reset(void); diff --git a/ports/analog/max32_port.h b/ports/analog/max32_port.h index fcab5b5976238..89830e96b0a49 100644 --- a/ports/analog/max32_port.h +++ b/ports/analog/max32_port.h @@ -25,6 +25,7 @@ // UART Ports & pins #include "peripherals/max32690/max32_uart.h" #include "peripherals/max32690/max32_i2c.h" +#include "peripherals/max32690/max32_spi.h" /** START: GPIO4 Handling specific to MAX32690 */ #define GPIO4_PIN_MASK 0x00000003 diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index 587349b7e2140..5a1dc8a9dc2f1 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -19,31 +19,30 @@ const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { { MXC_GPIO0, 0xFFFFFFFF, 0, 0, 0, 0}, // SPI1A - { MXC_GPIO1, (MXC_GPIO_PIN_23 | MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + { MXC_GPIO1, (MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI2A - { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4 | MXC_GPIO_PIN_5), + { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI3A - { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_19 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), + { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI4A - { MXC_GPIO1, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), + { MXC_GPIO1, (MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, }; int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, - const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs) { + const mcu_pin_obj_t *sck) { for (int i = 0; i < NUM_SPI; i++) { if ((spi_maps[i].port == (MXC_GPIO_GET_GPIO(mosi->port))) - && (spi_maps[i].mask == ((cs->mask) | (mosi->mask) | (miso->mask) | (sck->mask)))) { + && (spi_maps[i].mask == ((mosi->mask) | (miso->mask) | (sck->mask)))) { return i; } } mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an SPI matching pins... \ - \nMOSI: port %d mask %d\nMISO: port %d mask %d\n \ - \nSCK: port %d mask %d\nCS: port %d mask%d\n"), + \nMOSI: port %d mask %d\nMISO: port %d mask %d\n"), mosi->port, mosi->mask, miso->port, miso->mask, - sck->port, sck->mask, cs->port, cs->mask); + sck->port, sck->mask); return -1; } diff --git a/ports/analog/peripherals/max32690/max32_spi.h b/ports/analog/peripherals/max32690/max32_spi.h index d0b9c83201c2b..76bb48a59a7e5 100644 --- a/ports/analog/peripherals/max32690/max32_spi.h +++ b/ports/analog/peripherals/max32690/max32_spi.h @@ -14,4 +14,4 @@ #define NUM_SPI 5 int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, - const mcu_pin_obj_t *sck, const mcu_pin_obj_t *cs); + const mcu_pin_obj_t *sck); From ddd4cf63a1f3bd8ef5a5efe71380debe65723138 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 13:28:36 -0800 Subject: [PATCH 12/27] Add call to MXC_DelayHandler in SysTick ISR Signed-off-by: Brandon-Hurst --- ports/analog/supervisor/port.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index a919a747d50f5..8f14c8d90d626 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -70,6 +70,8 @@ volatile uint32_t system_ticks = 0; void SysTick_Handler(void) { system_ticks++; + + MXC_DelayHandler(); } From 32c6b3e2677d8aaed40da45fb3411bae77c4a47f Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Fri, 7 Mar 2025 14:35:50 -0800 Subject: [PATCH 13/27] Corrected I2C & SPI. Tested with example scripts; works with real peripherals. Signed-off-by: Brandon-Hurst --- ports/analog/Makefile | 2 +- ports/analog/common-hal/busio/I2C.c | 8 ++++++-- ports/analog/common-hal/busio/SPI.c | 20 ++++++++++++++++++- ports/analog/peripherals/max32690/max32_i2c.c | 4 ++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/ports/analog/Makefile b/ports/analog/Makefile index e2e2a24b33e51..13bf189286786 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -284,7 +284,7 @@ flash-openocd-jlink: JLINK_DEVICE = $(MCU_VARIANT_LOWER) JLINKEXE ?= JLink.exe -JLINKEXE += -if SWD -device ${JLINK_DEVICE} -speed 10000 +JLINKEXE += -if SWD -device ${JLINK_DEVICE} -speed 4000 COMMAND_FILE := tools/flash_max32.jlink flash-jlink: $(BUILD)/firmware.bin diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 1834db0e4a3d4..cba8fca94f50e 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -46,6 +46,9 @@ static uint8_t i2c_active = 0; static i2c_status_t i2c_status[NUM_I2C]; static volatile int i2c_err; +// I2C struct for configuring GPIO pins +extern const mxc_gpio_cfg_t i2c_maps[NUM_I2C]; + // I2C Interrupt Handler void i2c_isr(void) { for (int i = 0; i < NUM_I2C; i++) { @@ -88,13 +91,14 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // Init I2C as main / controller node (0x00 is ignored) if ((scl != NULL) && (sda != NULL)) { + MXC_GPIO_Config(&i2c_maps[self->i2c_id]); err = MXC_I2C_Init(self->i2c_regs, 1, 0x00); if (err) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init I2C.\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to init I2C. ERR: %d\n"), err); } err = MXC_I2C_SetFrequency(self->i2c_regs, frequency); if (err < 0) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to set I2C frequency\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to set I2C frequency. ERR: %d\n"), err); } } else if (scl != NULL) { mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 0c882d3ecc991..7f19ebd1f945c 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -88,13 +88,28 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, self->spi_regs = MXC_SPI_GET_SPI(temp); } + // Other pins default to true + mxc_spi_pins_t spi_pins = { + .clock = TRUE, + .mosi = TRUE, + .miso = TRUE, + .ss0 = FALSE, + .ss1 = FALSE, + .ss2 = FALSE, + .vddioh = true, + .drvstr = MXC_GPIO_DRVSTR_0 + }; + assert((self->spi_id >= 0) && (self->spi_id < NUM_SPI)); // Init I2C as main / controller node (0x00 is ignored) // FIXME: MUST map the SPI pins to a spi_pins_t struct if ((mosi != NULL) && (miso != NULL) && (sck != NULL)) { // spi, mastermode, quadModeUsed, numSubs, ssPolarity, frequency - err = MXC_SPI_RevA1_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000); + // err = MXC_SPI_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000, &spi_pins); + err = MXC_SPI_Init(self->spi_regs, MXC_SPI_TYPE_CONTROLLER, MXC_SPI_INTERFACE_STANDARD, + 1, 0x01, 1000000, spi_pins); + MXC_GPIO_SetVSSEL(MXC_GPIO_GET_GPIO(sck->port), MXC_GPIO_VSSEL_VDDIOH, (sck->mask | miso->mask | mosi->mask | MXC_GPIO_PIN_0)); if (err) { mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init SPI.\n")); } @@ -102,6 +117,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); } + // FIXME: Debugging + + // Attach SPI pins self->mosi = mosi; self->miso = miso; diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index 8a13cf7a9a5a3..2dabc9b16a768 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -16,10 +16,10 @@ const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { // I2C0A { MXC_GPIO0, (MXC_GPIO_PIN_30 | MXC_GPIO_PIN_31), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, // I2C1A { MXC_GPIO2, (MXC_GPIO_PIN_17 | MXC_GPIO_PIN_18), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, }; int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { From 88099be19b1417090e84c808ec2810d2252474ce Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 17 Mar 2025 17:14:08 -0700 Subject: [PATCH 14/27] Add extra I2C options for MAX32690 non-TQFN packages Also reformatted pinmaps for SPI/I2C/UART on MAX32690 Signed-off-by: Brandon Hurst --- ports/analog/peripherals/max32690/max32_i2c.c | 41 +++++++++++++++++++ ports/analog/peripherals/max32690/max32_spi.c | 15 ++++--- .../analog/peripherals/max32690/max32_uart.c | 20 +++------ 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index 2dabc9b16a768..d5c8da0743129 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -13,14 +13,44 @@ #include "py/runtime.h" #include "py/mperrno.h" + +/* Note: The MAX32690 assigns the same alternate function to multiple sets + * of pins. The drivers will enable both sets so that either can be used. + * Users should ensure the unused set is left unconnected. + * + * See MAX32690 Rev A2 Errata #16: + * https://www.analog.com/media/en/technical-documentation/data-sheets/max32690_a2_errata_rev2.pdf + * + * Additionally, note that the TQFN package does not expose some of the duplicate pins. For this package, + * enabling the un-routed GPIOs has been shown to cause initialization issues with the I2C block. + * To work around this, "MAX32690GTK_PACKAGE_TQFN" can be defined by the build system. The recommend place + * to do it is in the "board.mk" file of the BSP. This will prevent the inaccessible pins from being configured. + */ + const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { + // I2C0 + { MXC_GPIO2, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + // I2C1 + { MXC_GPIO0, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + // I2C2 + { MXC_GPIO1, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT3, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 };, +}; +#ifndef MAX32690GTK_PACKAGE_TQFN +const mxc_gpio_cfg_t i2c_maps_extra[NUM_I2C] = { // I2C0A { MXC_GPIO0, (MXC_GPIO_PIN_30 | MXC_GPIO_PIN_31), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, // I2C1A { MXC_GPIO2, (MXC_GPIO_PIN_17 | MXC_GPIO_PIN_18), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, + // I2C2C + { MXC_GPIO0, (MXC_GPIO_PIN_13 | MXC_GPIO_PIN_14), MXC_GPIO_FUNC_ALT3, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 };, }; +#endif int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { for (int i = 0; i < NUM_I2C; i++) { @@ -29,6 +59,17 @@ int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { return i; } } + + // Additional for loop to cover alternate potential I2C maps + #ifndef MAX32690GTK_PACKAGE_TQFN + for (int i = 0; i < NUM_I2C; i++) { + if ((i2c_maps_extra[i].port == (MXC_GPIO_GET_GPIO(sda->port))) + && (i2c_maps_extra[i].mask == ((sda->mask) | (scl->mask)))) { + return i; + } + } + #endif + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an I2C matching pins...\nSCL: port %d mask %d\nSDA: port %d mask %d\n"), sda->port, sda->mask, scl->port, scl->mask); return -1; diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index 5a1dc8a9dc2f1..ecd197036a49d 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -13,21 +13,20 @@ #include "py/runtime.h" #include "py/mperrno.h" -// TODO Decouple from APARD board const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { - // DUMMY entry for SPI0 (not on APARD board) - { MXC_GPIO0, 0xFFFFFFFF, 0, 0, 0, 0}, - - // SPI1A + // SPI0 + { MXC_GPIO2, (MXC_GPIO_PIN_27 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + // SPI1 { MXC_GPIO1, (MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - // SPI2A + // SPI2 { MXC_GPIO2, (MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3 | MXC_GPIO_PIN_4), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - // SPI3A + // SPI3 { MXC_GPIO0, (MXC_GPIO_PIN_16 | MXC_GPIO_PIN_20 | MXC_GPIO_PIN_21), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - // SPI4A + // SPI4 { MXC_GPIO1, (MXC_GPIO_PIN_1 | MXC_GPIO_PIN_2 | MXC_GPIO_PIN_3), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, }; diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index 3ccb930d85c14..3cfcc75ca0dc0 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -13,29 +13,19 @@ #include "py/runtime.h" #include "py/mperrno.h" -// FIXME: Remove upon test! -// mxc_uart_regs_t max32_uarts[NUM_UARTS] = { -// MXC_UART0, -// MXC_UART1, -// MXC_UART2, -// MXC_UART3, -// }; - const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { { MXC_GPIO2, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), - MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), - MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, - MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } + { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), MXC_GPIO_FUNC_ALT1, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, + { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), MXC_GPIO_FUNC_ALT2, + MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } }; int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { - for (int i = 0; i < NUM_UARTS; i++) { + for (int i = 0; i < uart_entries; i++) { if ((uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) && (uart_maps[i].mask == ((tx->mask) | (rx->mask)))) { return i; From 5cf030568b799866fb615526216139850acd18ec Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Thu, 1 May 2025 17:23:33 -0700 Subject: [PATCH 15/27] Clean up MAX32 BUSIO drivers - Fixed errors with peripheral bus hardware descriptions in MAX32690 "peripherals/" - Resolved all FIXME comments - Removed unused ringbuf API from common-hal/busio/UART.c Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 4 --- ports/analog/common-hal/busio/SPI.c | 13 +--------- ports/analog/common-hal/busio/UART.c | 25 ++++--------------- ports/analog/common-hal/busio/UART.h | 2 -- ports/analog/peripherals/max32690/max32_i2c.c | 10 ++++---- ports/analog/peripherals/max32690/max32_i2c.h | 2 +- ports/analog/peripherals/max32690/max32_spi.c | 2 +- .../analog/peripherals/max32690/max32_uart.c | 6 ++--- 8 files changed, 16 insertions(+), 48 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index cba8fca94f50e..f8a5a8bd20971 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -155,10 +155,6 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { self->scl = NULL; } -void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { - // FIXME: Implement -} - // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { int nack = 0; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 7f19ebd1f945c..d158f09673189 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -60,12 +60,6 @@ void spi_isr(void) { } } -// Reset SPI when reload -void spi_reset(void) { - // FIXME: Implement - return; -} - // Construct SPI protocol, this function init SPI peripheral // todo: figure out Chip select behavior void common_hal_busio_spi_construct(busio_spi_obj_t *self, @@ -102,11 +96,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, assert((self->spi_id >= 0) && (self->spi_id < NUM_SPI)); - // Init I2C as main / controller node (0x00 is ignored) - // FIXME: MUST map the SPI pins to a spi_pins_t struct + // Init SPI controller if ((mosi != NULL) && (miso != NULL) && (sck != NULL)) { // spi, mastermode, quadModeUsed, numSubs, ssPolarity, frequency - // err = MXC_SPI_Init((mxc_spi_reva_regs_t *)self->spi_regs, 1, 0, 1, 0x00, 1000000, &spi_pins); err = MXC_SPI_Init(self->spi_regs, MXC_SPI_TYPE_CONTROLLER, MXC_SPI_INTERFACE_STANDARD, 1, 0x01, 1000000, spi_pins); MXC_GPIO_SetVSSEL(MXC_GPIO_GET_GPIO(sck->port), MXC_GPIO_VSSEL_VDDIOH, (sck->mask | miso->mask | mosi->mask | MXC_GPIO_PIN_0)); @@ -117,9 +109,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); } - // FIXME: Debugging - - // Attach SPI pins self->mosi = mosi; self->miso = miso; diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 310965e34609b..408ae8452352e 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -96,7 +96,7 @@ static uint32_t timeout_ms = 0; static uint8_t uarts_active = 0; static uart_status_t uart_status[NUM_UARTS]; static volatile int uart_err; -// static uint8_t uart_never_reset_mask = 0; +static uint8_t uart_never_reset_mask = 0; static int isValidBaudrate(uint32_t baudrate) { switch (baudrate) { @@ -167,8 +167,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, - mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, - bool sigint_enabled) { + mp_float_t timeout, bool sigint_enabled) { int err, temp; // Check for NULL Pointers && valid UART settings @@ -236,21 +235,6 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->baudrate = baudrate; self->error = E_NO_ERROR; - // Initialize ringbuffer for receiving data - // FIXME: Either the use the ringbuf or get rid of it! - if (self->rx_pin) { - // if given a ringbuff, use that - if (receiver_buffer) { - ringbuf_init(&self->ringbuf, receiver_buffer, receiver_buffer_size); - } - // else create one and attach it - else { - if (!ringbuf_alloc(&self->ringbuf, receiver_buffer_size)) { - m_malloc_fail(receiver_buffer_size); - } - } - } - // Indicate to this module that the UART is active uarts_active |= (1 << self->uart_id); @@ -277,6 +261,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { // First disable the ISR to avoid pre-emption NVIC_DisableIRQ(UART0_IRQn); + // Shutdown the UART Controller MXC_UART_Shutdown(self->uart_regs); self->error = E_UNINITIALIZED; @@ -307,7 +292,7 @@ bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { }; } -// Read characters. len is in characters NOT bytes! +// Read characters. len is in characters. size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { int err; @@ -474,7 +459,7 @@ void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { common_hal_never_reset_pin(self->rx_pin); common_hal_never_reset_pin(self->cts_pin); common_hal_never_reset_pin(self->rts_pin); - // uart_never_reset_mask |= ( 1 << (self->uart_id) ); + uart_never_reset_mask |= (1 << (self->uart_id)); } #endif // CIRCUITPY_BUSIO_UART diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index f24f310fe3a52..c2c2d837ca8a5 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -33,8 +33,6 @@ typedef struct { int error; float timeout; - ringbuf_t ringbuf; - const mcu_pin_obj_t *rx_pin; const mcu_pin_obj_t *tx_pin; const mcu_pin_obj_t *rts_pin; diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index d5c8da0743129..daf665bbee741 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -20,7 +20,7 @@ * * See MAX32690 Rev A2 Errata #16: * https://www.analog.com/media/en/technical-documentation/data-sheets/max32690_a2_errata_rev2.pdf - * + * * Additionally, note that the TQFN package does not expose some of the duplicate pins. For this package, * enabling the un-routed GPIOs has been shown to cause initialization issues with the I2C block. * To work around this, "MAX32690GTK_PACKAGE_TQFN" can be defined by the build system. The recommend place @@ -30,13 +30,13 @@ const mxc_gpio_cfg_t i2c_maps[NUM_I2C] = { // I2C0 { MXC_GPIO2, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // I2C1 { MXC_GPIO0, (MXC_GPIO_PIN_11 | MXC_GPIO_PIN_12), MXC_GPIO_FUNC_ALT1, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // I2C2 { MXC_GPIO1, (MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8), MXC_GPIO_FUNC_ALT3, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 };, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, }; #ifndef MAX32690GTK_PACKAGE_TQFN const mxc_gpio_cfg_t i2c_maps_extra[NUM_I2C] = { @@ -48,7 +48,7 @@ const mxc_gpio_cfg_t i2c_maps_extra[NUM_I2C] = { MXC_GPIO_PAD_PULL_UP, MXC_GPIO_VSSEL_VDDIOH, MXC_GPIO_DRVSTR_0 }, // I2C2C { MXC_GPIO0, (MXC_GPIO_PIN_13 | MXC_GPIO_PIN_14), MXC_GPIO_FUNC_ALT3, - MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 };, + MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, }; #endif diff --git a/ports/analog/peripherals/max32690/max32_i2c.h b/ports/analog/peripherals/max32690/max32_i2c.h index 3e554da5abcde..b64cfd308dcf5 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.h +++ b/ports/analog/peripherals/max32690/max32_i2c.h @@ -11,6 +11,6 @@ #include "i2c.h" #include "peripherals/pins.h" -#define NUM_I2C 2 +#define NUM_I2C 3 int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl); diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index ecd197036a49d..f2594787598b2 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -16,7 +16,7 @@ const mxc_gpio_cfg_t spi_maps[NUM_SPI] = { // SPI0 { MXC_GPIO2, (MXC_GPIO_PIN_27 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), - MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }; + MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, // SPI1 { MXC_GPIO1, (MXC_GPIO_PIN_26 | MXC_GPIO_PIN_28 | MXC_GPIO_PIN_29), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_NONE, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index 3cfcc75ca0dc0..5f7a8568fb426 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -18,14 +18,14 @@ const mxc_gpio_cfg_t uart_maps[NUM_UARTS] = { MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, { MXC_GPIO2, (MXC_GPIO_PIN_14 | MXC_GPIO_PIN_16), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), MXC_GPIO_FUNC_ALT1, + { MXC_GPIO1, (MXC_GPIO_PIN_9 | MXC_GPIO_PIN_10), MXC_GPIO_FUNC_ALT1, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 }, - { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), MXC_GPIO_FUNC_ALT2, + { MXC_GPIO3, (MXC_GPIO_PIN_0 | MXC_GPIO_PIN_1), MXC_GPIO_FUNC_ALT2, MXC_GPIO_PAD_WEAK_PULL_UP, MXC_GPIO_VSSEL_VDDIO, MXC_GPIO_DRVSTR_0 } }; int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { - for (int i = 0; i < uart_entries; i++) { + for (int i = 0; i < NUM_UARTS; i++) { if ((uart_maps[i].port == (MXC_GPIO_GET_GPIO(tx->port))) && (uart_maps[i].mask == ((tx->mask) | (rx->mask)))) { return i; From deda9802e348f9481fe240025b79232a5682ea07 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Thu, 1 May 2025 17:39:22 -0700 Subject: [PATCH 16/27] Cleanup copy-paste comments in MAX32 busio files Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 27 +-------------------------- ports/analog/common-hal/busio/I2C.h | 1 - ports/analog/common-hal/busio/SPI.c | 22 ++-------------------- ports/analog/common-hal/busio/SPI.h | 1 - ports/analog/common-hal/busio/UART.c | 3 ++- ports/analog/common-hal/busio/UART.h | 5 ----- 6 files changed, 5 insertions(+), 54 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index f8a5a8bd20971..9fe903428f5b9 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -40,8 +40,7 @@ typedef enum { I2C_NEVER_RESET, } i2c_status_t; -// Set each bit to indicate an active UART -// will be checked by ISR Handler for which ones to call +// Set each bit to indicate an active I2c static uint8_t i2c_active = 0; static i2c_status_t i2c_status[NUM_I2C]; static volatile int i2c_err; @@ -49,23 +48,6 @@ static volatile int i2c_err; // I2C struct for configuring GPIO pins extern const mxc_gpio_cfg_t i2c_maps[NUM_I2C]; -// I2C Interrupt Handler -void i2c_isr(void) { - for (int i = 0; i < NUM_I2C; i++) { - if (i2c_active & (1 << i)) { - // NOTE: I2C_GET_TMR actually returns the I2C registers - MXC_I2C_AsyncHandler(MXC_I2C_GET_I2C(i)); - } - } -} - -// Callback gets called when AsyncRequest is COMPLETE -// (e.g. txLen == txCnt) -// static volatile void i2cCallback(mxc_i2c_req_t *req, int error) { -// i2c_status[MXC_I2C_GET_IDX(req->i2c)] = I2C_FREE; -// i2c_err = error; -// } - // Construct I2C protocol, this function init i2c peripheral void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, @@ -80,7 +62,6 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // Assign I2C ID based on pins temp = pinsToI2c(sda, scl); if (temp == -1) { - // Error will be indicated by pinsToUart(tx, rx) function return; } else { self->i2c_id = temp; @@ -124,12 +105,6 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, self->timeout = timeout; } - /* Setup I2C interrupt */ - NVIC_ClearPendingIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); - NVIC_DisableIRQ(MXC_I2C_GET_IRQ(self->i2c_id)); - NVIC_SetPriority(MXC_I2C_GET_IRQ(self->i2c_id), I2C_PRIORITY); - NVIC_SetVector(MXC_I2C_GET_IRQ(self->i2c_id), (uint32_t)i2c_isr); - return; } diff --git a/ports/analog/common-hal/busio/I2C.h b/ports/analog/common-hal/busio/I2C.h index 2c7ffec20785e..55c230ee2f97f 100644 --- a/ports/analog/common-hal/busio/I2C.h +++ b/ports/analog/common-hal/busio/I2C.h @@ -7,7 +7,6 @@ #pragma once #include "common-hal/microcontroller/Pin.h" -// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " #include "py/obj.h" // HAL-specific diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index d158f09673189..999eb8490b0eb 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -46,22 +46,11 @@ typedef enum { } spi_status_t; // Set each bit to indicate an active SPI -// will be checked by ISR Handler for which ones to call static uint8_t spi_active = 0; static spi_status_t spi_status[NUM_SPI]; static volatile int spi_err; -// SPI Interrupt Handler -void spi_isr(void) { - for (int i = 0; i < NUM_SPI; i++) { - if (spi_active & (1 << i)) { - MXC_SPI_AsyncHandler(MXC_SPI_GET_SPI(i)); - } - } -} - // Construct SPI protocol, this function init SPI peripheral -// todo: figure out Chip select behavior void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi, @@ -69,13 +58,12 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, bool half_duplex) { int temp, err = 0; - // Check for NULL Pointers && valid I2C settings + // Check for NULL Pointer assert(self); - // Assign I2C ID based on pins + // Assign SPI ID based on pins temp = pinsToSpi(mosi, miso, sck); if (temp == -1) { - // Error will be indicated by pinsToUart(tx, rx) function return; } else { self->spi_id = temp; @@ -120,12 +108,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Indicate to this module that the SPI is active spi_active |= (1 << self->spi_id); - /* Setup I2C interrupt */ - NVIC_ClearPendingIRQ(MXC_SPI_GET_IRQ(self->spi_id)); - NVIC_DisableIRQ(MXC_SPI_GET_IRQ(self->spi_id)); - NVIC_SetPriority(MXC_SPI_GET_IRQ(self->spi_id), SPI_PRIORITY); - NVIC_SetVector(MXC_SPI_GET_IRQ(self->spi_id), (uint32_t)spi_isr); - return; } diff --git a/ports/analog/common-hal/busio/SPI.h b/ports/analog/common-hal/busio/SPI.h index e70d4234d9407..d10601876fb5e 100644 --- a/ports/analog/common-hal/busio/SPI.h +++ b/ports/analog/common-hal/busio/SPI.h @@ -8,7 +8,6 @@ #define MICROPY_INCLUDED_MAX32_COMMON_HAL_BUSIO_SPI_H #include "common-hal/microcontroller/Pin.h" -// FIXME: Silabs includes "peripherals/periph.h. Figure out what's in this file. " #include "py/obj.h" // HAL-specific diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 408ae8452352e..3b159c7b29026 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -167,7 +167,8 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, const mcu_pin_obj_t *rs485_dir, bool rs485_invert, uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, - mp_float_t timeout, bool sigint_enabled) { + mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, + bool sigint_enabled) { int err, temp; // Check for NULL Pointers && valid UART settings diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index c2c2d837ca8a5..a727116f7b882 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -9,11 +9,6 @@ #include "common-hal/microcontroller/Pin.h" #include "py/obj.h" -#include "py/ringbuf.h" - -// #include "uart.h" -// #include "uart_regs.h" -// #include "mxc_sys.h" #include "max32_port.h" From 0f9ea2920979184a9e0d2048d6190ade71b905fd Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 5 May 2025 10:31:25 -0700 Subject: [PATCH 17/27] Correct ringbuffer code for ports/analog BUSIO - Add correct ringbuffer handling code to ports/analog/common-hal/UART.c Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/UART.c | 103 +++++++++++++++------------ ports/analog/common-hal/busio/UART.h | 8 +-- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 3b159c7b29026..f781da8705545 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -24,20 +24,27 @@ * THE SOFTWARE. */ +/** TODO: + * - Fix readline issue + * +*/ + #if CIRCUITPY_BUSIO_UART +#include "mpconfigport.h" +#include "supervisor/shared/tick.h" + #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/shared/tick.h" #include "shared-bindings/busio/UART.h" - #include "shared-bindings/microcontroller/Pin.h" - -#include "mpconfigport.h" #include "shared/readline/readline.h" #include "shared/runtime/interrupt_char.h" + #include "py/gc.h" +#include "py/ringbuf.h" #include "py/mperrno.h" +#include "py/mpprint.h" #include "py/runtime.h" #include "max32_port.h" @@ -47,29 +54,6 @@ // UART IRQ Priority #define UART_PRIORITY 1 -/** - * -// Define a struct for what BUSIO.UART should contain -typedef struct { - mp_obj_base_t base; - int uart_id; - mxc_uart_regs_t* uart_regs; - - const mcu_pin_obj_t *rx_pin; - const mcu_pin_obj_t *tx_pin; - const mcu_pin_obj_t *rts_pin; - const mcu_pin_obj_t *cts_pin; - - uint8_t bits; - uint32_t baudrate; - bool parity; - uint8_t stop_bits; - - uint32_t timeout_ms; - bool error; -} busio_uart_obj_t; - */ - typedef enum { UART_9600 = 9600, UART_14400 = 14400, @@ -82,7 +66,6 @@ typedef enum { UART_921600 = 921600, } uart_valid_baudrates; - typedef enum { UART_FREE = 0, UART_BUSY, @@ -97,6 +80,7 @@ static uint8_t uarts_active = 0; static uart_status_t uart_status[NUM_UARTS]; static volatile int uart_err; static uint8_t uart_never_reset_mask = 0; +static busio_uart_obj_t *context; static int isValidBaudrate(uint32_t baudrate) { switch (baudrate) { @@ -159,6 +143,10 @@ void uart_isr(void) { static volatile void uartCallback(mxc_uart_req_t *req, int error) { uart_status[MXC_UART_GET_IDX(req->uart)] = UART_FREE; uart_err = error; + + MXC_SYS_Crit_Enter(); + ringbuf_put_n(context->ringbuf, req->rxData, req->rxLen); + MXC_SYS_Crit_Exit(); } // Construct an underlying UART object. @@ -183,9 +171,15 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->uart_id = temp; self->uart_regs = MXC_UART_GET_UART(temp); } - assert((self->uart_id >= 0) && (self->uart_id < NUM_UARTS)); + // Check for size of ringbuffer, desire powers of 2 + // At least use 1 byte if no size is given + assert((receiver_buffer_size & (receiver_buffer_size - 1)) == 0); + if (receiver_buffer_size == 0) { + receiver_buffer_size += 1; + } + // Indicate RS485 not implemented if ((rs485_dir != NULL) || (rs485_invert)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("RS485")); @@ -246,12 +240,31 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->timeout = timeout; } - /* Setup UART interrupt */ + // Initialize ringbuffer + if (receiver_buffer == NULL) { + self->ringbuf = gc_alloc(receiver_buffer_size, false); + if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { + m_malloc_fail(receiver_buffer_size); + mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + } + } else { + if (!(ringbuf_init(self->ringbuf, receiver_buffer, receiver_buffer_size))) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + } + ; + } + + context = self; + + // Setup UART interrupt + NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); NVIC_SetVector(MXC_UART_GET_IRQ(self->uart_id), (uint32_t)uart_isr); + NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); + return; } @@ -260,7 +273,7 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { if (!common_hal_busio_uart_deinited(self)) { // First disable the ISR to avoid pre-emption - NVIC_DisableIRQ(UART0_IRQn); + NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); // Shutdown the UART Controller MXC_UART_Shutdown(self->uart_regs); @@ -280,6 +293,8 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { self->cts_pin = NULL; self->rts_pin = NULL; + ringbuf_deinit(self->ringbuf); + // Indicate to this module that the UART is not active uarts_active &= ~(1 << self->uart_id); } @@ -306,8 +321,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uart_status[self->uart_id] = UART_BUSY; bytes_remaining = len; - NVIC_EnableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mxc_uart_req_t uart_rd_req; uart_rd_req.rxCnt = 0; uart_rd_req.txCnt = 0; @@ -341,13 +354,16 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { + mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); } - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - return len; + // Copy the data from the ringbuf (or return error) + MXC_SYS_Crit_Enter(); + err = ringbuf_get_n(context->ringbuf, data, len); + MXC_SYS_Crit_Exit(); + + return err; } // Write characters. len is in characters NOT bytes! @@ -391,11 +407,10 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { // Call the handler and abort if errors - uart_err = MXC_UART_AsyncHandler(MXC_UART_GET_UART(0)); + uart_err = MXC_UART_AsyncHandler(self->uart_regs); if (uart_err != E_NO_ERROR) { - MXC_UART_AbortAsync(MXC_UART_GET_UART(0)); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(0)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); + mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + MXC_UART_AbortAsync(self->uart_regs); } } @@ -407,9 +422,8 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { + mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("MAX32 ERR: %d\n"), uart_err); } return len; @@ -444,11 +458,12 @@ void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeou } uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { - return MXC_UART_GetRXFIFOAvailable(self->uart_regs); + return ringbuf_num_filled(self->ringbuf); } void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { MXC_UART_ClearRXFIFO(self->uart_regs); + ringbuf_clear(self->ringbuf); } bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { diff --git a/ports/analog/common-hal/busio/UART.h b/ports/analog/common-hal/busio/UART.h index a727116f7b882..296c738772e68 100644 --- a/ports/analog/common-hal/busio/UART.h +++ b/ports/analog/common-hal/busio/UART.h @@ -9,25 +9,25 @@ #include "common-hal/microcontroller/Pin.h" #include "py/obj.h" +#include "py/ringbuf.h" #include "max32_port.h" // Define a struct for what BUSIO.UART should contain typedef struct { mp_obj_base_t base; + int error; + float timeout; int uart_id; int uart_map; mxc_uart_regs_t *uart_regs; - + ringbuf_t *ringbuf; bool parity; uint8_t bits; uint8_t stop_bits; uint32_t baudrate; - int error; - float timeout; - const mcu_pin_obj_t *rx_pin; const mcu_pin_obj_t *tx_pin; const mcu_pin_obj_t *rts_pin; From a305eced0dea38aea41763d62a0b1f251a405396 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Mon, 5 May 2025 10:34:22 -0700 Subject: [PATCH 18/27] Update jlink script for ports/analog Signed-off-by: Brandon Hurst --- ports/analog/tools/flash_max32.jlink | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/analog/tools/flash_max32.jlink b/ports/analog/tools/flash_max32.jlink index 4c9cbacb96fee..8e3647cb0afc7 100644 --- a/ports/analog/tools/flash_max32.jlink +++ b/ports/analog/tools/flash_max32.jlink @@ -1,6 +1,7 @@ si 1 erase -loadbin build-APARD/firmware.bin 0x10000000 -r -g +loadbin build-apard32690/firmware.bin 0x10000000 +reset +halt +go exit From cbbf34d39115f2e661a2baf19ea8dffcfa018dc2 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 09:19:43 -0700 Subject: [PATCH 19/27] Refactor ports/analog/common-hal/busio i2c probe function. - Used direct hardware values to rely on common HW implementation - Accounted for TX Lockout conditions in Transmit FIFO causing errors Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 54 +++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 9fe903428f5b9..ca114d337ede0 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -132,25 +132,49 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - int nack = 0; + int32_t flags = 0x0; + bool ret = false; + + MXC_I2C_ClearFlags(self->i2c_regs, 0xFF, 0xFF); + MXC_I2C_EnableInt(self->i2c_regs, 0xFF, 0xFF); + + // Pre-load target address into transmit FIFO + addr = (addr << 1); + self->i2c_regs->fifo = addr; + + // Set start bit & wait for it to clear + self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_START; + + // wait for ACK/NACK + // if tx_lockout occurs, clear the error and re-load the target address + while (!(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_ACK) && + !(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_NACK_ERR)) { + if (self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_TX_LOCKOUT) { + self->i2c_regs->intfl0 |= MXC_F_I2C_INTFL0_TX_LOCKOUT; + self->i2c_regs->fifo = addr; + } + } + flags = self->i2c_regs->intfl0; + self->i2c_regs->intfl0 = MXC_F_I2C_INTFL0_ADDR_ACK | MXC_F_I2C_INTFL0_ADDR_NACK_ERR - mxc_i2c_req_t addr_req = { - .addr = addr, - .i2c = self->i2c_regs, - .tx_len = 0, - .tx_buf = NULL, - .rx_len = 0, - .rx_buf = NULL, - .callback = NULL - }; + // Set / Wait for stop + self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_STOP; + while ((self->i2c_regs->mstctrl & MXC_F_I2C_MSTCTRL_STOP)) { + ; + } - // Probe the address - nack = MXC_I2C_MasterTransaction(&addr_req); - if (nack) { - return false; + // Wait for controller not busy, then clear flags + while (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { + ; + } + + if (flags & MXC_F_I2C_INTFL0_ADDR_ACK) { + ret = true; } else { - return true; + ret = false; } + MXC_I2C_ClearFlags(self->i2c_regs, 0xff, 0xff); + return ret; } // Lock I2C bus From c3ea18231badb4202e659a188eb87ab6b0d168ff Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 09:21:14 -0700 Subject: [PATCH 20/27] Expand command in ports/analog/tools/flash_max32.jlink for clarity. Signed-off-by: Brandon Hurst --- ports/analog/tools/flash_max32.jlink | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/analog/tools/flash_max32.jlink b/ports/analog/tools/flash_max32.jlink index 8e3647cb0afc7..0453f4cb077fd 100644 --- a/ports/analog/tools/flash_max32.jlink +++ b/ports/analog/tools/flash_max32.jlink @@ -1,4 +1,4 @@ -si 1 +selectinterface swd erase loadbin build-apard32690/firmware.bin 0x10000000 reset From db95dd00dc9834a18b6ce004a5bc0bcc5b0a2a65 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 14:08:22 -0700 Subject: [PATCH 21/27] Fix i2c scan bug with ports/analog/ BUSIO. - Probe function caused infinite loops / unreliable ACK values - Replaced with probe-function with low-level routines Signed-off-by: Brandon Hurst --- ports/analog/common-hal/busio/I2C.c | 42 +++++++++++------------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index ca114d337ede0..c1b1d9efe1b17 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -34,15 +34,8 @@ #define I2C_PRIORITY 1 -typedef enum { - I2C_FREE = 0, - I2C_BUSY, - I2C_NEVER_RESET, -} i2c_status_t; - // Set each bit to indicate an active I2c static uint8_t i2c_active = 0; -static i2c_status_t i2c_status[NUM_I2C]; static volatile int i2c_err; // I2C struct for configuring GPIO pins @@ -68,7 +61,9 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, self->i2c_regs = MXC_I2C_GET_I2C(temp); } + // Check for valid I2C controller assert((self->i2c_id >= 0) && (self->i2c_id < NUM_I2C)); + assert(!(i2c_active & (1 << self->i2c_id))); // Init I2C as main / controller node (0x00 is ignored) if ((scl != NULL) && (sda != NULL)) { @@ -132,48 +127,43 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - int32_t flags = 0x0; - bool ret = false; + uint32_t int_fl0, int_fl1; + bool ret = 0; - MXC_I2C_ClearFlags(self->i2c_regs, 0xFF, 0xFF); - MXC_I2C_EnableInt(self->i2c_regs, 0xFF, 0xFF); + // Clear FIFOs & all interrupt flags + MXC_I2C_ClearRXFIFO(self->i2c_regs); + MXC_I2C_ClearTXFIFO(self->i2c_regs); + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); // Pre-load target address into transmit FIFO addr = (addr << 1); self->i2c_regs->fifo = addr; // Set start bit & wait for it to clear - self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_START; + MXC_I2C_Start(self->i2c_regs); // wait for ACK/NACK - // if tx_lockout occurs, clear the error and re-load the target address while (!(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_ACK) && !(self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_ADDR_NACK_ERR)) { - if (self->i2c_regs->intfl0 & MXC_F_I2C_INTFL0_TX_LOCKOUT) { - self->i2c_regs->intfl0 |= MXC_F_I2C_INTFL0_TX_LOCKOUT; - self->i2c_regs->fifo = addr; - } } - flags = self->i2c_regs->intfl0; - self->i2c_regs->intfl0 = MXC_F_I2C_INTFL0_ADDR_ACK | MXC_F_I2C_INTFL0_ADDR_NACK_ERR - // Set / Wait for stop - self->i2c_regs->mstctrl |= MXC_F_I2C_MSTCTRL_STOP; - while ((self->i2c_regs->mstctrl & MXC_F_I2C_MSTCTRL_STOP)) { - ; - } + // Save interrupt flags for ACK/NACK checking + int_fl0 = self->i2c_regs->intfl0; + + // Set / Wait for stop + MXC_I2C_Stop(self->i2c_regs); // Wait for controller not busy, then clear flags while (self->i2c_regs->status & MXC_F_I2C_STATUS_BUSY) { ; } + MXC_I2C_ClearFlags(self->i2c_regs, 0xFFFFFF, 0xFFFFFF); - if (flags & MXC_F_I2C_INTFL0_ADDR_ACK) { + if (int_fl0 & MXC_F_I2C_INTFL0_ADDR_ACK) { ret = true; } else { ret = false; } - MXC_I2C_ClearFlags(self->i2c_regs, 0xff, 0xff); return ret; } From 9b8e08fc5fde378ab54f251336e810664118dea0 Mon Sep 17 00:00:00 2001 From: Brandon Hurst Date: Tue, 6 May 2025 14:41:26 -0700 Subject: [PATCH 22/27] Add translations for ports/analog/busio Signed-off-by: Brandon Hurst --- locale/circuitpython.pot | 114 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1c6fcce1d417a..942fe085356d2 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -28,6 +28,25 @@ msgid "" "Code stopped by auto-reload. Reloading soon.\n" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#, c-format +msgid "" +"\n" +"ERR: Error starting transaction: %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "" +"\n" +"ERR: Requested bus is busy\n" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "" +"\n" +"ERR: Uart transaction timed out.\n" +msgstr "" + #: supervisor/shared/safe_mode.c msgid "" "\n" @@ -632,6 +651,10 @@ msgid "" "disable.\n" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Baudrate invalid. Must be a standard UART baudrate.\n" +msgstr "" + #: ports/espressif/common-hal/canio/CAN.c msgid "Baudrate not supported by peripheral" msgstr "" @@ -721,6 +744,10 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "CPOL / CPHA must both be either 0 or 1\n" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -934,6 +961,38 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "ERR: Could not init ringbuffer\n" +msgstr "" + +#: ports/analog/peripherals/max32690/max32_uart.c +#, c-format +msgid "" +"ERR: Unable to find a uart matching pins...\n" +"TX: port %d mask %d\n" +"RX: port %d mask %d\n" +msgstr "" + +#: ports/analog/peripherals/max32690/max32_i2c.c +#, c-format +msgid "" +"ERR: Unable to find an I2C matching pins...\n" +"SCL: port %d mask %d\n" +"SDA: port %d mask %d\n" +msgstr "" + +#: ports/analog/peripherals/max32690/max32_spi.c +#, c-format +msgid "" +"ERR: Unable to find an SPI matching pins... \n" +"MOSI: port %d mask %d\n" +"MISO: port %d mask %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/I2C.c +msgid "ERROR during I2C Transaction\n" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c msgid "ESP-IDF memory allocation failed" @@ -1027,6 +1086,19 @@ msgstr "" msgid "Failed to enable continuous" msgstr "" +#: ports/analog/common-hal/busio/I2C.c +#, c-format +msgid "Failed to init I2C. ERR: %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to init SPI.\n" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "Failed to initialize UART.\n" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" msgstr "" @@ -1040,6 +1112,23 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" +#: ports/analog/common-hal/busio/I2C.c +#, c-format +msgid "Failed to set I2C frequency. ERR: %d\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Frame Size\n" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Frequency\n" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -1080,6 +1169,10 @@ msgstr "" msgid "Firmware is too big" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Flow Ctrl needs both CTS & RTS" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" @@ -1139,6 +1232,10 @@ msgstr "" msgid "I2C init error" msgstr "" +#: ports/analog/common-hal/busio/I2C.c +msgid "I2C needs SDA & SCL" +msgstr "" + #: ports/raspberrypi/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "I2C peripheral in use" @@ -1748,6 +1845,10 @@ msgstr "" msgid "Parameter error" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Parity must be ODD, EVEN, or NONE\n" +msgstr "" + #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" msgstr "" @@ -1861,6 +1962,7 @@ msgstr "" msgid "RNG Init Error" msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -1953,6 +2055,10 @@ msgstr "" msgid "SPI init error" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "" @@ -2084,6 +2190,10 @@ msgstr "" msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "Too many channels in sample" msgstr "" @@ -2127,6 +2237,10 @@ msgstr "" msgid "UART init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" From bb0529bb33f72193fdf9a67dc98b376cc8819214 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 12:32:20 -0700 Subject: [PATCH 23/27] Fix error reporting on ports/analog BUSIO for PR 10413 - Use existing error messages from locale/circuitpython.pot for most error messages - Replace ConnectionError (networking specific) calls with others (usually RuntimeError) - Remove '\n' from mp error calls (since they add it already) - Remove some redundant validation code that repeats checks done by shared-bindings/common-hal/busio code. e.g. pin validation Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/I2C.c | 35 +++++---------- ports/analog/common-hal/busio/SPI.c | 5 ++- ports/analog/common-hal/busio/UART.c | 45 ++++++++++--------- ports/analog/peripherals/max32690/max32_i2c.c | 3 +- ports/analog/peripherals/max32690/max32_spi.c | 5 +-- .../analog/peripherals/max32690/max32_uart.c | 3 +- 6 files changed, 39 insertions(+), 57 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index c1b1d9efe1b17..b75d916c9faf0 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -52,6 +52,11 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // Check for NULL Pointers && valid I2C settings assert(self); + /* NOTE: The validate_obj_is_free_pin() calls in shared-bindings/busio/I2C.c + will ensure that scl and sda are both pins and cannot be null + ref: https://github.com/adafruit/circuitpython/pull/10413 + */ + // Assign I2C ID based on pins temp = pinsToI2c(sda, scl); if (temp == -1) { @@ -65,25 +70,6 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, assert((self->i2c_id >= 0) && (self->i2c_id < NUM_I2C)); assert(!(i2c_active & (1 << self->i2c_id))); - // Init I2C as main / controller node (0x00 is ignored) - if ((scl != NULL) && (sda != NULL)) { - MXC_GPIO_Config(&i2c_maps[self->i2c_id]); - err = MXC_I2C_Init(self->i2c_regs, 1, 0x00); - if (err) { - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to init I2C. ERR: %d\n"), err); - } - err = MXC_I2C_SetFrequency(self->i2c_regs, frequency); - if (err < 0) { - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to set I2C frequency. ERR: %d\n"), err); - } - } else if (scl != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); - } else if (sda != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("I2C needs SDA & SCL")); - } else { - // Should not get here, as shared-bindings API should not call this way - } - // Attach I2C pins self->sda = sda; self->scl = scl; @@ -94,8 +80,8 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, i2c_active |= (1 << self->i2c_id); // Set the timeout to a default value - if (((timeout < 0.0) || (timeout > 100.0))) { - self->timeout = 1.0; + if (timeout > 100) { + self->timeout = 1; } else { self->timeout = timeout; } @@ -212,7 +198,6 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, } // Read into buffer from the device selected by address -// todo test uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -229,14 +214,14 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, }; ret = MXC_I2C_MasterTransaction(&rd_req); if (ret) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + // Return I/O error + return MP_EIO; } return 0; } // Write the bytes from out_data to the device selected by address, -// todo test uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { @@ -253,7 +238,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_rd_req); if (ret) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + return MP_EIO; } return 0; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 999eb8490b0eb..95ad1851a59ed 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -91,7 +91,8 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, 1, 0x01, 1000000, spi_pins); MXC_GPIO_SetVSSEL(MXC_GPIO_GET_GPIO(sck->port), MXC_GPIO_VSSEL_VDDIOH, (sck->mask | miso->mask | mosi->mask | MXC_GPIO_PIN_0)); if (err) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to init SPI.\n")); + // NOTE: Reuse existing messages from locales/circuitpython.pot to save space + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_SPI); } } else { mp_raise_NotImplementedError(MP_ERROR_TEXT("SPI needs MOSI, MISO, and SCK")); @@ -170,7 +171,7 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, clk_mode = MXC_SPI_CLKMODE_3; break; default: - mp_raise_ValueError(MP_ERROR_TEXT("CPOL / CPHA must both be either 0 or 1\n")); + // should not be reachable; validated in shared-bindings/busio/SPI.c return false; } diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index f781da8705545..80feebfb8f4b6 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -82,37 +82,37 @@ static volatile int uart_err; static uint8_t uart_never_reset_mask = 0; static busio_uart_obj_t *context; -static int isValidBaudrate(uint32_t baudrate) { +static bool isValidBaudrate(uint32_t baudrate) { switch (baudrate) { case UART_9600: - return 1; + return true; break; case UART_14400: - return 1; + return true; break; case UART_19200: - return 1; + return true; break; case UART_38400: - return 1; + return true; break; case UART_57600: - return 1; + return true; break; case UART_115200: - return 1; + return true; break; case UART_230400: - return 1; + return true; break; case UART_460800: - return 1; + return true; break; case UART_921600: - return 1; + return true; break; default: - return 0; + return false; break; } } @@ -126,7 +126,8 @@ static mxc_uart_parity_t convertParity(busio_uart_parity_t busio_parity) { case BUSIO_UART_PARITY_ODD: return MXC_UART_PARITY_ODD_0; default: - mp_raise_ValueError(MP_ERROR_TEXT("Parity must be ODD, EVEN, or NONE\n")); + // not reachable due to validation in shared-bindings/busio/SPI.c + return MXC_UART_PARITY_DISABLE; } } @@ -188,7 +189,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, if ((rx != NULL) && (tx != NULL)) { err = MXC_UART_Init(self->uart_regs, baudrate, MXC_UART_IBRO_CLK); if (err != E_NO_ERROR) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to initialize UART.\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_UART); } // attach & configure pins @@ -211,7 +212,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, common_hal_mcu_pin_claim(self->cts_pin); common_hal_mcu_pin_claim(self->rts_pin); } else if (cts || rts) { - mp_raise_ValueError(MP_ERROR_TEXT("Flow Ctrl needs both CTS & RTS")); + mp_raise_ValueError(MP_ERROR_TEXT("Both RX and TX required for flow control")); } // Set stop bits & data size @@ -338,7 +339,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, *errcode = err; MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("\nERR: Error starting transaction: %d\n"), err); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("UART read error")); } // Wait for transaction completion or timeout @@ -350,11 +351,11 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, if (uart_status[self->uart_id] != UART_FREE) { MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + mp_raise_RuntimeError(MP_ERROR_TEXT("UART transaction timeout")); } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { - mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } @@ -399,7 +400,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, *errcode = err; MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Requested bus is busy\n")); + mp_raise_ValueError(MP_ERROR_TEXT("All UART peripherals are in use")); } // Wait for transaction completion or timeout @@ -409,7 +410,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, // Call the handler and abort if errors uart_err = MXC_UART_AsyncHandler(self->uart_regs); if (uart_err != E_NO_ERROR) { - mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } } @@ -418,11 +419,11 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, if (uart_status[self->uart_id] != UART_FREE) { MXC_UART_AbortAsync(self->uart_regs); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_ConnectionError(MP_ERROR_TEXT("\nERR: Uart transaction timed out.\n")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Uart transaction timed out.")); } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { - mp_printf(&mp_sys_stdout_print, "MAX32 ERR: %d\n", uart_err); + // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } @@ -438,7 +439,7 @@ void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrat if (isValidBaudrate(baudrate)) { self->baudrate = baudrate; } else { - mp_raise_ValueError(MP_ERROR_TEXT("Baudrate invalid. Must be a standard UART baudrate.\n")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_baudrate); } } diff --git a/ports/analog/peripherals/max32690/max32_i2c.c b/ports/analog/peripherals/max32690/max32_i2c.c index daf665bbee741..4b9ec8b4db264 100644 --- a/ports/analog/peripherals/max32690/max32_i2c.c +++ b/ports/analog/peripherals/max32690/max32_i2c.c @@ -70,7 +70,6 @@ int pinsToI2c(const mcu_pin_obj_t *sda, const mcu_pin_obj_t *scl) { } #endif - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an I2C matching pins...\nSCL: port %d mask %d\nSDA: port %d mask %d\n"), - sda->port, sda->mask, scl->port, scl->mask); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); return -1; } diff --git a/ports/analog/peripherals/max32690/max32_spi.c b/ports/analog/peripherals/max32690/max32_spi.c index f2594787598b2..c78fd64dbd705 100644 --- a/ports/analog/peripherals/max32690/max32_spi.c +++ b/ports/analog/peripherals/max32690/max32_spi.c @@ -39,9 +39,6 @@ int pinsToSpi(const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, return i; } } - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find an SPI matching pins... \ - \nMOSI: port %d mask %d\nMISO: port %d mask %d\n"), - mosi->port, mosi->mask, miso->port, miso->mask, - sck->port, sck->mask); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); return -1; } diff --git a/ports/analog/peripherals/max32690/max32_uart.c b/ports/analog/peripherals/max32690/max32_uart.c index 5f7a8568fb426..7d37708797415 100644 --- a/ports/analog/peripherals/max32690/max32_uart.c +++ b/ports/analog/peripherals/max32690/max32_uart.c @@ -31,7 +31,6 @@ int pinsToUart(const mcu_pin_obj_t *rx, const mcu_pin_obj_t *tx) { return i; } } - mp_raise_RuntimeError_varg(MP_ERROR_TEXT("ERR: Unable to find a uart matching pins...\nTX: port %d mask %d\nRX: port %d mask %d\n"), - tx->port, tx->mask, rx->port, rx->mask); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pins); return -1; } From e681c444b78a1602be8b4406fd46e9013c030e8f Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 12:38:42 -0700 Subject: [PATCH 24/27] Minor changes in ports/analog/ busio UART. - Use m_malloc_without_collect storage API change from CircuitPython - Remove err number for asynchronous read error; just report it Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/UART.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 80feebfb8f4b6..71da89652af39 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -197,12 +197,8 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->rx_pin = rx; common_hal_mcu_pin_claim(self->tx_pin); common_hal_mcu_pin_claim(self->rx_pin); - } else if (tx != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); - } else if (rx != NULL) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); } else { - // Should not get here, as shared-bindings API should not call this way + mp_raise_NotImplementedError(MP_ERROR_TEXT("UART needs TX & RX")); } if ((cts) && (rts)) { @@ -243,7 +239,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Initialize ringbuffer if (receiver_buffer == NULL) { - self->ringbuf = gc_alloc(receiver_buffer_size, false); + self->ringbuf = m_malloc_without_collect(receiver_buffer_size, false); if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { m_malloc_fail(receiver_buffer_size); mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); From 81c0b7d2ff303c741910fc96aae09d87a2e96bbc Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 12:44:05 -0700 Subject: [PATCH 25/27] Fix UART malloc for ports/analog BUSIO - Remove excess argument from UART ringbuf malloc call - Remove unused err and intfl0 in I2C driver to remove warnings Signed-off-by: Brandon-Hurst --- ports/analog/common-hal/busio/I2C.c | 4 ++-- ports/analog/common-hal/busio/UART.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index b75d916c9faf0..19c71034eea4c 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -47,7 +47,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - int temp, err = 0; + int temp = 0; // Check for NULL Pointers && valid I2C settings assert(self); @@ -113,7 +113,7 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { // Probe device in I2C bus bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - uint32_t int_fl0, int_fl1; + uint32_t int_fl0; bool ret = 0; // Clear FIFOs & all interrupt flags diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 71da89652af39..633ecb1684005 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -239,7 +239,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, // Initialize ringbuffer if (receiver_buffer == NULL) { - self->ringbuf = m_malloc_without_collect(receiver_buffer_size, false); + self->ringbuf = m_malloc_without_collect(receiver_buffer_size); if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { m_malloc_fail(receiver_buffer_size); mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); From 3524b1d17f865e3aacaf9592e9744ccba841dcf8 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Sat, 5 Jul 2025 13:03:03 -0700 Subject: [PATCH 26/27] Commit locale changes from ports/analog BUSIO updates Signed-off-by: Brandon-Hurst --- locale/circuitpython.pot | 104 ++++++++------------------------------- 1 file changed, 21 insertions(+), 83 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 4c799f3b0e90f..3ac4cf3763bff 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -28,25 +28,6 @@ msgid "" "Code stopped by auto-reload. Reloading soon.\n" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#, c-format -msgid "" -"\n" -"ERR: Error starting transaction: %d\n" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "" -"\n" -"ERR: Requested bus is busy\n" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "" -"\n" -"ERR: Uart transaction timed out.\n" -msgstr "" - #: supervisor/shared/safe_mode.c msgid "" "\n" @@ -149,6 +130,7 @@ msgstr "" msgid "%q indices must be integers, not %s" msgstr "" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-module/bitbangio/SPI.c msgid "%q init failed" msgstr "" @@ -177,7 +159,7 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" -#: py/modsys.c py/runtime.c +#: py/runtime.c msgid "%q moved from %q to %q" msgstr "" @@ -521,7 +503,8 @@ msgstr "" msgid "All SPI peripherals are in use" msgstr "" -#: ports/espressif/common-hal/busio/UART.c ports/nordic/common-hal/busio/UART.c +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c msgid "All UART peripherals are in use" msgstr "" @@ -651,10 +634,6 @@ msgid "" "disable.\n" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Baudrate invalid. Must be a standard UART baudrate.\n" -msgstr "" - #: ports/espressif/common-hal/canio/CAN.c msgid "Baudrate not supported by peripheral" msgstr "" @@ -676,6 +655,7 @@ msgstr "" msgid "Boot device must be first (interface #0)." msgstr "" +#: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c msgid "Both RX and TX required for flow control" msgstr "" @@ -744,10 +724,6 @@ msgstr "" msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "CPOL / CPHA must both be either 0 or 1\n" -msgstr "" - #: ports/espressif/common-hal/espidf/__init__.c msgid "CRC or checksum was invalid" msgstr "" @@ -974,30 +950,6 @@ msgstr "" msgid "ERR: Could not init ringbuffer\n" msgstr "" -#: ports/analog/peripherals/max32690/max32_uart.c -#, c-format -msgid "" -"ERR: Unable to find a uart matching pins...\n" -"TX: port %d mask %d\n" -"RX: port %d mask %d\n" -msgstr "" - -#: ports/analog/peripherals/max32690/max32_i2c.c -#, c-format -msgid "" -"ERR: Unable to find an I2C matching pins...\n" -"SCL: port %d mask %d\n" -"SDA: port %d mask %d\n" -msgstr "" - -#: ports/analog/peripherals/max32690/max32_spi.c -#, c-format -msgid "" -"ERR: Unable to find an SPI matching pins... \n" -"MOSI: port %d mask %d\n" -"MISO: port %d mask %d\n" -msgstr "" - #: ports/analog/common-hal/busio/I2C.c msgid "ERROR during I2C Transaction\n" msgstr "" @@ -1095,19 +1047,6 @@ msgstr "" msgid "Failed to enable continuous" msgstr "" -#: ports/analog/common-hal/busio/I2C.c -#, c-format -msgid "Failed to init I2C. ERR: %d\n" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to init SPI.\n" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "Failed to initialize UART.\n" -msgstr "" - #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" msgstr "" @@ -1121,11 +1060,6 @@ msgstr "" msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: ports/analog/common-hal/busio/I2C.c -#, c-format -msgid "Failed to set I2C frequency. ERR: %d\n" -msgstr "" - #: ports/analog/common-hal/busio/SPI.c msgid "Failed to set SPI Clock Mode\n" msgstr "" @@ -1178,10 +1112,6 @@ msgstr "" msgid "Firmware is too big" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Flow Ctrl needs both CTS & RTS" -msgstr "" - #: shared-bindings/bitmaptools/__init__.c msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" @@ -1241,10 +1171,6 @@ msgstr "" msgid "I2C init error" msgstr "" -#: ports/analog/common-hal/busio/I2C.c -msgid "I2C needs SDA & SCL" -msgstr "" - #: ports/raspberrypi/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "I2C peripheral in use" @@ -1348,6 +1274,10 @@ msgstr "" msgid "Interrupted by output function" msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c @@ -1858,10 +1788,6 @@ msgstr "" msgid "Parameter error" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Parity must be ODD, EVEN, or NONE\n" -msgstr "" - #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" msgstr "" @@ -2286,6 +2212,14 @@ msgstr "" msgid "UART re-init" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + #: ports/stm/common-hal/busio/UART.c msgid "UART write" msgstr "" @@ -2322,6 +2256,10 @@ msgstr "" msgid "UUID value is not str, int or byte buffer" msgstr "" +#: ports/analog/common-hal/busio/UART.c +msgid "Uart transaction timed out." +msgstr "" + #: ports/raspberrypi/common-hal/memorymap/AddressRange.c msgid "Unable to access unaligned IO register" msgstr "" From bd6f5dd0e5dae6843fc2e50e0290dfa5b54cdac8 Mon Sep 17 00:00:00 2001 From: Brandon-Hurst Date: Thu, 10 Jul 2025 21:57:47 -0700 Subject: [PATCH 27/27] Reuse more existing error messages in ports/analog BUSIO - Reuse more messages in locales/circuitpython.pot in BUSIO - Remove UART write timeout - Refine some error handling for SPI initialization Signed-off-by: Brandon-Hurst --- locale/circuitpython.pot | 30 ++++-------------------- ports/analog/common-hal/busio/I2C.c | 2 +- ports/analog/common-hal/busio/SPI.c | 15 +++++------- ports/analog/common-hal/busio/UART.c | 34 +++++++--------------------- 4 files changed, 19 insertions(+), 62 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 7cee5bc8ffd26..bbc22af7c5150 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -163,10 +163,6 @@ msgstr "" msgid "%q must be %d" msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "" - #: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -242,6 +238,7 @@ msgstr "" msgid "%q out of bounds" msgstr "" +#: ports/analog/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/nordic/common-hal/pulseio/PulseIn.c @@ -946,14 +943,6 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "ERR: Could not init ringbuffer\n" -msgstr "" - -#: ports/analog/common-hal/busio/I2C.c -msgid "ERROR during I2C Transaction\n" -msgstr "" - #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c msgid "ESP-IDF memory allocation failed" @@ -1002,7 +991,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" @@ -1061,15 +1050,7 @@ msgid "Failed to release mutex, err 0x%04x" msgstr "" #: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode\n" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Frame Size\n" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Frequency\n" +msgid "Failed to set SPI Clock Mode" msgstr "" #: ports/zephyr-cp/common-hal/wifi/Radio.c @@ -1370,6 +1351,7 @@ msgstr "" msgid "Invalid socket for TLS" msgstr "" +#: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" @@ -2256,10 +2238,6 @@ msgstr "" msgid "UUID value is not str, int or byte buffer" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Uart transaction timed out." -msgstr "" - #: ports/raspberrypi/common-hal/memorymap/AddressRange.c msgid "Unable to access unaligned IO register" msgstr "" diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 19c71034eea4c..2c8f2e328eb1f 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -191,7 +191,7 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_req); if (ret) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERROR during I2C Transaction\n")); + return MP_EIO; } return 0; diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index 95ad1851a59ed..516ae26a8cf69 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -177,17 +177,19 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, ret = MXC_SPI_SetFrequency(self->spi_regs, baudrate); if (ret) { - mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frequency\n")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_baudrate); return false; } ret = MXC_SPI_SetDataSize(self->spi_regs, bits); - if (ret) { - mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Frame Size\n")); + if (ret == E_BAD_PARAM) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_bits); return false; + } else if (ret == E_BAD_STATE) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid state")); } ret = MXC_SPI_SetMode(self->spi_regs, clk_mode); if (ret) { - mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Clock Mode\n")); + mp_raise_ValueError(MP_ERROR_TEXT("Failed to set SPI Clock Mode")); return false; } return true; @@ -246,11 +248,6 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t write_value) { int ret = 0; - // uint8_t tx_buffer[len] = {0x0}; - - // for (int i = 0; i < len; i++) { - // tx_buffer[i] = write_value; - // } mxc_spi_req_t rd_req = { .spi = self->spi_regs, diff --git a/ports/analog/common-hal/busio/UART.c b/ports/analog/common-hal/busio/UART.c index 633ecb1684005..be7851f52a21c 100644 --- a/ports/analog/common-hal/busio/UART.c +++ b/ports/analog/common-hal/busio/UART.c @@ -24,11 +24,6 @@ * THE SOFTWARE. */ -/** TODO: - * - Fix readline issue - * -*/ - #if CIRCUITPY_BUSIO_UART #include "mpconfigport.h" @@ -242,19 +237,19 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, self->ringbuf = m_malloc_without_collect(receiver_buffer_size); if (!ringbuf_alloc(self->ringbuf, receiver_buffer_size)) { m_malloc_fail(receiver_buffer_size); - mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to allocate %q buffer"), + MP_QSTR_UART); } } else { if (!(ringbuf_init(self->ringbuf, receiver_buffer, receiver_buffer_size))) { - mp_raise_RuntimeError(MP_ERROR_TEXT("ERR: Could not init ringbuffer\n")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Failed to allocate %q buffer"), + MP_QSTR_UART); } - ; } context = self; // Setup UART interrupt - NVIC_ClearPendingIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); NVIC_SetPriority(MXC_UART_GET_IRQ(self->uart_id), UART_PRIORITY); @@ -351,7 +346,7 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, } // Check for errors from the callback else if (uart_err != E_NO_ERROR) { - // todo: indicate error? + mp_raise_RuntimeError(MP_ERROR_TEXT("UART read error")); MXC_UART_AbortAsync(self->uart_regs); } @@ -368,7 +363,6 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { int err; - uint32_t start_time = 0; static size_t bytes_remaining; // Setup globals & status tracking @@ -390,7 +384,6 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, uart_wr_req.callback = (void *)uartCallback; // Start the transaction - start_time = supervisor_ticks_ms64(); err = MXC_UART_TransactionAsync(&uart_wr_req); if (err != E_NO_ERROR) { *errcode = err; @@ -399,27 +392,16 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("All UART peripherals are in use")); } - // Wait for transaction completion or timeout - while ((uart_status[self->uart_id] != UART_FREE) && - (supervisor_ticks_ms64() - start_time < (self->timeout * 1000))) { - + // Wait for transaction completion + while (uart_status[self->uart_id] != UART_FREE) { // Call the handler and abort if errors uart_err = MXC_UART_AsyncHandler(self->uart_regs); if (uart_err != E_NO_ERROR) { - // todo: indicate error? MXC_UART_AbortAsync(self->uart_regs); } } - - // If the timeout gets hit, abort and error out - if (uart_status[self->uart_id] != UART_FREE) { - MXC_UART_AbortAsync(self->uart_regs); - NVIC_DisableIRQ(MXC_UART_GET_IRQ(self->uart_id)); - mp_raise_RuntimeError(MP_ERROR_TEXT("Uart transaction timed out.")); - } // Check for errors from the callback - else if (uart_err != E_NO_ERROR) { - // todo: indicate error? + if (uart_err != E_NO_ERROR) { MXC_UART_AbortAsync(self->uart_regs); }