From 41ad5e83fee9503d59f8a44822252be9c2d2cea5 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sat, 28 Dec 2024 21:45:11 +0100 Subject: [PATCH 01/51] add alternative constructors for more pin configuration options --- STM32_CAN.cpp | 250 +++++++++++++++++++------------------------------- STM32_CAN.h | 8 +- 2 files changed, 102 insertions(+), 156 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index b2b8080..ac882b5 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -15,35 +15,118 @@ static STM32_CAN* _CAN3 = nullptr; static CAN_HandleTypeDef hcan3; #endif -STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) { - - if (_canIsActive) { return; } +STM32_CAN::STM32_CAN(PinName rx, PinName tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) + : rx(rx), tx(tx), sizeRxBuffer(rxSize), sizeTxBuffer(txSize) +{ + init(); +} - sizeRxBuffer=rxSize; - sizeTxBuffer=txSize; +STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) + : sizeRxBuffer(rxSize), sizeTxBuffer(txSize) +{ + //get first matching pins from map + rx = pinmap_find_pin(canPort, PinMap_CAN_RD); + tx = pinmap_find_pin(canPort, PinMap_CAN_TD); + init(); +} +//lagacy pin config for compatibility +STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) + : rx(NC), tx(NC), sizeRxBuffer(rxSize), sizeTxBuffer(txSize) +{ if (canPort == CAN1) + { + switch(pins) + { + case DEF: + rx = PA_11; + tx = PA_12; + break; + case ALT: + rx = PB_8; + tx = PB_9; + break; + #if defined(__HAL_RCC_GPIOD_CLK_ENABLE) + case ALT_2: + rx = PD_0; + tx = PD_1; + break; + #endif + } + } +#ifdef CAN2 + else if(canPort == CAN2) + { + switch(pins) + { + case DEF: + rx = PB_12; + tx = PB_13; + break; + case ALT: + rx = PB_5; + tx = PB_6; + break; + } + } +#endif +#ifdef CAN3 + else if(canPort == CAN3) + { + switch(pins) + { + case DEF: + rx = PA_8; + tx = PA_15; + break; + case ALT: + rx = PB_3; + tx = PB_4; + break; + } + } +#endif + init(); +} + +void STM32_CAN::init(void) +{ + CAN_TypeDef * canPort_rx = (CAN_TypeDef *) pinmap_peripheral(rx, PinMap_CAN_RD); + CAN_TypeDef * canPort_tx = (CAN_TypeDef *) pinmap_peripheral(tx, PinMap_CAN_TD); + if ((canPort_rx != canPort_tx && canPort_tx != NP) || canPort_rx == NP) + { + //ensure pins relate to same peripheral OR only Rx is set/valid + // rx only can be used as listen only but needs a 3rd node for valid ACKs + + // do not allow Tx only since that would break arbitration + return; + } + + //clear tx pin in case it was set but does not match a peripheral + if(canPort_tx == NP) + tx = NC; + + if (canPort_rx == CAN1) { _CAN1 = this; n_pCanHandle = &hcan1; } #ifdef CAN2 - if( canPort == CAN2) + if( canPort_rx == CAN2) { _CAN2 = this; n_pCanHandle = &hcan2; } #endif #ifdef CAN3 - if (canPort == CAN3) + if (canPort_rx == CAN3) { _CAN3 = this; n_pCanHandle = &hcan3; } #endif - _canPort = canPort; - _pins = pins; + _canPort = canPort_rx; } // Init and start CAN @@ -54,9 +137,10 @@ void STM32_CAN::begin( bool retransmission ) { _canIsActive = true; - GPIO_InitTypeDef GPIO_InitStruct; - initializeBuffers(); + + pin_function(rx, pinmap_function(rx, PinMap_CAN_RD)); + pin_function(tx, pinmap_function(tx, PinMap_CAN_TD)); // Configure CAN if (_canPort == CAN1) @@ -64,95 +148,6 @@ void STM32_CAN::begin( bool retransmission ) { //CAN1 __HAL_RCC_CAN1_CLK_ENABLE(); - if (_pins == ALT) - { - __HAL_RCC_GPIOB_CLK_ENABLE(); - #if defined(__HAL_RCC_AFIO_CLK_ENABLE) // Some MCUs like F1xx uses AFIO to set pins, so if there is AFIO defined, we use that. - __HAL_AFIO_REMAP_CAN1_2(); // To use PB8/9 pins for CAN1. - __HAL_RCC_AFIO_CLK_ENABLE(); - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // If AFIO is used, there doesn't seem to be "very high" option for speed, so we use "high" -setting. - GPIO_InitStruct.Pin = GPIO_PIN_8; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - GPIO_InitStruct.Pin = GPIO_PIN_9; - #else // Without AFIO, this is the way to set the pins for CAN. - #if defined(GPIO_AF8_CAN1) // Depending on the MCU used, this can be AF8, AF4 or AF9 - GPIO_InitStruct.Alternate = GPIO_AF8_CAN1; - #elif defined(GPIO_AF4_CAN) - GPIO_InitStruct.Alternate = GPIO_AF4_CAN; - #else - GPIO_InitStruct.Alternate = GPIO_AF9_CAN1; - #endif - GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; - #if defined(GPIO_SPEED_FREQ_VERY_HIGH) - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - #else - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - #endif - #endif - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - } - if (_pins == DEF) - { - __HAL_RCC_GPIOA_CLK_ENABLE(); - GPIO_InitStruct.Pull = GPIO_NOPULL; - #if defined(__HAL_RCC_AFIO_CLK_ENABLE) - __HAL_AFIO_REMAP_CAN1_1(); // To use PA11/12 pins for CAN1. - __HAL_RCC_AFIO_CLK_ENABLE(); - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Pin = GPIO_PIN_11; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - GPIO_InitStruct.Pin = GPIO_PIN_12; - #else - #if defined(GPIO_AF4_CAN) - GPIO_InitStruct.Alternate = GPIO_AF4_CAN; - #else - GPIO_InitStruct.Alternate = GPIO_AF9_CAN1; - #endif - GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12; - #if defined(GPIO_SPEED_FREQ_VERY_HIGH) - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - #else - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - #endif - #endif - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - } - - #if defined(__HAL_RCC_GPIOD_CLK_ENABLE) // not all MCU variants have port GPIOD available - if (_pins == ALT_2) - { - __HAL_RCC_GPIOD_CLK_ENABLE(); - GPIO_InitStruct.Pull = GPIO_NOPULL; - #if defined(__HAL_RCC_AFIO_CLK_ENABLE) - __HAL_AFIO_REMAP_CAN1_3(); // To use PD0/1 pins for CAN1. - __HAL_RCC_AFIO_CLK_ENABLE(); - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Pin = GPIO_PIN_0; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); - GPIO_InitStruct.Pin = GPIO_PIN_1; - #else - #if defined(GPIO_AF4_CAN) - GPIO_InitStruct.Alternate = GPIO_AF4_CAN; - #else - GPIO_InitStruct.Alternate = GPIO_AF9_CAN1; - #endif - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; - #if defined(GPIO_SPEED_FREQ_VERY_HIGH) - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - #else - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - #endif - #endif - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); - } - #endif - // NVIC configuration for CAN1 Reception complete interrupt HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 15, 0); // 15 is lowest possible priority HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn ); @@ -168,43 +163,6 @@ void STM32_CAN::begin( bool retransmission ) { //CAN2 __HAL_RCC_CAN1_CLK_ENABLE(); // CAN1 clock needs to be enabled too, because CAN2 works as CAN1 slave. __HAL_RCC_CAN2_CLK_ENABLE(); - if (_pins == ALT) - { - __HAL_RCC_GPIOB_CLK_ENABLE(); - #if defined(__HAL_RCC_AFIO_CLK_ENABLE) - __HAL_AFIO_REMAP_CAN2_ENABLE(); // To use PB5/6 pins for CAN2. Don't ask me why this has different name than for CAN1. - __HAL_RCC_AFIO_CLK_ENABLE(); - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Pin = GPIO_PIN_5; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - GPIO_InitStruct.Pin = GPIO_PIN_6; - #else - GPIO_InitStruct.Alternate = GPIO_AF9_CAN2; - GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - #endif - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - } - if (_pins == DEF) { - __HAL_RCC_GPIOB_CLK_ENABLE(); - #if defined(__HAL_RCC_AFIO_CLK_ENABLE) - __HAL_AFIO_REMAP_CAN2_DISABLE(); // To use PB12/13 pins for CAN2. - __HAL_RCC_AFIO_CLK_ENABLE(); - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Pin = GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - GPIO_InitStruct.Pin = GPIO_PIN_13; - #else - GPIO_InitStruct.Alternate = GPIO_AF9_CAN2; - GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - #endif - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - } // NVIC configuration for CAN2 Reception complete interrupt HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 15, 0); // 15 is lowest possible priority @@ -222,24 +180,6 @@ void STM32_CAN::begin( bool retransmission ) { { //CAN3 __HAL_RCC_CAN3_CLK_ENABLE(); - if (_pins == ALT) - { - __HAL_RCC_GPIOB_CLK_ENABLE(); - GPIO_InitStruct.Alternate = GPIO_AF11_CAN3; - GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - } - if (_pins == DEF) - { - __HAL_RCC_GPIOA_CLK_ENABLE(); - GPIO_InitStruct.Alternate = GPIO_AF11_CAN3; - GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_15; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - } // NVIC configuration for CAN3 Reception complete interrupt HAL_NVIC_SetPriority(CAN3_RX0_IRQn, 15, 0); // 15 is lowest possible priority diff --git a/STM32_CAN.h b/STM32_CAN.h index d42519c..325d686 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -142,6 +142,9 @@ class STM32_CAN { public: // Default buffer sizes are set to 16. But this can be changed by using constructor in main code. + STM32_CAN(PinName rx, PinName tx = NC, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); + STM32_CAN(CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); + //legacy for compatibility STM32_CAN(CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); // Begin. By default the automatic retransmission is enabled. If it causes problems, use begin(false) to disable it. void begin(bool retransmission = false); @@ -183,6 +186,7 @@ class STM32_CAN { uint16_t sizeTxBuffer; private: + void init(void); void initializeFilters(); bool isInitialized() { return rx_buffer != 0; } void initRingBuffer(RingbufferTypeDef &ring, volatile CAN_message_t *buffer, uint32_t size); @@ -240,7 +244,9 @@ class STM32_CAN { }; bool _canIsActive = false; - CAN_PINS _pins; + + PinName rx; + PinName tx; CAN_HandleTypeDef *n_pCanHandle; CAN_TypeDef* _canPort; From f099f77f25e127208144bc210608e693cffe599b Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 29 Dec 2024 11:46:24 +0100 Subject: [PATCH 02/51] add setMode function to set a mode by arg. Better hints that modes are exclusive to each other. --- STM32_CAN.cpp | 26 ++++++++++++++++---------- STM32_CAN.h | 10 ++++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index ac882b5..408d5a2 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -16,13 +16,15 @@ static CAN_HandleTypeDef hcan3; #endif STM32_CAN::STM32_CAN(PinName rx, PinName tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) - : rx(rx), tx(tx), sizeRxBuffer(rxSize), sizeTxBuffer(txSize) + : rx(rx), tx(tx), sizeRxBuffer(rxSize), sizeTxBuffer(txSize), + mode(Mode::NORMAL) { init(); } STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) - : sizeRxBuffer(rxSize), sizeTxBuffer(txSize) + : sizeRxBuffer(rxSize), sizeTxBuffer(txSize), + mode(Mode::NORMAL) { //get first matching pins from map rx = pinmap_find_pin(canPort, PinMap_CAN_RD); @@ -32,7 +34,8 @@ STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE //lagacy pin config for compatibility STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) - : rx(NC), tx(NC), sizeRxBuffer(rxSize), sizeTxBuffer(txSize) + : rx(NC), tx(NC), sizeRxBuffer(rxSize), sizeTxBuffer(txSize), + mode(Mode::NORMAL) { if (canPort == CAN1) { @@ -199,7 +202,7 @@ void STM32_CAN::begin( bool retransmission ) { else { n_pCanHandle->Init.AutoRetransmission = DISABLE; } n_pCanHandle->Init.ReceiveFifoLocked = DISABLE; n_pCanHandle->Init.TransmitFifoPriority = ENABLE; - n_pCanHandle->Init.Mode = CAN_MODE_NORMAL; + n_pCanHandle->Init.Mode = mode; } void STM32_CAN::setBaudRate(uint32_t baud) @@ -743,19 +746,22 @@ void STM32_CAN::disableMBInterrupts() #endif } +void STM32_CAN::setMode(Mode mode) +{ + this->mode = mode; + n_pCanHandle->Init.Mode = mode; +} + void STM32_CAN::enableLoopBack( bool yes ) { - if (yes) { n_pCanHandle->Init.Mode = CAN_MODE_LOOPBACK; } - else { n_pCanHandle->Init.Mode = CAN_MODE_NORMAL; } + setMode(yes ? Mode::LOOPBACK : Mode::NORMAL); } void STM32_CAN::enableSilentMode( bool yes ) { - if (yes) { n_pCanHandle->Init.Mode = CAN_MODE_SILENT; } - else { n_pCanHandle->Init.Mode = CAN_MODE_NORMAL; } + setMode(yes ? Mode::SILENT : Mode::NORMAL); } void STM32_CAN::enableSilentLoopBack( bool yes ) { - if (yes) { n_pCanHandle->Init.Mode = CAN_MODE_SILENT_LOOPBACK; } - else { n_pCanHandle->Init.Mode = CAN_MODE_NORMAL; } + setMode(yes ? Mode::SILENT_LOOPBACK : Mode::NORMAL); } void STM32_CAN::enableFIFO(bool status) diff --git a/STM32_CAN.h b/STM32_CAN.h index 325d686..d256b0a 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -160,6 +160,14 @@ class STM32_CAN { bool setMBFilter(CAN_BANK bank_num, uint32_t id1, IDE = AUTO); /* input 1 ID to be filtered */ bool setMBFilter(CAN_BANK bank_num, uint32_t id1, uint32_t id2, IDE = AUTO); /* input 2 ID's to be filtered */ + enum Mode { + NORMAL = CAN_MODE_NORMAL, + LOOPBACK = CAN_MODE_LOOPBACK, + SILENT = CAN_MODE_SILENT, + SILENT_LOOPBACK = CAN_MODE_SILENT_LOOPBACK + }; + + void setMode(Mode mode); void enableLoopBack(bool yes = 1); void enableSilentMode(bool yes = 1); void enableSilentLoopBack(bool yes = 1); @@ -245,6 +253,8 @@ class STM32_CAN { bool _canIsActive = false; + Mode mode; + PinName rx; PinName tx; From c2ae037589972b2323f4c9a6ab6ba64b4643aaf2 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 29 Dec 2024 12:32:49 +0100 Subject: [PATCH 03/51] allow configuration of the IRQ priorities, default to lowest priority --- STM32_CAN.cpp | 28 +++++++++++++++++++--------- STM32_CAN.h | 4 ++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 408d5a2..d4bced0 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -1,5 +1,8 @@ #include "STM32_CAN.h" +//Max value, lowest priority +#define MAX_IRQ_PRIO_VALUE ((1UL << __NVIC_PRIO_BITS) - 1UL) + constexpr Baudrate_entry_t STM32_CAN::BAUD_RATE_TABLE_48M[]; constexpr Baudrate_entry_t STM32_CAN::BAUD_RATE_TABLE_45M[]; @@ -17,14 +20,14 @@ static CAN_HandleTypeDef hcan3; STM32_CAN::STM32_CAN(PinName rx, PinName tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) : rx(rx), tx(tx), sizeRxBuffer(rxSize), sizeTxBuffer(txSize), - mode(Mode::NORMAL) + mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) { init(); } STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) : sizeRxBuffer(rxSize), sizeTxBuffer(txSize), - mode(Mode::NORMAL) + mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) { //get first matching pins from map rx = pinmap_find_pin(canPort, PinMap_CAN_RD); @@ -35,7 +38,7 @@ STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE //lagacy pin config for compatibility STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) : rx(NC), tx(NC), sizeRxBuffer(rxSize), sizeTxBuffer(txSize), - mode(Mode::NORMAL) + mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) { if (canPort == CAN1) { @@ -132,6 +135,13 @@ void STM32_CAN::init(void) _canPort = canPort_rx; } +void STM32_CAN::setIRQPriority(uint32_t preemptPriority, uint32_t subPriority) +{ + //NOTE: limiting the IRQ prio, but not accounting for group setting + this->preemptPriority = min(preemptPriority, MAX_IRQ_PRIO_VALUE); + this->subPriority = min(subPriority, MAX_IRQ_PRIO_VALUE); +} + // Init and start CAN void STM32_CAN::begin( bool retransmission ) { @@ -152,10 +162,10 @@ void STM32_CAN::begin( bool retransmission ) { __HAL_RCC_CAN1_CLK_ENABLE(); // NVIC configuration for CAN1 Reception complete interrupt - HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 15, 0); // 15 is lowest possible priority + HAL_NVIC_SetPriority(CAN1_RX0_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn ); // NVIC configuration for CAN1 Transmission complete interrupt - HAL_NVIC_SetPriority(CAN1_TX_IRQn, 15, 0); // 15 is lowest possible priority + HAL_NVIC_SetPriority(CAN1_TX_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN1_TX_IRQn); n_pCanHandle->Instance = CAN1; @@ -168,10 +178,10 @@ void STM32_CAN::begin( bool retransmission ) { __HAL_RCC_CAN2_CLK_ENABLE(); // NVIC configuration for CAN2 Reception complete interrupt - HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 15, 0); // 15 is lowest possible priority + HAL_NVIC_SetPriority(CAN2_RX0_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn ); // NVIC configuration for CAN2 Transmission complete interrupt - HAL_NVIC_SetPriority(CAN2_TX_IRQn, 15, 0); // 15 is lowest possible priority + HAL_NVIC_SetPriority(CAN2_TX_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN2_TX_IRQn); n_pCanHandle->Instance = CAN2; @@ -185,10 +195,10 @@ void STM32_CAN::begin( bool retransmission ) { __HAL_RCC_CAN3_CLK_ENABLE(); // NVIC configuration for CAN3 Reception complete interrupt - HAL_NVIC_SetPriority(CAN3_RX0_IRQn, 15, 0); // 15 is lowest possible priority + HAL_NVIC_SetPriority(CAN3_RX0_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN3_RX0_IRQn ); // NVIC configuration for CAN3 Transmission complete interrupt - HAL_NVIC_SetPriority(CAN3_TX_IRQn, 15, 0); // 15 is lowest possible priority + HAL_NVIC_SetPriority(CAN3_TX_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN3_TX_IRQn); n_pCanHandle->Instance = CAN3; diff --git a/STM32_CAN.h b/STM32_CAN.h index d256b0a..4074355 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -146,6 +146,7 @@ class STM32_CAN { STM32_CAN(CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); //legacy for compatibility STM32_CAN(CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); + void setIRQPriority(uint32_t preemptPriority, uint32_t subPriority); // Begin. By default the automatic retransmission is enabled. If it causes problems, use begin(false) to disable it. void begin(bool retransmission = false); void setBaudRate(uint32_t baud); @@ -258,6 +259,9 @@ class STM32_CAN { PinName rx; PinName tx; + uint32_t preemptPriority; + uint32_t subPriority; + CAN_HandleTypeDef *n_pCanHandle; CAN_TypeDef* _canPort; From 0817a127cfc888bd3e8b8c58ee0ceb7873d89f95 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Mon, 30 Dec 2024 15:30:39 +0100 Subject: [PATCH 04/51] be specific with IRQ aliasing, add notes --- STM32_CAN.cpp | 26 ++++++++++++++ STM32_CAN.h | 98 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 113 insertions(+), 11 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index d4bced0..4d2ab33 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -161,12 +161,18 @@ void STM32_CAN::begin( bool retransmission ) { //CAN1 __HAL_RCC_CAN1_CLK_ENABLE(); + #ifdef CAN1_IRQn_AIO + // NVIC configuration for CAN1 common interrupt + HAL_NVIC_SetPriority(CAN1_IRQn_AIO, preemptPriority, subPriority); + HAL_NVIC_EnableIRQ(CAN1_IRQn_AIO); + #else // NVIC configuration for CAN1 Reception complete interrupt HAL_NVIC_SetPriority(CAN1_RX0_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn ); // NVIC configuration for CAN1 Transmission complete interrupt HAL_NVIC_SetPriority(CAN1_TX_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN1_TX_IRQn); + #endif /** else defined(CAN1_IRQn_AIO) */ n_pCanHandle->Instance = CAN1; } @@ -720,7 +726,11 @@ void STM32_CAN::enableMBInterrupts() { if (n_pCanHandle->Instance == CAN1) { + #ifdef CAN1_IRQn_AIO + HAL_NVIC_EnableIRQ(CAN1_IRQn_AIO); + #else HAL_NVIC_EnableIRQ(CAN1_TX_IRQn); + #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 else if (n_pCanHandle->Instance == CAN2) @@ -740,7 +750,11 @@ void STM32_CAN::disableMBInterrupts() { if (n_pCanHandle->Instance == CAN1) { + #ifdef CAN1_IRQn_AIO + HAL_NVIC_DisableIRQ(CAN1_IRQn_AIO); + #else HAL_NVIC_DisableIRQ(CAN1_TX_IRQn); + #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 else if (n_pCanHandle->Instance == CAN2) @@ -927,6 +941,15 @@ extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) //Enable_Interrupts(state); } +#ifdef CAN1_IRQHandler_AIO + +extern "C" void CAN1_IRQHandler_AIO(void) +{ + HAL_CAN_IRQHandler(&hcan1); +} + +#else + // RX IRQ handlers extern "C" void CAN1_RX0_IRQHandler(void) { @@ -964,3 +987,6 @@ extern "C" void CAN3_TX_IRQHandler(void) HAL_CAN_IRQHandler(&hcan3); } #endif + +#endif /* CAN1_IRQHandler_AIO */ + diff --git a/STM32_CAN.h b/STM32_CAN.h index 4074355..9ccff01 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -19,20 +19,96 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #ifndef STM32_CAN_H #define STM32_CAN_H -// couple of workarounds +/** Handling special cases for IRQ Handlers */ +#if defined(STM32F0xx) +#if defined(STM32F042x6) || defined(STM32F072xB) || defined(STM32F091xC) || defined(STM32F098xx) + + /** + * NOTE: STM32F0 share IRQ Handler with HDMI CEC + * and there is only a single IRQ Handler not 4 + * CEC_CAN_IRQn | CEC_CAN_IRQHandler + * + * define all in one alias for IRQn and Handler + */ + #define CAN1_IRQn_AIO CEC_CAN_IRQn + #define CAN1_IRQHandler_AIO CEC_CAN_IRQHandler + +#endif +#endif + +#if defined(STM32F1xx) +#if defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) +/** + * NOTE: STM32F103xx uses shared IRQ Handler with USB + * USB_HP_CAN1_TX_IRQn | USB_HP_CAN1_TX_IRQHandler + * USB_LP_CAN1_RX0_IRQn | USB_LP_CAN1_RX0_IRQHandler + * + * the CMSIS files define already aliases for the CAN *_IRQHandler and *_IRQn + * conforming with standard naming convention: + * CAN1_TX_IRQn | CAN1_TX_IRQHandler + * CAN1_RX0_IRQn | CAN1_RX0_IRQHandler + * + * when USB is enabled the USBDevice driver also implements these making a concurrent use impossible. + * + * Following are unaffected: + * CAN1_RX1_IRQn | CAN1_RX1_IRQHandler + * CAN1_SCE_IRQn | CAN1_SCE_IRQHandler + */ +#endif +#endif + #if defined(STM32F3xx) - #define GPIO_AF9_CAN1 GPIO_AF9_CAN - #define CAN1_RX0_IRQn CAN_RX0_IRQn - #define CAN1_TX_IRQn CAN_TX_IRQn - #define GPIO_SPEED_FREQ_VERY_HIGH GPIO_SPEED_FREQ_HIGH - #define CAN1_TX_IRQHandler CAN_TX_IRQHandler +#if defined(STM32F302x8) || defined(STM32F302xC) || defined(STM32F302xE)\ + || defined(STM32F303xC) || defined(STM32F303xE) + + /** + * NOTE: STM32F3 with USB share IRQ Handler with it + * USB_HP_CAN_TX_IRQn | USB_HP_CAN_TX_IRQHandler + * USB_LP_CAN_RX0_IRQn | USB_LP_CAN_RX0_IRQHandler + * + * the CMSIS files define already aliases for the CAN *_IRQHandler and *_IRQn + * missing peripheral index: + * CAN_TX_IRQn | CAN_TX_IRQHandler + * CAN_RX0_IRQn | CAN_RX0_IRQHandler + * + * when USB is enabled the USBDevice driver also implements these making a concurrent use impossible. + * + * Following are unaffected: + * CAN_RX1_IRQn | CAN_RX1_IRQHandler + * CAN_SCE_IRQn | CAN_SCE_IRQHandler + * + * define more aliases with peripheral index + */ + + #define CAN1_TX_IRQn USB_HP_CAN_TX_IRQn + #define CAN1_RX0_IRQn USB_LP_CAN_RX0_IRQn + #define CAN1_RX1_IRQn CAN_RX1_IRQn + #define CAN1_SCE_IRQn CAN_SCE_IRQn + + #define CAN1_TX_IRQHandler USB_HP_CAN_TX_IRQHandler + #define CAN1_RX0_IRQHandler USB_LP_CAN_RX0_IRQHandler + #define CAN1_RX1_IRQHandler CAN_RX1_IRQHandler + #define CAN1_SCE_IRQHandler CAN_SCE_IRQHandler + +#elif defined(STM32F303x8) || defined(STM32F328xx) || defined(STM32F334x8)\ + || defined(STM32F358xx) || defined(STM32F373xC)\ + || defined(STM32F378xx) || defined(STM32F398xx) + + /** + * NOTE: STM32F3 without USB define symbols without peripheral index + * define more aliases with peripheral index + */ + + #define CAN1_TX_IRQn CAN_TX_IRQn + #define CAN1_RX0_IRQn CAN_RX0_IRQn + #define CAN1_RX1_IRQn CAN_RX1_IRQn + #define CAN1_SCE_IRQn CAN_SCE_IRQn + + #define CAN1_TX_IRQHandler CAN_TX_IRQHandler #define CAN1_RX0_IRQHandler CAN_RX0_IRQHandler + #define CAN1_RX1_IRQHandler CAN_RX1_IRQHandler + #define CAN1_SCE_IRQHandler CAN_SCE_IRQHandler #endif - -#if defined(STM32F0xx) - #define CAN1_TX_IRQn CEC_CAN_IRQn - #define CAN1_RX0_IRQn CEC_CAN_IRQn - #define CAN1_RX0_IRQHandler CEC_CAN_IRQHandler #endif #include From ca37a270d1bcf88885bf6f1e9aa6adc3bf27956e Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Mon, 30 Dec 2024 15:38:31 +0100 Subject: [PATCH 05/51] enable / disable the Rx0 IRQ as well --- STM32_CAN.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 4d2ab33..e7c799b 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -730,18 +730,21 @@ void STM32_CAN::enableMBInterrupts() HAL_NVIC_EnableIRQ(CAN1_IRQn_AIO); #else HAL_NVIC_EnableIRQ(CAN1_TX_IRQn); + HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn); #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 else if (n_pCanHandle->Instance == CAN2) { HAL_NVIC_EnableIRQ(CAN2_TX_IRQn); + HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn); } #endif #ifdef CAN3 else if (n_pCanHandle->Instance == CAN3) { HAL_NVIC_EnableIRQ(CAN3_TX_IRQn); + HAL_NVIC_EnableIRQ(CAN3_RX0_IRQn); } #endif } @@ -754,18 +757,21 @@ void STM32_CAN::disableMBInterrupts() HAL_NVIC_DisableIRQ(CAN1_IRQn_AIO); #else HAL_NVIC_DisableIRQ(CAN1_TX_IRQn); + HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 else if (n_pCanHandle->Instance == CAN2) { HAL_NVIC_DisableIRQ(CAN2_TX_IRQn); + HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); } #endif #ifdef CAN3 else if (n_pCanHandle->Instance == CAN3) { HAL_NVIC_DisableIRQ(CAN3_TX_IRQn); + HAL_NVIC_DisableIRQ(CAN3_RX0_IRQn); } #endif } From 7d0bb7c3234b05e67ecfc90d4f0b9443d8df4a7f Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Mon, 30 Dec 2024 18:34:12 +0100 Subject: [PATCH 06/51] add hook for the CEC Handler for the F0 Platform. Inspired by how Arduino core does it for shared FDCAN+TIM IRQ on G0 Platform in HardwareTimer implementation --- STM32_CAN.cpp | 23 ++++++++++++++++++++++- STM32_CAN.h | 8 ++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index e7c799b..83b8200 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -1,5 +1,14 @@ #include "STM32_CAN.h" +#ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) +/** Pointer to CEC_HandleTypeDef structure that contains + * the configuration information for the specified CEC. + * Application have to declare them properly to be able to call + * the HAL_CEC_IRQHandler(). + */ +extern CEC_HandleTypeDef * phcec; +#endif + //Max value, lowest priority #define MAX_IRQ_PRIO_VALUE ((1UL << __NVIC_PRIO_BITS) - 1UL) @@ -754,7 +763,13 @@ void STM32_CAN::disableMBInterrupts() if (n_pCanHandle->Instance == CAN1) { #ifdef CAN1_IRQn_AIO - HAL_NVIC_DisableIRQ(CAN1_IRQn_AIO); + #ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) + //only disable if cec instance is not set/used + if(!phcec) + #endif + { + HAL_NVIC_DisableIRQ(CAN1_IRQn_AIO); + } #else HAL_NVIC_DisableIRQ(CAN1_TX_IRQn); HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); @@ -952,6 +967,12 @@ extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) extern "C" void CAN1_IRQHandler_AIO(void) { HAL_CAN_IRQHandler(&hcan1); + #ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) + if(phcec) + { + HAL_CEC_IRQHandler(phcec); + } + #endif } #else diff --git a/STM32_CAN.h b/STM32_CAN.h index 9ccff01..82faa15 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -32,6 +32,14 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e */ #define CAN1_IRQn_AIO CEC_CAN_IRQn #define CAN1_IRQHandler_AIO CEC_CAN_IRQHandler + /** + * NOTE: CAN IRQ is shared with CEC + * To use CEC with CAN declare: + * CEC_HandleTypeDef * phcec; + * and point to your CEC handle. + * Internal IRQ Handler will call CEC Handler as well. + */ + #define STM32_CAN1_SHARED_WITH_CEC #endif #endif From fe2af099355015a3f7ad0b90a66db40682ac25fa Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Mon, 30 Dec 2024 18:39:04 +0100 Subject: [PATCH 07/51] detect USB Driver and print incompatibility error --- STM32_CAN.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/STM32_CAN.h b/STM32_CAN.h index 82faa15..f03b92a 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -62,6 +62,11 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e * CAN1_RX1_IRQn | CAN1_RX1_IRQHandler * CAN1_SCE_IRQn | CAN1_SCE_IRQHandler */ + +#ifdef USBCON +#define STM32_CAN1_TX_RX0_BLOCKED_BY_USB +#endif + #endif #endif @@ -98,6 +103,10 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #define CAN1_RX1_IRQHandler CAN_RX1_IRQHandler #define CAN1_SCE_IRQHandler CAN_SCE_IRQHandler + #ifdef USBCON + #define STM32_CAN1_TX_RX0_BLOCKED_BY_USB + #endif + #elif defined(STM32F303x8) || defined(STM32F328xx) || defined(STM32F334x8)\ || defined(STM32F358xx) || defined(STM32F373xC)\ || defined(STM32F378xx) || defined(STM32F398xx) @@ -119,6 +128,10 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #endif #endif +#ifdef STM32_CAN1_TX_RX0_BLOCKED_BY_USB +#error "USB and CAN interrupts are shared on the F1/F3 platform, driver is not compatible with USBDevice of Arduino core. +#endif + #include // This struct is directly copied from Teensy FlexCAN library to retain compatibility with it. Not all are in use with STM32. From 6cbfeb8e46b3969055ef212ec2b17c0b16ee13d2 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Mon, 30 Dec 2024 20:23:31 +0100 Subject: [PATCH 08/51] Add workaround (enabled by user) for F1 in case USB is used. Uses FIFO1 instead of 0. Need to call polling function for TX event handling. --- STM32_CAN.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ STM32_CAN.h | 10 +++++++--- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 83b8200..b109823 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -1,5 +1,7 @@ #include "STM32_CAN.h" +#include "core_debug.h" + #ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) /** Pointer to CEC_HandleTypeDef structure that contains * the configuration information for the specified CEC. @@ -175,12 +177,18 @@ void STM32_CAN::begin( bool retransmission ) { HAL_NVIC_SetPriority(CAN1_IRQn_AIO, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN1_IRQn_AIO); #else + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + /** CAN Tx and Rx0 blocked by USB, only using Rx1 */ + HAL_NVIC_SetPriority(CAN1_RX1_IRQn, preemptPriority, subPriority); + HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn); + #else // NVIC configuration for CAN1 Reception complete interrupt HAL_NVIC_SetPriority(CAN1_RX0_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn ); // NVIC configuration for CAN1 Transmission complete interrupt HAL_NVIC_SetPriority(CAN1_TX_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN1_TX_IRQn); + #endif #endif /** else defined(CAN1_IRQn_AIO) */ n_pCanHandle->Instance = CAN1; @@ -245,7 +253,11 @@ void STM32_CAN::setBaudRate(uint32_t baud) HAL_CAN_Start( n_pCanHandle ); // Activate CAN RX notification + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + HAL_CAN_ActivateNotification( n_pCanHandle, CAN_IT_RX_FIFO1_MSG_PENDING); + #else HAL_CAN_ActivateNotification( n_pCanHandle, CAN_IT_RX_FIFO0_MSG_PENDING); + #endif // Activate CAN TX notification HAL_CAN_ActivateNotification( n_pCanHandle, CAN_IT_TX_MAILBOX_EMPTY); @@ -302,9 +314,19 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) { bool ret; + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + __HAL_CAN_DISABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO1_MSG_PENDING); + #else __HAL_CAN_DISABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO0_MSG_PENDING); + #endif + ret = removeFromRingBuffer(rxRing, CAN_rx_msg); + + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + __HAL_CAN_ENABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO1_MSG_PENDING); + #else __HAL_CAN_ENABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO0_MSG_PENDING); + #endif return ret; } @@ -315,6 +337,12 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I sFilterConfig.FilterBank = bank_num; sFilterConfig.FilterMode = filter_mode; sFilterConfig.FilterScale = filter_scale; + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + if(fifo == CAN_RX_FIFO0) + { + core_debug("WARNING: RX0 IRQ is blocked by USB Driver. Events only handled by polling and RX1 events!\n"); + } + #endif sFilterConfig.FilterFIFOAssignment = fifo; sFilterConfig.FilterActivation = ENABLE; @@ -406,7 +434,11 @@ void STM32_CAN::initializeFilters() sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; sFilterConfig.FilterMaskIdLow = 0x0000; + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO1; + #else sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; + #endif sFilterConfig.FilterActivation = ENABLE; #ifdef CAN2 // Filter banks from 14 to 27 are for Can2, so first for Can2 is bank 14. This is not relevant for devices with only one CAN @@ -913,14 +945,22 @@ extern "C" void HAL_CAN_TxMailbox2CompleteCallback( CAN_HandleTypeDef *CanHandle } // This is called by RX0_IRQHandler when there is message at RX FIFO0 buffer +#if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) +extern "C" void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *CanHandle) +#else extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) +#endif { CAN_message_t rxmsg; CAN_RxHeaderTypeDef RxHeader; //bool state = Disable_Interrupts(); // move the message from RX FIFO0 to RX ringbuffer + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + if (HAL_CAN_GetRxMessage( CanHandle, CAN_RX_FIFO1, &RxHeader, rxmsg.buf ) == HAL_OK) + #else if (HAL_CAN_GetRxMessage( CanHandle, CAN_RX_FIFO0, &RxHeader, rxmsg.buf ) == HAL_OK) + #endif { if ( RxHeader.IDE == CAN_ID_STD ) { @@ -978,7 +1018,12 @@ extern "C" void CAN1_IRQHandler_AIO(void) #else // RX IRQ handlers +#if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) +/** If USB blocks TX and RX0 IRQs, will use RX1 by default*/ +extern "C" void CAN1_RX1_IRQHandler(void) +#else extern "C" void CAN1_RX0_IRQHandler(void) +#endif { HAL_CAN_IRQHandler(&hcan1); } @@ -997,7 +1042,12 @@ extern "C" void CAN3_RX0_IRQHandler(void) #endif // TX IRQ handlers +#if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) +/** If USB blocks TX and RX0 IRQs, need to poll for Tx events*/ +extern "C" void STM32_CAN_Poll_IRQ_Handler(void) +#else extern "C" void CAN1_TX_IRQHandler(void) +#endif { HAL_CAN_IRQHandler(&hcan1); } diff --git a/STM32_CAN.h b/STM32_CAN.h index f03b92a..260a221 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -19,6 +19,8 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #ifndef STM32_CAN_H #define STM32_CAN_H +#include + /** Handling special cases for IRQ Handlers */ #if defined(STM32F0xx) #if defined(STM32F042x6) || defined(STM32F072xB) || defined(STM32F091xC) || defined(STM32F098xx) @@ -128,11 +130,13 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #endif #endif -#ifdef STM32_CAN1_TX_RX0_BLOCKED_BY_USB -#error "USB and CAN interrupts are shared on the F1/F3 platform, driver is not compatible with USBDevice of Arduino core. +#if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && !defined(STM32_CAN_USB_WORKAROUND_POLLING) +#error "USB and CAN interrupts are shared on the F1/F3 platform, driver is not compatible with USBDevice of Arduino core. Can define STM32_CAN_USB_WORKAROUND_POLLING to disable error msg and call STM32_CAN_Poll_IRQ_Handler to poll for Tx IRQ events. Only use FIFO 1." +#elif defined(USBCON) && defined(STM32_CAN_USB_WORKAROUND_POLLING) +#warning "CAN IRQ Handler is used by USBDevice driver, call STM32_CAN_Poll_IRQ_Handler() frequently to handle CAN events." +extern "C" void STM32_CAN_Poll_IRQ_Handler(void); #endif -#include // This struct is directly copied from Teensy FlexCAN library to retain compatibility with it. Not all are in use with STM32. // Source: https://github.com/tonton81/FlexCAN_T4/ From 9239e50f0bf68b394a4c9a675c541d1ef809140b Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Mon, 30 Dec 2024 22:46:47 +0100 Subject: [PATCH 09/51] add constructor that takes digital pins as arguments --- STM32_CAN.cpp | 9 +++++++++ STM32_CAN.h | 1 + 2 files changed, 10 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index b109823..dc5596a 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -29,6 +29,15 @@ static STM32_CAN* _CAN3 = nullptr; static CAN_HandleTypeDef hcan3; #endif +STM32_CAN::STM32_CAN(uint32_t rx, uint32_t tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) + : sizeRxBuffer(rxSize), sizeTxBuffer(txSize), + mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) +{ + this->rx = digitalPinToPinName(rx); + this->tx = digitalPinToPinName(tx); + init(); +} + STM32_CAN::STM32_CAN(PinName rx, PinName tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) : rx(rx), tx(tx), sizeRxBuffer(rxSize), sizeTxBuffer(txSize), mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) diff --git a/STM32_CAN.h b/STM32_CAN.h index 260a221..fc3de26 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -243,6 +243,7 @@ class STM32_CAN { public: // Default buffer sizes are set to 16. But this can be changed by using constructor in main code. + STM32_CAN(uint32_t rx, uint32_t tx = PNUM_NOT_DEFINED, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); STM32_CAN(PinName rx, PinName tx = NC, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); STM32_CAN(CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); //legacy for compatibility From 8cdb9470d9143c18a16d646693978bfe2d121b04 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Tue, 31 Dec 2024 17:55:50 +0100 Subject: [PATCH 10/51] move CAN_HandleTypeDef object into the class together with a pointer to self. Now always has a valid object to configure. Register pointer to it in global canObj list once CAN is actually started. --- STM32_CAN.cpp | 310 +++++++++++++++++++++++--------------------------- STM32_CAN.h | 9 +- 2 files changed, 149 insertions(+), 170 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index dc5596a..bc81f9b 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -17,17 +17,54 @@ extern CEC_HandleTypeDef * phcec; constexpr Baudrate_entry_t STM32_CAN::BAUD_RATE_TABLE_48M[]; constexpr Baudrate_entry_t STM32_CAN::BAUD_RATE_TABLE_45M[]; -static STM32_CAN* _CAN1 = nullptr; -static CAN_HandleTypeDef hcan1; uint32_t test = 0; + +typedef enum { +#ifdef CAN1 + CAN1_INDEX, +#endif #ifdef CAN2 -static STM32_CAN* _CAN2 = nullptr; -static CAN_HandleTypeDef hcan2; + CAN2_INDEX, #endif #ifdef CAN3 -static STM32_CAN* _CAN3 = nullptr; -static CAN_HandleTypeDef hcan3; + CAN3_INDEX, +#endif + CAN_NUM, + CAN_UNKNOWN = 0xFFFF +} can_index_t; + +static stm32_can_t * canObj[CAN_NUM] = {NULL}; + +stm32_can_t *get_can_obj(CAN_HandleTypeDef *hcan) +{ + stm32_can_t *obj; + obj = (stm32_can_t *)((char *)hcan - offsetof(stm32_can_t, handle)); + return (obj); +} + +can_index_t get_can_index(CAN_TypeDef *instance) +{ + can_index_t index = CAN_UNKNOWN; +#if defined(CAN1) + if (instance == CAN1) { + index = CAN1_INDEX; + } +#endif +#if defined(CAN2) + if (instance == CAN2) { + index = CAN2_INDEX; + } #endif +#if defined(CAN3) + if (instance == CAN3) { + index = CAN3_INDEX; + } +#endif + if (index == CAN_UNKNOWN) { + Error_Handler(); + } + return index; +} STM32_CAN::STM32_CAN(uint32_t rx, uint32_t tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) : sizeRxBuffer(rxSize), sizeTxBuffer(txSize), @@ -117,6 +154,9 @@ STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize, void STM32_CAN::init(void) { + _can.__this = (void*)this; + _can.handle.Instance = nullptr; + CAN_TypeDef * canPort_rx = (CAN_TypeDef *) pinmap_peripheral(rx, PinMap_CAN_RD); CAN_TypeDef * canPort_tx = (CAN_TypeDef *) pinmap_peripheral(tx, PinMap_CAN_TD); if ((canPort_rx != canPort_tx && canPort_tx != NP) || canPort_rx == NP) @@ -132,27 +172,7 @@ void STM32_CAN::init(void) if(canPort_tx == NP) tx = NC; - if (canPort_rx == CAN1) - { - _CAN1 = this; - n_pCanHandle = &hcan1; - } - #ifdef CAN2 - if( canPort_rx == CAN2) - { - _CAN2 = this; - n_pCanHandle = &hcan2; - } - #endif - #ifdef CAN3 - if (canPort_rx == CAN3) - { - _CAN3 = this; - n_pCanHandle = &hcan3; - } - #endif - - _canPort = canPort_rx; + _can.handle.Instance = canPort_rx; } void STM32_CAN::setIRQPriority(uint32_t preemptPriority, uint32_t subPriority) @@ -176,7 +196,7 @@ void STM32_CAN::begin( bool retransmission ) { pin_function(tx, pinmap_function(tx, PinMap_CAN_TD)); // Configure CAN - if (_canPort == CAN1) + if (_can.handle.Instance == CAN1) { //CAN1 __HAL_RCC_CAN1_CLK_ENABLE(); @@ -200,10 +220,10 @@ void STM32_CAN::begin( bool retransmission ) { #endif #endif /** else defined(CAN1_IRQn_AIO) */ - n_pCanHandle->Instance = CAN1; + _can.bus = 1; } #ifdef CAN2 - else if (_canPort == CAN2) + else if (_can.handle.Instance == CAN2) { //CAN2 __HAL_RCC_CAN1_CLK_ENABLE(); // CAN1 clock needs to be enabled too, because CAN2 works as CAN1 slave. @@ -216,12 +236,12 @@ void STM32_CAN::begin( bool retransmission ) { HAL_NVIC_SetPriority(CAN2_TX_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN2_TX_IRQn); - n_pCanHandle->Instance = CAN2; + _can.bus = 2; } #endif #ifdef CAN3 - else if (_canPort == CAN3) + else if (_can.handle.Instance == CAN3) { //CAN3 __HAL_RCC_CAN3_CLK_ENABLE(); @@ -233,43 +253,56 @@ void STM32_CAN::begin( bool retransmission ) { HAL_NVIC_SetPriority(CAN3_TX_IRQn, preemptPriority, subPriority); HAL_NVIC_EnableIRQ(CAN3_TX_IRQn); - n_pCanHandle->Instance = CAN3; + _can.bus = 3; } #endif - n_pCanHandle->Init.TimeTriggeredMode = DISABLE; - n_pCanHandle->Init.AutoBusOff = DISABLE; - n_pCanHandle->Init.AutoWakeUp = DISABLE; - if (retransmission){ n_pCanHandle->Init.AutoRetransmission = ENABLE; } - else { n_pCanHandle->Init.AutoRetransmission = DISABLE; } - n_pCanHandle->Init.ReceiveFifoLocked = DISABLE; - n_pCanHandle->Init.TransmitFifoPriority = ENABLE; - n_pCanHandle->Init.Mode = mode; + _can.handle.Init.TimeTriggeredMode = DISABLE; + _can.handle.Init.AutoBusOff = DISABLE; + _can.handle.Init.AutoWakeUp = DISABLE; + if (retransmission){ _can.handle.Init.AutoRetransmission = ENABLE; } + else { _can.handle.Init.AutoRetransmission = DISABLE; } + _can.handle.Init.ReceiveFifoLocked = DISABLE; + _can.handle.Init.TransmitFifoPriority = ENABLE; + _can.handle.Init.Mode = mode; } void STM32_CAN::setBaudRate(uint32_t baud) { + can_index_t index = get_can_index(_can.handle.Instance); + if(index >= CAN_NUM) + { + return; + } + if(canObj[index]) + { + //bus already in use by other instance + Error_Handler(); + return; + } + //register with global, we own this instance now + canObj[index] = &_can; // Calculate and set baudrate - calculateBaudrate( n_pCanHandle, baud ); + calculateBaudrate( &_can.handle, baud ); // Initializes CAN - HAL_CAN_Init( n_pCanHandle ); + HAL_CAN_Init( &_can.handle ); initializeFilters(); // Start the CAN peripheral - HAL_CAN_Start( n_pCanHandle ); + HAL_CAN_Start( &_can.handle ); // Activate CAN RX notification #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) - HAL_CAN_ActivateNotification( n_pCanHandle, CAN_IT_RX_FIFO1_MSG_PENDING); + HAL_CAN_ActivateNotification( &_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); #else - HAL_CAN_ActivateNotification( n_pCanHandle, CAN_IT_RX_FIFO0_MSG_PENDING); + HAL_CAN_ActivateNotification( &_can.handle, CAN_IT_RX_FIFO0_MSG_PENDING); #endif // Activate CAN TX notification - HAL_CAN_ActivateNotification( n_pCanHandle, CAN_IT_TX_MAILBOX_EMPTY); + HAL_CAN_ActivateNotification( &_can.handle, CAN_IT_TX_MAILBOX_EMPTY); } bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) @@ -278,7 +311,7 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) uint32_t TxMailbox; CAN_TxHeaderTypeDef TxHeader; - __HAL_CAN_DISABLE_IT(n_pCanHandle, CAN_IT_TX_MAILBOX_EMPTY); + __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_TX_MAILBOX_EMPTY); if (CAN_tx_msg.flags.extended == 1) // Extended ID when CAN_tx_msg.flags.extended is 1 { @@ -303,7 +336,7 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) TxHeader.TransmitGlobalTime = DISABLE; - if(HAL_CAN_AddTxMessage( n_pCanHandle, &TxHeader, CAN_tx_msg.buf, &TxMailbox) != HAL_OK) + if(HAL_CAN_AddTxMessage( &_can.handle, &TxHeader, CAN_tx_msg.buf, &TxMailbox) != HAL_OK) { /* in normal situation we add up the message to TX ring buffer, if there is no free TX mailbox. But the TX mailbox interrupt is using this same function to move the messages from ring buffer to empty TX mailboxes, so for that use case, there is this check */ @@ -316,7 +349,7 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) } else { ret = false; } } - __HAL_CAN_ENABLE_IT(n_pCanHandle, CAN_IT_TX_MAILBOX_EMPTY); + __HAL_CAN_ENABLE_IT(&_can.handle, CAN_IT_TX_MAILBOX_EMPTY); return ret; } @@ -324,17 +357,17 @@ bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) { bool ret; #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) - __HAL_CAN_DISABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO1_MSG_PENDING); + __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); #else - __HAL_CAN_DISABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO0_MSG_PENDING); + __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_RX_FIFO0_MSG_PENDING); #endif ret = removeFromRingBuffer(rxRing, CAN_rx_msg); #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) - __HAL_CAN_ENABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO1_MSG_PENDING); + __HAL_CAN_ENABLE_IT(&_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); #else - __HAL_CAN_ENABLE_IT(n_pCanHandle, CAN_IT_RX_FIFO0_MSG_PENDING); + __HAL_CAN_ENABLE_IT(&_can.handle, CAN_IT_RX_FIFO0_MSG_PENDING); #endif return ret; } @@ -375,7 +408,7 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I } // Enable filter - if (HAL_CAN_ConfigFilter( n_pCanHandle, &sFilterConfig ) != HAL_OK) + if (HAL_CAN_ConfigFilter( &_can.handle, &sFilterConfig ) != HAL_OK) { return 1; } @@ -392,7 +425,7 @@ void STM32_CAN::setMBFilter(CAN_BANK bank_num, CAN_FLTEN input) if (input == ACCEPT_ALL) { sFilterConfig.FilterActivation = ENABLE; } else { sFilterConfig.FilterActivation = DISABLE; } - HAL_CAN_ConfigFilter(n_pCanHandle, &sFilterConfig); + HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); } void STM32_CAN::setMBFilter(CAN_FLTEN input) @@ -401,15 +434,15 @@ void STM32_CAN::setMBFilter(CAN_FLTEN input) uint8_t max_bank_num = 27; uint8_t min_bank_num = 0; #ifdef CAN2 - if (_canPort == CAN1){ max_bank_num = 13;} - else if (_canPort == CAN2){ min_bank_num = 14;} + if (_can.handle.Instance == CAN1){ max_bank_num = 13;} + else if (_can.handle.Instance == CAN2){ min_bank_num = 14;} #endif for (uint8_t bank_num = min_bank_num ; bank_num <= max_bank_num ; bank_num++) { sFilterConfig.FilterBank = bank_num; if (input == ACCEPT_ALL) { sFilterConfig.FilterActivation = ENABLE; } else { sFilterConfig.FilterActivation = DISABLE; } - HAL_CAN_ConfigFilter(n_pCanHandle, &sFilterConfig); + HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); } } @@ -451,17 +484,17 @@ void STM32_CAN::initializeFilters() sFilterConfig.FilterActivation = ENABLE; #ifdef CAN2 // Filter banks from 14 to 27 are for Can2, so first for Can2 is bank 14. This is not relevant for devices with only one CAN - if (_canPort == CAN1) + if (_can.handle.Instance == CAN1) { sFilterConfig.SlaveStartFilterBank = 14; } - if (_canPort == CAN2) + if (_can.handle.Instance == CAN2) { sFilterConfig.FilterBank = 14; } #endif - HAL_CAN_ConfigFilter(n_pCanHandle, &sFilterConfig); + HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); } void STM32_CAN::initializeBuffers() @@ -774,7 +807,7 @@ uint32_t STM32_CAN::getAPB1Clock() void STM32_CAN::enableMBInterrupts() { - if (n_pCanHandle->Instance == CAN1) + if (_can.handle.Instance == CAN1) { #ifdef CAN1_IRQn_AIO HAL_NVIC_EnableIRQ(CAN1_IRQn_AIO); @@ -784,14 +817,14 @@ void STM32_CAN::enableMBInterrupts() #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 - else if (n_pCanHandle->Instance == CAN2) + else if (_can.handle.Instance == CAN2) { HAL_NVIC_EnableIRQ(CAN2_TX_IRQn); HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn); } #endif #ifdef CAN3 - else if (n_pCanHandle->Instance == CAN3) + else if (_can.handle.Instance == CAN3) { HAL_NVIC_EnableIRQ(CAN3_TX_IRQn); HAL_NVIC_EnableIRQ(CAN3_RX0_IRQn); @@ -801,7 +834,7 @@ void STM32_CAN::enableMBInterrupts() void STM32_CAN::disableMBInterrupts() { - if (n_pCanHandle->Instance == CAN1) + if (_can.handle.Instance == CAN1) { #ifdef CAN1_IRQn_AIO #ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) @@ -817,14 +850,14 @@ void STM32_CAN::disableMBInterrupts() #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 - else if (n_pCanHandle->Instance == CAN2) + else if (_can.handle.Instance == CAN2) { HAL_NVIC_DisableIRQ(CAN2_TX_IRQn); HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn); } #endif #ifdef CAN3 - else if (n_pCanHandle->Instance == CAN3) + else if (_can.handle.Instance == CAN3) { HAL_NVIC_DisableIRQ(CAN3_TX_IRQn); HAL_NVIC_DisableIRQ(CAN3_RX0_IRQn); @@ -835,7 +868,7 @@ void STM32_CAN::disableMBInterrupts() void STM32_CAN::setMode(Mode mode) { this->mode = mode; - n_pCanHandle->Init.Mode = mode; + _can.handle.Init.Mode = mode; } void STM32_CAN::enableLoopBack( bool yes ) { @@ -862,96 +895,39 @@ void STM32_CAN::enableFIFO(bool status) // There is 3 TX mailboxes. Each one has own transmit complete callback function, that we use to pull next message from TX ringbuffer to be sent out in TX mailbox. extern "C" void HAL_CAN_TxMailbox0CompleteCallback( CAN_HandleTypeDef *CanHandle ) { + stm32_can_t * canObj = get_can_obj(CanHandle); + STM32_CAN * _can = (STM32_CAN *)canObj->__this; CAN_message_t txmsg; - // use correct CAN instance - if (CanHandle->Instance == CAN1) - { - if (_CAN1->removeFromRingBuffer(_CAN1->txRing, txmsg)) - { - _CAN1->write(txmsg, true); - } - } -#ifdef CAN2 - else if (CanHandle->Instance == CAN2) - { - if (_CAN2->removeFromRingBuffer(_CAN2->txRing, txmsg)) - { - _CAN2->write(txmsg, true); - } - } -#endif -#ifdef CAN3 - else if (CanHandle->Instance == CAN3) + + if (_can->removeFromRingBuffer(_can->txRing, txmsg)) { - if (_CAN3->removeFromRingBuffer(_CAN3->txRing, txmsg)) - { - _CAN3->write(txmsg, true); - } + _can->write(txmsg, true); } -#endif } extern "C" void HAL_CAN_TxMailbox1CompleteCallback( CAN_HandleTypeDef *CanHandle ) { + stm32_can_t * canObj = get_can_obj(CanHandle); + STM32_CAN * _can = (STM32_CAN *)canObj->__this; CAN_message_t txmsg; - // use correct CAN instance - if (CanHandle->Instance == CAN1) - { - if (_CAN1->removeFromRingBuffer(_CAN1->txRing, txmsg)) - { - _CAN1->write(txmsg, true); - } - } -#ifdef CAN2 - else if (CanHandle->Instance == CAN2) - { - if (_CAN2->removeFromRingBuffer(_CAN2->txRing, txmsg)) - { - _CAN2->write(txmsg, true); - } - } -#endif -#ifdef CAN3 - else if (CanHandle->Instance == CAN3) + + if (_can->removeFromRingBuffer(_can->txRing, txmsg)) { - if (_CAN3->removeFromRingBuffer(_CAN3->txRing, txmsg)) - { - _CAN3->write(txmsg, true); - } + _can->write(txmsg, true); } -#endif } extern "C" void HAL_CAN_TxMailbox2CompleteCallback( CAN_HandleTypeDef *CanHandle ) { + stm32_can_t * canObj = get_can_obj(CanHandle); + STM32_CAN * _can = (STM32_CAN *)canObj->__this; CAN_message_t txmsg; - // use correct CAN instance - if (CanHandle->Instance == CAN1) - { - if (_CAN1->removeFromRingBuffer(_CAN1->txRing, txmsg)) - { - _CAN1->write(txmsg, true); - } - } -#ifdef CAN2 - else if (CanHandle->Instance == CAN2) - { - if (_CAN2->removeFromRingBuffer(_CAN2->txRing, txmsg)) - { - _CAN2->write(txmsg, true); - } - } -#endif -#ifdef CAN3 - else if (CanHandle->Instance == CAN3) - { - if (_CAN3->removeFromRingBuffer(_CAN3->txRing, txmsg)) + + if (_can->removeFromRingBuffer(_can->txRing, txmsg)) { - _CAN3->write(txmsg, true); + _can->write(txmsg, true); } } -#endif -} // This is called by RX0_IRQHandler when there is message at RX FIFO0 buffer #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) @@ -960,6 +936,8 @@ extern "C" void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *CanHandle) extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) #endif { + stm32_can_t * canObj = get_can_obj(CanHandle); + STM32_CAN * _can = (STM32_CAN *)canObj->__this; CAN_message_t rxmsg; CAN_RxHeaderTypeDef RxHeader; //bool state = Disable_Interrupts(); @@ -987,26 +965,8 @@ extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) rxmsg.timestamp = RxHeader.Timestamp; rxmsg.len = RxHeader.DLC; - // use correct ring buffer based on CAN instance - if (CanHandle->Instance == CAN1) - { - rxmsg.bus = 1; - _CAN1->addToRingBuffer(_CAN1->rxRing, rxmsg); - } -#ifdef CAN2 - else if (CanHandle->Instance == CAN2) - { - rxmsg.bus = 2; - _CAN2->addToRingBuffer(_CAN2->rxRing, rxmsg); - } -#endif -#ifdef CAN3 - else if (CanHandle->Instance == CAN3) - { - rxmsg.bus = 3; - _CAN3->addToRingBuffer(_CAN3->rxRing, rxmsg); - } -#endif + rxmsg.bus = canObj->bus; + _can->addToRingBuffer(_can->rxRing, rxmsg); } //Enable_Interrupts(state); } @@ -1015,7 +975,9 @@ extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) extern "C" void CAN1_IRQHandler_AIO(void) { - HAL_CAN_IRQHandler(&hcan1); + if(canObj[CAN1_INDEX]) { + HAL_CAN_IRQHandler(&canObj[CAN1_INDEX]->handle); + } #ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) if(phcec) { @@ -1034,19 +996,25 @@ extern "C" void CAN1_RX1_IRQHandler(void) extern "C" void CAN1_RX0_IRQHandler(void) #endif { - HAL_CAN_IRQHandler(&hcan1); + if(canObj[CAN1_INDEX]) { + HAL_CAN_IRQHandler(&canObj[CAN1_INDEX]->handle); + } } #ifdef CAN2 extern "C" void CAN2_RX0_IRQHandler(void) { - HAL_CAN_IRQHandler(&hcan2); + if(canObj[CAN2_INDEX]) { + HAL_CAN_IRQHandler(&canObj[CAN2_INDEX]->handle); + } } #endif #ifdef CAN3 extern "C" void CAN3_RX0_IRQHandler(void) { - HAL_CAN_IRQHandler(&hcan3); + if(canObj[CAN3_INDEX]) { + HAL_CAN_IRQHandler(&canObj[CAN3_INDEX]->handle); + } } #endif @@ -1058,19 +1026,25 @@ extern "C" void STM32_CAN_Poll_IRQ_Handler(void) extern "C" void CAN1_TX_IRQHandler(void) #endif { - HAL_CAN_IRQHandler(&hcan1); + if(canObj[CAN1_INDEX]) { + HAL_CAN_IRQHandler(&canObj[CAN1_INDEX]->handle); + } } #ifdef CAN2 extern "C" void CAN2_TX_IRQHandler(void) { - HAL_CAN_IRQHandler(&hcan2); + if(canObj[CAN2_INDEX]) { + HAL_CAN_IRQHandler(&canObj[CAN2_INDEX]->handle); + } } #endif #ifdef CAN3 extern "C" void CAN3_TX_IRQHandler(void) { - HAL_CAN_IRQHandler(&hcan3); + if(canObj[CAN3_INDEX]) { + HAL_CAN_IRQHandler(&canObj[CAN3_INDEX]->handle); + } } #endif diff --git a/STM32_CAN.h b/STM32_CAN.h index fc3de26..96791bd 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -239,6 +239,12 @@ typedef enum IDE { AUTO = 2 } IDE; +typedef struct { + void * __this; + CAN_HandleTypeDef handle; + uint32_t bus; +} stm32_can_t; + class STM32_CAN { public: @@ -364,8 +370,7 @@ class STM32_CAN { uint32_t preemptPriority; uint32_t subPriority; - CAN_HandleTypeDef *n_pCanHandle; - CAN_TypeDef* _canPort; + stm32_can_t _can; }; From 064f6d98bbfe327014247f78d51435f63474873c Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 11:27:10 +0100 Subject: [PATCH 11/51] protect HAL calls from uninitialized handle --- STM32_CAN.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index bc81f9b..bd3ee1d 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -310,6 +310,7 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) bool ret = true; uint32_t TxMailbox; CAN_TxHeaderTypeDef TxHeader; + if(!_can.handle.Instance) return false; __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_TX_MAILBOX_EMPTY); @@ -356,6 +357,8 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) { bool ret; + if(!_can.handle.Instance) return false; + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); #else @@ -375,6 +378,7 @@ bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE std_ext, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo) { CAN_FilterTypeDef sFilterConfig; + if(!_can.handle.Instance) return false; sFilterConfig.FilterBank = bank_num; sFilterConfig.FilterMode = filter_mode; @@ -421,6 +425,8 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I void STM32_CAN::setMBFilter(CAN_BANK bank_num, CAN_FLTEN input) { CAN_FilterTypeDef sFilterConfig; + if(!_can.handle.Instance) return; + sFilterConfig.FilterBank = uint8_t(bank_num); if (input == ACCEPT_ALL) { sFilterConfig.FilterActivation = ENABLE; } else { sFilterConfig.FilterActivation = DISABLE; } @@ -433,6 +439,8 @@ void STM32_CAN::setMBFilter(CAN_FLTEN input) CAN_FilterTypeDef sFilterConfig; uint8_t max_bank_num = 27; uint8_t min_bank_num = 0; + if(!_can.handle.Instance) return; + #ifdef CAN2 if (_can.handle.Instance == CAN1){ max_bank_num = 13;} else if (_can.handle.Instance == CAN2){ min_bank_num = 14;} @@ -468,6 +476,8 @@ bool STM32_CAN::setMBFilter(CAN_BANK bank_num, uint32_t id1, uint32_t id2, IDE s void STM32_CAN::initializeFilters() { CAN_FilterTypeDef sFilterConfig; + if(!_can.handle.Instance) return; + // We set first bank to accept all RX messages sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; From 817fa8aac979820f6c549fcaa83a34212cffeedf Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 17:10:55 +0100 Subject: [PATCH 12/51] fix: do not enable the Tx interrupt flag if TX IRQ is blocked by USB --- STM32_CAN.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index bd3ee1d..f721d9f 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -294,15 +294,13 @@ void STM32_CAN::setBaudRate(uint32_t baud) // Start the CAN peripheral HAL_CAN_Start( &_can.handle ); - // Activate CAN RX notification + // Activate CAN notifications #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) HAL_CAN_ActivateNotification( &_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); #else HAL_CAN_ActivateNotification( &_can.handle, CAN_IT_RX_FIFO0_MSG_PENDING); - #endif - - // Activate CAN TX notification HAL_CAN_ActivateNotification( &_can.handle, CAN_IT_TX_MAILBOX_EMPTY); + #endif } bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) @@ -312,7 +310,9 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) CAN_TxHeaderTypeDef TxHeader; if(!_can.handle.Instance) return false; + #if !defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_TX_MAILBOX_EMPTY); + #endif if (CAN_tx_msg.flags.extended == 1) // Extended ID when CAN_tx_msg.flags.extended is 1 { @@ -350,7 +350,10 @@ bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) } else { ret = false; } } + + #if !defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) __HAL_CAN_ENABLE_IT(&_can.handle, CAN_IT_TX_MAILBOX_EMPTY); + #endif return ret; } From 48982331d22cd2ec8cfdcef33feb383580a2f6ea Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 18:58:14 +0100 Subject: [PATCH 13/51] fix: handle the special case with shared USB IRQ in enableMBInterrupts() and disableMBInterrupts() --- STM32_CAN.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index f721d9f..50fe542 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -825,8 +825,12 @@ void STM32_CAN::enableMBInterrupts() #ifdef CAN1_IRQn_AIO HAL_NVIC_EnableIRQ(CAN1_IRQn_AIO); #else + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn); + #else HAL_NVIC_EnableIRQ(CAN1_TX_IRQn); HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn); + #endif #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 @@ -858,8 +862,12 @@ void STM32_CAN::disableMBInterrupts() HAL_NVIC_DisableIRQ(CAN1_IRQn_AIO); } #else + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn); + #else HAL_NVIC_DisableIRQ(CAN1_TX_IRQn); HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn); + #endif #endif /** else defined(CAN1_IRQn_AIO) */ } #ifdef CAN2 From be7ae1af79d016f2da288915ab5344febc77a571 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:01:27 +0100 Subject: [PATCH 14/51] fix: don't setup not connected pin --- STM32_CAN.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 50fe542..a5c38de 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -193,7 +193,10 @@ void STM32_CAN::begin( bool retransmission ) { initializeBuffers(); pin_function(rx, pinmap_function(rx, PinMap_CAN_RD)); - pin_function(tx, pinmap_function(tx, PinMap_CAN_TD)); + if(tx != NC) + { + pin_function(tx, pinmap_function(tx, PinMap_CAN_TD)); + } // Configure CAN if (_can.handle.Instance == CAN1) From 374018c17f43eb3b4342e3e611a66e73b0c0e4a8 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:53:51 +0100 Subject: [PATCH 15/51] move peripheral resolving and registration with globals into begin() --- STM32_CAN.cpp | 59 ++++++++++++++++++++++++++++++++++++++++----------- STM32_CAN.h | 3 +++ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index a5c38de..5a570df 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -66,6 +66,34 @@ can_index_t get_can_index(CAN_TypeDef *instance) return index; } +bool STM32_CAN::allocatePeripheral() +{ + can_index_t index = get_can_index(_can.handle.Instance); + if(index >= CAN_NUM) + { + return false; + } + if(canObj[index]) + { + //bus already in use by other instance + Error_Handler(); + return false; + } + //register with global, we own this instance now + canObj[index] = &_can; + return true; +} + +bool STM32_CAN::hasPeripheral() +{ + can_index_t index = get_can_index(_can.handle.Instance); + if(index >= CAN_NUM) + { + return false; + } + return canObj[index] == &_can; +} + STM32_CAN::STM32_CAN(uint32_t rx, uint32_t tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) : sizeRxBuffer(rxSize), sizeTxBuffer(txSize), mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) @@ -156,7 +184,10 @@ void STM32_CAN::init(void) { _can.__this = (void*)this; _can.handle.Instance = nullptr; +} +CAN_TypeDef * STM32_CAN::getPeripheral() +{ CAN_TypeDef * canPort_rx = (CAN_TypeDef *) pinmap_peripheral(rx, PinMap_CAN_RD); CAN_TypeDef * canPort_tx = (CAN_TypeDef *) pinmap_peripheral(tx, PinMap_CAN_TD); if ((canPort_rx != canPort_tx && canPort_tx != NP) || canPort_rx == NP) @@ -165,14 +196,14 @@ void STM32_CAN::init(void) // rx only can be used as listen only but needs a 3rd node for valid ACKs // do not allow Tx only since that would break arbitration - return; + return NP; } //clear tx pin in case it was set but does not match a peripheral if(canPort_tx == NP) tx = NC; - _can.handle.Instance = canPort_rx; + return canPort_rx; } void STM32_CAN::setIRQPriority(uint32_t preemptPriority, uint32_t subPriority) @@ -188,6 +219,19 @@ void STM32_CAN::begin( bool retransmission ) { // exit if CAN already is active if (_canIsActive) return; + _can.handle.Instance = getPeripheral(); + if(_can.handle.Instance == NP) + { + //impossible pinconfig, done here + _can.handle.Instance = nullptr; + return; + } + if(!allocatePeripheral()) + { + //peripheral already in use + return; + } + _canIsActive = true; initializeBuffers(); @@ -272,19 +316,10 @@ void STM32_CAN::begin( bool retransmission ) { void STM32_CAN::setBaudRate(uint32_t baud) { - can_index_t index = get_can_index(_can.handle.Instance); - if(index >= CAN_NUM) - { - return; - } - if(canObj[index]) + if(!hasPeripheral()) { - //bus already in use by other instance - Error_Handler(); return; } - //register with global, we own this instance now - canObj[index] = &_can; // Calculate and set baudrate calculateBaudrate( &_can.handle, baud ); diff --git a/STM32_CAN.h b/STM32_CAN.h index 96791bd..9af470a 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -304,6 +304,9 @@ class STM32_CAN { private: void init(void); + CAN_TypeDef * getPeripheral(void); + bool allocatePeripheral(void); + bool hasPeripheral(void); void initializeFilters(); bool isInitialized() { return rx_buffer != 0; } void initRingBuffer(RingbufferTypeDef &ring, volatile CAN_message_t *buffer, uint32_t size); From fb81317fb6e951da1814669ef66a78472d69ecfc Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 20:06:28 +0100 Subject: [PATCH 16/51] let setBaudrate() be called before begin(). Save baudrate and use on begin() --- STM32_CAN.cpp | 6 ++++++ STM32_CAN.h | 1 + 2 files changed, 7 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 5a570df..bc02cda 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -184,6 +184,7 @@ void STM32_CAN::init(void) { _can.__this = (void*)this; _can.handle.Instance = nullptr; + baudrate = 0UL; } CAN_TypeDef * STM32_CAN::getPeripheral() @@ -312,10 +313,15 @@ void STM32_CAN::begin( bool retransmission ) { _can.handle.Init.ReceiveFifoLocked = DISABLE; _can.handle.Init.TransmitFifoPriority = ENABLE; _can.handle.Init.Mode = mode; + + //try to start in case baudrate was set earlier + setBaudRate(baudrate); } void STM32_CAN::setBaudRate(uint32_t baud) { + baudrate = baud; + if(!hasPeripheral()) { return; diff --git a/STM32_CAN.h b/STM32_CAN.h index 9af470a..0e00a76 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -366,6 +366,7 @@ class STM32_CAN { bool _canIsActive = false; Mode mode; + uint32_t baudrate; PinName rx; PinName tx; From a9038c110b01a89c99d31b5718cb09b93110331a Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 21:02:03 +0100 Subject: [PATCH 17/51] allow restarting bus with other baudrate --- STM32_CAN.cpp | 32 ++++++++++++++++++++++++++------ STM32_CAN.h | 4 +++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index bc02cda..2363d59 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -330,6 +330,13 @@ void STM32_CAN::setBaudRate(uint32_t baud) // Calculate and set baudrate calculateBaudrate( &_can.handle, baud ); + // (re)-start + stop(); + start(); +} + +void STM32_CAN::start() +{ // Initializes CAN HAL_CAN_Init( &_can.handle ); @@ -347,6 +354,19 @@ void STM32_CAN::setBaudRate(uint32_t baud) #endif } +void STM32_CAN::stop() +{ + #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) + HAL_CAN_DeactivateNotification( &_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); + #else + HAL_CAN_DeactivateNotification( &_can.handle, CAN_IT_RX_FIFO0_MSG_PENDING); + HAL_CAN_DeactivateNotification( &_can.handle, CAN_IT_TX_MAILBOX_EMPTY); + #endif + + /** Calls Stop internally, clears all errors */ + HAL_CAN_DeInit( &_can.handle ); +} + bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) { bool ret = true; @@ -410,7 +430,7 @@ bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); #else __HAL_CAN_DISABLE_IT(&_can.handle, CAN_IT_RX_FIFO0_MSG_PENDING); - #endif +#endif ret = removeFromRingBuffer(rxRing, CAN_rx_msg); @@ -418,7 +438,7 @@ bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) __HAL_CAN_ENABLE_IT(&_can.handle, CAN_IT_RX_FIFO1_MSG_PENDING); #else __HAL_CAN_ENABLE_IT(&_can.handle, CAN_IT_RX_FIFO0_MSG_PENDING); - #endif +#endif return ret; } @@ -524,7 +544,7 @@ void STM32_CAN::initializeFilters() { CAN_FilterTypeDef sFilterConfig; if(!_can.handle.Instance) return; - + // We set first bank to accept all RX messages sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; @@ -543,7 +563,7 @@ void STM32_CAN::initializeFilters() // Filter banks from 14 to 27 are for Can2, so first for Can2 is bank 14. This is not relevant for devices with only one CAN if (_can.handle.Instance == CAN1) { - sFilterConfig.SlaveStartFilterBank = 14; + sFilterConfig.SlaveStartFilterBank = 14; } if (_can.handle.Instance == CAN2) { @@ -989,10 +1009,10 @@ extern "C" void HAL_CAN_TxMailbox2CompleteCallback( CAN_HandleTypeDef *CanHandle CAN_message_t txmsg; if (_can->removeFromRingBuffer(_can->txRing, txmsg)) - { + { _can->write(txmsg, true); - } } +} // This is called by RX0_IRQHandler when there is message at RX FIFO0 buffer #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) diff --git a/STM32_CAN.h b/STM32_CAN.h index 0e00a76..34672ac 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -122,7 +122,7 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #define CAN1_RX0_IRQn CAN_RX0_IRQn #define CAN1_RX1_IRQn CAN_RX1_IRQn #define CAN1_SCE_IRQn CAN_SCE_IRQn - + #define CAN1_TX_IRQHandler CAN_TX_IRQHandler #define CAN1_RX0_IRQHandler CAN_RX0_IRQHandler #define CAN1_RX1_IRQHandler CAN_RX1_IRQHandler @@ -307,6 +307,8 @@ class STM32_CAN { CAN_TypeDef * getPeripheral(void); bool allocatePeripheral(void); bool hasPeripheral(void); + void start(void); + void stop(void); void initializeFilters(); bool isInitialized() { return rx_buffer != 0; } void initRingBuffer(RingbufferTypeDef &ring, volatile CAN_message_t *buffer, uint32_t size); From 807198bd7686264b48ff42f5e4b4aa94a2775e56 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 21:05:20 +0100 Subject: [PATCH 18/51] only initialize filters on first start, not on each re-start --- STM32_CAN.cpp | 5 +++++ STM32_CAN.h | 1 + 2 files changed, 6 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 2363d59..c7c4e9b 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -185,6 +185,7 @@ void STM32_CAN::init(void) _can.__this = (void*)this; _can.handle.Instance = nullptr; baudrate = 0UL; + filtersInitialized = false; } CAN_TypeDef * STM32_CAN::getPeripheral() @@ -313,6 +314,8 @@ void STM32_CAN::begin( bool retransmission ) { _can.handle.Init.ReceiveFifoLocked = DISABLE; _can.handle.Init.TransmitFifoPriority = ENABLE; _can.handle.Init.Mode = mode; + + filtersInitialized = false; //try to start in case baudrate was set earlier setBaudRate(baudrate); @@ -544,6 +547,8 @@ void STM32_CAN::initializeFilters() { CAN_FilterTypeDef sFilterConfig; if(!_can.handle.Instance) return; + if(filtersInitialized) return; + filtersInitialized = true; // We set first bank to accept all RX messages sFilterConfig.FilterBank = 0; diff --git a/STM32_CAN.h b/STM32_CAN.h index 34672ac..93f3d4a 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -369,6 +369,7 @@ class STM32_CAN { Mode mode; uint32_t baudrate; + bool filtersInitialized; PinName rx; PinName tx; From 8a821fedb75d8e18787246ef904c1095f05252eb Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 21:28:40 +0100 Subject: [PATCH 19/51] add end() function to de-initialize and release can peripheral --- STM32_CAN.cpp | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ STM32_CAN.h | 3 ++ 2 files changed, 80 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index c7c4e9b..7c8d355 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -84,6 +84,23 @@ bool STM32_CAN::allocatePeripheral() return true; } +bool STM32_CAN::freePeripheral() +{ + can_index_t index = get_can_index(_can.handle.Instance); + if(index >= CAN_NUM) + { + return false; + } + if(canObj[index] == &_can) + { + canObj[index] = nullptr; + _can.handle.Instance = nullptr; + return true; + } + Error_Handler(); + return false; +} + bool STM32_CAN::hasPeripheral() { can_index_t index = get_can_index(_can.handle.Instance); @@ -321,6 +338,51 @@ void STM32_CAN::begin( bool retransmission ) { setBaudRate(baudrate); } +void STM32_CAN::end() +{ + if(!hasPeripheral()) + { + return; + } + + stop(); + + disableMBInterrupts(); + + if (_can.handle.Instance == CAN1) + { + __HAL_RCC_CAN1_CLK_DISABLE(); + } +#ifdef CAN2 + else if (_can.handle.Instance == CAN2) + { + __HAL_RCC_CAN2_CLK_DISABLE(); + //only disable CAN1 clock if its not used + if(canObj[CAN1_INDEX] == nullptr) + { + __HAL_RCC_CAN1_CLK_DISABLE(); + } + } +#endif +#ifdef CAN3 + else if (_can.handle.Instance == CAN3) + { + __HAL_RCC_CAN3_CLK_DISABLE(); + } +#endif + + /** un-init pins, enable tx PULLUP for weak driving of recessive state */ + pin_function(rx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, GPIO_AF_NONE)); + if(tx != NC) + pin_function(tx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLUP, GPIO_AF_NONE)); + + freeBuffers(); + + freePeripheral(); + + _canIsActive = false; +} + void STM32_CAN::setBaudRate(uint32_t baud) { baudrate = baud; @@ -597,6 +659,21 @@ void STM32_CAN::initializeBuffers() initRingBuffer(rxRing, rx_buffer, sizeRxBuffer); } +void STM32_CAN::freeBuffers() +{ + txRing.head = 0; + txRing.tail = 0; + txRing.buffer = nullptr; + delete[] tx_buffer; + tx_buffer = nullptr; + + rxRing.head = 0; + rxRing.tail = 0; + rxRing.buffer = nullptr; + delete[] rx_buffer; + rx_buffer = nullptr; +} + void STM32_CAN::initRingBuffer(RingbufferTypeDef &ring, volatile CAN_message_t *buffer, uint32_t size) { ring.buffer = buffer; diff --git a/STM32_CAN.h b/STM32_CAN.h index 93f3d4a..6ae442d 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -257,6 +257,7 @@ class STM32_CAN { void setIRQPriority(uint32_t preemptPriority, uint32_t subPriority); // Begin. By default the automatic retransmission is enabled. If it causes problems, use begin(false) to disable it. void begin(bool retransmission = false); + void end(void); void setBaudRate(uint32_t baud); bool write(CAN_message_t &CAN_tx_msg, bool sendMB = false); bool read(CAN_message_t &CAN_rx_msg); @@ -306,6 +307,7 @@ class STM32_CAN { void init(void); CAN_TypeDef * getPeripheral(void); bool allocatePeripheral(void); + bool freePeripheral(void); bool hasPeripheral(void); void start(void); void stop(void); @@ -313,6 +315,7 @@ class STM32_CAN { bool isInitialized() { return rx_buffer != 0; } void initRingBuffer(RingbufferTypeDef &ring, volatile CAN_message_t *buffer, uint32_t size); void initializeBuffers(void); + void freeBuffers(void); bool isRingBufferEmpty(RingbufferTypeDef &ring); uint32_t ringBufferCount(RingbufferTypeDef &ring); From 53271d9b9df9b018d040c74956a9eb7aa2b8c93e Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 1 Jan 2025 21:38:16 +0100 Subject: [PATCH 20/51] on F1 platform verify that both pins are using the same alternate function setting --- STM32_CAN.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 7c8d355..a76ae78 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -218,6 +218,24 @@ CAN_TypeDef * STM32_CAN::getPeripheral() return NP; } + #ifdef STM32F1xx + /** AF remapping on the F1 platform only possible in pairs + * Verify that both pins use the same remapping + * Only enforced if both pins are used, in Rx only Tx pin is not set to AF*/ + if(canPort_rx != NP && canPort_tx != NP) + { + uint32_t rx_func = pinmap_function(rx, PinMap_CAN_RD); + uint32_t tx_func = pinmap_function(tx, PinMap_CAN_TD); + uint32_t rx_afnum = STM_PIN_AFNUM(rx_func); + uint32_t tx_afnum = STM_PIN_AFNUM(tx_func); + if(rx_afnum != tx_afnum) + { + //ERROR + return NP; + } + } + #endif + //clear tx pin in case it was set but does not match a peripheral if(canPort_tx == NP) tx = NC; From f3aa639e876312b8f3ce277f2281ab82be729e36 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:09:51 +0100 Subject: [PATCH 21/51] fix: set SlaveStartFilterBank for all ConfigFilter calls. And cleanup some magic numbers --- STM32_CAN.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index a76ae78..72e4e68 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -11,6 +11,10 @@ extern CEC_HandleTypeDef * phcec; #endif +#define STM32_CAN_SINGLE_CAN_FILTER_COUNT 14 +#define STM32_CAN_DUAL_CAN_FILTER_COUNT 28 +#define STM32_CAN_CAN2_FILTER_OFFSET 14 + //Max value, lowest priority #define MAX_IRQ_PRIO_VALUE ((1UL << __NVIC_PRIO_BITS) - 1UL) @@ -561,6 +565,9 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I sFilterConfig.FilterMaskIdHigh = (uint16_t) (mask >> 13); } + #ifdef CAN2 + sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; + #endif // Enable filter if (HAL_CAN_ConfigFilter( &_can.handle, &sFilterConfig ) != HAL_OK) { @@ -578,6 +585,13 @@ void STM32_CAN::setMBFilter(CAN_BANK bank_num, CAN_FLTEN input) if(!_can.handle.Instance) return; sFilterConfig.FilterBank = uint8_t(bank_num); + #ifdef CAN2 + sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; + if (_can.handle.Instance == CAN2) + { + sFilterConfig.FilterBank += STM32_CAN_CAN2_FILTER_OFFSET; + } + #endif if (input == ACCEPT_ALL) { sFilterConfig.FilterActivation = ENABLE; } else { sFilterConfig.FilterActivation = DISABLE; } @@ -587,13 +601,21 @@ void STM32_CAN::setMBFilter(CAN_BANK bank_num, CAN_FLTEN input) void STM32_CAN::setMBFilter(CAN_FLTEN input) { CAN_FilterTypeDef sFilterConfig; - uint8_t max_bank_num = 27; + uint8_t max_bank_num = STM32_CAN_SINGLE_CAN_FILTER_COUNT-1; uint8_t min_bank_num = 0; if(!_can.handle.Instance) return; #ifdef CAN2 - if (_can.handle.Instance == CAN1){ max_bank_num = 13;} - else if (_can.handle.Instance == CAN2){ min_bank_num = 14;} + sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; + if (_can.handle.Instance == CAN1) + { + max_bank_num = max(STM32_CAN_CAN2_FILTER_OFFSET-1, 0); + } + else if (_can.handle.Instance == CAN2) + { + min_bank_num = STM32_CAN_CAN2_FILTER_OFFSET; + max_bank_num = STM32_CAN_DUAL_CAN_FILTER_COUNT-1; + } #endif for (uint8_t bank_num = min_bank_num ; bank_num <= max_bank_num ; bank_num++) { @@ -646,13 +668,10 @@ void STM32_CAN::initializeFilters() sFilterConfig.FilterActivation = ENABLE; #ifdef CAN2 // Filter banks from 14 to 27 are for Can2, so first for Can2 is bank 14. This is not relevant for devices with only one CAN - if (_can.handle.Instance == CAN1) - { - sFilterConfig.SlaveStartFilterBank = 14; - } + sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; if (_can.handle.Instance == CAN2) { - sFilterConfig.FilterBank = 14; + sFilterConfig.FilterBank = STM32_CAN_CAN2_FILTER_OFFSET; } #endif From a05be3d151aafafeab3d1ad2524b8906799602cb Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:34:05 +0100 Subject: [PATCH 22/51] turn off unused filters during init --- STM32_CAN.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 72e4e68..402fac6 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -676,6 +676,28 @@ void STM32_CAN::initializeFilters() #endif HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); + + /** turn off all other filters that might sill be setup from before */ + sFilterConfig.FilterActivation = DISABLE; + uint8_t filter_count = STM32_CAN_SINGLE_CAN_FILTER_COUNT; + uint8_t filter_start = 1; + #ifdef CAN2 + /** In dual CAN devices filter banks are shared and setup to equal amounts */ + if (_can.handle.Instance == CAN1) + { + filter_count = STM32_CAN_CAN2_FILTER_OFFSET; + } + else if (_can.handle.Instance == CAN2) + { + filter_start += STM32_CAN_CAN2_FILTER_OFFSET; + filter_count = STM32_CAN_DUAL_CAN_FILTER_COUNT; + } + #endif + for (uint8_t bank_num = filter_start ; bank_num < filter_count ; bank_num++) + { + sFilterConfig.FilterBank = bank_num; + HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); + } } void STM32_CAN::initializeBuffers() From b583569a894e994030feb5c25fa7624d022b64cb Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:49:04 +0100 Subject: [PATCH 23/51] add feedback to baudrate calculation, don't start with impossible clock configs --- STM32_CAN.cpp | 14 +++++++++----- STM32_CAN.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 402fac6..6f79101 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -415,7 +415,10 @@ void STM32_CAN::setBaudRate(uint32_t baud) } // Calculate and set baudrate - calculateBaudrate( &_can.handle, baud ); + if(!calculateBaudrate( &_can.handle, baud )) + { + return; + } // (re)-start stop(); @@ -940,7 +943,7 @@ bool STM32_CAN::lookupBaudrate(CAN_HandleTypeDef *CanHandle, int baud, const T(& return false; } -void STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) +bool STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) { uint8_t bs1; uint8_t bs2; @@ -949,9 +952,9 @@ void STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) const uint32_t frequency = getAPB1Clock(); if (frequency == 48000000) { - if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_48M)) return; + if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_48M)) return true; } else if (frequency == 45000000) { - if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_45M)) return; + if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_45M)) return true; } /* this loop seeks a precise baudrate match, with the sample point positioned @@ -980,12 +983,13 @@ void STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) if (baud_cur != baud) continue; setBaudRateValues(CanHandle, prescaler, bs1, bs2, 4); - return; + return true; } } } /* uhoh, failed to calculate an acceptable baud rate... */ + return false; } uint32_t STM32_CAN::getAPB1Clock() diff --git a/STM32_CAN.h b/STM32_CAN.h index 6ae442d..f1db4fe 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -321,7 +321,7 @@ class STM32_CAN { template bool lookupBaudrate(CAN_HandleTypeDef *CanHandle, int Baudrate, const T(&table)[N]); - void calculateBaudrate(CAN_HandleTypeDef *CanHandle, int Baudrate); + bool calculateBaudrate(CAN_HandleTypeDef *CanHandle, int Baudrate); void setBaudRateValues(CAN_HandleTypeDef *CanHandle, uint16_t prescaler, uint8_t timeseg1, uint8_t timeseg2, uint8_t sjw); uint32_t getAPB1Clock(void); From dc1206164a738d78bcc0b9fb9a022b4fcaa57840 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 02:11:29 +0100 Subject: [PATCH 24/51] use HAL function to get bus clock directly --- STM32_CAN.cpp | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 6f79101..12ae5e3 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -994,37 +994,8 @@ bool STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) uint32_t STM32_CAN::getAPB1Clock() { - RCC_ClkInitTypeDef clkInit; - uint32_t flashLatency; - HAL_RCC_GetClockConfig(&clkInit, &flashLatency); - - uint32_t hclkClock = HAL_RCC_GetHCLKFreq(); - uint8_t clockDivider = 1; - switch (clkInit.APB1CLKDivider) - { - case RCC_HCLK_DIV1: - clockDivider = 1; - break; - case RCC_HCLK_DIV2: - clockDivider = 2; - break; - case RCC_HCLK_DIV4: - clockDivider = 4; - break; - case RCC_HCLK_DIV8: - clockDivider = 8; - break; - case RCC_HCLK_DIV16: - clockDivider = 16; - break; - default: - // should not happen - break; - } - - uint32_t apb1Clock = hclkClock / clockDivider; - - return apb1Clock; + //APB1 is PCLK1 + return HAL_RCC_GetPCLK1Freq(); } void STM32_CAN::enableMBInterrupts() From 6d50b4f92a9664b54490508d5cbd9fbbfe4e8db5 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 02:17:25 +0100 Subject: [PATCH 25/51] remove redundant mode member variable --- STM32_CAN.cpp | 12 ++++++------ STM32_CAN.h | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 12ae5e3..de40729 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -117,7 +117,7 @@ bool STM32_CAN::hasPeripheral() STM32_CAN::STM32_CAN(uint32_t rx, uint32_t tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) : sizeRxBuffer(rxSize), sizeTxBuffer(txSize), - mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) + preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) { this->rx = digitalPinToPinName(rx); this->tx = digitalPinToPinName(tx); @@ -126,14 +126,14 @@ STM32_CAN::STM32_CAN(uint32_t rx, uint32_t tx, RXQUEUE_TABLE rxSize, TXQUEUE_TAB STM32_CAN::STM32_CAN(PinName rx, PinName tx, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize) : rx(rx), tx(tx), sizeRxBuffer(rxSize), sizeTxBuffer(txSize), - mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) + preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) { init(); } STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) : sizeRxBuffer(rxSize), sizeTxBuffer(txSize), - mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) + preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) { //get first matching pins from map rx = pinmap_find_pin(canPort, PinMap_CAN_RD); @@ -144,7 +144,7 @@ STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE //lagacy pin config for compatibility STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize, TXQUEUE_TABLE txSize ) : rx(NC), tx(NC), sizeRxBuffer(rxSize), sizeTxBuffer(txSize), - mode(Mode::NORMAL), preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) + preemptPriority(MAX_IRQ_PRIO_VALUE), subPriority(0) { if (canPort == CAN1) { @@ -207,6 +207,8 @@ void STM32_CAN::init(void) _can.handle.Instance = nullptr; baudrate = 0UL; filtersInitialized = false; + + _can.handle.Init.Mode = Mode::NORMAL; } CAN_TypeDef * STM32_CAN::getPeripheral() @@ -352,7 +354,6 @@ void STM32_CAN::begin( bool retransmission ) { else { _can.handle.Init.AutoRetransmission = DISABLE; } _can.handle.Init.ReceiveFifoLocked = DISABLE; _can.handle.Init.TransmitFifoPriority = ENABLE; - _can.handle.Init.Mode = mode; filtersInitialized = false; @@ -1068,7 +1069,6 @@ void STM32_CAN::disableMBInterrupts() void STM32_CAN::setMode(Mode mode) { - this->mode = mode; _can.handle.Init.Mode = mode; } diff --git a/STM32_CAN.h b/STM32_CAN.h index f1db4fe..b78e101 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -370,7 +370,6 @@ class STM32_CAN { bool _canIsActive = false; - Mode mode; uint32_t baudrate; bool filtersInitialized; From ff8fbfc58c8bc05263b855da6db492677926f8cd Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 02:21:48 +0100 Subject: [PATCH 26/51] move static init value initialization from begin() to init() --- STM32_CAN.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index de40729..28b56c8 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -208,6 +208,11 @@ void STM32_CAN::init(void) baudrate = 0UL; filtersInitialized = false; + _can.handle.Init.TimeTriggeredMode = DISABLE; + _can.handle.Init.AutoBusOff = DISABLE; + _can.handle.Init.AutoWakeUp = DISABLE; + _can.handle.Init.ReceiveFifoLocked = DISABLE; + _can.handle.Init.TransmitFifoPriority = ENABLE; _can.handle.Init.Mode = Mode::NORMAL; } @@ -347,13 +352,8 @@ void STM32_CAN::begin( bool retransmission ) { } #endif - _can.handle.Init.TimeTriggeredMode = DISABLE; - _can.handle.Init.AutoBusOff = DISABLE; - _can.handle.Init.AutoWakeUp = DISABLE; if (retransmission){ _can.handle.Init.AutoRetransmission = ENABLE; } else { _can.handle.Init.AutoRetransmission = DISABLE; } - _can.handle.Init.ReceiveFifoLocked = DISABLE; - _can.handle.Init.TransmitFifoPriority = ENABLE; filtersInitialized = false; From 53d09a09300b54014ef7d87e862a777317c024bc Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:21:46 +0100 Subject: [PATCH 27/51] add proper support for all filter types. Legacy function still has old broken behaviour. --- STM32_CAN.cpp | 119 ++++++++++++++++++++++++++++++++++++++++---------- STM32_CAN.h | 6 +++ 2 files changed, 102 insertions(+), 23 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 28b56c8..070d698 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -533,7 +533,95 @@ bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) return ret; } +static uint32_t format32bitFilter(uint32_t id, IDE std_ext, bool mask) +{ + uint32_t id_reg; + if (std_ext == AUTO) + { + std_ext = (id <= 0x7FF) ? STD : EXT; + } + if (std_ext == STD) + { + id <<= 18; + } + id_reg = id << 3; + //set IDE bit + if (mask || std_ext == EXT) + { + id_reg |= (1 << 2); + } + return id_reg; +} + +static uint32_t format16bitFilter(uint32_t id, IDE std_ext, bool mask) +{ + uint32_t id_reg; + if (std_ext == AUTO) + { + std_ext = (id <= 0x7FF) ? STD : EXT; + } + if (std_ext == STD) + { + id <<= 18; + } + //set STID + id_reg = (id >> (18-5)) & 0xFFE0UL; + //set EXTI [17:15] + id_reg |= (id >> (18-3)) & 0x003UL; + //set IDE bit + if (mask || std_ext == EXT) + { + id_reg |= (1 << 3); + } + return id_reg; +} + +bool STM32_CAN::setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, uint32_t fifo, bool enabled) +{ + uint32_t id_reg = format32bitFilter(id, std_ext, false); + uint32_t mask_reg = format32bitFilter(mask, std_ext, true); + return setFilterRaw(bank_num, id_reg, mask_reg, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_32BIT, fifo, enabled); +} + +bool STM32_CAN::setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, uint32_t fifo, bool enabled) +{ + uint32_t id = format32bitFilter(id1, std_ext1, false); + uint32_t mask = format32bitFilter(id2, std_ext2, false); + return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_32BIT, fifo, enabled); +} + +bool STM32_CAN::setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, uint32_t fifo, bool enabled) +{ + uint32_t id = (uint32_t)format16bitFilter(id1, std_ext1, false) | (((uint32_t)format16bitFilter(mask1, std_ext1, true)) << 16); + uint32_t mask = (uint32_t)format16bitFilter(id2, std_ext2, false) | (((uint32_t)format16bitFilter(mask2, std_ext2, true)) << 16); + return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_16BIT, fifo, enabled); +} + +bool STM32_CAN::setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, uint32_t fifo, bool enabled) +{ + uint32_t id = (uint32_t)format16bitFilter(id1, std_ext1, false) | (((uint32_t)format16bitFilter(id2, std_ext2, false)) << 16); + uint32_t mask = (uint32_t)format16bitFilter(id3, std_ext3, false) | (((uint32_t)format16bitFilter(id4, std_ext4, false)) << 16); + return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_16BIT, fifo, enabled); +} + bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE std_ext, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo) +{ + /** NOTE: legacy, this function only implemented 32 bit scaling mode in mask mode, other modes will be broken*/ + if(filter_scale != CAN_FILTERSCALE_32BIT) + { + core_debug("WARNING: legacy function only implements 32 bit filter scale. Filter will be broken!\n"); + } + if(filter_scale != CAN_FILTERMODE_IDMASK) + { + core_debug("WARNING: legacy function only implements ID Mask mode. Filter will be broken!\n"); + } + /** re-implement broken implementation for legacy behaviour */ + uint32_t id_reg = format32bitFilter(filter_id, std_ext, false); + uint32_t mask_reg = format32bitFilter(mask, std_ext, true); + return setFilterRaw(bank_num, id_reg, mask_reg, filter_mode, filter_scale, fifo); +} + +bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo, bool enabled) { CAN_FilterTypeDef sFilterConfig; if(!_can.handle.Instance) return false; @@ -548,26 +636,12 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I } #endif sFilterConfig.FilterFIFOAssignment = fifo; - sFilterConfig.FilterActivation = ENABLE; + sFilterConfig.FilterActivation = enabled ? ENABLE : DISABLE; - if (std_ext == STD || (std_ext == AUTO && filter_id <= 0x7FF)) - { - // Standard ID can be only 11 bits long - sFilterConfig.FilterIdHigh = (uint16_t) (filter_id << 5); - sFilterConfig.FilterIdLow = 0; - sFilterConfig.FilterMaskIdHigh = (uint16_t) (mask << 5); - sFilterConfig.FilterMaskIdLow = CAN_ID_EXT; - } - else - { - // Extended ID - sFilterConfig.FilterIdLow = (uint16_t) (filter_id << 3); - sFilterConfig.FilterIdLow |= CAN_ID_EXT; - sFilterConfig.FilterIdHigh = (uint16_t) (filter_id >> 13); - sFilterConfig.FilterMaskIdLow = (uint16_t) (mask << 3); - sFilterConfig.FilterMaskIdLow |= CAN_ID_EXT; - sFilterConfig.FilterMaskIdHigh = (uint16_t) (mask >> 13); - } + sFilterConfig.FilterIdLow = id & 0xFFFFUL; + sFilterConfig.FilterIdHigh = id >> 16; + sFilterConfig.FilterMaskIdLow = mask & 0xFFFFUL; + sFilterConfig.FilterMaskIdHigh = mask >> 16; #ifdef CAN2 sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; @@ -633,19 +707,18 @@ void STM32_CAN::setMBFilter(CAN_FLTEN input) bool STM32_CAN::setMBFilterProcessing(CAN_BANK bank_num, uint32_t filter_id, uint32_t mask, IDE std_ext) { // just convert the MB number enum to bank number. - return setFilter(uint8_t(bank_num), filter_id, mask, std_ext); + return setFilterSingleMask(uint8_t(bank_num), filter_id, mask, std_ext); } bool STM32_CAN::setMBFilter(CAN_BANK bank_num, uint32_t id1, IDE std_ext) { // by setting the mask to 0x1FFFFFFF we only filter the ID set as Filter ID. - return setFilter(uint8_t(bank_num), id1, 0x1FFFFFFF, std_ext); + return setFilterSingleMask(uint8_t(bank_num), id1, 0x1FFFFFFF, std_ext); } bool STM32_CAN::setMBFilter(CAN_BANK bank_num, uint32_t id1, uint32_t id2, IDE std_ext) { - // if we set the filter mode as IDLIST, the mask becomes filter ID too. So we can filter two totally independent IDs in same bank. - return setFilter(uint8_t(bank_num), id1, id2, AUTO, CAN_FILTERMODE_IDLIST, std_ext); + return setFilterDualID(uint8_t(bank_num), id1, id2, std_ext, std_ext); } // TBD, do this using "setFilter" -function diff --git a/STM32_CAN.h b/STM32_CAN.h index b78e101..73e0785 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -262,6 +262,12 @@ class STM32_CAN { bool write(CAN_message_t &CAN_tx_msg, bool sendMB = false); bool read(CAN_message_t &CAN_rx_msg); // Manually set STM32 filter bank parameters + bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); + bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); + bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); + bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); + bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); + // Legacy, broken! Only works correctly for 32 bit mask mode bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO, uint32_t filter_mode = CAN_FILTERMODE_IDMASK, uint32_t filter_scale = CAN_FILTERSCALE_32BIT, uint32_t fifo = CAN_FILTER_FIFO0); // Teensy FlexCAN style "set filter" -functions bool setMBFilterProcessing(CAN_BANK bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO); From f44452a23db10a67ba7c57ff6e748d1d409ac0d9 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:32:48 +0100 Subject: [PATCH 28/51] change FIFO target to action in prep for FDCAN --- STM32_CAN.cpp | 33 +++++++++++++++++++++------------ STM32_CAN.h | 14 +++++++++----- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 070d698..29ea93c 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -576,32 +576,32 @@ static uint32_t format16bitFilter(uint32_t id, IDE std_ext, bool mask) return id_reg; } -bool STM32_CAN::setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, uint32_t fifo, bool enabled) +bool STM32_CAN::setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action, bool enabled) { uint32_t id_reg = format32bitFilter(id, std_ext, false); uint32_t mask_reg = format32bitFilter(mask, std_ext, true); - return setFilterRaw(bank_num, id_reg, mask_reg, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_32BIT, fifo, enabled); + return setFilterRaw(bank_num, id_reg, mask_reg, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_32BIT, action, enabled); } -bool STM32_CAN::setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, uint32_t fifo, bool enabled) +bool STM32_CAN::setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action, bool enabled) { uint32_t id = format32bitFilter(id1, std_ext1, false); uint32_t mask = format32bitFilter(id2, std_ext2, false); - return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_32BIT, fifo, enabled); + return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_32BIT, action, enabled); } -bool STM32_CAN::setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, uint32_t fifo, bool enabled) +bool STM32_CAN::setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action, bool enabled) { uint32_t id = (uint32_t)format16bitFilter(id1, std_ext1, false) | (((uint32_t)format16bitFilter(mask1, std_ext1, true)) << 16); uint32_t mask = (uint32_t)format16bitFilter(id2, std_ext2, false) | (((uint32_t)format16bitFilter(mask2, std_ext2, true)) << 16); - return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_16BIT, fifo, enabled); + return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_16BIT, action, enabled); } -bool STM32_CAN::setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, uint32_t fifo, bool enabled) +bool STM32_CAN::setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FilterAction action, bool enabled) { uint32_t id = (uint32_t)format16bitFilter(id1, std_ext1, false) | (((uint32_t)format16bitFilter(id2, std_ext2, false)) << 16); uint32_t mask = (uint32_t)format16bitFilter(id3, std_ext3, false) | (((uint32_t)format16bitFilter(id4, std_ext4, false)) << 16); - return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_16BIT, fifo, enabled); + return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_16BIT, action, enabled); } bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE std_ext, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo) @@ -618,10 +618,11 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I /** re-implement broken implementation for legacy behaviour */ uint32_t id_reg = format32bitFilter(filter_id, std_ext, false); uint32_t mask_reg = format32bitFilter(mask, std_ext, true); - return setFilterRaw(bank_num, id_reg, mask_reg, filter_mode, filter_scale, fifo); + FilterAction action = (fifo==CAN_FILTER_FIFO0) ? FilterAction::STORE_FIFO0 : FilterAction::STORE_FIFO1; + return setFilterRaw(bank_num, id_reg, mask_reg, filter_mode, filter_scale, action); } -bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo, bool enabled) +bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action, bool enabled) { CAN_FilterTypeDef sFilterConfig; if(!_can.handle.Instance) return false; @@ -630,12 +631,20 @@ bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint3 sFilterConfig.FilterMode = filter_mode; sFilterConfig.FilterScale = filter_scale; #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) - if(fifo == CAN_RX_FIFO0) + if(action == FilterAction::STORE_FIFO0) { core_debug("WARNING: RX0 IRQ is blocked by USB Driver. Events only handled by polling and RX1 events!\n"); } #endif - sFilterConfig.FilterFIFOAssignment = fifo; + switch (action) + { + case FilterAction::STORE_FIFO0: + sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; + break; + case FilterAction::STORE_FIFO1: + sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO1; + break; + } sFilterConfig.FilterActivation = enabled ? ENABLE : DISABLE; sFilterConfig.FilterIdLow = id & 0xFFFFUL; diff --git a/STM32_CAN.h b/STM32_CAN.h index 73e0785..035c480 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -262,11 +262,15 @@ class STM32_CAN { bool write(CAN_message_t &CAN_tx_msg, bool sendMB = false); bool read(CAN_message_t &CAN_rx_msg); // Manually set STM32 filter bank parameters - bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); - bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); - bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); - bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); - bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo = CAN_FILTER_FIFO0, bool enabled = true); + enum FilterAction { + STORE_FIFO0, + STORE_FIFO1 + }; + bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = STORE_FIFO0, bool enabled = true); + bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action = STORE_FIFO0, bool enabled = true); + bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action = STORE_FIFO0, bool enabled = true); + bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FilterAction action = STORE_FIFO0, bool enabled = true); + bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action = STORE_FIFO0, bool enabled = true); // Legacy, broken! Only works correctly for 32 bit mask mode bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO, uint32_t filter_mode = CAN_FILTERMODE_IDMASK, uint32_t filter_scale = CAN_FILTERSCALE_32BIT, uint32_t fifo = CAN_FILTER_FIFO0); // Teensy FlexCAN style "set filter" -functions From 473b58d2ed52cb1694cec3022050a1bf10a25e63 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:58:57 +0100 Subject: [PATCH 29/51] add setFilter variant that sets filter state without changing filter rules --- STM32_CAN.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ STM32_CAN.h | 2 ++ 2 files changed, 46 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 29ea93c..a485e3b 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -576,6 +576,50 @@ static uint32_t format16bitFilter(uint32_t id, IDE std_ext, bool mask) return id_reg; } +bool STM32_CAN::setFilter(uint8_t bank_num, bool enabled, FilterAction action) +{ + CAN_TypeDef *can_ip = _can.handle.Instance; + /** CAN2 shares filter banks with CAN1 + * Driver allocates equal amount to each + * Filter Banks located at CAN1 base address + */ + #ifdef CAN2 + if(_can.handle.Instance == CAN2) + { + can_ip = CAN1; + bank_num += STM32_CAN_CAN2_FILTER_OFFSET; + } + #endif + + uint32_t filternbrbitpos = (uint32_t)1 << (bank_num & 0x1FU); + + /* Initialisation mode for the filter */ + SET_BIT(can_ip->FMR, CAN_FMR_FINIT); + + /* Filter Deactivation */ + CLEAR_BIT(can_ip->FA1R, filternbrbitpos); + + /* Filter FIFO assignment */ + switch (action) + { + case FilterAction::STORE_FIFO0: + CLEAR_BIT(can_ip->FFA1R, filternbrbitpos); + break; + case FilterAction::STORE_FIFO1: + SET_BIT(can_ip->FFA1R, filternbrbitpos); + break; + } + + /* Filter activation */ + if(enabled) + { + SET_BIT(can_ip->FA1R, filternbrbitpos); + } + /* Leave the initialisation mode for the filter */ + CLEAR_BIT(can_ip->FMR, CAN_FMR_FINIT); + return true; +} + bool STM32_CAN::setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action, bool enabled) { uint32_t id_reg = format32bitFilter(id, std_ext, false); diff --git a/STM32_CAN.h b/STM32_CAN.h index 035c480..5885109 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -266,6 +266,8 @@ class STM32_CAN { STORE_FIFO0, STORE_FIFO1 }; + /** set filter state and action, keeps filter rules intact */ + bool setFilter(uint8_t bank_num, bool state, FilterAction action = STORE_FIFO0); bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = STORE_FIFO0, bool enabled = true); bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action = STORE_FIFO0, bool enabled = true); bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action = STORE_FIFO0, bool enabled = true); From ea1900b3b50a81dc01408654b5320cb561bdc955 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:01:33 +0100 Subject: [PATCH 30/51] fix: add CAN2 filter index offset --- STM32_CAN.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index a485e3b..8a902ff 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -698,6 +698,10 @@ bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint3 #ifdef CAN2 sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; + if(_can.handle.Instance == CAN2) + { + sFilterConfig.FilterBank += STM32_CAN_CAN2_FILTER_OFFSET; + } #endif // Enable filter if (HAL_CAN_ConfigFilter( &_can.handle, &sFilterConfig ) != HAL_OK) From a2d634fa92d1f05b85369e61694f3e9d8cc46add Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:21:37 +0100 Subject: [PATCH 31/51] fix: properly only set state without clobbering other filter settings in setMBFilter(bank_num) and setMBFilter(bank_num, input) --- STM32_CAN.cpp | 40 +++------------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 8a902ff..229b88c 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -716,48 +716,14 @@ bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint3 void STM32_CAN::setMBFilter(CAN_BANK bank_num, CAN_FLTEN input) { - CAN_FilterTypeDef sFilterConfig; - if(!_can.handle.Instance) return; - - sFilterConfig.FilterBank = uint8_t(bank_num); - #ifdef CAN2 - sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; - if (_can.handle.Instance == CAN2) - { - sFilterConfig.FilterBank += STM32_CAN_CAN2_FILTER_OFFSET; - } - #endif - if (input == ACCEPT_ALL) { sFilterConfig.FilterActivation = ENABLE; } - else { sFilterConfig.FilterActivation = DISABLE; } - - HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); + setFilter(bank_num, (input == ACCEPT_ALL)); } void STM32_CAN::setMBFilter(CAN_FLTEN input) { - CAN_FilterTypeDef sFilterConfig; - uint8_t max_bank_num = STM32_CAN_SINGLE_CAN_FILTER_COUNT-1; - uint8_t min_bank_num = 0; - if(!_can.handle.Instance) return; - - #ifdef CAN2 - sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; - if (_can.handle.Instance == CAN1) - { - max_bank_num = max(STM32_CAN_CAN2_FILTER_OFFSET-1, 0); - } - else if (_can.handle.Instance == CAN2) - { - min_bank_num = STM32_CAN_CAN2_FILTER_OFFSET; - max_bank_num = STM32_CAN_DUAL_CAN_FILTER_COUNT-1; - } - #endif - for (uint8_t bank_num = min_bank_num ; bank_num <= max_bank_num ; bank_num++) + for (uint8_t bank_num = 0 ; bank_num < STM32_CAN_SINGLE_CAN_FILTER_COUNT ; bank_num++) { - sFilterConfig.FilterBank = bank_num; - if (input == ACCEPT_ALL) { sFilterConfig.FilterActivation = ENABLE; } - else { sFilterConfig.FilterActivation = DISABLE; } - HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); + setFilter(bank_num, (input == ACCEPT_ALL)); } } From 221a84c586e3beb82ff4f16e6c93190c8847d2d6 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:52:59 +0100 Subject: [PATCH 32/51] add macros to select default FIFO based on platform limitations --- STM32_CAN.cpp | 6 +----- STM32_CAN.h | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 229b88c..0504c35 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -760,11 +760,7 @@ void STM32_CAN::initializeFilters() sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; sFilterConfig.FilterMaskIdLow = 0x0000; - #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) - sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO1; - #else - sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; - #endif + sFilterConfig.FilterFIFOAssignment = CAN_FILTER_DEFAULT_FIFO; sFilterConfig.FilterActivation = ENABLE; #ifdef CAN2 // Filter banks from 14 to 27 are for Can2, so first for Can2 is bank 14. This is not relevant for devices with only one CAN diff --git a/STM32_CAN.h b/STM32_CAN.h index 5885109..09be9ef 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -135,6 +135,11 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #elif defined(USBCON) && defined(STM32_CAN_USB_WORKAROUND_POLLING) #warning "CAN IRQ Handler is used by USBDevice driver, call STM32_CAN_Poll_IRQ_Handler() frequently to handle CAN events." extern "C" void STM32_CAN_Poll_IRQ_Handler(void); +#define CAN_FILTER_DEFAULT_FIFO CAN_FILTER_FIFO1 +#define CAN_FILTER_DEFAULT_ACTION STORE_FIFO1 +#else +#define CAN_FILTER_DEFAULT_FIFO CAN_FILTER_FIFO0 +#define CAN_FILTER_DEFAULT_ACTION STORE_FIFO0 #endif @@ -267,14 +272,14 @@ class STM32_CAN { STORE_FIFO1 }; /** set filter state and action, keeps filter rules intact */ - bool setFilter(uint8_t bank_num, bool state, FilterAction action = STORE_FIFO0); - bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = STORE_FIFO0, bool enabled = true); - bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action = STORE_FIFO0, bool enabled = true); - bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action = STORE_FIFO0, bool enabled = true); - bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FilterAction action = STORE_FIFO0, bool enabled = true); - bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action = STORE_FIFO0, bool enabled = true); + bool setFilter(uint8_t bank_num, bool state, FilterAction action = CAN_FILTER_DEFAULT_ACTION); + bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); // Legacy, broken! Only works correctly for 32 bit mask mode - bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO, uint32_t filter_mode = CAN_FILTERMODE_IDMASK, uint32_t filter_scale = CAN_FILTERSCALE_32BIT, uint32_t fifo = CAN_FILTER_FIFO0); + bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO, uint32_t filter_mode = CAN_FILTERMODE_IDMASK, uint32_t filter_scale = CAN_FILTERSCALE_32BIT, uint32_t fifo = CAN_FILTER_DEFAULT_FIFO); // Teensy FlexCAN style "set filter" -functions bool setMBFilterProcessing(CAN_BANK bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO); void setMBFilter(CAN_FLTEN input); /* enable/disable traffic for all MBs (for individual masking) */ From 972ca0e4281ca3a09b48e82d9097b1f757574e72 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:01:32 +0100 Subject: [PATCH 33/51] use custom filter functions for filter initialization --- STM32_CAN.cpp | 46 +++++----------------------------------------- 1 file changed, 5 insertions(+), 41 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 0504c35..821299f 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -744,55 +744,19 @@ bool STM32_CAN::setMBFilter(CAN_BANK bank_num, uint32_t id1, uint32_t id2, IDE s return setFilterDualID(uint8_t(bank_num), id1, id2, std_ext, std_ext); } -// TBD, do this using "setFilter" -function void STM32_CAN::initializeFilters() { - CAN_FilterTypeDef sFilterConfig; - if(!_can.handle.Instance) return; if(filtersInitialized) return; filtersInitialized = true; - // We set first bank to accept all RX messages - sFilterConfig.FilterBank = 0; - sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; - sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; - sFilterConfig.FilterIdHigh = 0x0000; - sFilterConfig.FilterIdLow = 0x0000; - sFilterConfig.FilterMaskIdHigh = 0x0000; - sFilterConfig.FilterMaskIdLow = 0x0000; - sFilterConfig.FilterFIFOAssignment = CAN_FILTER_DEFAULT_FIFO; - sFilterConfig.FilterActivation = ENABLE; - #ifdef CAN2 - // Filter banks from 14 to 27 are for Can2, so first for Can2 is bank 14. This is not relevant for devices with only one CAN - sFilterConfig.SlaveStartFilterBank = STM32_CAN_CAN2_FILTER_OFFSET; - if (_can.handle.Instance == CAN2) - { - sFilterConfig.FilterBank = STM32_CAN_CAN2_FILTER_OFFSET; - } - #endif - - HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); + /** Let everything in by default */ + setFilterRaw(0, 0UL, 0UL, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_32BIT, + FilterAction::CAN_FILTER_DEFAULT_ACTION, true); /** turn off all other filters that might sill be setup from before */ - sFilterConfig.FilterActivation = DISABLE; - uint8_t filter_count = STM32_CAN_SINGLE_CAN_FILTER_COUNT; - uint8_t filter_start = 1; - #ifdef CAN2 - /** In dual CAN devices filter banks are shared and setup to equal amounts */ - if (_can.handle.Instance == CAN1) - { - filter_count = STM32_CAN_CAN2_FILTER_OFFSET; - } - else if (_can.handle.Instance == CAN2) - { - filter_start += STM32_CAN_CAN2_FILTER_OFFSET; - filter_count = STM32_CAN_DUAL_CAN_FILTER_COUNT; - } - #endif - for (uint8_t bank_num = filter_start ; bank_num < filter_count ; bank_num++) + for (uint8_t bank_num = 1 ; bank_num < STM32_CAN_SINGLE_CAN_FILTER_COUNT ; bank_num++) { - sFilterConfig.FilterBank = bank_num; - HAL_CAN_ConfigFilter(&_can.handle, &sFilterConfig); + setFilter(bank_num, false); } } From 6e07d48332d336b9ed50e85bc0a3adb6c19b737a Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Thu, 2 Jan 2025 19:10:09 +0100 Subject: [PATCH 34/51] read all pending messages. Multiple message events can happen before IRQ handler is called --- STM32_CAN.cpp | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 821299f..a4476a7 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -1201,30 +1201,34 @@ extern "C" void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *CanHandle) // move the message from RX FIFO0 to RX ringbuffer #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) - if (HAL_CAN_GetRxMessage( CanHandle, CAN_RX_FIFO1, &RxHeader, rxmsg.buf ) == HAL_OK) + const uint32_t fifo = CAN_RX_FIFO1; #else - if (HAL_CAN_GetRxMessage( CanHandle, CAN_RX_FIFO0, &RxHeader, rxmsg.buf ) == HAL_OK) + const uint32_t fifo = CAN_RX_FIFO0; #endif + do { - if ( RxHeader.IDE == CAN_ID_STD ) + if (HAL_CAN_GetRxMessage( CanHandle, fifo, &RxHeader, rxmsg.buf ) == HAL_OK) { - rxmsg.id = RxHeader.StdId; - rxmsg.flags.extended = 0; - } - else - { - rxmsg.id = RxHeader.ExtId; - rxmsg.flags.extended = 1; - } + if ( RxHeader.IDE == CAN_ID_STD ) + { + rxmsg.id = RxHeader.StdId; + rxmsg.flags.extended = 0; + } + else + { + rxmsg.id = RxHeader.ExtId; + rxmsg.flags.extended = 1; + } - rxmsg.flags.remote = RxHeader.RTR; - rxmsg.mb = RxHeader.FilterMatchIndex; - rxmsg.timestamp = RxHeader.Timestamp; - rxmsg.len = RxHeader.DLC; + rxmsg.flags.remote = RxHeader.RTR; + rxmsg.mb = RxHeader.FilterMatchIndex; + rxmsg.timestamp = RxHeader.Timestamp; + rxmsg.len = RxHeader.DLC; - rxmsg.bus = canObj->bus; - _can->addToRingBuffer(_can->rxRing, rxmsg); - } + rxmsg.bus = canObj->bus; + _can->addToRingBuffer(_can->rxRing, rxmsg); + } + } while(HAL_CAN_GetRxFifoFillLevel(CanHandle, fifo)); //Enable_Interrupts(state); } From 6b1f21f786a1a89dcac54c608e7bba9faea8c418 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 12:58:28 +0100 Subject: [PATCH 35/51] rename getAPB1Clock() to more generic getCanPeripheralClock() --- STM32_CAN.cpp | 6 +++--- STM32_CAN.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index a4476a7..701dfbd 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -1006,7 +1006,7 @@ bool STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) uint8_t bs2; uint16_t prescaler; - const uint32_t frequency = getAPB1Clock(); + const uint32_t frequency = getCanPeripheralClock(); if (frequency == 48000000) { if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_48M)) return true; @@ -1049,9 +1049,9 @@ bool STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) return false; } -uint32_t STM32_CAN::getAPB1Clock() +uint32_t STM32_CAN::getCanPeripheralClock() { - //APB1 is PCLK1 + //All bxCAN get clocked by APB1 / PCLK1 return HAL_RCC_GetPCLK1Freq(); } diff --git a/STM32_CAN.h b/STM32_CAN.h index 09be9ef..bb9e12f 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -341,7 +341,7 @@ class STM32_CAN { bool calculateBaudrate(CAN_HandleTypeDef *CanHandle, int Baudrate); void setBaudRateValues(CAN_HandleTypeDef *CanHandle, uint16_t prescaler, uint8_t timeseg1, uint8_t timeseg2, uint8_t sjw); - uint32_t getAPB1Clock(void); + uint32_t getCanPeripheralClock(void); volatile CAN_message_t *rx_buffer = nullptr; volatile CAN_message_t *tx_buffer = nullptr; From 60a9e2dc64d3ee7f1020cd33b0dd071de4e84e32 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 13:06:37 +0100 Subject: [PATCH 36/51] remove CanHandle arg from baudrate calculation functions, use member variable --- STM32_CAN.cpp | 26 +++++++++++++------------- STM32_CAN.h | 8 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 701dfbd..dcdce3a 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -416,7 +416,7 @@ void STM32_CAN::setBaudRate(uint32_t baud) } // Calculate and set baudrate - if(!calculateBaudrate( &_can.handle, baud )) + if(!calculateBaudrate( baud )) { return; } @@ -858,8 +858,8 @@ uint32_t STM32_CAN::ringBufferCount(RingbufferTypeDef &ring) return((uint32_t)entries); } -void STM32_CAN::setBaudRateValues(CAN_HandleTypeDef *CanHandle, uint16_t prescaler, uint8_t timeseg1, - uint8_t timeseg2, uint8_t sjw) +void STM32_CAN::setBaudRateValues(uint16_t prescaler, uint8_t timeseg1, + uint8_t timeseg2, uint8_t sjw) { uint32_t _SyncJumpWidth = 0; uint32_t _TimeSeg1 = 0; @@ -979,28 +979,28 @@ void STM32_CAN::setBaudRateValues(CAN_HandleTypeDef *CanHandle, uint16_t prescal } _Prescaler = prescaler; - CanHandle->Init.SyncJumpWidth = _SyncJumpWidth; - CanHandle->Init.TimeSeg1 = _TimeSeg1; - CanHandle->Init.TimeSeg2 = _TimeSeg2; - CanHandle->Init.Prescaler = _Prescaler; + _can.handle.Init.SyncJumpWidth = _SyncJumpWidth; + _can.handle.Init.TimeSeg1 = _TimeSeg1; + _can.handle.Init.TimeSeg2 = _TimeSeg2; + _can.handle.Init.Prescaler = _Prescaler; } template -bool STM32_CAN::lookupBaudrate(CAN_HandleTypeDef *CanHandle, int baud, const T(&table)[N]) { +bool STM32_CAN::lookupBaudrate(int baud, const T(&table)[N]) { for (size_t i = 0; i < N; i++) { if (baud != (int)table[i].baudrate) { continue; } /* for the best chance at interoperability, use the widest SJW possible */ - setBaudRateValues(CanHandle, table[i].prescaler, table[i].timeseg1, table[i].timeseg2, 4); + setBaudRateValues(table[i].prescaler, table[i].timeseg1, table[i].timeseg2, 4); return true; } return false; } -bool STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) +bool STM32_CAN::calculateBaudrate(int baud) { uint8_t bs1; uint8_t bs2; @@ -1009,9 +1009,9 @@ bool STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) const uint32_t frequency = getCanPeripheralClock(); if (frequency == 48000000) { - if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_48M)) return true; + if (lookupBaudrate(baud, BAUD_RATE_TABLE_48M)) return true; } else if (frequency == 45000000) { - if (lookupBaudrate(CanHandle, baud, BAUD_RATE_TABLE_45M)) return true; + if (lookupBaudrate(baud, BAUD_RATE_TABLE_45M)) return true; } /* this loop seeks a precise baudrate match, with the sample point positioned @@ -1039,7 +1039,7 @@ bool STM32_CAN::calculateBaudrate(CAN_HandleTypeDef *CanHandle, int baud) if (baud_cur != baud) continue; - setBaudRateValues(CanHandle, prescaler, bs1, bs2, 4); + setBaudRateValues(prescaler, bs1, bs2, 4); return true; } } diff --git a/STM32_CAN.h b/STM32_CAN.h index bb9e12f..ca1ad78 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -337,10 +337,10 @@ class STM32_CAN { uint32_t ringBufferCount(RingbufferTypeDef &ring); template - bool lookupBaudrate(CAN_HandleTypeDef *CanHandle, int Baudrate, const T(&table)[N]); - bool calculateBaudrate(CAN_HandleTypeDef *CanHandle, int Baudrate); - void setBaudRateValues(CAN_HandleTypeDef *CanHandle, uint16_t prescaler, uint8_t timeseg1, - uint8_t timeseg2, uint8_t sjw); + bool lookupBaudrate(int Baudrate, const T(&table)[N]); + bool calculateBaudrate(int Baudrate); + void setBaudRateValues(uint16_t prescaler, uint8_t timeseg1, + uint8_t timeseg2, uint8_t sjw); uint32_t getCanPeripheralClock(void); volatile CAN_message_t *rx_buffer = nullptr; From 50edb2feff88f38eda9be2a8bfc07f27eba04d36 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 13:59:43 +0100 Subject: [PATCH 37/51] formatting, group functions according to operational state --- STM32_CAN.cpp | 56 +++++++++++++++++++++++++++++++++++---------------- STM32_CAN.h | 56 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index dcdce3a..25abd8c 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -254,6 +254,11 @@ CAN_TypeDef * STM32_CAN::getPeripheral() return canPort_rx; } +/**------------------------------------------------------------- + * setup functions + * no effect after begin() + * ------------------------------------------------------------- + */ void STM32_CAN::setIRQPriority(uint32_t preemptPriority, uint32_t subPriority) { //NOTE: limiting the IRQ prio, but not accounting for group setting @@ -261,6 +266,28 @@ void STM32_CAN::setIRQPriority(uint32_t preemptPriority, uint32_t subPriority) this->subPriority = min(subPriority, MAX_IRQ_PRIO_VALUE); } +void STM32_CAN::setMode(Mode mode) +{ + _can.handle.Init.Mode = mode; +} + +void STM32_CAN::enableLoopBack( bool yes ) { + setMode(yes ? Mode::LOOPBACK : Mode::NORMAL); +} + +void STM32_CAN::enableSilentMode( bool yes ) { + setMode(yes ? Mode::SILENT : Mode::NORMAL); +} + +void STM32_CAN::enableSilentLoopBack( bool yes ) { + setMode(yes ? Mode::SILENT_LOOPBACK : Mode::NORMAL); +} + +/**------------------------------------------------------------- + * lifecycle functions + * setBaudRate may be called before or after begin + * ------------------------------------------------------------- + */ // Init and start CAN void STM32_CAN::begin( bool retransmission ) { @@ -458,6 +485,12 @@ void STM32_CAN::stop() HAL_CAN_DeInit( &_can.handle ); } + +/**------------------------------------------------------------- + * post begin(), setup filters, data transfer + * ------------------------------------------------------------- + */ + bool STM32_CAN::write(CAN_message_t &CAN_tx_msg, bool sendMB) { bool ret = true; @@ -714,6 +747,12 @@ bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint3 } } + +/**------------------------------------------------------------- + * Teensy FlexCAN compatibility functions + * ------------------------------------------------------------- + */ + void STM32_CAN::setMBFilter(CAN_BANK bank_num, CAN_FLTEN input) { setFilter(bank_num, (input == ACCEPT_ALL)); @@ -1123,23 +1162,6 @@ void STM32_CAN::disableMBInterrupts() #endif } -void STM32_CAN::setMode(Mode mode) -{ - _can.handle.Init.Mode = mode; -} - -void STM32_CAN::enableLoopBack( bool yes ) { - setMode(yes ? Mode::LOOPBACK : Mode::NORMAL); -} - -void STM32_CAN::enableSilentMode( bool yes ) { - setMode(yes ? Mode::SILENT : Mode::NORMAL); -} - -void STM32_CAN::enableSilentLoopBack( bool yes ) { - setMode(yes ? Mode::SILENT_LOOPBACK : Mode::NORMAL); -} - void STM32_CAN::enableFIFO(bool status) { //Nothing to do here. The FIFO is on by default. This is just to work with code made for Teensy FlexCan. diff --git a/STM32_CAN.h b/STM32_CAN.h index ca1ad78..e1f9b70 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -253,24 +253,55 @@ typedef struct { class STM32_CAN { public: + enum Mode { + NORMAL = CAN_MODE_NORMAL, + SILENT = CAN_MODE_SILENT, + SILENT_LOOPBACK = CAN_MODE_SILENT_LOOPBACK, + LOOPBACK = CAN_MODE_LOOPBACK + }; + + enum FilterAction { + STORE_FIFO0, + STORE_FIFO1, + }; + // Default buffer sizes are set to 16. But this can be changed by using constructor in main code. STM32_CAN(uint32_t rx, uint32_t tx = PNUM_NOT_DEFINED, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); STM32_CAN(PinName rx, PinName tx = NC, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); STM32_CAN(CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); //legacy for compatibility STM32_CAN(CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); +/**------------------------------------------------------------- + * setup functions + * no effect after begin() + * ------------------------------------------------------------- + */ void setIRQPriority(uint32_t preemptPriority, uint32_t subPriority); + + void setMode(Mode mode); + void enableLoopBack(bool yes = 1); + void enableSilentMode(bool yes = 1); + void enableSilentLoopBack(bool yes = 1); + +/**------------------------------------------------------------- + * lifecycle functions + * setBaudRate may be called before or after begin + * ------------------------------------------------------------- + */ // Begin. By default the automatic retransmission is enabled. If it causes problems, use begin(false) to disable it. void begin(bool retransmission = false); void end(void); + void setBaudRate(uint32_t baud); + +/**------------------------------------------------------------- + * post begin(), setup filters, data transfer + * ------------------------------------------------------------- + */ bool write(CAN_message_t &CAN_tx_msg, bool sendMB = false); bool read(CAN_message_t &CAN_rx_msg); + // Manually set STM32 filter bank parameters - enum FilterAction { - STORE_FIFO0, - STORE_FIFO1 - }; /** set filter state and action, keeps filter rules intact */ bool setFilter(uint8_t bank_num, bool state, FilterAction action = CAN_FILTER_DEFAULT_ACTION); bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); @@ -280,24 +311,17 @@ class STM32_CAN { bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); // Legacy, broken! Only works correctly for 32 bit mask mode bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO, uint32_t filter_mode = CAN_FILTERMODE_IDMASK, uint32_t filter_scale = CAN_FILTERSCALE_32BIT, uint32_t fifo = CAN_FILTER_DEFAULT_FIFO); - // Teensy FlexCAN style "set filter" -functions + +/**------------------------------------------------------------- + * Teensy FlexCAN compatibility functions + * ------------------------------------------------------------- + */ bool setMBFilterProcessing(CAN_BANK bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO); void setMBFilter(CAN_FLTEN input); /* enable/disable traffic for all MBs (for individual masking) */ void setMBFilter(CAN_BANK bank_num, CAN_FLTEN input); /* set specific MB to accept/deny traffic */ bool setMBFilter(CAN_BANK bank_num, uint32_t id1, IDE = AUTO); /* input 1 ID to be filtered */ bool setMBFilter(CAN_BANK bank_num, uint32_t id1, uint32_t id2, IDE = AUTO); /* input 2 ID's to be filtered */ - enum Mode { - NORMAL = CAN_MODE_NORMAL, - LOOPBACK = CAN_MODE_LOOPBACK, - SILENT = CAN_MODE_SILENT, - SILENT_LOOPBACK = CAN_MODE_SILENT_LOOPBACK - }; - - void setMode(Mode mode); - void enableLoopBack(bool yes = 1); - void enableSilentMode(bool yes = 1); - void enableSilentLoopBack(bool yes = 1); void enableFIFO(bool status = 1); void enableMBInterrupts(); void disableMBInterrupts(); From c13ee3e4010e09845fc3946f0c7c39d025dac11b Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 14:36:07 +0100 Subject: [PATCH 38/51] change STM32 style filter function return value to true on success. Keep FlexCan compat value as false for success --- STM32_CAN.cpp | 17 +++++------------ STM32_CAN.h | 10 ++++++++-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 25abd8c..768f6a2 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -696,7 +696,7 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I uint32_t id_reg = format32bitFilter(filter_id, std_ext, false); uint32_t mask_reg = format32bitFilter(mask, std_ext, true); FilterAction action = (fifo==CAN_FILTER_FIFO0) ? FilterAction::STORE_FIFO0 : FilterAction::STORE_FIFO1; - return setFilterRaw(bank_num, id_reg, mask_reg, filter_mode, filter_scale, action); + return !setFilterRaw(bank_num, id_reg, mask_reg, filter_mode, filter_scale, action); } bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action, bool enabled) @@ -737,14 +737,7 @@ bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint3 } #endif // Enable filter - if (HAL_CAN_ConfigFilter( &_can.handle, &sFilterConfig ) != HAL_OK) - { - return 1; - } - else - { - return 0; - } + return (HAL_CAN_ConfigFilter( &_can.handle, &sFilterConfig ) == HAL_OK); } @@ -769,18 +762,18 @@ void STM32_CAN::setMBFilter(CAN_FLTEN input) bool STM32_CAN::setMBFilterProcessing(CAN_BANK bank_num, uint32_t filter_id, uint32_t mask, IDE std_ext) { // just convert the MB number enum to bank number. - return setFilterSingleMask(uint8_t(bank_num), filter_id, mask, std_ext); + return !setFilterSingleMask(uint8_t(bank_num), filter_id, mask, std_ext); } bool STM32_CAN::setMBFilter(CAN_BANK bank_num, uint32_t id1, IDE std_ext) { // by setting the mask to 0x1FFFFFFF we only filter the ID set as Filter ID. - return setFilterSingleMask(uint8_t(bank_num), id1, 0x1FFFFFFF, std_ext); + return !setFilterSingleMask(uint8_t(bank_num), id1, 0x1FFFFFFF, std_ext); } bool STM32_CAN::setMBFilter(CAN_BANK bank_num, uint32_t id1, uint32_t id2, IDE std_ext) { - return setFilterDualID(uint8_t(bank_num), id1, id2, std_ext, std_ext); + return !setFilterDualID(uint8_t(bank_num), id1, id2, std_ext, std_ext); } void STM32_CAN::initializeFilters() diff --git a/STM32_CAN.h b/STM32_CAN.h index e1f9b70..a0e4747 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -301,7 +301,10 @@ class STM32_CAN { bool write(CAN_message_t &CAN_tx_msg, bool sendMB = false); bool read(CAN_message_t &CAN_rx_msg); - // Manually set STM32 filter bank parameters + /** + * Manually set STM32 filter bank parameters + * These return true on success + */ /** set filter state and action, keeps filter rules intact */ bool setFilter(uint8_t bank_num, bool state, FilterAction action = CAN_FILTER_DEFAULT_ACTION); bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); @@ -309,12 +312,15 @@ class STM32_CAN { bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); - // Legacy, broken! Only works correctly for 32 bit mask mode + /** Legacy, broken! Only works correctly for 32 bit mask mode + * Retruns true on Error, false on Success (like Teensy functions, opposite of STM32 function) + */ bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO, uint32_t filter_mode = CAN_FILTERMODE_IDMASK, uint32_t filter_scale = CAN_FILTERSCALE_32BIT, uint32_t fifo = CAN_FILTER_DEFAULT_FIFO); /**------------------------------------------------------------- * Teensy FlexCAN compatibility functions * ------------------------------------------------------------- + * These return false on success */ bool setMBFilterProcessing(CAN_BANK bank_num, uint32_t filter_id, uint32_t mask, IDE = AUTO); void setMBFilter(CAN_FLTEN input); /* enable/disable traffic for all MBs (for individual masking) */ From a9bcfa31af551693248a495e3f620a307f149752 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 14:41:35 +0100 Subject: [PATCH 39/51] fix: check filter bank bounds --- STM32_CAN.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 768f6a2..1789afe 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -734,8 +734,15 @@ bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint3 if(_can.handle.Instance == CAN2) { sFilterConfig.FilterBank += STM32_CAN_CAN2_FILTER_OFFSET; + if(sFilterConfig.FilterBank >= STM32_CAN_DUAL_CAN_FILTER_COUNT) + return false; } + else #endif + if(sFilterConfig.FilterBank >= STM32_CAN_SINGLE_CAN_FILTER_COUNT) + { + return false; + } // Enable filter return (HAL_CAN_ConfigFilter( &_can.handle, &sFilterConfig ) == HAL_OK); } From f594cf6a2f4fda95e1bafcfcdb134d09b0ed65e2 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 14:43:04 +0100 Subject: [PATCH 40/51] fix: check if instance is initialized --- STM32_CAN.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 1789afe..eca35a7 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -612,6 +612,7 @@ static uint32_t format16bitFilter(uint32_t id, IDE std_ext, bool mask) bool STM32_CAN::setFilter(uint8_t bank_num, bool enabled, FilterAction action) { CAN_TypeDef *can_ip = _can.handle.Instance; + if(!_can.handle.Instance) return false; /** CAN2 shares filter banks with CAN1 * Driver allocates equal amount to each * Filter Banks located at CAN1 base address From 6add54adbacf9ea2c0ae9c2ff673f59b87188ea8 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 15:20:54 +0100 Subject: [PATCH 41/51] fix: rename state arg to enabled --- STM32_CAN.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STM32_CAN.h b/STM32_CAN.h index a0e4747..fdfba74 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -306,7 +306,7 @@ class STM32_CAN { * These return true on success */ /** set filter state and action, keeps filter rules intact */ - bool setFilter(uint8_t bank_num, bool state, FilterAction action = CAN_FILTER_DEFAULT_ACTION); + bool setFilter(uint8_t bank_num, bool enabled, FilterAction action = CAN_FILTER_DEFAULT_ACTION); bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); From db1bca543e0a898f230b50113e44b344a3a90a30 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 15:53:46 +0100 Subject: [PATCH 42/51] add discovery functions for type and amount of filter banks --- STM32_CAN.cpp | 17 +++++++++++++++++ STM32_CAN.h | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index eca35a7..93281c2 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -566,6 +566,23 @@ bool STM32_CAN::read(CAN_message_t &CAN_rx_msg) return ret; } +uint8_t STM32_CAN::getFilterBankCount(IDE std_ext) +{ + (void)std_ext; + if(_can.handle.Instance == nullptr) return 0; + #ifdef CAN2 + if(_can.handle.Instance == CAN1) + { + return STM32_CAN_CAN2_FILTER_OFFSET; + } + if(_can.handle.Instance == CAN2) + { + return STM32_CAN_DUAL_CAN_FILTER_COUNT - STM32_CAN_CAN2_FILTER_OFFSET; + } + #endif + return STM32_CAN_SINGLE_CAN_FILTER_COUNT; +} + static uint32_t format32bitFilter(uint32_t id, IDE std_ext, bool mask) { uint32_t id_reg; diff --git a/STM32_CAN.h b/STM32_CAN.h index fdfba74..874d297 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -301,6 +301,13 @@ class STM32_CAN { bool write(CAN_message_t &CAN_tx_msg, bool sendMB = false); bool read(CAN_message_t &CAN_rx_msg); + /** returns number of available filter banks. If hasSharedFilterBanks() is false counts may differ by id type. */ + uint8_t getFilterBankCount(IDE std_ext = STD); + /** returns if filter count and index are shared (true) or dedicated per id type (false) */ + bool hasSharedFilterBanks() { + return true; + } + /** * Manually set STM32 filter bank parameters * These return true on success From 053cfb3bc4de174391062f617c24de937bae38a6 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 16:28:08 +0100 Subject: [PATCH 43/51] Rename enums to upper snake case --- STM32_CAN.cpp | 36 ++++++++++++++++++------------------ STM32_CAN.h | 18 +++++++++--------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 93281c2..ecb3e47 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -213,7 +213,7 @@ void STM32_CAN::init(void) _can.handle.Init.AutoWakeUp = DISABLE; _can.handle.Init.ReceiveFifoLocked = DISABLE; _can.handle.Init.TransmitFifoPriority = ENABLE; - _can.handle.Init.Mode = Mode::NORMAL; + _can.handle.Init.Mode = MODE::NORMAL; } CAN_TypeDef * STM32_CAN::getPeripheral() @@ -266,21 +266,21 @@ void STM32_CAN::setIRQPriority(uint32_t preemptPriority, uint32_t subPriority) this->subPriority = min(subPriority, MAX_IRQ_PRIO_VALUE); } -void STM32_CAN::setMode(Mode mode) +void STM32_CAN::setMode(MODE mode) { _can.handle.Init.Mode = mode; } void STM32_CAN::enableLoopBack( bool yes ) { - setMode(yes ? Mode::LOOPBACK : Mode::NORMAL); + setMode(yes ? MODE::LOOPBACK : MODE::NORMAL); } void STM32_CAN::enableSilentMode( bool yes ) { - setMode(yes ? Mode::SILENT : Mode::NORMAL); + setMode(yes ? MODE::SILENT : MODE::NORMAL); } void STM32_CAN::enableSilentLoopBack( bool yes ) { - setMode(yes ? Mode::SILENT_LOOPBACK : Mode::NORMAL); + setMode(yes ? MODE::SILENT_LOOPBACK : MODE::NORMAL); } /**------------------------------------------------------------- @@ -626,7 +626,7 @@ static uint32_t format16bitFilter(uint32_t id, IDE std_ext, bool mask) return id_reg; } -bool STM32_CAN::setFilter(uint8_t bank_num, bool enabled, FilterAction action) +bool STM32_CAN::setFilter(uint8_t bank_num, bool enabled, FILTER_ACTION action) { CAN_TypeDef *can_ip = _can.handle.Instance; if(!_can.handle.Instance) return false; @@ -653,10 +653,10 @@ bool STM32_CAN::setFilter(uint8_t bank_num, bool enabled, FilterAction action) /* Filter FIFO assignment */ switch (action) { - case FilterAction::STORE_FIFO0: + case FILTER_ACTION::STORE_FIFO0: CLEAR_BIT(can_ip->FFA1R, filternbrbitpos); break; - case FilterAction::STORE_FIFO1: + case FILTER_ACTION::STORE_FIFO1: SET_BIT(can_ip->FFA1R, filternbrbitpos); break; } @@ -671,28 +671,28 @@ bool STM32_CAN::setFilter(uint8_t bank_num, bool enabled, FilterAction action) return true; } -bool STM32_CAN::setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action, bool enabled) +bool STM32_CAN::setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FILTER_ACTION action, bool enabled) { uint32_t id_reg = format32bitFilter(id, std_ext, false); uint32_t mask_reg = format32bitFilter(mask, std_ext, true); return setFilterRaw(bank_num, id_reg, mask_reg, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_32BIT, action, enabled); } -bool STM32_CAN::setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action, bool enabled) +bool STM32_CAN::setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FILTER_ACTION action, bool enabled) { uint32_t id = format32bitFilter(id1, std_ext1, false); uint32_t mask = format32bitFilter(id2, std_ext2, false); return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_32BIT, action, enabled); } -bool STM32_CAN::setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action, bool enabled) +bool STM32_CAN::setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FILTER_ACTION action, bool enabled) { uint32_t id = (uint32_t)format16bitFilter(id1, std_ext1, false) | (((uint32_t)format16bitFilter(mask1, std_ext1, true)) << 16); uint32_t mask = (uint32_t)format16bitFilter(id2, std_ext2, false) | (((uint32_t)format16bitFilter(mask2, std_ext2, true)) << 16); return setFilterRaw(bank_num, id, mask, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_16BIT, action, enabled); } -bool STM32_CAN::setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FilterAction action, bool enabled) +bool STM32_CAN::setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FILTER_ACTION action, bool enabled) { uint32_t id = (uint32_t)format16bitFilter(id1, std_ext1, false) | (((uint32_t)format16bitFilter(id2, std_ext2, false)) << 16); uint32_t mask = (uint32_t)format16bitFilter(id3, std_ext3, false) | (((uint32_t)format16bitFilter(id4, std_ext4, false)) << 16); @@ -713,11 +713,11 @@ bool STM32_CAN::setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, I /** re-implement broken implementation for legacy behaviour */ uint32_t id_reg = format32bitFilter(filter_id, std_ext, false); uint32_t mask_reg = format32bitFilter(mask, std_ext, true); - FilterAction action = (fifo==CAN_FILTER_FIFO0) ? FilterAction::STORE_FIFO0 : FilterAction::STORE_FIFO1; + FILTER_ACTION action = (fifo==CAN_FILTER_FIFO0) ? FILTER_ACTION::STORE_FIFO0 : FILTER_ACTION::STORE_FIFO1; return !setFilterRaw(bank_num, id_reg, mask_reg, filter_mode, filter_scale, action); } -bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action, bool enabled) +bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FILTER_ACTION action, bool enabled) { CAN_FilterTypeDef sFilterConfig; if(!_can.handle.Instance) return false; @@ -726,17 +726,17 @@ bool STM32_CAN::setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint3 sFilterConfig.FilterMode = filter_mode; sFilterConfig.FilterScale = filter_scale; #if defined(STM32_CAN1_TX_RX0_BLOCKED_BY_USB) && defined(STM32_CAN_USB_WORKAROUND_POLLING) - if(action == FilterAction::STORE_FIFO0) + if(action == FILTER_ACTION::STORE_FIFO0) { core_debug("WARNING: RX0 IRQ is blocked by USB Driver. Events only handled by polling and RX1 events!\n"); } #endif switch (action) { - case FilterAction::STORE_FIFO0: + case FILTER_ACTION::STORE_FIFO0: sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; break; - case FilterAction::STORE_FIFO1: + case FILTER_ACTION::STORE_FIFO1: sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO1; break; } @@ -808,7 +808,7 @@ void STM32_CAN::initializeFilters() /** Let everything in by default */ setFilterRaw(0, 0UL, 0UL, CAN_FILTERMODE_IDMASK, CAN_FILTERSCALE_32BIT, - FilterAction::CAN_FILTER_DEFAULT_ACTION, true); + FILTER_ACTION::CAN_FILTER_DEFAULT_ACTION, true); /** turn off all other filters that might sill be setup from before */ for (uint8_t bank_num = 1 ; bank_num < STM32_CAN_SINGLE_CAN_FILTER_COUNT ; bank_num++) diff --git a/STM32_CAN.h b/STM32_CAN.h index 874d297..3f36ed2 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -253,14 +253,14 @@ typedef struct { class STM32_CAN { public: - enum Mode { + enum MODE { NORMAL = CAN_MODE_NORMAL, SILENT = CAN_MODE_SILENT, SILENT_LOOPBACK = CAN_MODE_SILENT_LOOPBACK, LOOPBACK = CAN_MODE_LOOPBACK }; - enum FilterAction { + enum FILTER_ACTION { STORE_FIFO0, STORE_FIFO1, }; @@ -278,7 +278,7 @@ class STM32_CAN { */ void setIRQPriority(uint32_t preemptPriority, uint32_t subPriority); - void setMode(Mode mode); + void setMode(MODE mode); void enableLoopBack(bool yes = 1); void enableSilentMode(bool yes = 1); void enableSilentLoopBack(bool yes = 1); @@ -313,12 +313,12 @@ class STM32_CAN { * These return true on success */ /** set filter state and action, keeps filter rules intact */ - bool setFilter(uint8_t bank_num, bool enabled, FilterAction action = CAN_FILTER_DEFAULT_ACTION); - bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); - bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); - bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); - bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); - bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FilterAction action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilter(uint8_t bank_num, bool enabled, FILTER_ACTION action = CAN_FILTER_DEFAULT_ACTION); + bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext, FILTER_ACTION action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterDualID(uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2, FILTER_ACTION action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterDualMask(uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2, FILTER_ACTION action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterQuadID(uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4, FILTER_ACTION action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); + bool setFilterRaw(uint8_t bank_num, uint32_t id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, FILTER_ACTION action = CAN_FILTER_DEFAULT_ACTION, bool enabled = true); /** Legacy, broken! Only works correctly for 32 bit mask mode * Retruns true on Error, false on Success (like Teensy functions, opposite of STM32 function) */ From 0cb3e845bbf62236279970309ed4df583ef6aeb5 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 18:06:17 +0100 Subject: [PATCH 44/51] add setters for pre-begin() configuration options --- STM32_CAN.cpp | 40 +++++++++++++++++++++++++++++++++------- STM32_CAN.h | 18 ++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index ecb3e47..759c189 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -208,12 +208,13 @@ void STM32_CAN::init(void) baudrate = 0UL; filtersInitialized = false; - _can.handle.Init.TimeTriggeredMode = DISABLE; - _can.handle.Init.AutoBusOff = DISABLE; + setTimestampCounter(false); + setAutoBusOffRecovery(false); _can.handle.Init.AutoWakeUp = DISABLE; - _can.handle.Init.ReceiveFifoLocked = DISABLE; - _can.handle.Init.TransmitFifoPriority = ENABLE; - _can.handle.Init.Mode = MODE::NORMAL; + setRxFIFOLock(false); + setTxBufferMode(TX_BUFFER_MODE::FIFO); + setMode(MODE::NORMAL); + setAutoRetransmission(true); } CAN_TypeDef * STM32_CAN::getPeripheral() @@ -266,6 +267,27 @@ void STM32_CAN::setIRQPriority(uint32_t preemptPriority, uint32_t subPriority) this->subPriority = min(subPriority, MAX_IRQ_PRIO_VALUE); } +void STM32_CAN::setAutoRetransmission(bool enabled) +{ + _can.handle.Init.AutoRetransmission = enabled ? (ENABLE) : (DISABLE); +} + +void STM32_CAN::setRxFIFOLock(bool fifo0locked, bool fifo1locked) +{ + (void)fifo1locked; + _can.handle.Init.ReceiveFifoLocked = fifo0locked ? (ENABLE) : (DISABLE); +} + +void STM32_CAN::setTxBufferMode(TX_BUFFER_MODE mode) +{ + _can.handle.Init.TransmitFifoPriority = (FunctionalState)mode; +} + +void STM32_CAN::setTimestampCounter(bool enabled) +{ + _can.handle.Init.TimeTriggeredMode = enabled ? (ENABLE) : (DISABLE); +} + void STM32_CAN::setMode(MODE mode) { _can.handle.Init.Mode = mode; @@ -283,6 +305,11 @@ void STM32_CAN::enableSilentLoopBack( bool yes ) { setMode(yes ? MODE::SILENT_LOOPBACK : MODE::NORMAL); } +void STM32_CAN::setAutoBusOffRecovery(bool enabled) +{ + _can.handle.Init.AutoBusOff = enabled ? (ENABLE) : (DISABLE); +} + /**------------------------------------------------------------- * lifecycle functions * setBaudRate may be called before or after begin @@ -379,8 +406,7 @@ void STM32_CAN::begin( bool retransmission ) { } #endif - if (retransmission){ _can.handle.Init.AutoRetransmission = ENABLE; } - else { _can.handle.Init.AutoRetransmission = DISABLE; } + setAutoRetransmission(retransmission); filtersInitialized = false; diff --git a/STM32_CAN.h b/STM32_CAN.h index 3f36ed2..e65cd60 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -265,6 +265,12 @@ class STM32_CAN { STORE_FIFO1, }; + enum TX_BUFFER_MODE { + FIFO = ENABLE, /** Sequencial transfers order */ + QUEUE = DISABLE /** Sequence based on msg ID priorites. Only effects hardware queue. */ + }; + + // Default buffer sizes are set to 16. But this can be changed by using constructor in main code. STM32_CAN(uint32_t rx, uint32_t tx = PNUM_NOT_DEFINED, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); STM32_CAN(PinName rx, PinName tx = NC, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); @@ -278,11 +284,23 @@ class STM32_CAN { */ void setIRQPriority(uint32_t preemptPriority, uint32_t subPriority); + /** send message again on arbitration failure */ + void setAutoRetransmission(bool enabled); + + /** If locked incoming msg is dropped when fifo is full, + * when unlocked last msg in fifo is overwritten + * 2nd arg has no effect, setting effects both fifos */ + void setRxFIFOLock(bool fifo0locked, bool fifo1locked = true); + void setTxBufferMode(TX_BUFFER_MODE mode); + void setTimestampCounter(bool enabled); + void setMode(MODE mode); void enableLoopBack(bool yes = 1); void enableSilentMode(bool yes = 1); void enableSilentLoopBack(bool yes = 1); + void setAutoBusOffRecovery(bool enabled); + /**------------------------------------------------------------- * lifecycle functions * setBaudRate may be called before or after begin From 8e3e6b5d578ff045c31d9ffd26cec4c4422ac014 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sun, 5 Jan 2025 22:58:35 +0100 Subject: [PATCH 45/51] add additional workaround for USB+CAN on F3 Platform. If USB IRQs are re-mapped, CAN IRQs are not blocked by USB anymore. --- STM32_CAN.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/STM32_CAN.h b/STM32_CAN.h index e65cd60..4eeaf4a 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -105,7 +105,9 @@ to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See e #define CAN1_RX1_IRQHandler CAN_RX1_IRQHandler #define CAN1_SCE_IRQHandler CAN_SCE_IRQHandler - #ifdef USBCON + /** NOTE: USE_USB_INTERRUPT_REMAPPED may be used to use + * different USB IRQs and not block the CAN IRQ handlers */ + #if defined(USBCON) && !defined(USE_USB_INTERRUPT_REMAPPED) #define STM32_CAN1_TX_RX0_BLOCKED_BY_USB #endif From eb6de542090054ab08f080539d7803287405f13c Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:08:05 +0100 Subject: [PATCH 46/51] fix: don't use ifdef for combined logic --- STM32_CAN.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 759c189..e010051 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -2,7 +2,7 @@ #include "core_debug.h" -#ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) +#if defined(HAL_CEC_MODULE_ENABLED) && defined(STM32_CAN1_SHARED_WITH_CEC) /** Pointer to CEC_HandleTypeDef structure that contains * the configuration information for the specified CEC. * Application have to declare them properly to be able to call @@ -1174,7 +1174,7 @@ void STM32_CAN::disableMBInterrupts() if (_can.handle.Instance == CAN1) { #ifdef CAN1_IRQn_AIO - #ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) + #if defined(HAL_CEC_MODULE_ENABLED) && defined(STM32_CAN1_SHARED_WITH_CEC) //only disable if cec instance is not set/used if(!phcec) #endif @@ -1305,7 +1305,7 @@ extern "C" void CAN1_IRQHandler_AIO(void) if(canObj[CAN1_INDEX]) { HAL_CAN_IRQHandler(&canObj[CAN1_INDEX]->handle); } - #ifdef HAL_CEC_MODULE_ENABLED && defined(STM32_CAN1_SHARED_WITH_CEC) + #if defined(HAL_CEC_MODULE_ENABLED) && defined(STM32_CAN1_SHARED_WITH_CEC) if(phcec) { HAL_CEC_IRQHandler(phcec); From 392b5e15e7026fecabbcb0c795a76d7c3d48bc32 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:52:35 +0100 Subject: [PATCH 47/51] fix: don't lock up (Error_Handler) when calling hasPeripheral or freePeripheral when no peripheral has been allocated. --- STM32_CAN.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index e010051..57a9954 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -90,6 +90,7 @@ bool STM32_CAN::allocatePeripheral() bool STM32_CAN::freePeripheral() { + if (_can.handle.Instance == nullptr) return false; can_index_t index = get_can_index(_can.handle.Instance); if(index >= CAN_NUM) { @@ -107,6 +108,7 @@ bool STM32_CAN::freePeripheral() bool STM32_CAN::hasPeripheral() { + if (_can.handle.Instance == nullptr) return false; can_index_t index = get_can_index(_can.handle.Instance); if(index >= CAN_NUM) { From b1351e6869b7599a5b567f8ec340c87cd8d72f43 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:58:45 +0100 Subject: [PATCH 48/51] allocatePeripheral() takes peripheral as arg and sets up handle.Instance if successful. --- STM32_CAN.cpp | 12 ++++++------ STM32_CAN.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 57a9954..2714438 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -70,9 +70,9 @@ can_index_t get_can_index(CAN_TypeDef *instance) return index; } -bool STM32_CAN::allocatePeripheral() +bool STM32_CAN::allocatePeripheral(CAN_TypeDef *instance) { - can_index_t index = get_can_index(_can.handle.Instance); + can_index_t index = get_can_index(instance); if(index >= CAN_NUM) { return false; @@ -83,6 +83,7 @@ bool STM32_CAN::allocatePeripheral() Error_Handler(); return false; } + _can.handle.Instance = instance; //register with global, we own this instance now canObj[index] = &_can; return true; @@ -323,14 +324,13 @@ void STM32_CAN::begin( bool retransmission ) { // exit if CAN already is active if (_canIsActive) return; - _can.handle.Instance = getPeripheral(); - if(_can.handle.Instance == NP) + auto instance = getPeripheral(); + if(instance == NP) { //impossible pinconfig, done here - _can.handle.Instance = nullptr; return; } - if(!allocatePeripheral()) + if(!allocatePeripheral(instance)) { //peripheral already in use return; diff --git a/STM32_CAN.h b/STM32_CAN.h index 4eeaf4a..ff0949b 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -380,7 +380,7 @@ class STM32_CAN { private: void init(void); CAN_TypeDef * getPeripheral(void); - bool allocatePeripheral(void); + bool allocatePeripheral(CAN_TypeDef *instance); bool freePeripheral(void); bool hasPeripheral(void); void start(void); From 89dd4d9bababc72d2c9c9d59a46e042466de08eb Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:41:27 +0100 Subject: [PATCH 49/51] add destructor, stop peripheral and release everything --- STM32_CAN.cpp | 5 +++++ STM32_CAN.h | 1 + 2 files changed, 6 insertions(+) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 2714438..094a734 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -204,6 +204,11 @@ STM32_CAN::STM32_CAN( CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize, init(); } +STM32_CAN::~STM32_CAN() +{ + end(); +} + void STM32_CAN::init(void) { _can.__this = (void*)this; diff --git a/STM32_CAN.h b/STM32_CAN.h index ff0949b..5df758a 100644 --- a/STM32_CAN.h +++ b/STM32_CAN.h @@ -279,6 +279,7 @@ class STM32_CAN { STM32_CAN(CAN_TypeDef* canPort, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); //legacy for compatibility STM32_CAN(CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16); + ~STM32_CAN(); /**------------------------------------------------------------- * setup functions * no effect after begin() From 7589260e55040c7cac336ca13e84ba9c2485cedc Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Sat, 18 Jan 2025 19:08:01 +0100 Subject: [PATCH 50/51] enable RX pullup. Eases use of loopback modes without external circuitry. --- STM32_CAN.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/STM32_CAN.cpp b/STM32_CAN.cpp index 094a734..7e7daec 100644 --- a/STM32_CAN.cpp +++ b/STM32_CAN.cpp @@ -345,7 +345,15 @@ void STM32_CAN::begin( bool retransmission ) { initializeBuffers(); - pin_function(rx, pinmap_function(rx, PinMap_CAN_RD)); + /** + * NOTE: enabling the internal pullup of RX pin + * in case no external circuitry (CAN Transceiver) is connected this will ensure a valid recessive level. + * A valid recessive level on RX is needed to leave init mode and enter normal mode. + * This is even the case if loopback is enabled where the input is internally connected. + * This lets loopback only tests without external circuitry sill function. + */ + uint32_t rx_func = pinmap_function(rx, PinMap_CAN_RD); + pin_function(rx, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, STM_PIN_AFNUM(rx_func))); if(tx != NC) { pin_function(tx, pinmap_function(tx, PinMap_CAN_TD)); From 990065205458d3c27be3a52b51722fda8270e9d9 Mon Sep 17 00:00:00 2001 From: duckylotl <163729266+duckylotl@users.noreply.github.com> Date: Wed, 22 Jan 2025 21:43:00 +0100 Subject: [PATCH 51/51] update readme --- README.md | 141 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 4fe0444..f40ade5 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,27 @@ STM32 core: https://github.com/stm32duino/Arduino_Core_STM32 ## How to use. To use this library, CAN module needs to be enabled in HAL drivers. If PIO is used, it's enough -to add -DHAL_CAN_MODULE_ENABLED as build flag. With Arduino IDE it's easiest to create hal_conf_extra.h -file -to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See examples for this. +to add `-DHAL_CAN_MODULE_ENABLED` as build flag. With Arduino IDE it's easiest to create `hal_conf_extra.h` file +to same folder with sketch and haven `#define HAL_CAN_MODULE_ENABLED` there. See examples for this. ### Setup The sketch needs include in the header to use the library. -``` +```Cpp #include "STM32_CAN.h" ``` Use constructor to set which CAN interface and pins to use. +```Cpp +STM32_CAN Can1( CAN1 ); //by peripheral. Uses first pin defined in arduino PeripheralPins maps +STM32_CAN Can1( PA11 /* rx pin */, PA12 /* tx pin */); //by arduino digital pin number. Finds matching peripheral automatically +STM32_CAN Can1( PA_11, PA_12 ); //by PinName. Finds matching peripheral automatically ``` +**Note**: Digital pin and PinName may not be mixed or one will be implicitly converted and possibly causing unintended behavior. PinNames are defined with an underscore between port and pin. Digital pin numbers are aliased with port and pinnumber without an underscore. +Can convert between the two with `digitalPinToPinName()` and `pinNametoDigitalPin()`. + +Tx pin may be defined as `PNUM_NOT_DEFINED` (digital pin number) or `NC` (PinName). Then only Rx is setup, allowing a listen only mode. + +The original method by choosing from 3 sets of fixed pin combinations can still be used as well for compatibility. +```Cpp STM32_CAN Can1( CAN1, DEF ); ``` Depending on the STM32 model, there is CAN1, CAN2 and CAN3 available. @@ -45,11 +56,98 @@ The pins are: - ALT: PB3/4 In constructor you can optionally set TX and RX buffer sizes. Default is 16 messages. +```Cpp +STM32_CAN Can1 (PA_11, PA_12, RX_SIZE_256, TX_SIZE_256); +``` + +#### Additional settings +Following settings may be changed before starting the driver with `begin()`. +```Cpp +setIRQPriority(uint32_t preemptPriority, uint32_t subPriority); // default: lowest prio, 0 +setAutoRetransmission(bool enabled); //default: true +setRxFIFOLock(bool fifo0locked); //default: false +setTxBufferMode(TX_BUFFER_MODE mode); //default: FIFO +setTimestampCounter(bool enabled); //default: false +setMode(MODE mode); //default: NORMAL +setAutoBusOffRecovery(bool enabled); //default: false +``` +**Note**: `setTimestampCounter()` should always be set `false`. Feature is marked as non functioning in Erratas. + +**Note**: begin() will overwrite `setAutoRetransmission()` setting (`false` by default). + +#### Start / Stop bus + +Before using library commands, begin must be called. +```Cpp +Can1.begin(); +``` +Optionally automatic retransmission can be enabled with begin. +```Cpp +Can1.begin(true); +``` +Set baud rate by using. +```Cpp +Can1.setBaudRate(500000); +``` +500 kbit/s in this case. + +`setBaudRate` may be called before or after begin. Bus start once both are called. + +It may also be called while running to change baudrate. + +Call +```Cpp +Can1.end(); +``` +to stop the bus and release all resources. Will be implicitly called by destructor when freeing object. +Only one STM32_CAN instance can control a CAN Peripheral at one time. It reserves the peripheral from begin() to end(). + +#### Filters +Filters may only be set after bus is started (`begin()` & `setBaudRate()` was called). + +By default bank 0 will receive CAN messages with all IDs. But using filters, we can set the CAN to receive +only specific message IDs. The CAN peripheral has many different methods of defining filters for messages. +These functions help setting up filters: +```Cpp +bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext); +bool setFilterDualID (uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2); +bool setFilterDualMask (uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2); +bool setFilterQuadID (uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4); +``` +The simplest one is `setFilterSingleMask`. The others allow setting multiple filters into a single filter bank. When using the functions `setFilterDualMask` and `setFilterQuadID` for extended ids, the 15 LSBs of the ID are always masked out. + +Example: we want to receive only messages with standard ID 0x153 and extended ID 0x613, so we use bank 0 and 1. +```Cpp +Can1.setFilterSingleMask( 0, 0x153, 0x7FF, STD); +Can1.setFilterSingleMask( 1, 0x613, 0x1FFFFFFF, EXT); +``` +First number is the bank number. Second is message ID. 3rd ID mask. And last one defines ID type: `AUTO`, `STD` or `EXT`. + + +**Note**: optional args of filter settings allow storing messages into the non-default RxFIFO. `read()` currently only reads from the default FIFO, so messages will not be accessible if sent to other FIFO. + +**Note**: the following function allowed setting filters in the past. This function was bugged and did only work as long as optional args filter_mode and filter_scale where not changed. +Its behavior was kept in the broken state for compatibility. It has a 4th arg for ID type, defaults to `AUTO`. +```Cpp +bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask) ``` -STM32_CAN Can1 (CAN1, ALT_2, RX_SIZE_256, TX_SIZE_256); + +To disable a filter bank call (`true` to re-enable it) +```Cpp +Can1.setFilter(bank_num, false); ``` -There is structure to contain CAN packets and info about those. + + +The amount of available filter banks can be queried with: +```Cpp +Can1.getFilterBankCount() ``` +**Note**: Single CAN devices have 14, dual CAN devices 28. Driver does split the 28 into 14 for each CAN instance. + + +### Main loop +The library defines this structure to describe a CAN message. +```Cpp typedef struct CAN_message_t { uint32_t id = 0; // can identifier uint16_t timestamp = 0; // time when message arrived @@ -67,41 +165,20 @@ typedef struct CAN_message_t { bool seq = 0; // sequential frames } CAN_message_t; ``` -In sketch. -``` -static CAN_message_t CAN_msg; -``` -Before using library commands, begin must be called. -``` -Can1.begin(); -``` -Optionally automatic retransmission can be enabled with begin. -``` -Can1.begin(true); -``` -Set baud rate by using. -``` -Can1.setBaudRate(500000); -``` -500 kbit/s in this case. -By default bank 0 will receive CAN messages with all IDs. But using filters, we can set the CAN to receive -only specific message IDs. Ie. if we want to receive only message IDs 0x153 and 0x613, so we use bank 0 and 1. -``` -Can1.setFilter( 0, 0x153, 0x1FFFFFFF ); -Can1.setFilter( 1, 0x613, 0x1FFFFFFF ); +Define variable to store a message +```Cpp +CAN_message_t CAN_msg; ``` -First number is the bank number. Second is message ID. And last one is mask. -### Main loop To read CAN messages from buffer: -``` -Can1.read(CAN_msg) +```Cpp +Can1.read(CAN_msg); ``` This will return true if there is messages available on receive buffer. To write messages to send queue. -``` +```Cpp Can1.write(CAN_msg); ``` This will return true if there room in the send queue.