From d526f4a8c244c4e2ac816de86b88d1cb70692153 Mon Sep 17 00:00:00 2001 From: SamantazFox Date: Fri, 27 Dec 2024 16:43:17 +0100 Subject: [PATCH 01/12] canio: Add HAL for i.MX RT10xx chips --- ports/mimxrt10xx/common-hal/canio/CAN.c | 421 +++++++++++++++++++ ports/mimxrt10xx/common-hal/canio/CAN.h | 44 ++ ports/mimxrt10xx/common-hal/canio/Listener.c | 137 ++++++ ports/mimxrt10xx/common-hal/canio/Listener.h | 36 ++ ports/mimxrt10xx/common-hal/canio/__init__.c | 113 +++++ ports/mimxrt10xx/common-hal/canio/__init__.h | 76 ++++ 6 files changed, 827 insertions(+) create mode 100644 ports/mimxrt10xx/common-hal/canio/CAN.c create mode 100644 ports/mimxrt10xx/common-hal/canio/CAN.h create mode 100644 ports/mimxrt10xx/common-hal/canio/Listener.c create mode 100644 ports/mimxrt10xx/common-hal/canio/Listener.h create mode 100644 ports/mimxrt10xx/common-hal/canio/__init__.c create mode 100644 ports/mimxrt10xx/common-hal/canio/__init__.h diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.c b/ports/mimxrt10xx/common-hal/canio/CAN.c new file mode 100644 index 000000000000..3a3cade68be0 --- /dev/null +++ b/ports/mimxrt10xx/common-hal/canio/CAN.c @@ -0,0 +1,421 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 + +#include "py/runtime.h" +#include "py/mperrno.h" + +#include "common-hal/canio/CAN.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" +#include "supervisor/shared/tick.h" + +#include "sdk/drivers/flexcan/fsl_flexcan.h" + +static CAN_Type *const flexcan_bases[] = CAN_BASE_PTRS; // e.g.: { (CAN_Type *)0u, CAN1, CAN2, CAN3 } +static canio_can_obj_t *can_objs[MP_ARRAY_SIZE(mcu_can_banks)]; + +// Get frequency of flexcan clock. +#define MIMXRT10XX_FLEXCAN_CLK_FREQ ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (CLOCK_GetDiv(kCLOCK_CanDiv) + 1)) + +static void config_periph_pin(const mcu_periph_obj_t *periph) { + if (!periph) { + return; + } + IOMUXC_SetPinMux( + periph->pin->mux_reg, periph->mux_mode, + periph->input_reg, periph->input_idx, + 0, + 0); + + IOMUXC_SetPinConfig(0, 0, 0, 0, + periph->pin->cfg_reg, + IOMUXC_SW_PAD_CTL_PAD_PUS(0) // Pull Up/Down Config. Field: 100K Ohm Pull Down + #if IMXRT10XX + | IOMUXC_SW_PAD_CTL_PAD_HYS(0) // Hyst. Enable Field: Hysteresis Disabled + | IOMUXC_SW_PAD_CTL_PAD_PKE(1) // Pull/Keep Enable Field: Pull/Keeper Enabled + | IOMUXC_SW_PAD_CTL_PAD_SPEED(2) // Speed Field: medium (100MHz) + #endif + | IOMUXC_SW_PAD_CTL_PAD_PUE(0) // Pull/Keep Select Field: Keeper + | IOMUXC_SW_PAD_CTL_PAD_ODE(0) // Open Drain Enable Field: Open Drain Disabled + | IOMUXC_SW_PAD_CTL_PAD_DSE(6) // Drive Strength Field: R0/6 + | IOMUXC_SW_PAD_CTL_PAD_SRE(0)); // Slew Rate Field: Slow Slew Rate +} + +static uint8_t mimxrt10xx_flexcan_get_free_tx_mbid(canio_can_obj_t *self) { + // Get the next free tx message buffer atomically so that an interrupt can't occur while + // doing bit search. + // + // The idea here is that in an integer each bit acts as a boolean telling us if a + // tx message buffer is in use or not. + // If a free message buffer is found then we set it as used and return it's index. + bool found_free_tx_mb = false; + int8_t tx_array_id = 0; + mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + for ( ; tx_array_id < MIMXRT10XX_FLEXCAN_TX_MB_NUM ; ++tx_array_id) + { + uint64_t tx_array_id_bit = (1UL << tx_array_id); + if (!(self->data->tx_state & tx_array_id_bit)) + { + // Found a free tx array id. Mark it as used. + self->data->tx_state |= tx_array_id_bit; + found_free_tx_mb = true; + break; + } + } + MICROPY_END_ATOMIC_SECTION(atomic_state); + + if (!found_free_tx_mb) { + mp_raise_ValueError(MP_ERROR_TEXT("Unable to send CAN Message: all tx message buffer is busy")); + } + + return MIMXRT10XX_FLEXCAN_TX_ARRID_TO_MBID(tx_array_id); +} + +static void mimxrt10xx_flexcan_set_tx_mb_free_by_mbid(canio_can_obj_t *self, uint8_t mb_idx) +{ + // We simply set the Nth bit zero. This means that that message buffer is free to use. + uint64_t tx_array_id_bit = (1UL << MIMXRT10XX_FLEXCAN_TX_MBID_TO_ARRID(mb_idx)); + self->data->tx_state &= ~(tx_array_id_bit); +} + +static void mimxrt10xx_flexcan_set_tx_mb_busy_by_mbid(canio_can_obj_t *self, uint8_t mb_idx) +{ + // We simply set the Nth bit 1. This means that that message buffer is busy and cannot be used. + uint64_t tx_array_id_bit = (1UL << MIMXRT10XX_FLEXCAN_TX_MBID_TO_ARRID(mb_idx)); + self->data->tx_state |= tx_array_id_bit; +} + +static void mimxrt10xx_flexcan_abort_tx_frames(canio_can_obj_t *self) +{ + for (uint8_t tx_array_id = 0 ; tx_array_id < MIMXRT10XX_FLEXCAN_TX_MB_NUM ; ++tx_array_id) + { + uint64_t tx_array_id_bit = (1UL << tx_array_id); + if (self->data->tx_state & tx_array_id_bit) + { + // Found a used/busy tx message buffer. Abort it. + FLEXCAN_TransferAbortSend(self->data->base, &self->data->handle, MIMXRT10XX_FLEXCAN_TX_ARRID_TO_MBID(tx_array_id)); + + self->data->tx_state &= ~(tx_array_id_bit); // Mark tx message buffer as free. + } + } +} + +static void mimxrt10xx_flexcan_handle_error(canio_can_obj_t *self) { + canio_bus_state_t state = common_hal_canio_can_state_get(self); + if (state == BUS_STATE_OFF) + { + // Abort any pending tx and rx in case of bus-off. + mimxrt10xx_flexcan_abort_tx_frames(self); + FLEXCAN_TransferAbortReceiveFifo(self->data->base, &self->data->handle); + } +} + +static void mimxrt10xx_flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *selfPtr) +{ + (void) base; // unused variable + (void) handle; // unused variable + // The result field can either be a message buffer index or a status flags value. + + canio_can_obj_t *self = (canio_can_obj_t*) selfPtr; + + switch (status) { + + // Process rx message buffer is idle event. + case kStatus_FLEXCAN_RxIdle: + // We don't control any rx message buffers 'manually'. The rx fifo has control. + break; + + // Process tx message buffer is idle event. + case kStatus_FLEXCAN_TxIdle: + mimxrt10xx_flexcan_set_tx_mb_free_by_mbid(self, result); + break; + + // Process tx message buffer is busy event. + case kStatus_FLEXCAN_TxBusy: + mimxrt10xx_flexcan_set_tx_mb_busy_by_mbid(self, result); + break; + + // Process remote message is send out and message buffer changed to receive one event. + case kStatus_FLEXCAN_TxSwitchToRx: + mimxrt10xx_flexcan_set_tx_mb_free_by_mbid(self, result); + break; + + // Process rx message buffer is busy event. + case kStatus_FLEXCAN_RxBusy: + break; + + // Process rx message buffer is overflowed event. + case kStatus_FLEXCAN_RxOverflow: + break; + + // Process rx message fifo is busy event. + case kStatus_FLEXCAN_RxFifoBusy: + break; + + // Process rx message fifo is idle event. + case kStatus_FLEXCAN_RxFifoIdle: + break; + + // Process rx message fifo is overflowed event. + case kStatus_FLEXCAN_RxFifoOverflow: + break; + + // Process rx message fifo is almost overflowed event. + case kStatus_FLEXCAN_RxFifoWarning: + break; + + // Process rx message fifo is disabled during reading event. + case kStatus_FLEXCAN_RxFifoDisabled: + break; + + // Process FlexCAN is waken up from stop mode event. + case kStatus_FLEXCAN_WakeUp: + break; + + // Process unhandled interrupt asserted event. + case kStatus_FLEXCAN_UnHandled: + // Process FlexCAN module error and status event. + case kStatus_FLEXCAN_ErrorStatus: + // We could do some fancy statistics update, but canio does not have. + mimxrt10xx_flexcan_handle_error(self); + break; + } +} + +void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) { + + int instance = -1; + const mcu_periph_obj_t *rx_periph = find_pin_function(mcu_can_rx_list, rx, &instance, MP_QSTR_rx); + const mcu_periph_obj_t *tx_periph = find_pin_function(mcu_can_tx_list, tx, &instance, MP_QSTR_tx); + + // mp_printf(&mp_plat_print, "can instance: %d\n", instance); + // mp_printf(&mp_plat_print, "can loopback: %d\n", loopback ? 1 : 0); + // mp_printf(&mp_plat_print, "can silent: %d\n", silent ? 1 : 0); + // mp_printf(&mp_plat_print, "can baudrate: %d\n", baudrate); + + self->rx_pin = rx; + self->tx_pin = tx; + config_periph_pin(rx_periph); + config_periph_pin(tx_periph); + + self->loopback = loopback; + self->silent = silent; + self->baudrate = baudrate; + + self->data = m_new_obj(mimxrt10xx_flexcan_data_t); + self->data->base = flexcan_bases[instance]; // 'flexcan_bases' start indexing from 1. (The first element is NULL) + self->data->tx_state = 0; + + // Get flexcan module default configuration. + flexcan_config_t config; + FLEXCAN_GetDefaultConfig(&config); + + // Change default flexcan module configuration based on canio constructor parameters. + config.clkSrc = CLOCK_GetMux(kCLOCK_CanMux); + config.baudRate = baudrate; + config.enableLoopBack = loopback; + config.enableListenOnlyMode = silent; + config.maxMbNum = 64; + config.enableIndividMask = true; + // config.disableSelfReception = true; // TODO: do we want to disable this? + + #if (defined(MIMXRT10XX_FLEXCAN_USE_IMPROVED_TIMING_CONFIG) && MIMXRT10XX_FLEXCAN_USE_IMPROVED_TIMING_CONFIG) + // If improved timing configuration is enabled then tell the SDK to calculate it. + flexcan_timing_config_t timing_config; + memset(&timing_config, 0, sizeof(flexcan_timing_config_t)); + if (FLEXCAN_CalculateImprovedTimingValues(self->data->base, config.baudRate, MIMXRT10XX_FLEXCAN_CLK_FREQ, &timing_config)) + { + // SDK could calculate the improved timing configuration. Yay! + // Let's update our flexcan module config to use it. + memcpy(&(config.timingConfig), &timing_config, sizeof(flexcan_timing_config_t)); + } + #endif + + // Initialize the flexcan module with user-defined settings. + FLEXCAN_Init(self->data->base, &config, MIMXRT10XX_FLEXCAN_CLK_FREQ); + + // Create FlexCAN handle structure and set call back function. + // As callback data we set 'self'. In callback we can cast it back to 'canio_can_obj_t'. + FLEXCAN_TransferCreateHandle(self->data->base, &self->data->handle, mimxrt10xx_flexcan_callback, (void*)self); + + // Set rx mask to don't care on all bits. + FLEXCAN_SetRxMbGlobalMask(self->data->base, FLEXCAN_RX_MB_EXT_MASK(0x00, 0, 0)); + FLEXCAN_SetRxFifoGlobalMask(self->data->base, FLEXCAN_RX_MB_EXT_MASK(0x00, 0, 0)); + + flexcan_rx_fifo_config_t fifo_config; + fifo_config.idFilterNum = 0; + fifo_config.idFilterTable = self->data->rx_fifo_filter; + fifo_config.idFilterType = kFLEXCAN_RxFifoFilterTypeA; + fifo_config.priority = kFLEXCAN_RxFifoPrioHigh; + FLEXCAN_SetRxFifoConfig(self->data->base, &fifo_config, true); + + claim_pin(rx); + claim_pin(tx); + + can_objs[instance] = self; +} + +bool common_hal_canio_can_loopback_get(canio_can_obj_t *self) { + return self->loopback; +} + +int common_hal_canio_can_baudrate_get(canio_can_obj_t *self) { + return self->baudrate; +} + +int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self) { + uint8_t tx_err_cnt; // Transmit error counter. + FLEXCAN_GetBusErrCount(self->data->base, &tx_err_cnt, NULL); + return tx_err_cnt; +} + +int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self) { + uint8_t rx_err_cnt; // Transmit error counter. + FLEXCAN_GetBusErrCount(self->data->base, NULL, &rx_err_cnt); + return rx_err_cnt; +} + +canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) { + uint64_t status_flags = FLEXCAN_GetStatusFlags(self->data->base); + if ((status_flags & CAN_ESR1_FLTCONF(2)) != 0U) { + return BUS_STATE_OFF; + } + if ((status_flags & CAN_ESR1_FLTCONF(1)) != 0U) { + return BUS_STATE_ERROR_PASSIVE; + } + if ((status_flags & (kFLEXCAN_TxErrorWarningFlag | kFLEXCAN_RxErrorWarningFlag)) != 0) { + return BUS_STATE_ERROR_WARNING; + } + return BUS_STATE_ERROR_ACTIVE; +} + +void common_hal_canio_can_restart(canio_can_obj_t *self) { + // Supposedly the felxcan SDK has built in recovery. + // But I will leave this code here just in case. + + canio_bus_state_t state = common_hal_canio_can_state_get(self); + if (state != BUS_STATE_OFF) return; + + self->data->base->CTRL1 &= ~CAN_CTRL1_BOFFREC_MASK; + + // Hard coded wait time for bus to recover. + uint64_t deadline = supervisor_ticks_ms64() + 100; // 100ms timeout + do { + if (supervisor_ticks_ms64() > deadline) { + break; + } + RUN_BACKGROUND_TASKS; + } while (common_hal_canio_can_state_get(self) == BUS_STATE_OFF); + + self->data->base->CTRL1 |= CAN_CTRL1_BOFFREC_MASK; +} + +bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) { + return self->auto_restart; +} + +void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) { + self->auto_restart = value; +} + +static void maybe_auto_restart(canio_can_obj_t *self) { + if (self->auto_restart) { + common_hal_canio_can_restart(self); + } +} + +void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message_in) { + maybe_auto_restart(self); + + canio_bus_state_t state = common_hal_canio_can_state_get(self); + if (state == BUS_STATE_OFF) + { + // Bus is off. Transmit failed. + mp_raise_OSError(MP_ENODEV); + } + + canio_message_obj_t *message = message_in; + flexcan_frame_t tx_frame; + if (!mimxrt_canio_message_obj_to_flexcan_frame(message, &tx_frame)) { + mp_raise_ValueError(MP_ERROR_TEXT("Unable to send CAN Message: missing or malformed canio message object")); + } + + flexcan_mb_transfer_t tx_xfer; + tx_xfer.mbIdx = mimxrt10xx_flexcan_get_free_tx_mbid(self); + tx_xfer.frame = &tx_frame; + + // Setup tx message buffer. + FLEXCAN_SetTxMbConfig(self->data->base, tx_xfer.mbIdx, true); + + if (FLEXCAN_TransferSendNonBlocking(self->data->base, &self->data->handle, &tx_xfer) != kStatus_Success) { + mp_raise_OSError(MP_EIO); + } +} + +bool common_hal_canio_can_silent_get(canio_can_obj_t *self) { + return self->silent; +} + +bool common_hal_canio_can_deinited(canio_can_obj_t *self) { + return !self->data; +} + +void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) { + if (common_hal_canio_can_deinited(self)) { + raise_deinited_error(); + } +} + +void common_hal_canio_can_deinit(canio_can_obj_t *self) { + if (self->data) { + mimxrt10xx_flexcan_abort_tx_frames(self); + FLEXCAN_TransferAbortReceiveFifo(self->data->base, &self->data->handle); + + FLEXCAN_Deinit(self->data->base); + + // Free can data by doing nothing and letting gc take care of it. + // If the VM has finished already, this will be safe. + self->data = NULL; + } + + common_hal_reset_pin(self->rx_pin); + common_hal_reset_pin(self->tx_pin); + + self->rx_pin = NULL; + self->tx_pin = NULL; +} + +void common_hal_canio_reset(void) { + for (size_t i = 0; i < MP_ARRAY_SIZE(can_objs); i++) { + if (can_objs[i]) { + common_hal_canio_can_deinit(can_objs[i]); + can_objs[i] = NULL; + } + } +} diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.h b/ports/mimxrt10xx/common-hal/canio/CAN.h new file mode 100644 index 000000000000..1bf3ab6bcf4b --- /dev/null +++ b/ports/mimxrt10xx/common-hal/canio/CAN.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/canio/__init__.h" +#include "shared-bindings/canio/CAN.h" +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/canio/__init__.h" + +typedef struct canio_can_obj { + mp_obj_base_t base; + mimxrt10xx_flexcan_data_t* data; + int baudrate; + const mcu_pin_obj_t *rx_pin; + const mcu_pin_obj_t *tx_pin; + bool loopback : 1; + bool silent : 1; + bool auto_restart : 1; +} canio_can_obj_t; diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.c b/ports/mimxrt10xx/common-hal/canio/Listener.c new file mode 100644 index 000000000000..b04376a97ee1 --- /dev/null +++ b/ports/mimxrt10xx/common-hal/canio/Listener.c @@ -0,0 +1,137 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mperrno.h" + +#include "shared/runtime/interrupt_char.h" + +#include "common-hal/canio/__init__.h" +#include "common-hal/canio/Listener.h" +#include "shared-bindings/canio/Listener.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/tick.h" +#include "sdk/drivers/flexcan/fsl_flexcan.h" + +/* +typedef struct { + mp_obj_base_t base; + int id; + int mask; + bool extended; +} canio_match_obj_t; +*/ + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { + + common_hal_canio_listener_set_timeout(self, timeout); + + if (nmatch > MIMXRT10XX_FLEXCAN_RX_FILTER_COUNT) { + mp_raise_ValueError(MP_ERROR_TEXT("Filters too complex")); + } + + self->can = can; + + for (size_t i = 0; i < nmatch; i++) { + if (matches[i]->extended) { + self->can->data->rx_fifo_filter[i] = FLEXCAN_RX_FIFO_STD_FILTER_TYPE_A(matches[i]->id, 0, 1); + } else { + self->can->data->rx_fifo_filter[i] = FLEXCAN_RX_FIFO_STD_FILTER_TYPE_A(matches[i]->id, 0, 0); + } + } + + flexcan_rx_fifo_config_t fifo_config; + fifo_config.idFilterNum = nmatch; + fifo_config.idFilterTable = self->can->data->rx_fifo_filter; + fifo_config.idFilterType = kFLEXCAN_RxFifoFilterTypeA; + fifo_config.priority = kFLEXCAN_RxFifoPrioHigh; + FLEXCAN_SetRxFifoConfig(self->can->data->base, &fifo_config, true); +} + +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) { + self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); +} + +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) { + return self->timeout_ms / 1000.0f; +} + +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { + if (!self->can) { + raise_deinited_error(); + } + common_hal_canio_can_check_for_deinit(self->can); +} + +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { + if(FLEXCAN_GetMbStatusFlags(self->can->data->base, kFLEXCAN_RxFifoFrameAvlFlag)) return 1; + return 0; +} + +mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self) { + if (!common_hal_canio_listener_in_waiting(self)) { + uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; + do { + if (supervisor_ticks_ms64() > deadline) { + return NULL; + } + RUN_BACKGROUND_TASKS; + // Allow user to break out of a timeout with a KeyboardInterrupt. + if (mp_hal_is_interrupted()) { + return NULL; + } + } while (!common_hal_canio_listener_in_waiting(self)); + } + + flexcan_frame_t rx_frame; + if(FLEXCAN_ReadRxFifo(self->can->data->base, &rx_frame) != kStatus_Success) { + mp_raise_OSError(MP_EIO); + } + + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); + if (!mimxrt_flexcan_frame_to_canio_message_obj(&rx_frame, message)) { + mp_raise_ValueError(MP_ERROR_TEXT("Unable to receive CAN Message: missing or malformed flexcan frame")); + } + + return message; +} + +void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { + if (self->can) { + // Clear all filters. + flexcan_rx_fifo_config_t fifo_config; + fifo_config.idFilterNum = 0; + fifo_config.idFilterTable = self->can->data->rx_fifo_filter; + fifo_config.idFilterType = kFLEXCAN_RxFifoFilterTypeA; + fifo_config.priority = kFLEXCAN_RxFifoPrioHigh; + FLEXCAN_SetRxFifoConfig(self->can->data->base, &fifo_config, true); + } + self->can = NULL; +} diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.h b/ports/mimxrt10xx/common-hal/canio/Listener.h new file mode 100644 index 000000000000..23a00f9f1db4 --- /dev/null +++ b/ports/mimxrt10xx/common-hal/canio/Listener.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "common-hal/canio/CAN.h" +#include "shared-module/canio/Match.h" + +typedef struct canio_listener_obj { + mp_obj_base_t base; + canio_can_obj_t *can; + uint32_t timeout_ms; +} canio_listener_obj_t; diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.c b/ports/mimxrt10xx/common-hal/canio/__init__.c new file mode 100644 index 000000000000..4b75d0969a5f --- /dev/null +++ b/ports/mimxrt10xx/common-hal/canio/__init__.c @@ -0,0 +1,113 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 "common-hal/canio/__init__.h" +#include "shared-bindings/canio/RemoteTransmissionRequest.h" + +typedef union +{ + uint32_t word; + uint8_t bytes[4]; +} mimxrt_word_bytes_t; + +// Convert from back from FLEXCAN IDs to normal CAN IDs. +#define FLEXCAN_ID_TO_CAN_ID_STD(id) \ + ((uint32_t)((((uint32_t)(id)) & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT)) + +#define FLEXCAN_ID_TO_CAN_ID_EXT(id) \ + ((uint32_t)((((uint32_t)(id)) & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK)) \ + >> CAN_ID_EXT_SHIFT)) + +bool mimxrt_canio_message_obj_to_flexcan_frame(canio_message_obj_t *src, flexcan_frame_t *dst) +{ + memset(dst, 0, sizeof(*dst)); // Zero out output. + if (src == NULL) return false; // Missing input. + + if (src->extended) { // CAN Frame Identifier (STD or EXT format). + dst->id = FLEXCAN_ID_EXT(src->id); // CAN Frame Identifier (EXT). + dst->format = kFLEXCAN_FrameFormatExtend; + } else { + dst->id = FLEXCAN_ID_STD(src->id); // CAN Frame Identifier (STD). + dst->format = kFLEXCAN_FrameFormatStandard; + } + + bool rtr = src->base.type == &canio_remote_transmission_request_type; + if (rtr) { // CAN Frame Type(DATA or REMOTE). + dst->type = kFLEXCAN_FrameTypeRemote; + } else { + dst->type = kFLEXCAN_FrameTypeData; + } + + dst->length = src->size; // CAN frame data length in bytes (Range: 0~8). + mimxrt_word_bytes_t mixVal; + mixVal.bytes[0] = src->data[0]; + mixVal.bytes[1] = src->data[1]; + mixVal.bytes[2] = src->data[2]; + mixVal.bytes[3] = src->data[3]; + dst->dataWord0 = mixVal.word; // CAN Frame payload word0. + mixVal.bytes[0] = src->data[4]; + mixVal.bytes[1] = src->data[5]; + mixVal.bytes[2] = src->data[6]; + mixVal.bytes[3] = src->data[7]; + dst->dataWord1 = mixVal.word; // CAN Frame payload word1. + + return true; +} + +bool mimxrt_flexcan_frame_to_canio_message_obj(flexcan_frame_t *src, canio_message_obj_t *dst) +{ + memset(dst, 0, sizeof(*dst)); // Zero out output. + if (src == NULL) return false; // Missing input. + + if (src->format == kFLEXCAN_FrameFormatExtend) { // CAN Frame Identifier (STD or EXT format). + dst->extended = true; + dst->id = FLEXCAN_ID_TO_CAN_ID_EXT(src->id); // CAN Frame Identifier (EXT). + } else { + dst->extended = false; + dst->id = FLEXCAN_ID_TO_CAN_ID_STD(src->id); // CAN Frame Identifier (STD). + } + + if (src->type == kFLEXCAN_FrameTypeRemote) { // CAN Frame Type(DATA or REMOTE). + dst->base.type = &canio_remote_transmission_request_type; + } else { + dst->base.type = &canio_message_type; + } + + dst->size = src->length; // CAN frame data length in bytes (Range: 0~8). + mimxrt_word_bytes_t mixVal; + mixVal.word = src->dataWord0; // CAN Frame payload word0. + dst->data[0] = mixVal.bytes[0]; + dst->data[1] = mixVal.bytes[1]; + dst->data[2] = mixVal.bytes[2]; + dst->data[3] = mixVal.bytes[3]; + mixVal.word = src->dataWord1; // CAN Frame payload word1. + dst->data[4] = mixVal.bytes[0]; + dst->data[5] = mixVal.bytes[1]; + dst->data[6] = mixVal.bytes[2]; + dst->data[7] = mixVal.bytes[3]; + + return true; +} diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.h b/ports/mimxrt10xx/common-hal/canio/__init__.h new file mode 100644 index 000000000000..4a2daa647c28 --- /dev/null +++ b/ports/mimxrt10xx/common-hal/canio/__init__.h @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "shared-module/canio/Message.h" +#include "sdk/drivers/flexcan/fsl_flexcan.h" + +typedef struct canio_listener canio_listener_t; +typedef struct canio_can canio_can_t; +typedef uint32_t canio_can_filter_t; + +// There are 64 message buffers in each mimxrt10xx chip. +// Rx fifo will use the message buffers at the front (from index zero). +// As far as I can see rx fifo uses message buffer 0 to 5. +// Also id filter table might occupy message buffer memory area 6 to 37. +// +// Let's use the last few message buffers for sending. +// +// We use 8 (tx) message buffers in total. +// This makes tracking the state (free/busy) of each (tx) message buffer easy. +// We can use a single byte, where each bit represent the state. +// Zero means the message buffer can be used for sending. +// One means the message buffer is busy sending. +// If you make this larger then you have to change the type of 'tx_state' in struct 'mimxrt10xx_flexcan_data_t'. +#define MIMXRT10XX_FLEXCAN_TX_MB_NUM (8) + +// For safety we use SDK provided macro to get the last message buffer index instead of hard coding it. +#define MIMXRT10XX_FLEXCAN_TX_MBID_MAX (FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(0)) +#define MIMXRT10XX_FLEXCAN_TX_MBID_MIN (MIMXRT10XX_FLEXCAN_TX_MBID_MAX - MIMXRT10XX_FLEXCAN_TX_MB_NUM) + +// Convert from tx message buffer index to frame array index. +#define MIMXRT10XX_FLEXCAN_TX_MBID_TO_ARRID(x) (x - MIMXRT10XX_FLEXCAN_TX_MBID_MIN) + +// Convert from frame array index to tx message buffer index. +#define MIMXRT10XX_FLEXCAN_TX_ARRID_TO_MBID(x) (x + MIMXRT10XX_FLEXCAN_TX_MBID_MIN) + +// Limits the Canio module's Listener filter complexity. +#define MIMXRT10XX_FLEXCAN_RX_FILTER_COUNT (8) + +// Enables/disables SDK calculated "improved" timing configuration. +#define MIMXRT10XX_FLEXCAN_USE_IMPROVED_TIMING_CONFIG (1) + +typedef struct { + CAN_Type *base; // FlexCAN peripheral base address. + flexcan_handle_t handle; // FlexCAN handle which can be used for FlexCAN transactional APIs. + uint8_t tx_state; + uint32_t rx_fifo_filter[MIMXRT10XX_FLEXCAN_RX_FILTER_COUNT]; +} mimxrt10xx_flexcan_data_t; + +bool mimxrt_canio_message_obj_to_flexcan_frame(canio_message_obj_t *src, flexcan_frame_t *dst); +bool mimxrt_flexcan_frame_to_canio_message_obj(flexcan_frame_t *src, canio_message_obj_t *dst); + From 1a9b7e5d5b769aef8b1871e86f1a2dd5998d6064 Mon Sep 17 00:00:00 2001 From: SamantazFox Date: Fri, 27 Dec 2024 16:44:33 +0100 Subject: [PATCH 02/12] canio: Add support to teensy 4.1 board --- ports/mimxrt10xx/Makefile | 1 + .../boards/teensy41/mpconfigboard.mk | 1 + ports/mimxrt10xx/boards/teensy41/pins.c | 18 ++++++++++ .../mimxrt10xx/MIMXRT1062/clocks.c | 4 +-- .../mimxrt10xx/MIMXRT1062/periph.c | 34 +++++++++++++++++++ .../mimxrt10xx/MIMXRT1062/periph.h | 4 +++ .../mimxrt10xx/tools/gen_peripherals_data.py | 25 ++++++++++++++ 7 files changed, 85 insertions(+), 2 deletions(-) diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index f13207451e6c..072a3df3509a 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -120,6 +120,7 @@ SRC_SDK := \ drivers/snvs_hp/fsl_snvs_hp.c \ drivers/snvs_lp/fsl_snvs_lp.c \ drivers/trng/fsl_trng.c \ + drivers/flexcan/fsl_flexcan.c \ ifeq ($(CIRCUITPY_ANALOGIO), 1) SRC_SDK += drivers/adc_12b1msps_sar/fsl_adc.c \ diff --git a/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk b/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk index 7d16b797c522..6d1f802d6e35 100644 --- a/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk +++ b/ports/mimxrt10xx/boards/teensy41/mpconfigboard.mk @@ -7,5 +7,6 @@ CHIP_VARIANT = MIMXRT1062DVJ6A CHIP_FAMILY = MIMXRT1062 FLASH = W25Q64JV CIRCUITPY__EVE = 1 +CIRCUITPY_CANIO = 1 CIRCUITPY_USB_HOST = 1 CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY = 1 diff --git a/ports/mimxrt10xx/boards/teensy41/pins.c b/ports/mimxrt10xx/boards/teensy41/pins.c index 64eac9e4b70c..84236382330d 100644 --- a/ports/mimxrt10xx/boards/teensy41/pins.c +++ b/ports/mimxrt10xx/boards/teensy41/pins.c @@ -179,5 +179,23 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { {MP_OBJ_NEW_QSTR(MP_QSTR_TX7), MP_ROM_PTR(&pin_GPIO_EMC_31)}, {MP_OBJ_NEW_QSTR(MP_QSTR_RX8), MP_ROM_PTR(&pin_GPIO_B1_13)}, {MP_OBJ_NEW_QSTR(MP_QSTR_TX8), MP_ROM_PTR(&pin_GPIO_B1_12)}, + + // CAN and CAN-FD + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN1_RX), MP_ROM_PTR(&pin_GPIO_AD_B1_09)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN1_TX), MP_ROM_PTR(&pin_GPIO_AD_B1_08)}, + + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN2_RX), MP_ROM_PTR(&pin_GPIO_AD_B0_03)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN2_TX), MP_ROM_PTR(&pin_GPIO_AD_B0_02)}, + + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN3_RX), MP_ROM_PTR(&pin_GPIO_EMC_37)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN3_TX), MP_ROM_PTR(&pin_GPIO_EMC_36)}, + + // "CAN" is an alias for CAN1 + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_GPIO_AD_B1_09)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_GPIO_AD_B1_08)}, + + // "CANFD" is an alias for CAN3 + {MP_OBJ_NEW_QSTR(MP_QSTR_CANFD_RX), MP_ROM_PTR(&pin_GPIO_EMC_37)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_CANFD_TX), MP_ROM_PTR(&pin_GPIO_EMC_36)}, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/clocks.c b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/clocks.c index 9385c9cc4c71..86ae09f7ca02 100644 --- a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/clocks.c +++ b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/clocks.c @@ -167,9 +167,9 @@ void clocks_init(void) { CLOCK_DisableClock(kCLOCK_Can2S); CLOCK_DisableClock(kCLOCK_Can3S); /* Set CAN_CLK_PODF. */ - CLOCK_SetDiv(kCLOCK_CanDiv, 1); + CLOCK_SetDiv(kCLOCK_CanDiv, 2); // Clock divider for master flexcan clock source /* Set Can clock source. */ - CLOCK_SetMux(kCLOCK_CanMux, 2); + CLOCK_SetMux(kCLOCK_CanMux, 0); // Select 60M clock divided by USB1 PLL (480 MHz) as master flexcan clock source /* Disable UART clock gate. */ CLOCK_DisableClock(kCLOCK_Lpuart1); CLOCK_DisableClock(kCLOCK_Lpuart2); diff --git a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.c b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.c index 4d5e909bede0..cc19dc137b6a 100644 --- a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.c +++ b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.c @@ -276,6 +276,40 @@ const mcu_periph_obj_t mcu_mqs_right_list[3] = { PERIPH_PIN(3, 2, 0, 0, &pin_GPIO_B0_00), }; +CAN_Type *const mcu_can_banks[3] = { CAN1, CAN2, CAN3 }; + +const mcu_periph_obj_t mcu_can_rx_list[11] = { + PERIPH_PIN(1, 4, kIOMUXC_FLEXCAN1_RX_SELECT_INPUT, 0, &pin_GPIO_SD_B1_03), + PERIPH_PIN(1, 3, kIOMUXC_FLEXCAN1_RX_SELECT_INPUT, 1, &pin_GPIO_EMC_18), + PERIPH_PIN(1, 2, kIOMUXC_FLEXCAN1_RX_SELECT_INPUT, 2, &pin_GPIO_AD_B1_09), + PERIPH_PIN(1, 2, kIOMUXC_FLEXCAN1_RX_SELECT_INPUT, 3, &pin_GPIO_B0_03), + + PERIPH_PIN(2, 3, kIOMUXC_FLEXCAN2_RX_SELECT_INPUT, 0, &pin_GPIO_EMC_10), + PERIPH_PIN(2, 0, kIOMUXC_FLEXCAN2_RX_SELECT_INPUT, 1, &pin_GPIO_AD_B0_03), + PERIPH_PIN(2, 6, kIOMUXC_FLEXCAN2_RX_SELECT_INPUT, 2, &pin_GPIO_AD_B0_15), + PERIPH_PIN(2, 6, kIOMUXC_FLEXCAN2_RX_SELECT_INPUT, 3, &pin_GPIO_B1_09), + + PERIPH_PIN(3, 9, 0, 0, &pin_GPIO_EMC_37), + PERIPH_PIN(3, 8, 0, 0, &pin_GPIO_AD_B0_11), + PERIPH_PIN(3, 8, 0, 0, &pin_GPIO_AD_B0_15), +}; + +const mcu_periph_obj_t mcu_can_tx_list[11] = { + PERIPH_PIN(1, 3, 0, 0, &pin_GPIO_EMC_17), + PERIPH_PIN(1, 2, 0, 0, &pin_GPIO_AD_B1_08), + PERIPH_PIN(1, 2, 0, 0, &pin_GPIO_B0_02), + PERIPH_PIN(1, 4, 0, 0, &pin_GPIO_SD_B1_02), + + PERIPH_PIN(2, 3, 0, 0, &pin_GPIO_EMC_09), + PERIPH_PIN(2, 0, 0, 0, &pin_GPIO_AD_B0_02), + PERIPH_PIN(2, 6, 0, 0, &pin_GPIO_AD_B0_14), + PERIPH_PIN(2, 6, 0, 0, &pin_GPIO_B1_08), + + PERIPH_PIN(3, 9, 0, 0, &pin_GPIO_EMC_36), + PERIPH_PIN(3, 8, 0, 0, &pin_GPIO_AD_B0_10), + PERIPH_PIN(3, 8, 0, 0, &pin_GPIO_AD_B0_14), +}; + const mcu_pwm_obj_t mcu_pwm_list[67] = { PWM_PIN(PWM1, kPWM_Module_0, kPWM_PwmA, IOMUXC_GPIO_EMC_23_FLEXPWM1_PWMA00, &pin_GPIO_EMC_23), PWM_PIN(PWM1, kPWM_Module_0, kPWM_PwmA, IOMUXC_GPIO_SD_B0_00_FLEXPWM1_PWMA00, &pin_GPIO_SD_B0_00), diff --git a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.h b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.h index ab1355ae55a5..9c41e563c482 100644 --- a/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.h +++ b/ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/periph.h @@ -41,4 +41,8 @@ extern const mcu_periph_obj_t mcu_i2s_mclk_list[7]; extern const mcu_periph_obj_t mcu_mqs_left_list[3]; extern const mcu_periph_obj_t mcu_mqs_right_list[3]; +extern CAN_Type *const mcu_can_banks[3]; +extern const mcu_periph_obj_t mcu_can_rx_list[11]; +extern const mcu_periph_obj_t mcu_can_tx_list[11]; + extern const mcu_pwm_obj_t mcu_pwm_list[67]; diff --git a/ports/mimxrt10xx/tools/gen_peripherals_data.py b/ports/mimxrt10xx/tools/gen_peripherals_data.py index e255ed844a5e..1d8fa5cd7181 100644 --- a/ports/mimxrt10xx/tools/gen_peripherals_data.py +++ b/ports/mimxrt10xx/tools/gen_peripherals_data.py @@ -1,4 +1,5 @@ import sys +import re import pathlib import xml.etree.ElementTree as ET @@ -8,6 +9,7 @@ "LPUART": ["RX", "TX", "RTS", "CTS"], "I2S": ["RX_DATA0", "RX_SYNC", "TX_BCLK", "TX_DATA0", "TX_SYNC", "MCLK"], "MQS": ["LEFT", "RIGHT"], + "CAN": ["RX", "TX"], } SIGNAL_RENAME = { @@ -21,6 +23,22 @@ "RX_DATA": "RX_DATA0", } +INSTANCE_RENAME = { + "FLEXCAN" : "CAN" +} + +INSTANCE_RE = re.compile("([a-zA-Z0-9]+?)([0-9]+)$") +def rename_instance(instance:str)-> str: + instance_match = INSTANCE_RE.match(instance) + if instance_match is None: + return instance + instance_res = instance_match.groups() + if len(instance_res) < 2: + return instance + instance_name = str(instance_res[0]) + instance_id = str(instance_res[1]) + return INSTANCE_RENAME.get(instance_name, instance_name) + instance_id + SKIP_LPSR = True svd_folder = pathlib.Path(sys.argv[1]) @@ -54,6 +72,7 @@ print(device) autogen_warning = autogen_warning_template.format(device) svd_fn = svd_folder / device / (device + ".xml") + if not svd_fn.exists(): svd_fn = svd_folder / device / (device + "_cm7.xml") @@ -144,8 +163,10 @@ if name.endswith("SELECT_INPUT"): name_split = name.split("_") instance = name_split[0] + instance = rename_instance(instance) signal = "_".join(name_split[1:-2]) signal = SIGNAL_RENAME.get(signal, signal) + if instance not in peripheral_inputs: peripheral_inputs[instance] = {} if signal not in peripheral_inputs[instance]: @@ -161,6 +182,7 @@ continue alt = int(alt[3:]) value = int(evalue.find("value").text, 0) + #print(f"instance: {instance}, signal: {signal}, pin_name: {pin_name}") peripheral_inputs[instance][signal][pin_name] = [alt, name, value] # Mux registers come before PAD registers. elif name.startswith("SW_MUX_CTL_PAD_GPIO"): @@ -232,6 +254,7 @@ print("skipping", pin_name, connection) continue instance, signal = connection.split("_", maxsplit=1) + instance = rename_instance(instance) signal = SIGNAL_RENAME.get(signal, signal) if instance not in peripheral_inputs: peripheral_inputs[instance] = {} @@ -288,6 +311,7 @@ short_name = ptype.lower() if short_name.startswith("lp"): short_name = short_name[2:] + # Only one MQS exists and it is related to SAI3 if ptype != "MQS": periph_h.append( @@ -301,6 +325,7 @@ for signal in SIGNALS[ptype]: pin_count = 0 for instance in instances: + ###print(f"instance: {instance}") if instance not in peripheral_inputs or signal not in peripheral_inputs[instance]: continue pin_count += len(peripheral_inputs[instance][signal]) From 3483d73c13c5d51cde3212bc9fd7c71ecd4382df Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Fri, 17 Jan 2025 11:04:31 +0100 Subject: [PATCH 03/12] canio: mimxrt10xx: Add some debug code --- ports/mimxrt10xx/common-hal/canio/CAN.c | 33 ++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.c b/ports/mimxrt10xx/common-hal/canio/CAN.c index 3a3cade68be0..6c17752d228b 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.c +++ b/ports/mimxrt10xx/common-hal/canio/CAN.c @@ -37,6 +37,15 @@ #include "sdk/drivers/flexcan/fsl_flexcan.h" + +// Be verbose +#define MIMXRT_CANIO_CAN_DEBUG(...) (void)0 +//#define MIMXRT_CANIO_CAN_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) + +#define MIMXRT_CANIO_CAN_CALLBACK_DEBUG(...) (void)0 +//#define MIMXRT_CANIO_CAN_CALLBACK_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) + + static CAN_Type *const flexcan_bases[] = CAN_BASE_PTRS; // e.g.: { (CAN_Type *)0u, CAN1, CAN2, CAN3 } static canio_can_obj_t *can_objs[MP_ARRAY_SIZE(mcu_can_banks)]; @@ -83,6 +92,7 @@ static uint8_t mimxrt10xx_flexcan_get_free_tx_mbid(canio_can_obj_t *self) { if (!(self->data->tx_state & tx_array_id_bit)) { // Found a free tx array id. Mark it as used. + MIMXRT_CANIO_CAN_DEBUG("canio: Found free Tx MB: %d\n", tx_array_id); self->data->tx_state |= tx_array_id_bit; found_free_tx_mb = true; break; @@ -148,60 +158,75 @@ static void mimxrt10xx_flexcan_callback(CAN_Type *base, flexcan_handle_t *handle // Process rx message buffer is idle event. case kStatus_FLEXCAN_RxIdle: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxIdle\n"); // We don't control any rx message buffers 'manually'. The rx fifo has control. break; // Process tx message buffer is idle event. case kStatus_FLEXCAN_TxIdle: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = TxIdle\n"); mimxrt10xx_flexcan_set_tx_mb_free_by_mbid(self, result); break; // Process tx message buffer is busy event. case kStatus_FLEXCAN_TxBusy: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = TxBusy\n"); mimxrt10xx_flexcan_set_tx_mb_busy_by_mbid(self, result); break; // Process remote message is send out and message buffer changed to receive one event. case kStatus_FLEXCAN_TxSwitchToRx: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = TxSwitchToRx\n"); mimxrt10xx_flexcan_set_tx_mb_free_by_mbid(self, result); break; // Process rx message buffer is busy event. case kStatus_FLEXCAN_RxBusy: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxBusy\n"); break; // Process rx message buffer is overflowed event. case kStatus_FLEXCAN_RxOverflow: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxOverflow\n"); break; // Process rx message fifo is busy event. case kStatus_FLEXCAN_RxFifoBusy: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxFifoBusy\n"); break; // Process rx message fifo is idle event. case kStatus_FLEXCAN_RxFifoIdle: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxFifoIdle\n"); break; // Process rx message fifo is overflowed event. case kStatus_FLEXCAN_RxFifoOverflow: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxFifoOverflow\n"); break; // Process rx message fifo is almost overflowed event. case kStatus_FLEXCAN_RxFifoWarning: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxFifoWarning\n"); break; // Process rx message fifo is disabled during reading event. case kStatus_FLEXCAN_RxFifoDisabled: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = RxFifoDisabled\n"); break; // Process FlexCAN is waken up from stop mode event. case kStatus_FLEXCAN_WakeUp: + MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = WakeUp\n"); break; // Process unhandled interrupt asserted event. case kStatus_FLEXCAN_UnHandled: // Process FlexCAN module error and status event. case kStatus_FLEXCAN_ErrorStatus: + // This is *very* verbose when the bus is disconnected! + //MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = UnHandled or ErrorStatus"); + // We could do some fancy statistics update, but canio does not have. mimxrt10xx_flexcan_handle_error(self); break; @@ -214,10 +239,10 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t * const mcu_periph_obj_t *rx_periph = find_pin_function(mcu_can_rx_list, rx, &instance, MP_QSTR_rx); const mcu_periph_obj_t *tx_periph = find_pin_function(mcu_can_tx_list, tx, &instance, MP_QSTR_tx); - // mp_printf(&mp_plat_print, "can instance: %d\n", instance); - // mp_printf(&mp_plat_print, "can loopback: %d\n", loopback ? 1 : 0); - // mp_printf(&mp_plat_print, "can silent: %d\n", silent ? 1 : 0); - // mp_printf(&mp_plat_print, "can baudrate: %d\n", baudrate); + MIMXRT_CANIO_CAN_DEBUG("canio: init instance: %d\n", instance); + MIMXRT_CANIO_CAN_DEBUG("canio: init loopback: %d\n", loopback ? 1 : 0); + MIMXRT_CANIO_CAN_DEBUG("canio: init silent: %d\n", silent ? 1 : 0); + MIMXRT_CANIO_CAN_DEBUG("canio: init baudrate: %d\n", baudrate); self->rx_pin = rx; self->tx_pin = tx; From 62ea6f9e56575a3628b929751fb85ce6b219550a Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Wed, 15 Jan 2025 23:44:42 +0100 Subject: [PATCH 04/12] canio: mimxrt10xx: Fix inverted byte order in CAN frames --- ports/mimxrt10xx/common-hal/canio/__init__.c | 46 ++++++++------------ 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.c b/ports/mimxrt10xx/common-hal/canio/__init__.c index 4b75d0969a5f..206d9b6bc68d 100644 --- a/ports/mimxrt10xx/common-hal/canio/__init__.c +++ b/ports/mimxrt10xx/common-hal/canio/__init__.c @@ -27,12 +27,6 @@ #include "common-hal/canio/__init__.h" #include "shared-bindings/canio/RemoteTransmissionRequest.h" -typedef union -{ - uint32_t word; - uint8_t bytes[4]; -} mimxrt_word_bytes_t; - // Convert from back from FLEXCAN IDs to normal CAN IDs. #define FLEXCAN_ID_TO_CAN_ID_STD(id) \ ((uint32_t)((((uint32_t)(id)) & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT)) @@ -62,17 +56,15 @@ bool mimxrt_canio_message_obj_to_flexcan_frame(canio_message_obj_t *src, flexcan } dst->length = src->size; // CAN frame data length in bytes (Range: 0~8). - mimxrt_word_bytes_t mixVal; - mixVal.bytes[0] = src->data[0]; - mixVal.bytes[1] = src->data[1]; - mixVal.bytes[2] = src->data[2]; - mixVal.bytes[3] = src->data[3]; - dst->dataWord0 = mixVal.word; // CAN Frame payload word0. - mixVal.bytes[0] = src->data[4]; - mixVal.bytes[1] = src->data[5]; - mixVal.bytes[2] = src->data[6]; - mixVal.bytes[3] = src->data[7]; - dst->dataWord1 = mixVal.word; // CAN Frame payload word1. + + dst->dataByte0 = src->data[0]; + dst->dataByte1 = src->data[1]; + dst->dataByte2 = src->data[2]; + dst->dataByte3 = src->data[3]; + dst->dataByte4 = src->data[4]; + dst->dataByte5 = src->data[5]; + dst->dataByte6 = src->data[6]; + dst->dataByte7 = src->data[7]; return true; } @@ -97,17 +89,15 @@ bool mimxrt_flexcan_frame_to_canio_message_obj(flexcan_frame_t *src, canio_messa } dst->size = src->length; // CAN frame data length in bytes (Range: 0~8). - mimxrt_word_bytes_t mixVal; - mixVal.word = src->dataWord0; // CAN Frame payload word0. - dst->data[0] = mixVal.bytes[0]; - dst->data[1] = mixVal.bytes[1]; - dst->data[2] = mixVal.bytes[2]; - dst->data[3] = mixVal.bytes[3]; - mixVal.word = src->dataWord1; // CAN Frame payload word1. - dst->data[4] = mixVal.bytes[0]; - dst->data[5] = mixVal.bytes[1]; - dst->data[6] = mixVal.bytes[2]; - dst->data[7] = mixVal.bytes[3]; + + dst->data[0] = src->dataByte0; + dst->data[1] = src->dataByte1; + dst->data[2] = src->dataByte2; + dst->data[3] = src->dataByte3; + dst->data[4] = src->dataByte4; + dst->data[5] = src->dataByte5; + dst->data[6] = src->dataByte6; + dst->data[7] = src->dataByte7; return true; } From 7d302b9764c62ce9d635b4ea8672b7ca36643a57 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Thu, 16 Jan 2025 18:07:32 +0100 Subject: [PATCH 05/12] canio: mimxrt10xx: Fix CAN frame reception This code clears the "frame available" flag, which allows the CPU to read and serve the next entry of the Rx FIFO. Without that, the CPU would never advance in the Rx FIFO and will serve the oldest mailbox over and over, until the Rx FIFO overflows. --- ports/mimxrt10xx/common-hal/canio/Listener.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.c b/ports/mimxrt10xx/common-hal/canio/Listener.c index b04376a97ee1..b4a1b20aacc2 100644 --- a/ports/mimxrt10xx/common-hal/canio/Listener.c +++ b/ports/mimxrt10xx/common-hal/canio/Listener.c @@ -115,6 +115,10 @@ mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self) { mp_raise_OSError(MP_EIO); } + // We've read from the FIFO, clear the "frame available" flag, which + // allows the CPU to serve the next FIFO entry + FLEXCAN_ClearMbStatusFlags(self->can->data->base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag); + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); if (!mimxrt_flexcan_frame_to_canio_message_obj(&rx_frame, message)) { mp_raise_ValueError(MP_ERROR_TEXT("Unable to receive CAN Message: missing or malformed flexcan frame")); From e3b9814a0c1f5637e319150719c8048bd77db78e Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Fri, 17 Jan 2025 10:52:55 +0100 Subject: [PATCH 06/12] canio: mimxrt10xx: Fix Listener filters/masks initialization --- ports/mimxrt10xx/common-hal/canio/CAN.c | 5 +-- ports/mimxrt10xx/common-hal/canio/Listener.c | 36 +++++++++++++++----- ports/mimxrt10xx/common-hal/canio/__init__.h | 7 +++- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.c b/ports/mimxrt10xx/common-hal/canio/CAN.c index 6c17752d228b..bd55f4ed5817 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.c +++ b/ports/mimxrt10xx/common-hal/canio/CAN.c @@ -267,7 +267,7 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t * config.enableLoopBack = loopback; config.enableListenOnlyMode = silent; config.maxMbNum = 64; - config.enableIndividMask = true; + config.enableIndividMask = true; // required to enable matching using a 'Listener' // config.disableSelfReception = true; // TODO: do we want to disable this? #if (defined(MIMXRT10XX_FLEXCAN_USE_IMPROVED_TIMING_CONFIG) && MIMXRT10XX_FLEXCAN_USE_IMPROVED_TIMING_CONFIG) @@ -290,9 +290,6 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t * FLEXCAN_TransferCreateHandle(self->data->base, &self->data->handle, mimxrt10xx_flexcan_callback, (void*)self); // Set rx mask to don't care on all bits. - FLEXCAN_SetRxMbGlobalMask(self->data->base, FLEXCAN_RX_MB_EXT_MASK(0x00, 0, 0)); - FLEXCAN_SetRxFifoGlobalMask(self->data->base, FLEXCAN_RX_MB_EXT_MASK(0x00, 0, 0)); - flexcan_rx_fifo_config_t fifo_config; fifo_config.idFilterNum = 0; fifo_config.idFilterTable = self->data->rx_fifo_filter; diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.c b/ports/mimxrt10xx/common-hal/canio/Listener.c index b4a1b20aacc2..b8ba9e96e9e1 100644 --- a/ports/mimxrt10xx/common-hal/canio/Listener.c +++ b/ports/mimxrt10xx/common-hal/canio/Listener.c @@ -59,19 +59,39 @@ void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_o self->can = can; - for (size_t i = 0; i < nmatch; i++) { - if (matches[i]->extended) { - self->can->data->rx_fifo_filter[i] = FLEXCAN_RX_FIFO_STD_FILTER_TYPE_A(matches[i]->id, 0, 1); - } else { - self->can->data->rx_fifo_filter[i] = FLEXCAN_RX_FIFO_STD_FILTER_TYPE_A(matches[i]->id, 0, 0); - } - } - + // Init configuration variables flexcan_rx_fifo_config_t fifo_config; fifo_config.idFilterNum = nmatch; fifo_config.idFilterTable = self->can->data->rx_fifo_filter; fifo_config.idFilterType = kFLEXCAN_RxFifoFilterTypeA; fifo_config.priority = kFLEXCAN_RxFifoPrioHigh; + + if (nmatch == 0) { + // If the user has provided no matches, we need to set at least one + // filter that instructs the system to ignore all bits. + fifo_config.idFilterNum = 1; + self->can->data->rx_fifo_filter[0] = 0x0; + FLEXCAN_SetRxIndividualMask(self->can->data->base, 0, 0x0); + } + else { + // Required to touch any CAN registers + FLEXCAN_EnterFreezeMode(self->can->data->base); + + for (size_t i = 0; i < nmatch; i++) { + if (matches[i]->extended) { + self->can->data->rx_fifo_filter[i] = FLEXCAN_RX_FIFO_EXT_FILTER_TYPE_A(matches[i]->id, 0, 1); + self->can->data->base->RXIMR[i] = FLEXCAN_RX_FIFO_EXT_MASK_TYPE_A(matches[i]->mask, 0, 1); + } else { + self->can->data->rx_fifo_filter[i] = FLEXCAN_RX_FIFO_STD_FILTER_TYPE_A(matches[i]->id, 0, 0); + self->can->data->base->RXIMR[i] = FLEXCAN_RX_FIFO_STD_MASK_TYPE_A(matches[i]->mask, 0, 0); + } + } + + // For consistency, even though FLEXCAN_SetRxFifoConfig() below will + // enter and exit freeze mode again anyway + FLEXCAN_ExitFreezeMode(self->can->data->base); + } + FLEXCAN_SetRxFifoConfig(self->can->data->base, &fifo_config, true); } diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.h b/ports/mimxrt10xx/common-hal/canio/__init__.h index 4a2daa647c28..ff67cbcbceb2 100644 --- a/ports/mimxrt10xx/common-hal/canio/__init__.h +++ b/ports/mimxrt10xx/common-hal/canio/__init__.h @@ -58,7 +58,12 @@ typedef uint32_t canio_can_filter_t; // Convert from frame array index to tx message buffer index. #define MIMXRT10XX_FLEXCAN_TX_ARRID_TO_MBID(x) (x + MIMXRT10XX_FLEXCAN_TX_MBID_MIN) -// Limits the Canio module's Listener filter complexity. +// We limit the amount of filter+mask pairs to 8 because above that the filters +// are impacted by the global mask rather than individual masks alone, which is +// not compatible with the current canio implementation. +// +// See Table 44-22 of the i.MX RT1060 Processor Reference Manual, Rev. 3 +// for more details. #define MIMXRT10XX_FLEXCAN_RX_FILTER_COUNT (8) // Enables/disables SDK calculated "improved" timing configuration. From 241f98a354150c769fa0a50f2f70b442a029ac3f Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Fri, 17 Jan 2025 11:17:51 +0100 Subject: [PATCH 07/12] canio: mimxrt10xx: Minor fixes in hal/CAN.c --- ports/mimxrt10xx/common-hal/canio/CAN.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.c b/ports/mimxrt10xx/common-hal/canio/CAN.c index bd55f4ed5817..c2d54fdbe30c 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.c +++ b/ports/mimxrt10xx/common-hal/canio/CAN.c @@ -101,7 +101,7 @@ static uint8_t mimxrt10xx_flexcan_get_free_tx_mbid(canio_can_obj_t *self) { MICROPY_END_ATOMIC_SECTION(atomic_state); if (!found_free_tx_mb) { - mp_raise_ValueError(MP_ERROR_TEXT("Unable to send CAN Message: all tx message buffer is busy")); + mp_raise_ValueError(MP_ERROR_TEXT("Unable to send CAN Message: all Tx message buffers are busy")); } return MIMXRT10XX_FLEXCAN_TX_ARRID_TO_MBID(tx_array_id); @@ -146,13 +146,13 @@ static void mimxrt10xx_flexcan_handle_error(canio_can_obj_t *self) { } } -static void mimxrt10xx_flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *selfPtr) +static FLEXCAN_CALLBACK(mimxrt10xx_flexcan_callback) { (void) base; // unused variable (void) handle; // unused variable // The result field can either be a message buffer index or a status flags value. - canio_can_obj_t *self = (canio_can_obj_t*) selfPtr; + canio_can_obj_t *self = (canio_can_obj_t*) userData; switch (status) { From 608211014c14b3687a8167b66c892be4ca03d2c6 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Mon, 20 Jan 2025 14:03:01 +0100 Subject: [PATCH 08/12] canio: mimxrt10xx: Remove unused code and merge message functions --- ports/mimxrt10xx/common-hal/canio/CAN.c | 31 +++++++- ports/mimxrt10xx/common-hal/canio/Listener.c | 46 ++++++++--- ports/mimxrt10xx/common-hal/canio/__init__.c | 76 ------------------- ports/mimxrt10xx/common-hal/canio/__init__.h | 8 -- .../mimxrt10xx/tools/gen_peripherals_data.py | 2 - 5 files changed, 65 insertions(+), 98 deletions(-) diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.c b/ports/mimxrt10xx/common-hal/canio/CAN.c index c2d54fdbe30c..754b6995c7f6 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.c +++ b/ports/mimxrt10xx/common-hal/canio/CAN.c @@ -383,11 +383,38 @@ void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message_in) { } canio_message_obj_t *message = message_in; + flexcan_frame_t tx_frame; - if (!mimxrt_canio_message_obj_to_flexcan_frame(message, &tx_frame)) { - mp_raise_ValueError(MP_ERROR_TEXT("Unable to send CAN Message: missing or malformed canio message object")); + memset(&tx_frame, 0, sizeof(tx_frame)); // Zero out output. + + if (message->extended) { + tx_frame.id = FLEXCAN_ID_EXT(message->id); + tx_frame.format = kFLEXCAN_FrameFormatExtend; + } else { + tx_frame.id = FLEXCAN_ID_STD(message->id); + tx_frame.format = kFLEXCAN_FrameFormatStandard; + } + + if (message->base.type == &canio_remote_transmission_request_type) { + tx_frame.type = kFLEXCAN_FrameTypeRemote; + } else { + tx_frame.type = kFLEXCAN_FrameTypeData; } + tx_frame.length = message->size; + + // We can safely copy all bytes, as both flexcan_frame_t and + // canio_message_obj_t define the data array as 8 bytes long, + // even if the actual DLC is shorter. + tx_frame.dataByte0 = message->data[0]; + tx_frame.dataByte1 = message->data[1]; + tx_frame.dataByte2 = message->data[2]; + tx_frame.dataByte3 = message->data[3]; + tx_frame.dataByte4 = message->data[4]; + tx_frame.dataByte5 = message->data[5]; + tx_frame.dataByte6 = message->data[6]; + tx_frame.dataByte7 = message->data[7]; + flexcan_mb_transfer_t tx_xfer; tx_xfer.mbIdx = mimxrt10xx_flexcan_get_free_tx_mbid(self); tx_xfer.frame = &tx_frame; diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.c b/ports/mimxrt10xx/common-hal/canio/Listener.c index b8ba9e96e9e1..cbac95453d1f 100644 --- a/ports/mimxrt10xx/common-hal/canio/Listener.c +++ b/ports/mimxrt10xx/common-hal/canio/Listener.c @@ -40,14 +40,15 @@ #include "supervisor/shared/tick.h" #include "sdk/drivers/flexcan/fsl_flexcan.h" -/* -typedef struct { - mp_obj_base_t base; - int id; - int mask; - bool extended; -} canio_match_obj_t; -*/ + +// Convert from back from FLEXCAN IDs to normal CAN IDs. +#define FLEXCAN_ID_TO_CAN_ID_STD(id) \ + ((uint32_t)((((uint32_t)(id)) & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT)) + +#define FLEXCAN_ID_TO_CAN_ID_EXT(id) \ + ((uint32_t)((((uint32_t)(id)) & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK)) \ + >> CAN_ID_EXT_SHIFT)) + void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { @@ -140,10 +141,35 @@ mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self) { FLEXCAN_ClearMbStatusFlags(self->can->data->base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag); canio_message_obj_t *message = m_new_obj(canio_message_obj_t); - if (!mimxrt_flexcan_frame_to_canio_message_obj(&rx_frame, message)) { - mp_raise_ValueError(MP_ERROR_TEXT("Unable to receive CAN Message: missing or malformed flexcan frame")); + memset(message, 0, sizeof(canio_message_obj_t)); + + if (rx_frame.format == kFLEXCAN_FrameFormatExtend) { + message->extended = true; + message->id = rx_frame.id; + } else { + message->extended = false; + message->id = rx_frame.id >> 18; // standard ids are left-aligned } + if (rx_frame.type == kFLEXCAN_FrameTypeRemote) { + message->base.type = &canio_remote_transmission_request_type; + } else { + message->base.type = &canio_message_type; + } + + message->size = rx_frame.length; + + // We can safely copy all bytes, as both flexcan_frame_t and + // canio_message_obj_t define the data array as 8 bytes long. + message->data[0] = rx_frame.dataByte0; + message->data[1] = rx_frame.dataByte1; + message->data[2] = rx_frame.dataByte2; + message->data[3] = rx_frame.dataByte3; + message->data[4] = rx_frame.dataByte4; + message->data[5] = rx_frame.dataByte5; + message->data[6] = rx_frame.dataByte6; + message->data[7] = rx_frame.dataByte7; + return message; } diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.c b/ports/mimxrt10xx/common-hal/canio/__init__.c index 206d9b6bc68d..c158c9a73d25 100644 --- a/ports/mimxrt10xx/common-hal/canio/__init__.c +++ b/ports/mimxrt10xx/common-hal/canio/__init__.c @@ -25,79 +25,3 @@ */ #include "common-hal/canio/__init__.h" -#include "shared-bindings/canio/RemoteTransmissionRequest.h" - -// Convert from back from FLEXCAN IDs to normal CAN IDs. -#define FLEXCAN_ID_TO_CAN_ID_STD(id) \ - ((uint32_t)((((uint32_t)(id)) & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT)) - -#define FLEXCAN_ID_TO_CAN_ID_EXT(id) \ - ((uint32_t)((((uint32_t)(id)) & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK)) \ - >> CAN_ID_EXT_SHIFT)) - -bool mimxrt_canio_message_obj_to_flexcan_frame(canio_message_obj_t *src, flexcan_frame_t *dst) -{ - memset(dst, 0, sizeof(*dst)); // Zero out output. - if (src == NULL) return false; // Missing input. - - if (src->extended) { // CAN Frame Identifier (STD or EXT format). - dst->id = FLEXCAN_ID_EXT(src->id); // CAN Frame Identifier (EXT). - dst->format = kFLEXCAN_FrameFormatExtend; - } else { - dst->id = FLEXCAN_ID_STD(src->id); // CAN Frame Identifier (STD). - dst->format = kFLEXCAN_FrameFormatStandard; - } - - bool rtr = src->base.type == &canio_remote_transmission_request_type; - if (rtr) { // CAN Frame Type(DATA or REMOTE). - dst->type = kFLEXCAN_FrameTypeRemote; - } else { - dst->type = kFLEXCAN_FrameTypeData; - } - - dst->length = src->size; // CAN frame data length in bytes (Range: 0~8). - - dst->dataByte0 = src->data[0]; - dst->dataByte1 = src->data[1]; - dst->dataByte2 = src->data[2]; - dst->dataByte3 = src->data[3]; - dst->dataByte4 = src->data[4]; - dst->dataByte5 = src->data[5]; - dst->dataByte6 = src->data[6]; - dst->dataByte7 = src->data[7]; - - return true; -} - -bool mimxrt_flexcan_frame_to_canio_message_obj(flexcan_frame_t *src, canio_message_obj_t *dst) -{ - memset(dst, 0, sizeof(*dst)); // Zero out output. - if (src == NULL) return false; // Missing input. - - if (src->format == kFLEXCAN_FrameFormatExtend) { // CAN Frame Identifier (STD or EXT format). - dst->extended = true; - dst->id = FLEXCAN_ID_TO_CAN_ID_EXT(src->id); // CAN Frame Identifier (EXT). - } else { - dst->extended = false; - dst->id = FLEXCAN_ID_TO_CAN_ID_STD(src->id); // CAN Frame Identifier (STD). - } - - if (src->type == kFLEXCAN_FrameTypeRemote) { // CAN Frame Type(DATA or REMOTE). - dst->base.type = &canio_remote_transmission_request_type; - } else { - dst->base.type = &canio_message_type; - } - - dst->size = src->length; // CAN frame data length in bytes (Range: 0~8). - - dst->data[0] = src->dataByte0; - dst->data[1] = src->dataByte1; - dst->data[2] = src->dataByte2; - dst->data[3] = src->dataByte3; - dst->data[4] = src->dataByte4; - dst->data[5] = src->dataByte5; - dst->data[6] = src->dataByte6; - dst->data[7] = src->dataByte7; - - return true; -} diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.h b/ports/mimxrt10xx/common-hal/canio/__init__.h index ff67cbcbceb2..b522615c671e 100644 --- a/ports/mimxrt10xx/common-hal/canio/__init__.h +++ b/ports/mimxrt10xx/common-hal/canio/__init__.h @@ -29,10 +29,6 @@ #include "shared-module/canio/Message.h" #include "sdk/drivers/flexcan/fsl_flexcan.h" -typedef struct canio_listener canio_listener_t; -typedef struct canio_can canio_can_t; -typedef uint32_t canio_can_filter_t; - // There are 64 message buffers in each mimxrt10xx chip. // Rx fifo will use the message buffers at the front (from index zero). // As far as I can see rx fifo uses message buffer 0 to 5. @@ -75,7 +71,3 @@ typedef struct { uint8_t tx_state; uint32_t rx_fifo_filter[MIMXRT10XX_FLEXCAN_RX_FILTER_COUNT]; } mimxrt10xx_flexcan_data_t; - -bool mimxrt_canio_message_obj_to_flexcan_frame(canio_message_obj_t *src, flexcan_frame_t *dst); -bool mimxrt_flexcan_frame_to_canio_message_obj(flexcan_frame_t *src, canio_message_obj_t *dst); - diff --git a/ports/mimxrt10xx/tools/gen_peripherals_data.py b/ports/mimxrt10xx/tools/gen_peripherals_data.py index 1d8fa5cd7181..af7230818709 100644 --- a/ports/mimxrt10xx/tools/gen_peripherals_data.py +++ b/ports/mimxrt10xx/tools/gen_peripherals_data.py @@ -182,7 +182,6 @@ def rename_instance(instance:str)-> str: continue alt = int(alt[3:]) value = int(evalue.find("value").text, 0) - #print(f"instance: {instance}, signal: {signal}, pin_name: {pin_name}") peripheral_inputs[instance][signal][pin_name] = [alt, name, value] # Mux registers come before PAD registers. elif name.startswith("SW_MUX_CTL_PAD_GPIO"): @@ -325,7 +324,6 @@ def rename_instance(instance:str)-> str: for signal in SIGNALS[ptype]: pin_count = 0 for instance in instances: - ###print(f"instance: {instance}") if instance not in peripheral_inputs or signal not in peripheral_inputs[instance]: continue pin_count += len(peripheral_inputs[instance][signal]) From 497aefce6c5f251ce42a63a5b7031faa099524d3 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Mon, 20 Jan 2025 13:58:07 +0100 Subject: [PATCH 09/12] canio: mimxrt10xx: Fix copyright notices --- ports/mimxrt10xx/common-hal/canio/CAN.c | 31 ++++-------------- ports/mimxrt10xx/common-hal/canio/CAN.h | 30 +++-------------- ports/mimxrt10xx/common-hal/canio/Listener.c | 32 ++++--------------- ports/mimxrt10xx/common-hal/canio/Listener.h | 30 +++-------------- ports/mimxrt10xx/common-hal/canio/__init__.c | 31 ++++-------------- ports/mimxrt10xx/common-hal/canio/__init__.h | 31 ++++-------------- .../mimxrt10xx/tools/gen_peripherals_data.py | 1 + 7 files changed, 36 insertions(+), 150 deletions(-) diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.c b/ports/mimxrt10xx/common-hal/canio/CAN.c index 754b6995c7f6..852ef9163e36 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.c +++ b/ports/mimxrt10xx/common-hal/canio/CAN.c @@ -1,28 +1,9 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 qutefox +// SPDX-FileCopyrightText: Copyright (c) 2025 SamantazFox +// +// SPDX-License-Identifier: MIT #include diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.h b/ports/mimxrt10xx/common-hal/canio/CAN.h index 1bf3ab6bcf4b..8bbb707a8916 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.h +++ b/ports/mimxrt10xx/common-hal/canio/CAN.h @@ -1,28 +1,8 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 qutefox +// +// SPDX-License-Identifier: MIT #pragma once diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.c b/ports/mimxrt10xx/common-hal/canio/Listener.c index cbac95453d1f..b9e3f3ea7c12 100644 --- a/ports/mimxrt10xx/common-hal/canio/Listener.c +++ b/ports/mimxrt10xx/common-hal/canio/Listener.c @@ -1,28 +1,10 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 qutefox +// SPDX-FileCopyrightText: Copyright (c) 2025 SamantazFox +// +// SPDX-License-Identifier: MIT + #include #include diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.h b/ports/mimxrt10xx/common-hal/canio/Listener.h index 23a00f9f1db4..2c1c1c82d50c 100644 --- a/ports/mimxrt10xx/common-hal/canio/Listener.h +++ b/ports/mimxrt10xx/common-hal/canio/Listener.h @@ -1,28 +1,8 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 qutefox +// +// SPDX-License-Identifier: MIT #pragma once diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.c b/ports/mimxrt10xx/common-hal/canio/__init__.c index c158c9a73d25..aaae9be4d4c7 100644 --- a/ports/mimxrt10xx/common-hal/canio/__init__.c +++ b/ports/mimxrt10xx/common-hal/canio/__init__.c @@ -1,27 +1,8 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 qutefox +// SPDX-FileCopyrightText: Copyright (c) 2025 SamantazFox +// +// SPDX-License-Identifier: MIT #include "common-hal/canio/__init__.h" diff --git a/ports/mimxrt10xx/common-hal/canio/__init__.h b/ports/mimxrt10xx/common-hal/canio/__init__.h index b522615c671e..8f63b6c2f117 100644 --- a/ports/mimxrt10xx/common-hal/canio/__init__.h +++ b/ports/mimxrt10xx/common-hal/canio/__init__.h @@ -1,28 +1,9 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 qutefox +// SPDX-FileCopyrightText: Copyright (c) 2025 SamantazFox +// +// SPDX-License-Identifier: MIT #pragma once diff --git a/ports/mimxrt10xx/tools/gen_peripherals_data.py b/ports/mimxrt10xx/tools/gen_peripherals_data.py index af7230818709..341b36e83a53 100644 --- a/ports/mimxrt10xx/tools/gen_peripherals_data.py +++ b/ports/mimxrt10xx/tools/gen_peripherals_data.py @@ -55,6 +55,7 @@ def rename_instance(instance:str)-> str: // SPDX-FileCopyrightText: Copyright (c) 2019 Lucian Copeland for Adafruit Industries // SPDX-FileCopyrightText: Copyright (c) 2019 Artur Pacholec // SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2023 qutefox // // SPDX-License-Identifier: MIT """ From 7f66a3739fb0774e9dac59cacdcb61c0d68e37a3 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Mon, 20 Jan 2025 15:08:37 +0100 Subject: [PATCH 10/12] canio: Update platform specific documentation --- shared-bindings/canio/CAN.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-bindings/canio/CAN.c b/shared-bindings/canio/CAN.c index 82bf86dd97b2..47ba5d62df8b 100644 --- a/shared-bindings/canio/CAN.c +++ b/shared-bindings/canio/CAN.c @@ -187,6 +187,10 @@ static MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart); //| //| ESP32S2 supports one Listener. There is a single filter block, which can either match a //| standard address with mask or an extended address with mask. +//| +//| i.MX RT10xx supports one Listener and 8 filter blocks per CAN interface. +//| Each interface is fully independent from the other. A filter block can match +//| either a single address or a mask of addresses, both standard or extended. //| """ //| ... static mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { From 6979e967a3b4e9774c0d256b26cf3316aa9f21df Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Mon, 20 Jan 2025 15:16:18 +0100 Subject: [PATCH 11/12] Make formatting changes requested by pre-commit hook --- locale/circuitpython.pot | 5 ++ ports/mimxrt10xx/common-hal/canio/CAN.c | 70 +++++++++---------- ports/mimxrt10xx/common-hal/canio/CAN.h | 2 +- ports/mimxrt10xx/common-hal/canio/Listener.c | 9 +-- .../mimxrt10xx/tools/gen_peripherals_data.py | 9 +-- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 28712b4f1cfa..c8d7cec4b98f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1019,6 +1019,7 @@ msgstr "" #: ports/atmel-samd/common-hal/canio/Listener.c #: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c #: ports/stm/common-hal/canio/Listener.c msgid "Filters too complex" msgstr "" @@ -2140,6 +2141,10 @@ msgstr "" msgid "Unable to read color palette data" msgstr "" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" +msgstr "" + #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c msgid "Unable to start mDNS query" diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.c b/ports/mimxrt10xx/common-hal/canio/CAN.c index 852ef9163e36..ba2c2482a34b 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.c +++ b/ports/mimxrt10xx/common-hal/canio/CAN.c @@ -21,10 +21,10 @@ // Be verbose #define MIMXRT_CANIO_CAN_DEBUG(...) (void)0 -//#define MIMXRT_CANIO_CAN_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +// #define MIMXRT_CANIO_CAN_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) #define MIMXRT_CANIO_CAN_CALLBACK_DEBUG(...) (void)0 -//#define MIMXRT_CANIO_CAN_CALLBACK_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +// #define MIMXRT_CANIO_CAN_CALLBACK_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) static CAN_Type *const flexcan_bases[] = CAN_BASE_PTRS; // e.g.: { (CAN_Type *)0u, CAN1, CAN2, CAN3 } @@ -67,11 +67,10 @@ static uint8_t mimxrt10xx_flexcan_get_free_tx_mbid(canio_can_obj_t *self) { bool found_free_tx_mb = false; int8_t tx_array_id = 0; mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); - for ( ; tx_array_id < MIMXRT10XX_FLEXCAN_TX_MB_NUM ; ++tx_array_id) + for ( ; tx_array_id < MIMXRT10XX_FLEXCAN_TX_MB_NUM; ++tx_array_id) { uint64_t tx_array_id_bit = (1UL << tx_array_id); - if (!(self->data->tx_state & tx_array_id_bit)) - { + if (!(self->data->tx_state & tx_array_id_bit)) { // Found a free tx array id. Mark it as used. MIMXRT_CANIO_CAN_DEBUG("canio: Found free Tx MB: %d\n", tx_array_id); self->data->tx_state |= tx_array_id_bit; @@ -88,27 +87,23 @@ static uint8_t mimxrt10xx_flexcan_get_free_tx_mbid(canio_can_obj_t *self) { return MIMXRT10XX_FLEXCAN_TX_ARRID_TO_MBID(tx_array_id); } -static void mimxrt10xx_flexcan_set_tx_mb_free_by_mbid(canio_can_obj_t *self, uint8_t mb_idx) -{ +static void mimxrt10xx_flexcan_set_tx_mb_free_by_mbid(canio_can_obj_t *self, uint8_t mb_idx) { // We simply set the Nth bit zero. This means that that message buffer is free to use. uint64_t tx_array_id_bit = (1UL << MIMXRT10XX_FLEXCAN_TX_MBID_TO_ARRID(mb_idx)); self->data->tx_state &= ~(tx_array_id_bit); } -static void mimxrt10xx_flexcan_set_tx_mb_busy_by_mbid(canio_can_obj_t *self, uint8_t mb_idx) -{ +static void mimxrt10xx_flexcan_set_tx_mb_busy_by_mbid(canio_can_obj_t *self, uint8_t mb_idx) { // We simply set the Nth bit 1. This means that that message buffer is busy and cannot be used. uint64_t tx_array_id_bit = (1UL << MIMXRT10XX_FLEXCAN_TX_MBID_TO_ARRID(mb_idx)); self->data->tx_state |= tx_array_id_bit; } -static void mimxrt10xx_flexcan_abort_tx_frames(canio_can_obj_t *self) -{ - for (uint8_t tx_array_id = 0 ; tx_array_id < MIMXRT10XX_FLEXCAN_TX_MB_NUM ; ++tx_array_id) +static void mimxrt10xx_flexcan_abort_tx_frames(canio_can_obj_t *self) { + for (uint8_t tx_array_id = 0; tx_array_id < MIMXRT10XX_FLEXCAN_TX_MB_NUM; ++tx_array_id) { uint64_t tx_array_id_bit = (1UL << tx_array_id); - if (self->data->tx_state & tx_array_id_bit) - { + if (self->data->tx_state & tx_array_id_bit) { // Found a used/busy tx message buffer. Abort it. FLEXCAN_TransferAbortSend(self->data->base, &self->data->handle, MIMXRT10XX_FLEXCAN_TX_ARRID_TO_MBID(tx_array_id)); @@ -119,8 +114,7 @@ static void mimxrt10xx_flexcan_abort_tx_frames(canio_can_obj_t *self) static void mimxrt10xx_flexcan_handle_error(canio_can_obj_t *self) { canio_bus_state_t state = common_hal_canio_can_state_get(self); - if (state == BUS_STATE_OFF) - { + if (state == BUS_STATE_OFF) { // Abort any pending tx and rx in case of bus-off. mimxrt10xx_flexcan_abort_tx_frames(self); FLEXCAN_TransferAbortReceiveFifo(self->data->base, &self->data->handle); @@ -129,11 +123,11 @@ static void mimxrt10xx_flexcan_handle_error(canio_can_obj_t *self) { static FLEXCAN_CALLBACK(mimxrt10xx_flexcan_callback) { - (void) base; // unused variable - (void) handle; // unused variable + (void)base; // unused variable + (void)handle; // unused variable // The result field can either be a message buffer index or a status flags value. - canio_can_obj_t *self = (canio_can_obj_t*) userData; + canio_can_obj_t *self = (canio_can_obj_t *)userData; switch (status) { @@ -206,7 +200,7 @@ static FLEXCAN_CALLBACK(mimxrt10xx_flexcan_callback) // Process FlexCAN module error and status event. case kStatus_FLEXCAN_ErrorStatus: // This is *very* verbose when the bus is disconnected! - //MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = UnHandled or ErrorStatus"); + // MIMXRT_CANIO_CAN_CALLBACK_DEBUG("canio: callback got status = UnHandled or ErrorStatus"); // We could do some fancy statistics update, but canio does not have. mimxrt10xx_flexcan_handle_error(self); @@ -243,24 +237,23 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t * FLEXCAN_GetDefaultConfig(&config); // Change default flexcan module configuration based on canio constructor parameters. - config.clkSrc = CLOCK_GetMux(kCLOCK_CanMux); - config.baudRate = baudrate; - config.enableLoopBack = loopback; + config.clkSrc = CLOCK_GetMux(kCLOCK_CanMux); + config.baudRate = baudrate; + config.enableLoopBack = loopback; config.enableListenOnlyMode = silent; - config.maxMbNum = 64; - config.enableIndividMask = true; // required to enable matching using a 'Listener' + config.maxMbNum = 64; + config.enableIndividMask = true; // required to enable matching using a 'Listener' // config.disableSelfReception = true; // TODO: do we want to disable this? #if (defined(MIMXRT10XX_FLEXCAN_USE_IMPROVED_TIMING_CONFIG) && MIMXRT10XX_FLEXCAN_USE_IMPROVED_TIMING_CONFIG) - // If improved timing configuration is enabled then tell the SDK to calculate it. - flexcan_timing_config_t timing_config; - memset(&timing_config, 0, sizeof(flexcan_timing_config_t)); - if (FLEXCAN_CalculateImprovedTimingValues(self->data->base, config.baudRate, MIMXRT10XX_FLEXCAN_CLK_FREQ, &timing_config)) - { - // SDK could calculate the improved timing configuration. Yay! - // Let's update our flexcan module config to use it. - memcpy(&(config.timingConfig), &timing_config, sizeof(flexcan_timing_config_t)); - } + // If improved timing configuration is enabled then tell the SDK to calculate it. + flexcan_timing_config_t timing_config; + memset(&timing_config, 0, sizeof(flexcan_timing_config_t)); + if (FLEXCAN_CalculateImprovedTimingValues(self->data->base, config.baudRate, MIMXRT10XX_FLEXCAN_CLK_FREQ, &timing_config)) { + // SDK could calculate the improved timing configuration. Yay! + // Let's update our flexcan module config to use it. + memcpy(&(config.timingConfig), &timing_config, sizeof(flexcan_timing_config_t)); + } #endif // Initialize the flexcan module with user-defined settings. @@ -268,7 +261,7 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t * // Create FlexCAN handle structure and set call back function. // As callback data we set 'self'. In callback we can cast it back to 'canio_can_obj_t'. - FLEXCAN_TransferCreateHandle(self->data->base, &self->data->handle, mimxrt10xx_flexcan_callback, (void*)self); + FLEXCAN_TransferCreateHandle(self->data->base, &self->data->handle, mimxrt10xx_flexcan_callback, (void *)self); // Set rx mask to don't care on all bits. flexcan_rx_fifo_config_t fifo_config; @@ -323,7 +316,9 @@ void common_hal_canio_can_restart(canio_can_obj_t *self) { // But I will leave this code here just in case. canio_bus_state_t state = common_hal_canio_can_state_get(self); - if (state != BUS_STATE_OFF) return; + if (state != BUS_STATE_OFF) { + return; + } self->data->base->CTRL1 &= ~CAN_CTRL1_BOFFREC_MASK; @@ -357,8 +352,7 @@ void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message_in) { maybe_auto_restart(self); canio_bus_state_t state = common_hal_canio_can_state_get(self); - if (state == BUS_STATE_OFF) - { + if (state == BUS_STATE_OFF) { // Bus is off. Transmit failed. mp_raise_OSError(MP_ENODEV); } diff --git a/ports/mimxrt10xx/common-hal/canio/CAN.h b/ports/mimxrt10xx/common-hal/canio/CAN.h index 8bbb707a8916..11c77c9d4a4f 100644 --- a/ports/mimxrt10xx/common-hal/canio/CAN.h +++ b/ports/mimxrt10xx/common-hal/canio/CAN.h @@ -14,7 +14,7 @@ typedef struct canio_can_obj { mp_obj_base_t base; - mimxrt10xx_flexcan_data_t* data; + mimxrt10xx_flexcan_data_t *data; int baudrate; const mcu_pin_obj_t *rx_pin; const mcu_pin_obj_t *tx_pin; diff --git a/ports/mimxrt10xx/common-hal/canio/Listener.c b/ports/mimxrt10xx/common-hal/canio/Listener.c index b9e3f3ea7c12..c2812b8b9934 100644 --- a/ports/mimxrt10xx/common-hal/canio/Listener.c +++ b/ports/mimxrt10xx/common-hal/canio/Listener.c @@ -55,8 +55,7 @@ void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_o fifo_config.idFilterNum = 1; self->can->data->rx_fifo_filter[0] = 0x0; FLEXCAN_SetRxIndividualMask(self->can->data->base, 0, 0x0); - } - else { + } else { // Required to touch any CAN registers FLEXCAN_EnterFreezeMode(self->can->data->base); @@ -94,7 +93,9 @@ void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { } int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { - if(FLEXCAN_GetMbStatusFlags(self->can->data->base, kFLEXCAN_RxFifoFrameAvlFlag)) return 1; + if (FLEXCAN_GetMbStatusFlags(self->can->data->base, kFLEXCAN_RxFifoFrameAvlFlag)) { + return 1; + } return 0; } @@ -114,7 +115,7 @@ mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self) { } flexcan_frame_t rx_frame; - if(FLEXCAN_ReadRxFifo(self->can->data->base, &rx_frame) != kStatus_Success) { + if (FLEXCAN_ReadRxFifo(self->can->data->base, &rx_frame) != kStatus_Success) { mp_raise_OSError(MP_EIO); } diff --git a/ports/mimxrt10xx/tools/gen_peripherals_data.py b/ports/mimxrt10xx/tools/gen_peripherals_data.py index 341b36e83a53..664e1c655658 100644 --- a/ports/mimxrt10xx/tools/gen_peripherals_data.py +++ b/ports/mimxrt10xx/tools/gen_peripherals_data.py @@ -23,12 +23,12 @@ "RX_DATA": "RX_DATA0", } -INSTANCE_RENAME = { - "FLEXCAN" : "CAN" -} +INSTANCE_RENAME = {"FLEXCAN": "CAN"} INSTANCE_RE = re.compile("([a-zA-Z0-9]+?)([0-9]+)$") -def rename_instance(instance:str)-> str: + + +def rename_instance(instance: str) -> str: instance_match = INSTANCE_RE.match(instance) if instance_match is None: return instance @@ -39,6 +39,7 @@ def rename_instance(instance:str)-> str: instance_id = str(instance_res[1]) return INSTANCE_RENAME.get(instance_name, instance_name) + instance_id + SKIP_LPSR = True svd_folder = pathlib.Path(sys.argv[1]) From 69c88eb577940cc90b59fc9644664a4e145856cd Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Mon, 20 Jan 2025 15:34:05 +0100 Subject: [PATCH 12/12] mimxrt10xx: Add fsl_flexcan driver source only if supported For instance, i.MX RT1011 and 1015 don't have CAN interfaces --- ports/mimxrt10xx/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index 072a3df3509a..04b8c6787aff 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -120,13 +120,16 @@ SRC_SDK := \ drivers/snvs_hp/fsl_snvs_hp.c \ drivers/snvs_lp/fsl_snvs_lp.c \ drivers/trng/fsl_trng.c \ - drivers/flexcan/fsl_flexcan.c \ ifeq ($(CIRCUITPY_ANALOGIO), 1) SRC_SDK += drivers/adc_12b1msps_sar/fsl_adc.c \ drivers/tempmon/fsl_tempmon.c endif +ifeq ($(CIRCUITPY_CANIO), 1) +SRC_SDK += drivers/flexcan/fsl_flexcan.c +endif + ifeq ($(CHIP_FAMILY), MIMXRT1176) SRC_SDK += devices/$(CHIP_FAMILY)/drivers/fsl_anatop_ai.c \ devices/$(CHIP_FAMILY)/drivers/fsl_dcdc.c \