From c4ea154c8fcb1ccf336cede66d31735cb82ae325 Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Tue, 9 Mar 2021 01:10:14 -0800 Subject: [PATCH] backport fdcan driver --- os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c | 90 ++++++++++++++----- os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h | 60 ++++++++----- os/hal/ports/STM32/STM32H7xx/stm32_registry.h | 14 +-- 3 files changed, 113 insertions(+), 51 deletions(-) diff --git a/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c b/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c index 38e5ff688..b6b46ee07 100644 --- a/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c +++ b/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.c @@ -134,7 +134,7 @@ static bool fdcan_clock_stop(CANDriver *canp) { canp->fdcan->CCCR |= FDCAN_CCCR_CSR; start = osalOsGetSystemTimeX(); end = osalTimeAddX(start, TIME_MS2I(TIMEOUT_INIT_MS)); - while ((canp->fdcan->CCCR & FDCAN_CCCR_CSA) != 0U) { + while ((canp->fdcan->CCCR & FDCAN_CCCR_CSA) == 0U) { if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { return true; } @@ -202,21 +202,21 @@ void can_lld_init(void) { /* Driver initialization.*/ canObjectInit(&CAND1); CAND1.fdcan = FDCAN1; - CAND1.ram_base = (uint32_t *) (SRAMCAN_BASE + 0U * SRAMCAN_SIZE); + CAND1.ram_base = (uint32_t *)(SRAMCAN_BASE + 0U * SRAMCAN_SIZE); #endif #if STM32_CAN_USE_FDCAN2 /* Driver initialization.*/ canObjectInit(&CAND2); CAND2.fdcan = FDCAN2; - CAND2.ram_base = (uint32_t *) (SRAMCAN_BASE + 1U * SRAMCAN_SIZE); + CAND2.ram_base = (uint32_t *)(SRAMCAN_BASE + 1U * SRAMCAN_SIZE); #endif #if STM32_CAN_USE_FDCAN3 /* Driver initialization.*/ canObjectInit(&CAND3); CAND3.fdcan = FDCAN3; - CAND3.ram_base = (uint32_t *) (SRAMCAN_BASE + 2U * SRAMCAN_SIZE); + CAND3.ram_base = (uint32_t *)(SRAMCAN_BASE + 2U * SRAMCAN_SIZE); #endif } @@ -276,20 +276,46 @@ bool can_lld_start(CANDriver *canp) { } /* Configuration can be performed now.*/ - canp->fdcan->CCCR |= FDCAN_CCCR_CCE; + canp->fdcan->CCCR |= FDCAN_CCCR_CCE; + canp->fdcan->CCCR &= ~(FDCAN_CCCR_CSR | FDCAN_CCCR_CSA); /* Setting up operation mode except driver-controlled bits.*/ - canp->fdcan->DBTP = canp->config->DBTP; - canp->fdcan->CCCR = canp->config->CCCR & ~(FDCAN_CCCR_CSR | FDCAN_CCCR_CSA | - FDCAN_CCCR_CCE | FDCAN_CCCR_INIT); - canp->fdcan->TEST = canp->config->TEST; + canp->fdcan->NBTP = canp->config->NBTP; + canp->fdcan->DBTP = canp->config->DBTP; + canp->fdcan->CCCR |= canp->config->CCCR & ~(FDCAN_CCCR_CSR | FDCAN_CCCR_CSA | + FDCAN_CCCR_CCE | FDCAN_CCCR_INIT); + canp->fdcan->TEST = canp->config->TEST; +#ifdef STM32G4XX + canp->fdcan->RXGFC = canp->config->RXGFC; +#elif defined(STM32H7XX) + canp->fdcan->GFC = canp->config->RXGFC; +#else +#error "Unsupported STM32 for FDCAN LLD driver" +#endif /* Enabling interrupts, only using interrupt zero.*/ - canp->fdcan->IR = (uint32_t)-1; - canp->fdcan->IE = FDCAN_IE_RF1NE | FDCAN_IE_RF1LE | - FDCAN_IE_RF0NE | FDCAN_IE_RF0LE | - FDCAN_IE_TCE; - canp->fdcan->ILE = FDCAN_ILE_EINT0; + canp->fdcan->IR = (uint32_t)-1; + canp->fdcan->IE = FDCAN_IE_RF1NE | FDCAN_IE_RF1LE | + FDCAN_IE_RF0NE | FDCAN_IE_RF0LE | + FDCAN_IE_TCE; + canp->fdcan->TXBTIE = FDCAN_TXBTIE_TIE; + canp->fdcan->ILE = FDCAN_ILE_EINT0; + +#ifdef STM32H7XX + /* H7 version of FDCAN has configurable memory layout, so configure it */ + canp->fdcan->SIDFC = STM32_FDCAN_FLS_NBR << 16 | SRAMCAN_FLSSA; + canp->fdcan->XIDFC = STM32_FDCAN_FLE_NBR << 16 | SRAMCAN_FLESA; + canp->fdcan->RXF0C = STM32_FDCAN_RF0_NBR << 16 | SRAMCAN_RF0SA; + canp->fdcan->RXF1C = STM32_FDCAN_RF1_NBR << 16 | SRAMCAN_RF1SA; + canp->fdcan->RXBC = SRAMCAN_RBSA; + canp->fdcan->TXEFC = STM32_FDCAN_TEF_NBR << 16 | SRAMCAN_TEFSA; + /* NB: this doesn't set NDTB, but sets TFQS to run in queue mode with no dedicated buffers */ + canp->fdcan->TXBC = STM32_FDCAN_TB_NBR << 24 | SRAMCAN_TBSA; + + /* set to use the full 18-byte size buffer elements */ + canp->fdcan->TXESC = 0x007; + canp->fdcan->RXESC = 0x777; +#endif /* STM32H7XX */ /* Going in active mode.*/ if (fdcan_active_mode(canp)) { @@ -315,6 +341,7 @@ void can_lld_stop(CANDriver *canp) { canp->fdcan->IE = 0U; canp->fdcan->IR = (uint32_t)-1; canp->fdcan->ILE = 0U; + canp->fdcan->TXBTIE = 0U; /* Disables the peripheral.*/ (void) fdcan_clock_stop(canp); @@ -371,22 +398,29 @@ bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { * * @notapi */ -void can_lld_transmit(CANDriver *canp, - canmbx_t mailbox, - const CANTxFrame *ctfp) { +void can_lld_transmit(CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp) { + uint32_t put_index; uint32_t *tx_address; (void)mailbox; osalDbgCheck(dlc_to_bytes[ctfp->DLC] <= CAN_MAX_DLC_BYTES); + /* Retrieve the TX FIFO put index.*/ + put_index = ((canp->fdcan->TXFQS & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos); + /* Writing frame.*/ - tx_address = canp->ram_base + (SRAMCAN_TBSA / sizeof (uint32_t)); + tx_address = canp->ram_base + + ((SRAMCAN_TBSA + (put_index * SRAMCAN_TB_SIZE)) / sizeof (uint32_t)); + *tx_address++ = ctfp->header32[0]; *tx_address++ = ctfp->header32[1]; for (unsigned i = 0U; i < dlc_to_bytes[ctfp->DLC]; i += 4U) { *tx_address++ = ctfp->data32[i / 4U]; } + + /* Starting transmission.*/ + canp->fdcan->TXBAR = ((uint32_t)1 << put_index); } /** @@ -440,11 +474,19 @@ void can_lld_receive(CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp) { return; } } - - /* GET index, add it and the length to the rx_address.*/ - get_index = (canp->fdcan->RXF0S & FDCAN_RXF0S_F0GI_Msk) >> FDCAN_RXF0S_F0GI_Pos; - rx_address = canp->ram_base + (SRAMCAN_RF0SA + - (get_index * SRAMCAN_RF0_SIZE)) / sizeof (uint32_t); + + if (mailbox == 1U) { + /* GET index RXF0, add it and the length to the rx_address.*/ + get_index = (canp->fdcan->RXF0S & FDCAN_RXF0S_F0GI_Msk) >> FDCAN_RXF0S_F0GI_Pos; + rx_address = canp->ram_base + (SRAMCAN_RF0SA + + (get_index * SRAMCAN_RF0_SIZE)) / sizeof (uint32_t); + } + else { + /* GET index RXF1, add it and the length to the rx_address.*/ + get_index = (canp->fdcan->RXF1S & FDCAN_RXF1S_F1GI_Msk) >> FDCAN_RXF1S_F1GI_Pos; + rx_address = canp->ram_base + (SRAMCAN_RF1SA + + (get_index * SRAMCAN_RF1_SIZE)) / sizeof (uint32_t); + } crfp->header32[0] = *rx_address++; crfp->header32[1] = *rx_address++; @@ -548,7 +590,7 @@ void can_lld_serve_interrupt(CANDriver *canp) { } /* Overflow events.*/ - if ((ir & FDCAN_IR_RF0N) != 0U) { + if (((ir & FDCAN_IR_RF0L) != 0U) || ((ir & FDCAN_IR_RF1L) != 0U) ) { _can_error_isr(canp, CAN_OVERFLOW_ERROR); } diff --git a/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h b/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h index eb02c344e..ede1e459e 100644 --- a/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h +++ b/os/hal/ports/STM32/LLD/FDCANv1/hal_can_lld.h @@ -181,14 +181,19 @@ typedef struct { union { struct { union { - uint32_t EID:29; /**< @brief Extended identifier. */ + struct { + uint32_t EID:29; /**< @brief Extended identifier. */ + } ext; struct { uint32_t _R1:18; /**< @brief Reserved for offset. */ uint32_t SID:11; /**< @brief Standard identifier. */ + } std; + struct { + uint32_t _R1:29; /**< @brief Reserved for offset. */ uint32_t RTR:1; /**< @brief Remote transmit request.*/ uint32_t XTD:1; /**< @brief Extended identifier. */ uint32_t ESI:1; /**< @brief Error state indicator. */ - }; + } common; }; uint32_t _R2:16; uint32_t DLC:4; /**< @brief Data length code. */ @@ -221,27 +226,34 @@ typedef struct { /** * @brief Frame header. */ - struct { - union { - uint32_t EID:29; /**< @brief Extended Identifier. */ - struct { - uint32_t _R1:18; - uint32_t SID:11; /**< @brief Standard identifier. */ - uint32_t RTR:1; /**< @brief Remote transmit request.*/ - uint32_t XTD:1; /**< @brief Extended identifier. */ - uint32_t ESI:1; /**< @brief Error state indicator. */ + union { + struct { + union { + struct { + uint32_t EID:29; /**< @brief Extended identifier. */ + } ext; + struct { + uint32_t _R1:18; + uint32_t SID:11; /**< @brief Standard identifier. */ + } std; + struct { + uint32_t _R1:29; /**< @brief Reserved for offset. */ + uint32_t RTR:1; /**< @brief Remote transmit request.*/ + uint32_t XTD:1; /**< @brief Extended identifier. */ + uint32_t ESI:1; /**< @brief Error state indicator. */ + } common; }; - }; - uint16_t RXTS:16; /**< @brief TX time stamp. */ - uint8_t DLC:4; /**< @brief Data length code. */ - uint8_t BRS:1; /**< @brief Bit rate switch. */ - uint8_t FDF:1; /**< @brief FDCAN frame format. */ - uint8_t _R2:2; - uint8_t FIDX:7; /**< @brief Filter index. */ - uint8_t ANMF:1; /**< @brief Accepted non-matching + uint32_t RXTS:16; /**< @brief TX time stamp. */ + uint32_t DLC:4; /**< @brief Data length code. */ + uint32_t BRS:1; /**< @brief Bit rate switch. */ + uint32_t FDF:1; /**< @brief FDCAN frame format. */ + uint32_t _R2:2; + uint32_t FIDX:7; /**< @brief Filter index. */ + uint32_t ANMF:1; /**< @brief Accepted non-matching frame. */ + }; + uint32_t header32[2]; }; - uint32_t header32[2]; /** * @brief Frame data. */ @@ -304,6 +316,10 @@ typedef struct { * @brief Driver configuration structure. */ typedef struct { + /** + * @brief Nominal bit timing and prescaler register. + */ + uint32_t NBTP; /** * @brief Data bit timing and prescaler register. */ @@ -316,6 +332,10 @@ typedef struct { * @brief Test configuration register. */ uint32_t TEST; + /** + * @brief Global filter configuration register. + */ + uint32_t RXGFC; } CANConfig; /** diff --git a/os/hal/ports/STM32/STM32H7xx/stm32_registry.h b/os/hal/ports/STM32/STM32H7xx/stm32_registry.h index 7ae52a3e9..d3118dd7a 100644 --- a/os/hal/ports/STM32/STM32H7xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32H7xx/stm32_registry.h @@ -123,14 +123,14 @@ #define STM32_HAS_FDCAN1 TRUE #define STM32_HAS_FDCAN2 TRUE #define STM32_HAS_FDCAN3 FALSE -#define STM32_FDCAN_FLS_NBR 128U -#define STM32_FDCAN_FLE_NBR 128U -#define STM32_FDCAN_RF0_NBR 64U -#define STM32_FDCAN_RF1_NBR 64U -#define STM32_FDCAN_RB_NBR 64U -#define STM32_FDCAN_TEF_NBR 32U +#define STM32_FDCAN_FLS_NBR 64U +#define STM32_FDCAN_FLE_NBR 64U +#define STM32_FDCAN_RF0_NBR 56U +#define STM32_FDCAN_RF1_NBR 56U +#define STM32_FDCAN_RB_NBR 0U +#define STM32_FDCAN_TEF_NBR 0U #define STM32_FDCAN_TB_NBR 32U -#define STM32_FDCAN_TM_NBR 64U +#define STM32_FDCAN_TM_NBR 0U /* DAC attributes.*/ #define STM32_HAS_DAC1_CH1 TRUE