diff --git a/ports/stm32/fdcan.c b/ports/stm32/fdcan.c index 2892572f40..778902735e 100644 --- a/ports/stm32/fdcan.c +++ b/ports/stm32/fdcan.c @@ -44,6 +44,13 @@ #define FDCAN_ELEMENT_MASK_FIDX (0x7f000000) // Filter Index #define FDCAN_ELEMENT_MASK_ANMF (0x80000000) // Accepted Non-matching Frame +#define FDCAN_RX_FIFO0_MASK (FDCAN_FLAG_RX_FIFO0_MESSAGE_LOST | FDCAN_FLAG_RX_FIFO0_FULL | FDCAN_FLAG_RX_FIFO0_NEW_MESSAGE) +#define FDCAN_RX_FIFO1_MASK (FDCAN_FLAG_RX_FIFO1_MESSAGE_LOST | FDCAN_FLAG_RX_FIFO1_FULL | FDCAN_FLAG_RX_FIFO1_NEW_MESSAGE) +#define FDCAN_ERROR_STATUS_MASK (FDCAN_FLAG_ERROR_PASSIVE | FDCAN_FLAG_ERROR_WARNING | FDCAN_FLAG_BUS_OFF) + +// also defined in _hal_fdcan.c, but not able to declare extern and reach the variable +static const uint8_t DLCtoBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64}; + 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; @@ -60,6 +67,16 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_ init->TransmitPause = DISABLE; init->ProtocolException = ENABLE; + #if defined(STM32G4) + init->ClockDivider = FDCAN_CLOCK_DIV1; + init->DataPrescaler = 1; + init->DataSyncJumpWidth = 1; + init->DataTimeSeg1 = 1; + init->DataTimeSeg2 = 1; + #endif + + #if defined(STM32H7) + // variable used to specify RAM address in HAL, only for H7, G4 uses defined offset address in HAL // 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) { @@ -67,6 +84,14 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_ } else { init->MessageRAMOffset = 2560 / 2; } + #endif + + #if defined(STM32G4) + + init->StdFiltersNbr = 28; // /2 ? if FDCAN2 is used !!? + init->ExtFiltersNbr = 0; // Not used + + #elif defined(STM32H7) init->StdFiltersNbr = 64; // 128 / 2 init->ExtFiltersNbr = 0; // Not used @@ -83,6 +108,9 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_ init->TxFifoQueueElmtsNbr = 16; // Tx fifo elements init->TxElmtSize = FDCAN_DATA_BYTES_8; + + #endif + init->TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; FDCAN_GlobalTypeDef *CANx = NULL; @@ -148,21 +176,27 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_ NVIC_SetPriority(FDCAN1_IT1_IRQn, IRQ_PRI_CAN); HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn); break; + #if defined(MICROPY_HW_CAN2_TX) 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; + #endif default: return false; } + // FDCAN IT 0 + HAL_FDCAN_ConfigInterruptLines(&can_obj->can, FDCAN_IT_GROUP_RX_FIFO0 | FDCAN_IT_GROUP_BIT_LINE_ERROR | FDCAN_IT_GROUP_PROTOCOL_ERROR, FDCAN_INTERRUPT_LINE0); + // FDCAN IT 1 + HAL_FDCAN_ConfigInterruptLines(&can_obj->can, FDCAN_IT_GROUP_RX_FIFO1, FDCAN_INTERRUPT_LINE1); - __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); - + uint32_t ActiveITs = FDCAN_IT_BUS_OFF | FDCAN_IT_ERROR_WARNING | FDCAN_IT_ERROR_PASSIVE; + ActiveITs |= FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO1_NEW_MESSAGE; + ActiveITs |= FDCAN_IT_RX_FIFO0_MESSAGE_LOST | FDCAN_IT_RX_FIFO1_MESSAGE_LOST; + ActiveITs |= FDCAN_IT_RX_FIFO0_FULL | FDCAN_IT_RX_FIFO1_FULL; + HAL_FDCAN_ActivateNotification(&can_obj->can, ActiveITs, 0); return true; } @@ -227,10 +261,19 @@ int can_receive(FDCAN_HandleTypeDef *can, int fifo, FDCAN_RxHeaderTypeDef *hdr, uint32_t index, *address; if (fifo == FDCAN_RX_FIFO0) { index = (*rxf & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos; + #if defined(STM32G4) + address = (uint32_t *)(can->msgRam.RxFIFO0SA + (index * (18U * 4U))); // SRAMCAN_RF0_SIZE bytes, size not configurable + #else address = (uint32_t *)(can->msgRam.RxFIFO0SA + (index * can->Init.RxFifo0ElmtSize * 4)); + #endif } else { index = (*rxf & FDCAN_RXF1S_F1GI) >> FDCAN_RXF1S_F1GI_Pos; + #if defined(STM32G4) + // ToDo: test FIFO1, FIFO 0 is ok + address = (uint32_t *)(can->msgRam.RxFIFO1SA + (index * (18U * 4U))); // SRAMCAN_RF1_SIZE bytes, size not configurable + #else address = (uint32_t *)(can->msgRam.RxFIFO1SA + (index * can->Init.RxFifo1ElmtSize * 4)); + #endif } // Parse header of message @@ -251,7 +294,7 @@ int can_receive(FDCAN_HandleTypeDef *can, int fifo, FDCAN_RxHeaderTypeDef *hdr, // Copy data uint8_t *pdata = (uint8_t *)address; - for (uint32_t i = 0; i < 8; ++i) { // TODO use DLCtoBytes[hdr->DataLength] for length > 8 + for (uint32_t i = 0; i < DLCtoBytes[hdr->DataLength]; ++i) { *data++ = *pdata++; } @@ -269,41 +312,97 @@ STATIC void can_rx_irq_handler(uint can_id, uint fifo_id) { self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1]; + CAN_TypeDef *can = self->can.Instance; + + uint32_t RxFifo0ITs; + uint32_t RxFifo1ITs; + // uint32_t Errors; + uint32_t ErrorStatusITs; + uint32_t Psr; + + RxFifo0ITs = can->IR & FDCAN_RX_FIFO0_MASK; + RxFifo0ITs &= can->IE; + RxFifo1ITs = can->IR & FDCAN_RX_FIFO1_MASK; + RxFifo1ITs &= can->IE; + // Errors = (&self->can)->Instance->IR & FDCAN_ERROR_MASK; + // Errors &= (&self->can)->Instance->IE; + ErrorStatusITs = can->IR & FDCAN_ERROR_STATUS_MASK; + ErrorStatusITs &= can->IE; + Psr = can->PSR; + if (fifo_id == FDCAN_RX_FIFO0) { callback = self->rxcallback0; state = &self->rx_state0; + if (RxFifo0ITs & FDCAN_FLAG_RX_FIFO0_NEW_MESSAGE) { + __HAL_FDCAN_DISABLE_IT(&self->can, FDCAN_IT_RX_FIFO0_NEW_MESSAGE); + __HAL_FDCAN_CLEAR_FLAG(&self->can, FDCAN_FLAG_RX_FIFO0_NEW_MESSAGE); + irq_reason = MP_OBJ_NEW_SMALL_INT(0); + *state = RX_STATE_MESSAGE_PENDING; + + } + if (RxFifo0ITs & FDCAN_FLAG_RX_FIFO0_FULL) { + __HAL_FDCAN_DISABLE_IT(&self->can, FDCAN_IT_RX_FIFO0_FULL); + __HAL_FDCAN_CLEAR_FLAG(&self->can, FDCAN_FLAG_RX_FIFO0_FULL); + irq_reason = MP_OBJ_NEW_SMALL_INT(1); + *state = RX_STATE_FIFO_FULL; + + } + if (RxFifo0ITs & FDCAN_FLAG_RX_FIFO0_MESSAGE_LOST) { + __HAL_FDCAN_DISABLE_IT(&self->can, FDCAN_IT_RX_FIFO0_MESSAGE_LOST); + __HAL_FDCAN_CLEAR_FLAG(&self->can, FDCAN_FLAG_RX_FIFO0_MESSAGE_LOST); + irq_reason = MP_OBJ_NEW_SMALL_INT(2); + *state = RX_STATE_FIFO_OVERFLOW; + } + } 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); + if (RxFifo1ITs & FDCAN_FLAG_RX_FIFO1_NEW_MESSAGE) { + __HAL_FDCAN_DISABLE_IT(&self->can, FDCAN_IT_RX_FIFO1_NEW_MESSAGE); + __HAL_FDCAN_CLEAR_FLAG(&self->can, FDCAN_FLAG_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); + + } + if (RxFifo1ITs & FDCAN_FLAG_RX_FIFO1_FULL) { + __HAL_FDCAN_DISABLE_IT(&self->can, FDCAN_IT_RX_FIFO1_FULL); + __HAL_FDCAN_CLEAR_FLAG(&self->can, 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); + + } + if (RxFifo1ITs & FDCAN_FLAG_RX_FIFO1_MESSAGE_LOST) { + __HAL_FDCAN_DISABLE_IT(&self->can, FDCAN_IT_RX_FIFO1_MESSAGE_LOST); + __HAL_FDCAN_CLEAR_FLAG(&self->can, 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; + } + } + + if (ErrorStatusITs & FDCAN_FLAG_ERROR_WARNING) { + __HAL_FDCAN_CLEAR_FLAG(&self->can, FDCAN_FLAG_ERROR_WARNING); + if (Psr & FDCAN_PSR_EW) { + irq_reason = MP_OBJ_NEW_SMALL_INT(3); + // mp_printf(MICROPY_ERROR_PRINTER, "clear warning %08x\n", (can->IR & FDCAN_ERROR_STATUS_MASK)); + } + } + if (ErrorStatusITs & FDCAN_FLAG_ERROR_PASSIVE) { + __HAL_FDCAN_CLEAR_FLAG(&self->can, FDCAN_FLAG_ERROR_PASSIVE); + if (Psr & FDCAN_PSR_EP) { + irq_reason = MP_OBJ_NEW_SMALL_INT(4); + // mp_printf(MICROPY_ERROR_PRINTER, "clear passive %08x\n", (can->IR & FDCAN_ERROR_STATUS_MASK)); + } + } + if (ErrorStatusITs & FDCAN_FLAG_BUS_OFF) { + __HAL_FDCAN_CLEAR_FLAG(&self->can, FDCAN_FLAG_BUS_OFF); + if (Psr & FDCAN_PSR_BO) { + irq_reason = MP_OBJ_NEW_SMALL_INT(5); + // mp_printf(MICROPY_ERROR_PRINTER, "bus off %08x\n", (can->IR & FDCAN_ERROR_STATUS_MASK)); + } } pyb_can_handle_callback(self, fifo_id, callback, irq_reason); + // mp_printf(MICROPY_ERROR_PRINTER, "Ints: %08x, %08x, %08x\n", RxFifo0ITs, RxFifo1ITs, ErrorStatusITs); } #if defined(MICROPY_HW_CAN1_TX) diff --git a/ports/stm32/make-stmconst.py b/ports/stm32/make-stmconst.py index 217a801a8f..554d662384 100644 --- a/ports/stm32/make-stmconst.py +++ b/ports/stm32/make-stmconst.py @@ -64,7 +64,7 @@ class Lexer: ( "#define typedef", re.compile( - r"#define +(?P[A-Z0-9_]+(ext)?) +\(\([A-Za-z0-9_]+_TypeDef \*\) (?P[A-Za-z0-9_]+)\)($| +/\*)" + r"#define +(?P[A-Z0-9_]+(ext)?) +\(\([A-Za-z0-9_]+_(Global)?TypeDef \*\) (?P[A-Za-z0-9_]+)\)($| +/\*)" ), ), ("typedef struct", re.compile(r"typedef struct$")), @@ -281,6 +281,7 @@ def main(): #'CAN_FIFOMailBox', #'CAN_FilterRegister', #'CAN', + "FDCAN", "CRC", "DAC", "DBGMCU", diff --git a/ports/stm32/pyb_can.c b/ports/stm32/pyb_can.c index 3e55069ab9..8007fd9e3c 100644 --- a/ports/stm32/pyb_can.c +++ b/ports/stm32/pyb_can.c @@ -47,8 +47,14 @@ #define CAN_FIFO1 FDCAN_RX_FIFO1 #define CAN_FILTER_FIFO0 (0) -// Default timings; 125Kbps assuming 48MHz clock +// Default timings; 125Kbps +#if defined(STM32G4) +// assuming 24MHz clock +#define CAN_DEFAULT_PRESCALER (16) +#else +// assuming 48MHz clock #define CAN_DEFAULT_PRESCALER (32) +#endif #define CAN_DEFAULT_SJW (1) #define CAN_DEFAULT_BS1 (8) #define CAN_DEFAULT_BS2 (3) @@ -60,8 +66,10 @@ #define CAN1_RX0_IRQn FDCAN1_IT0_IRQn #define CAN1_RX1_IRQn FDCAN1_IT1_IRQn +#if defined(CAN2) #define CAN2_RX0_IRQn FDCAN2_IT0_IRQn #define CAN2_RX1_IRQn FDCAN2_IT1_IRQn +#endif #define CAN_IT_FIFO0_FULL FDCAN_IT_RX_FIFO0_FULL #define CAN_IT_FIFO1_FULL FDCAN_IT_RX_FIFO1_FULL @@ -326,6 +334,9 @@ STATIC mp_obj_t pyb_can_restart(mp_obj_t self_in) { can->CCCR |= FDCAN_CCCR_INIT; while ((can->CCCR & FDCAN_CCCR_INIT) == 0) { } + can->CCCR |= FDCAN_CCCR_CCE; + while ((can->CCCR & FDCAN_CCCR_CCE) == 0) { + } can->CCCR &= ~FDCAN_CCCR_INIT; while ((can->CCCR & FDCAN_CCCR_INIT)) { } @@ -348,11 +359,12 @@ STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) { if (self->is_enabled) { CAN_TypeDef *can = self->can.Instance; #if MICROPY_HW_ENABLE_FDCAN - if (can->PSR & FDCAN_PSR_BO) { + uint32_t psr = can->PSR; + if (psr & FDCAN_PSR_BO) { state = CAN_STATE_BUS_OFF; - } else if (can->PSR & FDCAN_PSR_EP) { + } else if (psr & FDCAN_PSR_EP) { state = CAN_STATE_ERROR_PASSIVE; - } else if (can->PSR & FDCAN_PSR_EW) { + } else if (psr & FDCAN_PSR_EW) { state = CAN_STATE_ERROR_WARNING; } else { state = CAN_STATE_ERROR_ACTIVE; @@ -375,10 +387,6 @@ 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) { @@ -392,6 +400,20 @@ STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { mp_raise_ValueError(NULL); } } + + #if MICROPY_HW_ENABLE_FDCAN + FDCAN_GlobalTypeDef *can = self->can.Instance; + uint32_t esr = can->ECR; + list->items[0] = MP_OBJ_NEW_SMALL_INT((esr & FDCAN_ECR_TEC_Msk) >> FDCAN_ECR_TEC_Pos); + list->items[1] = MP_OBJ_NEW_SMALL_INT((esr & FDCAN_ECR_REC_Msk) >> FDCAN_ECR_REC_Pos); + list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning); + list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive); + list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off); + uint32_t TXEFS = can->TXEFS; + list->items[5] = MP_OBJ_NEW_SMALL_INT(TXEFS & 0x7); + list->items[6] = MP_OBJ_NEW_SMALL_INT((can->RXF0S & FDCAN_RXF0S_F0FL_Msk) >> FDCAN_RXF0S_F0FL_Pos); + list->items[7] = MP_OBJ_NEW_SMALL_INT((can->RXF1S & FDCAN_RXF1S_F1FL_Msk) >> FDCAN_RXF1S_F1FL_Pos); + #else CAN_TypeDef *can = self->can.Instance; uint32_t esr = can->ESR; list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff); @@ -403,8 +425,9 @@ STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) { list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending); 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 + + return MP_OBJ_FROM_PTR(list); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info);