From f7a07b36057d61264958e3577f7e4555e77d520c Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Mon, 16 Sep 2019 01:56:38 +0200 Subject: [PATCH] stm32: Add support for FDCAN peripheral, exposed as pyb.CAN. The new fdcan.c file provides the low-level C interface to the FDCAN peripheral, and pyb_can.c is updated to support both traditional CAN and FDCAN, depending on the MCU being compiled for. --- ports/stm32/Makefile | 1 + ports/stm32/can.c | 30 +-- ports/stm32/can.h | 12 +- ports/stm32/fdcan.c | 325 +++++++++++++++++++++++++++++ ports/stm32/mpconfigboard_common.h | 3 + ports/stm32/pin_defs_stm32.h | 8 + ports/stm32/pyb_can.c | 277 ++++++++++++++++++++---- 7 files changed, 604 insertions(+), 52 deletions(-) create mode 100644 ports/stm32/fdcan.c diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 38540e6d92..8dde851297 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -256,6 +256,7 @@ SRC_C = \ qspi.c \ uart.c \ can.c \ + fdcan.c \ pyb_can.c \ usb.c \ wdt.c \ diff --git a/ports/stm32/can.c b/ports/stm32/can.c index 371c590a43..1ee46492c2 100644 --- a/ports/stm32/can.c +++ b/ports/stm32/can.c @@ -47,6 +47,8 @@ void can_deinit_all(void) { } } +#if !MICROPY_HW_ENABLE_FDCAN + bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_t sjw, uint32_t bs1, uint32_t bs2, bool auto_restart) { CAN_InitTypeDef *init = &can_obj->can.Init; init->Mode = mode << 4; // shift-left so modes fit in a small-int @@ -158,7 +160,7 @@ void can_deinit(pyb_can_obj_t *self) { } } -void can_clearfilter(uint32_t f, uint8_t bank) { +void can_clearfilter(pyb_can_obj_t *self, uint32_t f, uint8_t bank) { CAN_FilterConfTypeDef filter; filter.FilterIdHigh = 0; @@ -175,12 +177,12 @@ void can_clearfilter(uint32_t f, uint8_t bank) { HAL_CAN_ConfigFilter(NULL, &filter); } -int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeout_ms) { +int can_receive(CAN_HandleTypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint8_t *data, uint32_t timeout_ms) { volatile uint32_t *rfr; if (fifo == CAN_FIFO0) { - rfr = &can->RF0R; + rfr = &can->Instance->RF0R; } else { - rfr = &can->RF1R; + rfr = &can->Instance->RF1R; } // Wait for a message to become available, with timeout @@ -193,7 +195,7 @@ int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeo } // Read message data - CAN_FIFOMailBox_TypeDef *box = &can->sFIFOMailBox[fifo]; + CAN_FIFOMailBox_TypeDef *box = &can->Instance->sFIFOMailBox[fifo]; msg->IDE = box->RIR & 4; if (msg->IDE == CAN_ID_STD) { msg->StdId = box->RIR >> 21; @@ -204,15 +206,15 @@ int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeo msg->DLC = box->RDTR & 0xf; msg->FMI = box->RDTR >> 8 & 0xff; uint32_t rdlr = box->RDLR; - msg->Data[0] = rdlr; - msg->Data[1] = rdlr >> 8; - msg->Data[2] = rdlr >> 16; - msg->Data[3] = rdlr >> 24; + data[0] = rdlr; + data[1] = rdlr >> 8; + data[2] = rdlr >> 16; + data[3] = rdlr >> 24; uint32_t rdhr = box->RDHR; - msg->Data[4] = rdhr; - msg->Data[5] = rdhr >> 8; - msg->Data[6] = rdhr >> 16; - msg->Data[7] = rdhr >> 24; + data[4] = rdhr; + data[5] = rdhr >> 8; + data[6] = rdhr >> 16; + data[7] = rdhr >> 24; // Release (free) message from FIFO *rfr |= CAN_RF0R_RFOM0; @@ -427,4 +429,6 @@ void CAN3_SCE_IRQHandler(void) { } #endif +#endif // !MICROPY_HW_ENABLE_FDCAN + #endif // MICROPY_HW_ENABLE_CAN diff --git a/ports/stm32/can.h b/ports/stm32/can.h index 777da7e458..085070b601 100644 --- a/ports/stm32/can.h +++ b/ports/stm32/can.h @@ -37,6 +37,13 @@ #define MASK32 (2) #define LIST32 (3) +#if MICROPY_HW_ENABLE_FDCAN +#define CAN_TypeDef FDCAN_GlobalTypeDef +#define CAN_HandleTypeDef FDCAN_HandleTypeDef +#define CanTxMsgTypeDef FDCAN_TxHeaderTypeDef +#define CanRxMsgTypeDef FDCAN_RxHeaderTypeDef +#endif + enum { CAN_STATE_STOPPED, CAN_STATE_ERROR_ACTIVE, @@ -74,10 +81,9 @@ void can_deinit_all(void); bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_t sjw, uint32_t bs1, uint32_t bs2, bool auto_restart); void can_deinit(pyb_can_obj_t *self); -void can_clearfilter(uint32_t f, uint8_t bank); -int can_receive(CAN_TypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint32_t timeout_ms); +void can_clearfilter(pyb_can_obj_t *self, uint32_t f, uint8_t bank); +int can_receive(CAN_HandleTypeDef *can, int fifo, CanRxMsgTypeDef *msg, uint8_t *data, uint32_t timeout_ms); HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout); - void pyb_can_handle_callback(pyb_can_obj_t *self, uint fifo_id, mp_obj_t callback, mp_obj_t irq_reason); #endif // MICROPY_INCLUDED_STM32_CAN_H diff --git a/ports/stm32/fdcan.c b/ports/stm32/fdcan.c new file mode 100644 index 0000000000..611ebe1aaf --- /dev/null +++ b/ports/stm32/fdcan.c @@ -0,0 +1,325 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Damien P. George + * + * 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 "py/runtime.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "can.h" +#include "irq.h" + +#if MICROPY_HW_ENABLE_CAN && MICROPY_HW_ENABLE_FDCAN + +#define FDCAN_ELEMENT_MASK_STDID (0x1ffc0000) // Standard Identifier +#define FDCAN_ELEMENT_MASK_EXTID (0x1fffffff) // Extended Identifier +#define FDCAN_ELEMENT_MASK_RTR (0x20000000) // Remote Transmission Request +#define FDCAN_ELEMENT_MASK_XTD (0x40000000) // Extended Identifier +#define FDCAN_ELEMENT_MASK_ESI (0x80000000) // Error State Indicator +#define FDCAN_ELEMENT_MASK_TS (0x0000ffff) // Timestamp +#define FDCAN_ELEMENT_MASK_DLC (0x000f0000) // Data Length Code +#define FDCAN_ELEMENT_MASK_BRS (0x00100000) // Bit Rate Switch +#define FDCAN_ELEMENT_MASK_FDF (0x00200000) // FD Format +#define FDCAN_ELEMENT_MASK_FIDX (0x7f000000) // Filter Index +#define FDCAN_ELEMENT_MASK_ANMF (0x80000000) // Accepted Non-matching Frame + +bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_t sjw, uint32_t bs1, uint32_t bs2, bool auto_restart) { + (void)auto_restart; + + FDCAN_InitTypeDef *init = &can_obj->can.Init; + init->FrameFormat = FDCAN_FRAME_CLASSIC; + init->Mode = mode; + + init->NominalPrescaler = prescaler; // tq = NominalPrescaler x (1/fdcan_ker_ck) + init->NominalSyncJumpWidth = sjw; + init->NominalTimeSeg1 = bs1; // NominalTimeSeg1 = Propagation_segment + Phase_segment_1 + init->NominalTimeSeg2 = bs2; + + init->AutoRetransmission = ENABLE; + init->TransmitPause = DISABLE; + init->ProtocolException = ENABLE; + + // The Message RAM is shared between CAN1 and CAN2. Setting the offset to half + // the Message RAM for the second CAN and using half the resources for each CAN. + if (can_obj->can_id == PYB_CAN_1) { + init->MessageRAMOffset = 0; + } else { + init->MessageRAMOffset = 2560/2; + } + + init->StdFiltersNbr = 64; // 128 / 2 + init->ExtFiltersNbr = 0; // Not used + + init->TxEventsNbr = 16; // 32 / 2 + init->RxBuffersNbr = 32; // 64 / 2 + init->TxBuffersNbr = 16; // 32 / 2 + + init->RxFifo0ElmtsNbr = 64; // 128 / 2 + init->RxFifo0ElmtSize = FDCAN_DATA_BYTES_8; + + init->RxFifo1ElmtsNbr = 64; // 128 / 2 + init->RxFifo1ElmtSize = FDCAN_DATA_BYTES_8; + + init->TxFifoQueueElmtsNbr = 16; // Tx fifo elements + init->TxElmtSize = FDCAN_DATA_BYTES_8; + init->TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + + FDCAN_GlobalTypeDef *CANx = NULL; + const pin_obj_t *pins[2]; + + switch (can_obj->can_id) { + #if defined(MICROPY_HW_CAN1_TX) + case PYB_CAN_1: + CANx = FDCAN1; + pins[0] = MICROPY_HW_CAN1_TX; + pins[1] = MICROPY_HW_CAN1_RX; + break; + #endif + + #if defined(MICROPY_HW_CAN2_TX) + case PYB_CAN_2: + CANx = FDCAN2; + pins[0] = MICROPY_HW_CAN2_TX; + pins[1] = MICROPY_HW_CAN2_RX; + break; + #endif + + default: + return false; + } + + // Enable FDCAN clock + __HAL_RCC_FDCAN_CLK_ENABLE(); + + // init GPIO + uint32_t pin_mode = MP_HAL_PIN_MODE_ALT; + uint32_t pin_pull = MP_HAL_PIN_PULL_UP; + for (int i = 0; i < 2; ++i) { + if (!mp_hal_pin_config_alt(pins[i], pin_mode, pin_pull, AF_FN_CAN, can_obj->can_id)) { + return false; + } + } + + // init CANx + can_obj->can.Instance = CANx; + HAL_FDCAN_Init(&can_obj->can); + + // Disable acceptance of non-matching frames (enabled by default) + HAL_FDCAN_ConfigGlobalFilter(&can_obj->can, FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE); + + // The configuration registers are locked after CAN is started. + HAL_FDCAN_Start(&can_obj->can); + + // Reset all filters + for (int f = 0; f < 64; ++f) { + can_clearfilter(can_obj, f, 0); + } + + can_obj->is_enabled = true; + can_obj->num_error_warning = 0; + can_obj->num_error_passive = 0; + can_obj->num_bus_off = 0; + + switch (can_obj->can_id) { + case PYB_CAN_1: + NVIC_SetPriority(FDCAN1_IT0_IRQn, IRQ_PRI_CAN); + HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); + NVIC_SetPriority(FDCAN1_IT1_IRQn, IRQ_PRI_CAN); + HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn); + break; + case PYB_CAN_2: + NVIC_SetPriority(FDCAN2_IT0_IRQn, IRQ_PRI_CAN); + HAL_NVIC_EnableIRQ(FDCAN2_IT0_IRQn); + NVIC_SetPriority(FDCAN2_IT1_IRQn, IRQ_PRI_CAN); + HAL_NVIC_EnableIRQ(FDCAN2_IT1_IRQn); + break; + default: + return false; + } + + __HAL_FDCAN_ENABLE_IT(&can_obj->can, FDCAN_IT_BUS_OFF | FDCAN_IT_ERROR_WARNING | FDCAN_IT_ERROR_PASSIVE); + __HAL_FDCAN_ENABLE_IT(&can_obj->can, FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO1_NEW_MESSAGE); + __HAL_FDCAN_ENABLE_IT(&can_obj->can, FDCAN_IT_RX_FIFO0_MESSAGE_LOST | FDCAN_IT_RX_FIFO1_MESSAGE_LOST); + __HAL_FDCAN_ENABLE_IT(&can_obj->can, FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO1_FULL); + + return true; +} + +void can_deinit(pyb_can_obj_t *self) { + self->is_enabled = false; + HAL_FDCAN_DeInit(&self->can); + if (self->can.Instance == FDCAN1) { + HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn); + HAL_NVIC_DisableIRQ(FDCAN1_IT1_IRQn); + // TODO check if FDCAN2 is used. + __HAL_RCC_FDCAN_FORCE_RESET(); + __HAL_RCC_FDCAN_RELEASE_RESET(); + __HAL_RCC_FDCAN_CLK_DISABLE(); + #if defined(MICROPY_HW_CAN2_TX) + } else if (self->can.Instance == FDCAN2) { + HAL_NVIC_DisableIRQ(FDCAN2_IT0_IRQn); + HAL_NVIC_DisableIRQ(FDCAN2_IT1_IRQn); + // TODO check if FDCAN2 is used. + __HAL_RCC_FDCAN_FORCE_RESET(); + __HAL_RCC_FDCAN_RELEASE_RESET(); + __HAL_RCC_FDCAN_CLK_DISABLE(); + #endif + } +} + +void can_clearfilter(pyb_can_obj_t *self, uint32_t f, uint8_t bank) { + if (self && self->can.Instance) { + FDCAN_FilterTypeDef filter = {0}; + filter.IdType = FDCAN_STANDARD_ID; + filter.FilterIndex = f; + filter.FilterConfig = FDCAN_FILTER_DISABLE; + HAL_FDCAN_ConfigFilter(&self->can, &filter); + } +} + +int can_receive(FDCAN_HandleTypeDef *can, int fifo, FDCAN_RxHeaderTypeDef *hdr, uint8_t *data, uint32_t timeout_ms) { + volatile uint32_t *rxf, *rxa; + if (fifo == FDCAN_RX_FIFO0) { + rxf = &can->Instance->RXF0S; + rxa = &can->Instance->RXF0A; + } else { + rxf = &can->Instance->RXF1S; + rxa = &can->Instance->RXF1A; + } + + // Wait for a message to become available, with timeout + uint32_t start = HAL_GetTick(); + while ((*rxf & 7) == 0) { + MICROPY_EVENT_POLL_HOOK + if (HAL_GetTick() - start >= timeout_ms) { + return -MP_ETIMEDOUT; + } + } + + // Get pointer to incoming message + uint32_t index = (can->Instance->RXF0S & FDCAN_RXF0S_F0GI) >> 8; + uint32_t *address = (uint32_t*)(can->msgRam.RxFIFO0SA + (index * can->Init.RxFifo0ElmtSize * 4)); + + // Parse header of message + hdr->IdType = *address & FDCAN_ELEMENT_MASK_XTD; + if(hdr->IdType == FDCAN_STANDARD_ID) { + hdr->Identifier = (*address & FDCAN_ELEMENT_MASK_STDID) >> 18; + } else { + hdr->Identifier = *address & FDCAN_ELEMENT_MASK_EXTID; + } + hdr->RxFrameType = *address & FDCAN_ELEMENT_MASK_RTR; + hdr->ErrorStateIndicator = *address++ & FDCAN_ELEMENT_MASK_ESI; + hdr->RxTimestamp = *address & FDCAN_ELEMENT_MASK_TS; + hdr->DataLength = (*address & FDCAN_ELEMENT_MASK_DLC) >> 16; + hdr->BitRateSwitch = *address & FDCAN_ELEMENT_MASK_BRS; + hdr->FDFormat = *address & FDCAN_ELEMENT_MASK_FDF; + hdr->FilterIndex = (*address & FDCAN_ELEMENT_MASK_FIDX) >> 24; + hdr->IsFilterMatchingFrame = (*address++ & FDCAN_ELEMENT_MASK_ANMF) >> 31; + + // Copy data + uint8_t *pdata = (uint8_t*)address; + for(uint32_t i = 0; i < 8; ++i) { // TODO use DLCtoBytes[hdr->DataLength] for length > 8 + *data++ = *pdata++; + } + + // Release (free) message from FIFO + *rxa = index; + + return 0; // success +} + +STATIC void can_rx_irq_handler(uint can_id, uint fifo_id) { + mp_obj_t callback; + pyb_can_obj_t *self; + mp_obj_t irq_reason = MP_OBJ_NEW_SMALL_INT(0); + byte *state; + + self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + + if (fifo_id == FDCAN_RX_FIFO0) { + callback = self->rxcallback0; + state = &self->rx_state0; + } else { + callback = self->rxcallback1; + state = &self->rx_state1; + } + + switch (*state) { + case RX_STATE_FIFO_EMPTY: + __HAL_FDCAN_DISABLE_IT(&self->can, (fifo_id == FDCAN_RX_FIFO0) ? + FDCAN_IT_RX_FIFO0_NEW_MESSAGE : FDCAN_IT_RX_FIFO1_NEW_MESSAGE); + irq_reason = MP_OBJ_NEW_SMALL_INT(0); + *state = RX_STATE_MESSAGE_PENDING; + break; + case RX_STATE_MESSAGE_PENDING: + __HAL_FDCAN_DISABLE_IT(&self->can, (fifo_id == FDCAN_RX_FIFO0) ? FDCAN_IT_RX_FIFO0_FULL : FDCAN_IT_RX_FIFO1_FULL); + __HAL_FDCAN_CLEAR_FLAG(&self->can, (fifo_id == FDCAN_RX_FIFO0) ? FDCAN_FLAG_RX_FIFO0_FULL : FDCAN_FLAG_RX_FIFO1_FULL); + irq_reason = MP_OBJ_NEW_SMALL_INT(1); + *state = RX_STATE_FIFO_FULL; + break; + case RX_STATE_FIFO_FULL: + __HAL_FDCAN_DISABLE_IT(&self->can, (fifo_id == FDCAN_RX_FIFO0) ? + FDCAN_IT_RX_FIFO0_MESSAGE_LOST : FDCAN_IT_RX_FIFO1_MESSAGE_LOST); + __HAL_FDCAN_CLEAR_FLAG(&self->can, (fifo_id == FDCAN_RX_FIFO0) ? + FDCAN_FLAG_RX_FIFO0_MESSAGE_LOST : FDCAN_FLAG_RX_FIFO1_MESSAGE_LOST); + irq_reason = MP_OBJ_NEW_SMALL_INT(2); + *state = RX_STATE_FIFO_OVERFLOW; + break; + case RX_STATE_FIFO_OVERFLOW: + // This should never happen + break; + } + + pyb_can_handle_callback(self, fifo_id, callback, irq_reason); +} + +#if defined(MICROPY_HW_CAN1_TX) +void FDCAN1_IT0_IRQHandler(void) { + IRQ_ENTER(FDCAN1_IT0_IRQn); + can_rx_irq_handler(PYB_CAN_1, FDCAN_RX_FIFO0); + IRQ_EXIT(FDCAN1_IT0_IRQn); +} + +void FDCAN1_IT1_IRQHandler(void) { + IRQ_ENTER(FDCAN1_IT1_IRQn); + can_rx_irq_handler(PYB_CAN_1, FDCAN_RX_FIFO1); + IRQ_EXIT(FDCAN1_IT1_IRQn); +} +#endif + +#if defined(MICROPY_HW_CAN2_TX) +void FDCAN2_IT0_IRQHandler(void) { + IRQ_ENTER(FDCAN2_IT0_IRQn); + can_rx_irq_handler(PYB_CAN_2, FDCAN_RX_FIFO0); + IRQ_EXIT(FDCAN2_IT0_IRQn); +} + +void FDCAN2_IT1_IRQHandler(void) { + IRQ_ENTER(FDCAN2_IT1_IRQn); + can_rx_irq_handler(PYB_CAN_2, FDCAN_RX_FIFO1); + IRQ_EXIT(FDCAN2_IT1_IRQn); +} +#endif + +#endif // MICROPY_HW_ENABLE_CAN && MICROPY_HW_ENABLE_FDCAN diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index d353468f96..e0c77719e3 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -275,6 +275,9 @@ // Enable CAN if there are any peripherals defined #if defined(MICROPY_HW_CAN1_TX) || defined(MICROPY_HW_CAN2_TX) || defined(MICROPY_HW_CAN3_TX) #define MICROPY_HW_ENABLE_CAN (1) +#if defined(STM32H7) +#define MICROPY_HW_ENABLE_FDCAN (1) // define for MCUs with FDCAN +#endif #else #define MICROPY_HW_ENABLE_CAN (0) #define MICROPY_HW_MAX_CAN (0) diff --git a/ports/stm32/pin_defs_stm32.h b/ports/stm32/pin_defs_stm32.h index 89b659de5d..739083dd64 100644 --- a/ports/stm32/pin_defs_stm32.h +++ b/ports/stm32/pin_defs_stm32.h @@ -114,6 +114,14 @@ enum { #define I2S2 SPI2 #define I2S3 SPI3 +#if defined(STM32H7) +// Make H7 FDCAN more like CAN +#define CAN1 FDCAN1 +#define CAN2 FDCAN2 +#define GPIO_AF9_CAN1 GPIO_AF9_FDCAN1 +#define GPIO_AF9_CAN2 GPIO_AF9_FDCAN2 +#endif + enum { PIN_ADC1 = (1 << 0), PIN_ADC2 = (1 << 1), diff --git a/ports/stm32/pyb_can.c b/ports/stm32/pyb_can.c index 7aa6dad088..8e10bb9aa4 100644 --- a/ports/stm32/pyb_can.c +++ b/ports/stm32/pyb_can.c @@ -40,8 +40,73 @@ #if MICROPY_HW_ENABLE_CAN +#if MICROPY_HW_ENABLE_FDCAN + +#define CAN_MAX_FILTER (64) + +#define CAN_FIFO0 FDCAN_RX_FIFO0 +#define CAN_FIFO1 FDCAN_RX_FIFO1 +#define CAN_FILTER_FIFO0 (0) + +// Default timings; 125Kbps assuming 48MHz clock +#define CAN_DEFAULT_PRESCALER (32) +#define CAN_DEFAULT_SJW (1) +#define CAN_DEFAULT_BS1 (8) +#define CAN_DEFAULT_BS2 (3) + +#define CAN_MODE_NORMAL FDCAN_MODE_NORMAL +#define CAN_MODE_LOOPBACK FDCAN_MODE_EXTERNAL_LOOPBACK +#define CAN_MODE_SILENT FDCAN_MODE_BUS_MONITORING +#define CAN_MODE_SILENT_LOOPBACK FDCAN_MODE_INTERNAL_LOOPBACK + +#define CAN1_RX0_IRQn FDCAN1_IT0_IRQn +#define CAN1_RX1_IRQn FDCAN1_IT1_IRQn +#define CAN2_RX0_IRQn FDCAN2_IT0_IRQn +#define CAN2_RX1_IRQn FDCAN2_IT1_IRQn + +#define CAN_IT_FIFO0_FULL FDCAN_IT_RX_FIFO0_FULL +#define CAN_IT_FIFO1_FULL FDCAN_IT_RX_FIFO1_FULL +#define CAN_IT_FIFO0_OVRF FDCAN_IT_RX_FIFO0_MESSAGE_LOST +#define CAN_IT_FIFO1_OVRF FDCAN_IT_RX_FIFO1_MESSAGE_LOST +#define CAN_IT_FIFO0_PENDING FDCAN_IT_RX_FIFO0_NEW_MESSAGE +#define CAN_IT_FIFO1_PENDING FDCAN_IT_RX_FIFO1_NEW_MESSAGE +#define CAN_FLAG_FIFO0_FULL FDCAN_FLAG_RX_FIFO0_FULL +#define CAN_FLAG_FIFO1_FULL FDCAN_FLAG_RX_FIFO1_FULL +#define CAN_FLAG_FIFO0_OVRF FDCAN_FLAG_RX_FIFO0_MESSAGE_LOST +#define CAN_FLAG_FIFO1_OVRF FDCAN_FLAG_RX_FIFO1_MESSAGE_LOST + +#define __HAL_CAN_ENABLE_IT __HAL_FDCAN_ENABLE_IT +#define __HAL_CAN_DISABLE_IT __HAL_FDCAN_DISABLE_IT +#define __HAL_CAN_CLEAR_FLAG __HAL_FDCAN_CLEAR_FLAG +#define __HAL_CAN_MSG_PENDING HAL_FDCAN_GetRxFifoFillLevel + +// Both banks start at 0 +STATIC uint8_t can2_start_bank = 0; + +#else + +#define CAN_MAX_FILTER (28) + +#define CAN_DEFAULT_PRESCALER (100) +#define CAN_DEFAULT_SJW (1) +#define CAN_DEFAULT_BS1 (6) +#define CAN_DEFAULT_BS2 (8) + +#define CAN_IT_FIFO0_FULL CAN_IT_FF0 +#define CAN_IT_FIFO1_FULL CAN_IT_FF1 +#define CAN_IT_FIFO0_OVRF CAN_IT_FOV0 +#define CAN_IT_FIFO1_OVRF CAN_IT_FOV1 +#define CAN_IT_FIFO0_PENDING CAN_IT_FMP0 +#define CAN_IT_FIFO1_PENDING CAN_IT_FMP1 +#define CAN_FLAG_FIFO0_FULL CAN_FLAG_FF0 +#define CAN_FLAG_FIFO1_FULL CAN_FLAG_FF1 +#define CAN_FLAG_FIFO0_OVRF CAN_FLAG_FOV0 +#define CAN_FLAG_FIFO1_OVRF CAN_FLAG_FOV1 + STATIC uint8_t can2_start_bank = 14; +#endif + STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_can_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!self->is_enabled) { @@ -58,7 +123,12 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki self->can_id, mode, self->extframe ? MP_QSTR_True : MP_QSTR_False, - (self->can.Instance->MCR & CAN_MCR_ABOM) ? MP_QSTR_True : MP_QSTR_False); + #if MICROPY_HW_ENABLE_FDCAN + (self->can.Instance->CCCR & FDCAN_CCCR_DAR) ? MP_QSTR_True : MP_QSTR_False + #else + (self->can.Instance->MCR & CAN_MCR_ABOM) ? MP_QSTR_True : MP_QSTR_False + #endif + ); } } @@ -68,10 +138,10 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp static const mp_arg_t allowed_args[] = { { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL} }, { MP_QSTR_extframe, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_prescaler, MP_ARG_INT, {.u_int = 100} }, - { MP_QSTR_sjw, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_bs1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 6} }, - { MP_QSTR_bs2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_prescaler, MP_ARG_INT, {.u_int = CAN_DEFAULT_PRESCALER} }, + { MP_QSTR_sjw, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = CAN_DEFAULT_SJW} }, + { MP_QSTR_bs1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = CAN_DEFAULT_BS1} }, + { MP_QSTR_bs2, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = CAN_DEFAULT_BS2} }, { MP_QSTR_auto_restart, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; @@ -179,12 +249,21 @@ STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { mp_raise_ValueError(NULL); } CAN_TypeDef *can = self->can.Instance; + #if MICROPY_HW_ENABLE_FDCAN + can->CCCR |= FDCAN_CCCR_INIT; + while ((can->CCCR & FDCAN_CCCR_INIT) == 0) { + } + can->CCCR &= ~FDCAN_CCCR_INIT; + while ((can->CCCR & FDCAN_CCCR_INIT)) { + } + #else can->MCR |= CAN_MCR_INRQ; while ((can->MSR & CAN_MSR_INAK) == 0) { } can->MCR &= ~CAN_MCR_INRQ; while ((can->MSR & CAN_MSR_INAK)) { } + #endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_restart_obj, pyb_can_restart); @@ -195,6 +274,17 @@ STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { mp_int_t state = CAN_STATE_STOPPED; if (self->is_enabled) { CAN_TypeDef *can = self->can.Instance; + #if MICROPY_HW_ENABLE_FDCAN + if (can->PSR & FDCAN_PSR_BO) { + state = CAN_STATE_BUS_OFF; + } else if (can->PSR & FDCAN_PSR_EP) { + state = CAN_STATE_ERROR_PASSIVE; + } else if (can->PSR & FDCAN_PSR_EW) { + state = CAN_STATE_ERROR_WARNING; + } else { + state = CAN_STATE_ERROR_ACTIVE; + } + #else if (can->ESR & CAN_ESR_BOFF) { state = CAN_STATE_BUS_OFF; } else if (can->ESR & CAN_ESR_EPVF) { @@ -204,6 +294,7 @@ STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { } else { state = CAN_STATE_ERROR_ACTIVE; } + #endif } return MP_OBJ_NEW_SMALL_INT(state); } @@ -211,6 +302,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state); // Get info about error states and TX/RX buffers STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { + #if MICROPY_HW_ENABLE_FDCAN + // TODO implement for FDCAN + return mp_const_none; + #else pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); mp_obj_list_t *list; if (n_args == 1) { @@ -236,6 +331,7 @@ STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3); list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3); return MP_OBJ_FROM_PTR(list); + #endif } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info); @@ -282,6 +378,32 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // send the data CanTxMsgTypeDef tx_msg; + + #if MICROPY_HW_ENABLE_FDCAN + uint8_t tx_data[8]; + tx_msg.MessageMarker = 0; + tx_msg.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + tx_msg.BitRateSwitch = FDCAN_BRS_OFF; + tx_msg.FDFormat = FDCAN_CLASSIC_CAN; + tx_msg.TxEventFifoControl = FDCAN_NO_TX_EVENTS; + tx_msg.DataLength = (bufinfo.len << 16); // TODO DLC for len > 8 + + if (self->extframe) { + tx_msg.Identifier = args[ARG_id].u_int & 0x1FFFFFFF; + tx_msg.IdType = FDCAN_EXTENDED_ID; + } else { + tx_msg.Identifier = args[ARG_id].u_int & 0x7FF; + tx_msg.IdType = FDCAN_STANDARD_ID; + } + if (args[ARG_rtr].u_bool == false) { + tx_msg.TxFrameType = FDCAN_DATA_FRAME; + } else { + tx_msg.TxFrameType = FDCAN_REMOTE_FRAME; + } + #else + tx_msg.DLC = bufinfo.len; + uint8_t *tx_data = tx_msg.Data; // Data is uint32_t but holds only 1 byte + if (self->extframe) { tx_msg.ExtId = args[ARG_id].u_int & 0x1FFFFFFF; tx_msg.IDE = CAN_ID_EXT; @@ -294,13 +416,19 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t * } else { tx_msg.RTR = CAN_RTR_REMOTE; } - tx_msg.DLC = bufinfo.len; + #endif + for (mp_uint_t i = 0; i < bufinfo.len; i++) { - tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte + tx_data[i] = ((byte*)bufinfo.buf)[i]; } + HAL_StatusTypeDef status; + #if MICROPY_HW_ENABLE_FDCAN + status = HAL_FDCAN_AddMessageToTxFifoQ(&self->can, &tx_msg, tx_data); + #else self->can.pTxMsg = &tx_msg; - HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[ARG_timeout].u_int); + status = CAN_Transmit(&self->can, args[ARG_timeout].u_int); + #endif if (status != HAL_OK) { mp_hal_raise(status); @@ -326,13 +454,33 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * // receive the data CanRxMsgTypeDef rx_msg; - int ret = can_receive(self->can.Instance, args[ARG_fifo].u_int, &rx_msg, args[ARG_timeout].u_int); + #if MICROPY_HW_ENABLE_FDCAN + uint8_t rx_data[8]; + #else + uint8_t *rx_data = rx_msg.Data; + #endif + + mp_uint_t fifo = args[ARG_fifo].u_int; + if (fifo == 0) { + fifo = CAN_FIFO0; + } else if (fifo == 1) { + fifo = CAN_FIFO1; + } else { + mp_raise_TypeError(NULL); + } + + int ret = can_receive(&self->can, fifo, &rx_msg, rx_data, args[ARG_timeout].u_int); if (ret < 0) { mp_raise_OSError(-ret); } + #if MICROPY_HW_ENABLE_FDCAN + uint32_t rx_dlc = rx_msg.DataLength; + #else + uint32_t rx_dlc = rx_msg.DLC; + #endif + // Manage the rx state machine - mp_int_t fifo = args[ARG_fifo].u_int; if ((fifo == CAN_FIFO0 && self->rxcallback0 != mp_const_none) || (fifo == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) { byte *state = (fifo == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1; @@ -343,17 +491,17 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * case RX_STATE_MESSAGE_PENDING: if (__HAL_CAN_MSG_PENDING(&self->can, fifo) == 0) { // Fifo is empty - __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FIFO0_PENDING : CAN_IT_FIFO1_PENDING); *state = RX_STATE_FIFO_EMPTY; } break; case RX_STATE_FIFO_FULL: - __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FIFO0_FULL : CAN_IT_FIFO1_FULL); *state = RX_STATE_MESSAGE_PENDING; break; case RX_STATE_FIFO_OVERFLOW: - __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1); - __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FIFO0_OVRF : CAN_IT_FIFO1_OVRF); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == CAN_FIFO0) ? CAN_IT_FIFO0_FULL : CAN_IT_FIFO1_FULL); *state = RX_STATE_MESSAGE_PENDING; break; } @@ -366,7 +514,7 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * if (ret_obj == mp_const_none) { ret_obj = mp_obj_new_tuple(4, NULL); items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items; - items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC); + items[3] = mp_obj_new_bytes(rx_data, rx_dlc); } else { // User should provide a list of length at least 4 to hold the values if (!mp_obj_is_type(ret_obj, &mp_type_list)) { @@ -387,18 +535,20 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * || (mv->typecode | 0x20) == (MP_OBJ_ARRAY_TYPECODE_FLAG_RW | 'b'))) { mp_raise_ValueError(NULL); } - mv->len = rx_msg.DLC; - memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC); + mv->len = rx_dlc; + memcpy(mv->items, rx_data, rx_dlc); } // Populate the first 3 values of the tuple/list - if (rx_msg.IDE == CAN_ID_STD) { - items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); - } else { - items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); - } + #if MICROPY_HW_ENABLE_FDCAN + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.Identifier); + items[1] = rx_msg.RxFrameType == FDCAN_REMOTE_FRAME ? mp_const_true : mp_const_false; + items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FilterIndex); + #else + items[0] = MP_OBJ_NEW_SMALL_INT((rx_msg.IDE == CAN_ID_STD ? rx_msg.StdId : rx_msg.ExtId)); items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); + #endif // Return the result return ret_obj; @@ -407,12 +557,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv); // initfilterbanks(n) STATIC mp_obj_t pyb_can_initfilterbanks(mp_obj_t self, mp_obj_t bank_in) { + #if MICROPY_HW_ENABLE_FDCAN + can2_start_bank = 0; + #else can2_start_bank = mp_obj_get_int(bank_in); + #endif - for (int f = 0; f < 28; f++) { - can_clearfilter(f, can2_start_bank); + for (int f = 0; f < CAN_MAX_FILTER; f++) { + can_clearfilter(self, f, can2_start_bank); } - return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_initfilterbanks_fun_obj, pyb_can_initfilterbanks); @@ -424,7 +577,7 @@ STATIC mp_obj_t pyb_can_clearfilter(mp_obj_t self_in, mp_obj_t bank_in) { if (self->can_id == 2) { f += can2_start_bank; } - can_clearfilter(f, can2_start_bank); + can_clearfilter(self, f, can2_start_bank); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_clearfilter_obj, pyb_can_clearfilter); @@ -446,6 +599,41 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + #if MICROPY_HW_ENABLE_FDCAN + FDCAN_FilterTypeDef filter = {0}; + filter.IdType = FDCAN_STANDARD_ID; + // TODO check filter index + filter.FilterIndex = args[ARG_bank].u_int; + + // Check filter mode + if (((args[ARG_mode].u_int != FDCAN_FILTER_RANGE) && + (args[ARG_mode].u_int != FDCAN_FILTER_DUAL) && + (args[ARG_mode].u_int != FDCAN_FILTER_MASK))) { + goto error; + } + + // Check FIFO index. + if (args[ARG_fifo].u_int == 0) { + filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; + } else if (args[ARG_fifo].u_int == 1) { + filter.FilterConfig = FDCAN_FILTER_TO_RXFIFO1; + } else { + goto error; + } + + size_t len; + mp_obj_t *params; + mp_obj_get_array(args[ARG_params].u_obj, &len, ¶ms); + if (len != 2) { // Check params len + goto error; + } + filter.FilterID1 = mp_obj_get_int(params[0]); + filter.FilterID2 = mp_obj_get_int(params[1]); + filter.FilterType = args[ARG_mode].u_int; + HAL_FDCAN_ConfigFilter(&self->can, &filter); + + #else + size_t len; size_t rtr_len; mp_uint_t rtr_masks[4] = {0, 0, 0, 0}; @@ -553,9 +741,9 @@ STATIC mp_obj_t pyb_can_setfilter(size_t n_args, const mp_obj_t *pos_args, mp_ma filter.FilterActivation = ENABLE; filter.BankNumber = can2_start_bank; HAL_CAN_ConfigFilter(&self->can, &filter); + #endif return mp_const_none; - error: mp_raise_ValueError("CAN filter parameter error"); } @@ -568,11 +756,11 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t callback = (fifo == 0) ? &self->rxcallback0 : &self->rxcallback1; if (callback_in == mp_const_none) { - __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1); - __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1); - __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1); - __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FF0 : CAN_FLAG_FF1); - __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FOV0 : CAN_FLAG_FOV1); + __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FIFO0_PENDING : CAN_IT_FIFO1_PENDING); + __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FIFO0_FULL : CAN_IT_FIFO1_FULL); + __HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FIFO0_OVRF : CAN_IT_FIFO1_OVRF); + __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FIFO0_FULL : CAN_FLAG_FIFO1_FULL); + __HAL_CAN_CLEAR_FLAG(&self->can, (fifo == CAN_FIFO0) ? CAN_FLAG_FIFO0_OVRF : CAN_FLAG_FIFO1_OVRF); *callback = mp_const_none; } else if (*callback != mp_const_none) { // Rx call backs has already been initialized @@ -594,9 +782,9 @@ STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t } NVIC_SetPriority(irq, IRQ_PRI_CAN); HAL_NVIC_EnableIRQ(irq); - __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1); - __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1); - __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FIFO0_PENDING : CAN_IT_FIFO1_PENDING); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FIFO0_FULL : CAN_IT_FIFO1_FULL); + __HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FIFO0_OVRF : CAN_IT_FIFO1_OVRF); } return mp_const_none; } @@ -617,6 +805,16 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_clearfilter), MP_ROM_PTR(&pyb_can_clearfilter_obj) }, { MP_ROM_QSTR(MP_QSTR_rxcallback), MP_ROM_PTR(&pyb_can_rxcallback_obj) }, + #if MICROPY_HW_ENABLE_FDCAN + { MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_INT(CAN_MODE_NORMAL) }, + { MP_ROM_QSTR(MP_QSTR_LOOPBACK), MP_ROM_INT(CAN_MODE_LOOPBACK) }, + { MP_ROM_QSTR(MP_QSTR_SILENT), MP_ROM_INT(CAN_MODE_SILENT) }, + { MP_ROM_QSTR(MP_QSTR_SILENT_LOOPBACK), MP_ROM_INT(CAN_MODE_SILENT_LOOPBACK) }, + + { MP_ROM_QSTR(MP_QSTR_RANGE), MP_ROM_INT(FDCAN_FILTER_RANGE) }, + { MP_ROM_QSTR(MP_QSTR_DUAL), MP_ROM_INT(FDCAN_FILTER_DUAL) }, + { MP_ROM_QSTR(MP_QSTR_MASK), MP_ROM_INT(FDCAN_FILTER_MASK) }, + #else // class constants // Note: we use the ST constants >> 4 so they fit in a small-int. The // right-shift is undone when the constants are used in the init function. @@ -624,10 +822,12 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_LOOPBACK), MP_ROM_INT(CAN_MODE_LOOPBACK >> 4) }, { MP_ROM_QSTR(MP_QSTR_SILENT), MP_ROM_INT(CAN_MODE_SILENT >> 4) }, { MP_ROM_QSTR(MP_QSTR_SILENT_LOOPBACK), MP_ROM_INT(CAN_MODE_SILENT_LOOPBACK >> 4) }, + { MP_ROM_QSTR(MP_QSTR_MASK16), MP_ROM_INT(MASK16) }, { MP_ROM_QSTR(MP_QSTR_LIST16), MP_ROM_INT(LIST16) }, { MP_ROM_QSTR(MP_QSTR_MASK32), MP_ROM_INT(MASK32) }, { MP_ROM_QSTR(MP_QSTR_LIST32), MP_ROM_INT(LIST32) }, + #endif // values for CAN.state() { MP_ROM_QSTR(MP_QSTR_STOPPED), MP_ROM_INT(CAN_STATE_STOPPED) }, @@ -649,7 +849,12 @@ STATIC mp_uint_t can_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, i || (__HAL_CAN_MSG_PENDING(&self->can, CAN_FIFO1) != 0))) { ret |= MP_STREAM_POLL_RD; } - if ((flags & MP_STREAM_POLL_WR) && (self->can.Instance->TSR & CAN_TSR_TME)) { + #if MICROPY_HW_ENABLE_FDCAN + if ((flags & MP_STREAM_POLL_WR) && (self->can.Instance->IR & FDCAN_IR_TFE)) + #else + if ((flags & MP_STREAM_POLL_WR) && (self->can.Instance->TSR & CAN_TSR_TME)) + #endif + { ret |= MP_STREAM_POLL_WR; } } else {