diff options
| author | iabdalkader <i.abdalkader@gmail.com> | 2022-01-17 00:12:01 +0200 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2022-04-02 22:37:27 +1100 |
| commit | ff287d085f95ab0ca3fdf67ee9d8cce6f046b01e (patch) | |
| tree | 618272c7c9c40f080c19b04d9099fe2727164949 /ports/stm32/fdcan.c | |
| parent | 8baf05af8c8011d586ce767da70b4c6f47f55d6c (diff) | |
stm32/pyb_can: Enable CAN FD frame support and BRS.
- Enable CAN FD frame support and BRS.
- Optimize the message RAM usage per FDCAN instance.
- Document the usage and different sections of the Message RAM.
Diffstat (limited to 'ports/stm32/fdcan.c')
| -rw-r--r-- | ports/stm32/fdcan.c | 98 |
1 files changed, 60 insertions, 38 deletions
diff --git a/ports/stm32/fdcan.c b/ports/stm32/fdcan.c index 8465b806a..63c6c3123 100644 --- a/ports/stm32/fdcan.c +++ b/ports/stm32/fdcan.c @@ -56,14 +56,19 @@ #define FDCAN_IT_GROUP_RX_FIFO1 (FDCAN_ILS_RF1NL | FDCAN_ILS_RF1FL | FDCAN_ILS_RF1LL) #endif +// The dedicated Message RAM should be 2560 words, but the way it's defined in stm32h7xx_hal_fdcan.c +// as (SRAMCAN_BASE + FDCAN_MESSAGE_RAM_SIZE - 0x4U) limits the usable number of words to 2559 words. +#define FDCAN_MESSAGE_RAM_SIZE (2560 - 1) + // also defined in <PROC>_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}; +const uint8_t DLCtoBytes[16] = {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; FDCAN_InitTypeDef *init = &can_obj->can.Init; - init->FrameFormat = FDCAN_FRAME_CLASSIC; + // Configure FDCAN with FD frame and BRS support. + init->FrameFormat = FDCAN_FRAME_FD_BRS; init->Mode = mode; init->NominalPrescaler = prescaler; // tq = NominalPrescaler x (1/fdcan_ker_ck) @@ -81,46 +86,58 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_ 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. + init->StdFiltersNbr = 28; // /2 ? if FDCAN2 is used !!? + init->ExtFiltersNbr = 0; // Not used + init->TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + #elif defined(STM32H7) + // The dedicated FDCAN RAM is 2560 32-bit words and shared between the FDCAN instances. + // To support 2 FDCAN instances simultaneously, the Message RAM is divided in half by + // setting the second FDCAN memory offset to half the RAM size. With this configuration, + // the maximum words per FDCAN instance is 1280 32-bit words. if (can_obj->can_id == PYB_CAN_1) { init->MessageRAMOffset = 0; } else { - init->MessageRAMOffset = 2560 / 2; + init->MessageRAMOffset = FDCAN_MESSAGE_RAM_SIZE / 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 - - 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; + // An element stored in the Message RAM contains an identifier, DLC, control bits, the + // data field and the specific transmission or reception bits field for control. + // The following code configures the different Message RAM sections per FDCAN instance. + + // The RAM filtering section is configured for 64 x 1 word elements for 11-bit standard + // identifiers, and 31 x 2 words elements for 29-bit extended identifiers. + // The total number of words reserved for the filtering per FDCAN instance is 126 words. + init->StdFiltersNbr = 64; + // Note extended identifiers are Not used in pyb_can.c and Not handled correctly. + // Disable the extended identifiers filters for now until this is fixed properly. + init->ExtFiltersNbr = 0 /*31*/; + + // The Tx event FIFO is used to store the message ID and the timestamp of successfully + // transmitted elements. The Tx event FIFO can store a maximum of 32 (2 words) elements. + // NOTE: Events are stored in Tx event FIFO only if tx_msg.TxEventFifoControl is enabled. + init->TxEventsNbr = 0; + + // Transmission section is configured in FIFO mode operation, with no dedicated Tx buffers. + // The Tx FIFO can store a maximum of 32 elements (or 576 words), each element is 18 words + // long (to support a maximum of 64 bytes data field): + // 2 words header + 16 words data field (to support up to 64 bytes of data). + // The total number of words reserved for the Tx FIFO per FDCAN instance is 288 words. + init->TxBuffersNbr = 0; + init->TxFifoQueueElmtsNbr = 16; + init->TxElmtSize = FDCAN_DATA_BYTES_64; + init->TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + // Reception section is configured to use Rx FIFO 0 and Rx FIFO1, with no dedicated Rx buffers. + // Each Rx FIFO can store a maximum of 64 elements (1152 words), each element is 18 words + // long (to support a maximum of 64 bytes data field): + // 2 words header + 16 words data field (to support up to 64 bytes of data). + // The total number of words reserved for the Rx FIFOs per FDCAN instance is 864 words. + init->RxBuffersNbr = 0; + init->RxFifo0ElmtsNbr = 24; + init->RxFifo0ElmtSize = FDCAN_DATA_BYTES_64; + init->RxFifo1ElmtsNbr = 24; + init->RxFifo1ElmtSize = FDCAN_DATA_BYTES_64; #endif - init->TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; - FDCAN_GlobalTypeDef *CANx = NULL; const pin_obj_t *pins[2]; @@ -159,7 +176,10 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_ // init CANx can_obj->can.Instance = CANx; - HAL_FDCAN_Init(&can_obj->can); + // catch bad configuration errors. + if (HAL_FDCAN_Init(&can_obj->can) != HAL_OK) { + return false; + } // Disable acceptance of non-matching frames (enabled by default) HAL_FDCAN_ConfigGlobalFilter(&can_obj->can, FDCAN_REJECT, FDCAN_REJECT, DISABLE, DISABLE); @@ -168,7 +188,7 @@ bool can_init(pyb_can_obj_t *can_obj, uint32_t mode, uint32_t prescaler, uint32_ HAL_FDCAN_Start(&can_obj->can); // Reset all filters - for (int f = 0; f < 64; ++f) { + for (int f = 0; f < init->StdFiltersNbr; ++f) { can_clearfilter(can_obj, f, 0); } @@ -299,10 +319,12 @@ int can_receive(FDCAN_HandleTypeDef *can, int fifo, FDCAN_RxHeaderTypeDef *hdr, hdr->FDFormat = *address & FDCAN_ELEMENT_MASK_FDF; hdr->FilterIndex = (*address & FDCAN_ELEMENT_MASK_FIDX) >> 24; hdr->IsFilterMatchingFrame = (*address++ & FDCAN_ELEMENT_MASK_ANMF) >> 31; + // Convert DLC to Bytes. + hdr->DataLength = DLCtoBytes[hdr->DataLength]; // Copy data uint8_t *pdata = (uint8_t *)address; - for (uint32_t i = 0; i < DLCtoBytes[hdr->DataLength]; ++i) { + for (uint32_t i = 0; i < hdr->DataLength; ++i) { *data++ = *pdata++; } |
