From 1ed2b904a3518fe47dd69319fd75cf4fa92d5fd9 Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Mon, 29 Apr 2024 15:24:36 -0400 Subject: [PATCH 01/10] Modify Stm32Can to support multiple CAN interfaces. --- src/freertos_drivers/st/Stm32Can.cxx | 305 +++++++++++++++++++-------- src/freertos_drivers/st/Stm32Can.hxx | 18 +- 2 files changed, 227 insertions(+), 96 deletions(-) diff --git a/src/freertos_drivers/st/Stm32Can.cxx b/src/freertos_drivers/st/Stm32Can.cxx index 003c9e054..f2a7ad71e 100644 --- a/src/freertos_drivers/st/Stm32Can.cxx +++ b/src/freertos_drivers/st/Stm32Can.cxx @@ -36,6 +36,7 @@ #include "Stm32Can.hxx" #include +#include #include "can_ioctl.h" @@ -44,57 +45,79 @@ #if defined (STM32F072xB) || defined (STM32F091xC) #include "stm32f0xx_hal_cortex.h" -#define CAN_IRQN CEC_CAN_IRQn - +#define CAN1_IRQN CEC_CAN_IRQn +#define CAN1 CAN #define CAN_CLOCK cpu_clock_hz #elif defined (STM32F103xB) #include "stm32f1xx_hal_cortex.h" #define SPLIT_INT -#define CAN_TX_IRQN USB_HP_CAN1_TX_IRQn -#define CAN_IRQN CAN_TX_IRQN -#define CAN_SECOND_IRQN USB_LP_CAN1_RX0_IRQn -#define CAN_THIRD_IRQN CAN1_SCE_IRQn -#define CAN CAN1 +#define CAN1_TX_IRQN USB_HP_CAN1_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN USB_LP_CAN1_RX0_IRQn +#define CAN1_THIRD_IRQN CAN1_SCE_IRQn + +#ifdef CAN2 +#define CAN2_TX_IRQN USB_HP_CAN2_TX_IRQn +#define CAN2_IRQN CAN2_TX_IRQN +#define CAN2_SECOND_IRQN USB_LP_CAN2_RX0_IRQn +#define CAN2_THIRD_IRQN CAN2_SCE_IRQn +#endif + #define CAN_CLOCK (cm3_cpu_clock_hz >> 1) #elif defined (STM32F303xC) || defined (STM32F303xE) #include "stm32f3xx_hal_cortex.h" #define SPLIT_INT -#define CAN_TX_IRQN USB_HP_CAN_TX_IRQn -#define CAN_IRQN CAN_TX_IRQN -#define CAN_SECOND_IRQN USB_LP_CAN_RX0_IRQn -#define CAN_THIRD_IRQN CAN_SCE_IRQn +#define CAN1_TX_IRQN USB_HP_CAN_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN USB_LP_CAN_RX0_IRQn +#define CAN1_THIRD_IRQN CAN_SCE_IRQn +#define CAN1 CAN #define CAN_CLOCK (cm3_cpu_clock_hz >> 1) #elif defined (STM32L431xx) || defined (STM32L432xx) #include "stm32l4xx_hal_cortex.h" #define SPLIT_INT -#define CAN_TX_IRQN CAN1_TX_IRQn -#define CAN_IRQN CAN_TX_IRQN -#define CAN_SECOND_IRQN CAN1_RX0_IRQn -#define CAN_THIRD_IRQN CAN1_SCE_IRQn +#define CAN1_TX_IRQN CAN1_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN CAN1_RX0_IRQn +#define CAN1_THIRD_IRQN CAN1_SCE_IRQn +#define CAN1 CAN #define CAN_CLOCK (cm3_cpu_clock_hz) #elif defined (STM32F767xx) #include "stm32f7xx_hal_cortex.h" #define SPLIT_INT -#define CAN CAN1 -#define CAN_TX_IRQN CAN1_TX_IRQn -#define CAN_IRQN CAN_TX_IRQN -#define CAN_SECOND_IRQN CAN1_RX0_IRQn -#define CAN_THIRD_IRQN CAN1_SCE_IRQn +#define CAN1_TX_IRQN CAN1_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN CAN1_RX0_IRQn +#define CAN1_THIRD_IRQN CAN1_SCE_IRQn #define CAN_CLOCK (cm3_cpu_clock_hz >> 2) // 54 MHz, sysclk/4 +#ifdef CAN2 +#define CAN2_TX_IRQN CAN2_TX_IRQn +#define CAN2_IRQN CAN2_TX_IRQN +#define CAN2_SECOND_IRQN CAN2_RX0_IRQn +#define CAN2_THIRD_IRQN CAN2_SCE_IRQn +#endif + +#ifdef CAN3 +#define CAN3_TX_IRQN CAN3_TX_IRQn +#define CAN3_IRQN CAN3_TX_IRQN +#define CAN3_SECOND_IRQN CAN3_RX0_IRQn +#define CAN3_THIRD_IRQN CAN3_SCE_IRQn +#endif + #else #error Dont know what STM32 chip you have. #endif -Stm32Can *Stm32Can::instances[1] = {NULL}; +Stm32Can *Stm32Can::instances[MAXCANIFS] = {NULL,NULL,NULL}; /** Constructor. * @param name name of this device instance in the file system @@ -103,13 +126,58 @@ Stm32Can::Stm32Can(const char *name) : Can(name) , state_(CAN_STATE_STOPPED) { - /* only one instance allowed */ - HASSERT(instances[0] == NULL); + /* Get dev num (digit at the end of the devname). */ + char dev = name[strlen(name)-1]; + HASSERT(dev >= '0'); + int index = dev - '0'; +#if defined(CAN3) + HASSERT(index < 3); +#elif defined(CAN2) + HASSERT(index < 2); +#else + HASSERT(index < 1); +#endif + + /* only one instance per interface allowed */ + HASSERT(instances[index] == NULL); - instances[0] = this; + instances[index] = this; + switch (index) + { + case 0: /* CAN1... */ + can_ = CAN1; + can_irqn_ = CAN1_IRQN; +#ifdef SPLIT_INT + can_second_irqn_ = CAN1_SECOND_IRQN; + can_third_irqn_ = CAN1_THIRD_IRQN; +#endif + break; +#idef CAN2 + case 1: /* CAN2... */ + can_ = CAN2; + can_irqn_ = CAN2_IRQN; +#ifdef SPLIT_INT + can_second_irqn_ = CAN2_SECOND_IRQN; + can_third_irqn_ = CAN2_THIRD_IRQN; +#endif + break; +#endif +#ifdef CAN3 + case 2: /* CAN3... */ + can_ = CAN3; + can_irqn_ = CAN3_IRQN; +#ifdef SPLIT_INT + can_second_irqn_ = CAN3_SECOND_IRQN; + can_third_irqn_ = CAN3_THIRD_IRQN; +#endif + break; +#endif + default: + break; + } /* should already be disabled, but just in case */ - HAL_NVIC_DisableIRQ(CAN_IRQN); + HAL_NVIC_DisableIRQ(can_irqn_); #if defined (STM32F030x6) || defined (STM32F031x6) || defined (STM32F038xx) \ || defined (STM32F030x8) || defined (STM32F030xC) || defined (STM32F042x6) \ @@ -121,13 +189,13 @@ Stm32Can::Stm32Can(const char *name) /* The priority of CAN interrupt is as high as possible while maintaining * FreeRTOS compatibility. */ - SetInterruptPriority(CAN_IRQN, configKERNEL_INTERRUPT_PRIORITY); + SetInterruptPriority(can_irqn_, configKERNEL_INTERRUPT_PRIORITY); #ifdef SPLIT_INT - HAL_NVIC_DisableIRQ(CAN_SECOND_IRQN); - SetInterruptPriority(CAN_SECOND_IRQN, configKERNEL_INTERRUPT_PRIORITY); - HAL_NVIC_DisableIRQ(CAN_THIRD_IRQN); - SetInterruptPriority(CAN_THIRD_IRQN, configKERNEL_INTERRUPT_PRIORITY); + HAL_NVIC_DisableIRQ(can_second_irqn_); + SetInterruptPriority(can_second_irqn_, configKERNEL_INTERRUPT_PRIORITY); + HAL_NVIC_DisableIRQ(can_third_irqn_); + SetInterruptPriority(can_third_irqn_, configKERNEL_INTERRUPT_PRIORITY); #endif #endif } @@ -152,7 +220,7 @@ int Stm32Can::ioctl(File *file, unsigned long int key, unsigned long data) void Stm32Can::enable() { /* disable sleep, enter init mode */ - CAN->MCR = CAN_MCR_INRQ; + can_->MCR = CAN_MCR_INRQ; /* Time triggered tranmission off * Bus off state is left automatically @@ -161,40 +229,40 @@ void Stm32Can::enable() * receive FIFO not locked on overrun * TX FIFO mode on */ - CAN->MCR |= (CAN_MCR_ABOM | CAN_MCR_TXFP); + can_->MCR |= (CAN_MCR_ABOM | CAN_MCR_TXFP); /* Setup timing. * 125,000 Kbps = 8 usec/bit */ - CAN->BTR = (CAN_BS1_5TQ | CAN_BS2_2TQ | CAN_SJW_1TQ | + can_->BTR = (CAN_BS1_5TQ | CAN_BS2_2TQ | CAN_SJW_1TQ | ((CAN_CLOCK / 1000000) - 1)); /* enter normal mode */ - CAN->MCR &= ~CAN_MCR_INRQ; + can_->MCR &= ~CAN_MCR_INRQ; /* Enter filter initialization mode. Filter 0 will be used as a single * 32-bit filter, ID Mask Mode, we accept everything, no mask. */ - CAN->FMR |= CAN_FMR_FINIT; - CAN->FM1R = 0; - CAN->FS1R = 0x000000001; - CAN->FFA1R = 0; - CAN->sFilterRegister[0].FR1 = 0; - CAN->sFilterRegister[0].FR2 = 0; + can_->FMR |= CAN_FMR_FINIT; + can_->FM1R = 0; + can_->FS1R = 0x000000001; + can_->FFA1R = 0; + can_->sFilterRegister[0].FR1 = 0; + can_->sFilterRegister[0].FR2 = 0; /* Activeate filter and exit initialization mode. */ - CAN->FA1R = 0x000000001; - CAN->FMR &= ~CAN_FMR_FINIT; + can_->FA1R = 0x000000001; + can_->FMR &= ~CAN_FMR_FINIT; state_ = CAN_STATE_ACTIVE; /* enable interrupts */ - CAN->IER = (CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE); // errors - CAN->IER |= (CAN_IER_ERRIE | CAN_IER_FMPIE0); // error + receive - HAL_NVIC_EnableIRQ(CAN_IRQN); + can_->IER = (CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE); // errors + can_->IER |= (CAN_IER_ERRIE | CAN_IER_FMPIE0); // error + receive + HAL_NVIC_EnableIRQ(can_irqn_); #ifdef SPLIT_INT - HAL_NVIC_EnableIRQ(CAN_SECOND_IRQN); - HAL_NVIC_EnableIRQ(CAN_THIRD_IRQN); + HAL_NVIC_EnableIRQ(can_second_irqn_); + HAL_NVIC_EnableIRQ(can_third_irqn_); #endif } @@ -202,17 +270,17 @@ void Stm32Can::enable() */ void Stm32Can::disable() { - HAL_NVIC_DisableIRQ(CAN_IRQN); + HAL_NVIC_DisableIRQ(can_irqn_); #ifdef SPLIT_INT - HAL_NVIC_DisableIRQ(CAN_SECOND_IRQN); - HAL_NVIC_DisableIRQ(CAN_THIRD_IRQN); + HAL_NVIC_DisableIRQ(can_second_irqn_); + HAL_NVIC_DisableIRQ(can_third_irqn_); #endif - CAN->IER = 0; + can_->IER = 0; state_ = CAN_STATE_STOPPED; /* disable sleep, enter init mode */ - CAN->MCR = CAN_MCR_INRQ; + can_->MCR = CAN_MCR_INRQ; } /* Try and transmit a message. @@ -224,8 +292,8 @@ void Stm32Can::tx_msg() // workaround because the STM32 CAN controller can get stuck in this state // and never get to bus off if the TX attempts end up with no-ack (meaning // the controller is alone on the bus). - if ((CAN->ESR & CAN_ESR_EPVF) && ((CAN->ESR & CAN_ESR_LEC_Msk) != 0) && - ((CAN->TSR & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)) == 0)) + if ((can_->ESR & CAN_ESR_EPVF) && ((can_->ESR & CAN_ESR_LEC_Msk) != 0) && + ((can_->TSR & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)) == 0)) { txBuf->flush(); txBuf->signal_condition(); @@ -241,17 +309,17 @@ void Stm32Can::tx_msg() for (i = 0; i < msg_count; ++i, ++can_frame) { volatile CAN_TxMailBox_TypeDef *mailbox; - if (CAN->TSR & CAN_TSR_TME0) + if (can_->TSR & CAN_TSR_TME0) { - mailbox = CAN->sTxMailBox + 0; + mailbox = can_->sTxMailBox + 0; } - else if (CAN->TSR & CAN_TSR_TME1) + else if (can_->TSR & CAN_TSR_TME1) { - mailbox = CAN->sTxMailBox + 1; + mailbox = can_->sTxMailBox + 1; } - else if (CAN->TSR & CAN_TSR_TME2) + else if (can_->TSR & CAN_TSR_TME2) { - mailbox = CAN->sTxMailBox + 2; + mailbox = can_->sTxMailBox + 2; } else { @@ -296,7 +364,7 @@ void Stm32Can::tx_msg() } /* enable transmit interrupt */ - CAN->IER |= CAN_IER_TMEIE; + can_->IER |= CAN_IER_TMEIE; } /** Handle an interrupt. @@ -305,26 +373,26 @@ void Stm32Can::rx_interrupt_handler() { unsigned msg_receive_count = 0; - while (CAN->RF0R & CAN_RF0R_FMP0) + while (can_->RF0R & CAN_RF0R_FMP0) { /* rx data received */ struct can_frame *can_frame; size_t msg_count = rxBuf->data_write_pointer(&can_frame); if (msg_count) { - if (CAN->sFIFOMailBox[0].RIR & CAN_RI0R_IDE) + if (can_->sFIFOMailBox[0].RIR & CAN_RI0R_IDE) { /* extended frame */ - can_frame->can_id = CAN->sFIFOMailBox[0].RIR >> 3; + can_frame->can_id = can_->sFIFOMailBox[0].RIR >> 3; can_frame->can_eff = 1; } else { /* standard frame */ - can_frame->can_id = CAN->sFIFOMailBox[0].RIR >> 21; + can_frame->can_id = can_->sFIFOMailBox[0].RIR >> 21; can_frame->can_eff = 0; } - if (CAN->sFIFOMailBox[0].RIR & CAN_RI0R_RTR) + if (can_->sFIFOMailBox[0].RIR & CAN_RI0R_RTR) { /* remote frame */ can_frame->can_rtr = 1; @@ -334,15 +402,15 @@ void Stm32Can::rx_interrupt_handler() { /* data frame */ can_frame->can_rtr = 0; - can_frame->can_dlc = CAN->sFIFOMailBox[0].RDTR & CAN_RDT0R_DLC; - can_frame->data[0] = (CAN->sFIFOMailBox[0].RDLR >> 0) & 0xFF; - can_frame->data[1] = (CAN->sFIFOMailBox[0].RDLR >> 8) & 0xFF; - can_frame->data[2] = (CAN->sFIFOMailBox[0].RDLR >> 16) & 0xFF; - can_frame->data[3] = (CAN->sFIFOMailBox[0].RDLR >> 24) & 0xFF; - can_frame->data[4] = (CAN->sFIFOMailBox[0].RDHR >> 0) & 0xFF; - can_frame->data[5] = (CAN->sFIFOMailBox[0].RDHR >> 8) & 0xFF; - can_frame->data[6] = (CAN->sFIFOMailBox[0].RDHR >> 16) & 0xFF; - can_frame->data[7] = (CAN->sFIFOMailBox[0].RDHR >> 24) & 0xFF; + can_frame->can_dlc = can_->sFIFOMailBox[0].RDTR & CAN_RDT0R_DLC; + can_frame->data[0] = (can_->sFIFOMailBox[0].RDLR >> 0) & 0xFF; + can_frame->data[1] = (can_->sFIFOMailBox[0].RDLR >> 8) & 0xFF; + can_frame->data[2] = (can_->sFIFOMailBox[0].RDLR >> 16) & 0xFF; + can_frame->data[3] = (can_->sFIFOMailBox[0].RDLR >> 24) & 0xFF; + can_frame->data[4] = (can_->sFIFOMailBox[0].RDHR >> 0) & 0xFF; + can_frame->data[5] = (can_->sFIFOMailBox[0].RDHR >> 8) & 0xFF; + can_frame->data[6] = (can_->sFIFOMailBox[0].RDHR >> 16) & 0xFF; + can_frame->data[7] = (can_->sFIFOMailBox[0].RDHR >> 24) & 0xFF; } } else @@ -350,7 +418,7 @@ void Stm32Can::rx_interrupt_handler() ++overrunCount; } /* release FIFO */ - CAN->RF0R |= CAN_RF0R_RFOM0; + can_->RF0R |= CAN_RF0R_RFOM0; ++msg_receive_count; } @@ -365,7 +433,7 @@ void Stm32Can::rx_interrupt_handler() void Stm32Can::tx_interrupt_handler() { - if (CAN->TSR & (CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2)) + if (can_->TSR & (CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2)) { /* transmit request completed, should be able to send another */ struct can_frame *can_frame; @@ -379,17 +447,17 @@ void Stm32Can::tx_interrupt_handler() for (i = 0; i < msg_count; ++i, ++can_frame) { volatile CAN_TxMailBox_TypeDef *mailbox; - if (CAN->TSR & CAN_TSR_TME0) + if (can_->TSR & CAN_TSR_TME0) { - mailbox = CAN->sTxMailBox + 0; + mailbox = can_->sTxMailBox + 0; } - else if (CAN->TSR & CAN_TSR_TME1) + else if (can_->TSR & CAN_TSR_TME1) { - mailbox = CAN->sTxMailBox + 1; + mailbox = can_->sTxMailBox + 1; } - else if (CAN->TSR & CAN_TSR_TME2) + else if (can_->TSR & CAN_TSR_TME2) { - mailbox = CAN->sTxMailBox + 2; + mailbox = can_->sTxMailBox + 2; } else { @@ -431,7 +499,7 @@ void Stm32Can::tx_interrupt_handler() else { /* no more data left to transmit */ - CAN->IER &= ~CAN_IER_TMEIE; + can_->IER &= ~CAN_IER_TMEIE; } txBuf->signal_condition_from_isr(); state_ = CAN_STATE_ACTIVE; @@ -443,26 +511,26 @@ void Stm32Can::tx_interrupt_handler() */ void Stm32Can::sce_interrupt_handler() { - if (CAN->MSR & CAN_MSR_ERRI) + if (can_->MSR & CAN_MSR_ERRI) { /* error interrupt has occured */ - CAN->MSR |= CAN_MSR_ERRI; // clear flag + can_->MSR |= CAN_MSR_ERRI; // clear flag bool cancel_queue = false; - if (CAN->ESR & CAN_ESR_EWGF) + if (can_->ESR & CAN_ESR_EWGF) { /* error warning condition */ state_ = CAN_STATE_BUS_WARNING; } - if (CAN->ESR & CAN_ESR_EPVF) + if (can_->ESR & CAN_ESR_EPVF) { /* error passive condition */ ++softErrorCount; state_ = CAN_STATE_BUS_PASSIVE; cancel_queue = true; } - if (CAN->ESR & CAN_ESR_BOFF) + if (can_->ESR & CAN_ESR_BOFF) { /* bus off error condition */ ++busOffCount; @@ -471,10 +539,10 @@ void Stm32Can::sce_interrupt_handler() } if (cancel_queue) { - CAN->TSR |= CAN_TSR_ABRQ2; - CAN->TSR |= CAN_TSR_ABRQ1; - CAN->TSR |= CAN_TSR_ABRQ0; - CAN->IER &= ~CAN_IER_TMEIE; + can_->TSR |= CAN_TSR_ABRQ2; + can_->TSR |= CAN_TSR_ABRQ1; + can_->TSR |= CAN_TSR_ABRQ0; + can_->IER &= ~CAN_IER_TMEIE; txBuf->flush(); txBuf->signal_condition_from_isr(); } @@ -509,6 +577,24 @@ void can1_sce_interrupt_handler(void) Stm32Can::instances[0]->sce_interrupt_handler(); } +#ifdef CAN2 +void usb_hp_can2_tx_interrupt_handler(void) +{ + Stm32Can::instances[1]->tx_interrupt_handler(); +} + +void usb_lp_can2_rx0_interrupt_handler(void) +{ + Stm32Can::instances[1]->rx_interrupt_handler(); +} + +void can2_sce_interrupt_handler(void) +{ + Stm32Can::instances[1]->sce_interrupt_handler(); +} + +#endif + #elif defined(STM32F767xx) || defined(STM32L431xx) || defined(STM32L432xx) void can1_tx_interrupt_handler(void) @@ -526,6 +612,39 @@ void can1_sce_interrupt_handler(void) Stm32Can::instances[0]->sce_interrupt_handler(); } +#ifdef CAN2 +void can2_tx_interrupt_handler(void) +{ + Stm32Can::instances[1]->tx_interrupt_handler(); +} + +void can2_rx0_interrupt_handler(void) +{ + Stm32Can::instances[1]->rx_interrupt_handler(); +} + +void can2_sce_interrupt_handler(void) +{ + Stm32Can::instances[1]->sce_interrupt_handler(); +} +#endif +#ifdef CAN3 +void can3_tx_interrupt_handler(void) +{ + Stm32Can::instances[2]->tx_interrupt_handler(); +} + +void can3_rx0_interrupt_handler(void) +{ + Stm32Can::instances[2]->rx_interrupt_handler(); +} + +void can3_sce_interrupt_handler(void) +{ + Stm32Can::instances[2]->sce_interrupt_handler(); +} +#endif + #else #error Dont know what STM32 chip you have. #endif diff --git a/src/freertos_drivers/st/Stm32Can.hxx b/src/freertos_drivers/st/Stm32Can.hxx index fb54c334a..3259d2f01 100644 --- a/src/freertos_drivers/st/Stm32Can.hxx +++ b/src/freertos_drivers/st/Stm32Can.hxx @@ -45,6 +45,12 @@ #include "stm32f_hal_conf.hxx" +// Max possible number of CAN ifs across the whole STM32 -- the constructor +// will calculate the actual max for the specific chip compiling for +#define MAXCANIFS 3 + +struct CAN_TypeDef; + /** Specialization of CAN driver for LPC17xx and LPC40xx CAN. */ class Stm32Can : public Can @@ -69,7 +75,7 @@ public: void sce_interrupt_handler(); /** Instance pointers help us get context from the interrupt handler(s) */ - static Stm32Can *instances[1]; + static Stm32Can *instances[MAXCANIFS]; private: #ifndef ARDUINO @@ -91,11 +97,17 @@ private: static unsigned int intCount; uint8_t state_; ///< present bus state - + + struct CAN_TypeDef *can_; + int can_irqn_; + int can_second_irqn_; + int can_third_irqn_; + /** Default constructor. */ Stm32Can(); - + + DISALLOW_COPY_AND_ASSIGN(Stm32Can); }; From 38941d21b286d5f204e4162a54be90a1b652437a Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Mon, 29 Apr 2024 21:23:58 -0400 Subject: [PATCH 02/10] Minor fixes (CAN_TypeDef decl). --- src/freertos_drivers/st/Stm32Can.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/freertos_drivers/st/Stm32Can.hxx b/src/freertos_drivers/st/Stm32Can.hxx index 3259d2f01..abfe092b2 100644 --- a/src/freertos_drivers/st/Stm32Can.hxx +++ b/src/freertos_drivers/st/Stm32Can.hxx @@ -49,7 +49,7 @@ // will calculate the actual max for the specific chip compiling for #define MAXCANIFS 3 -struct CAN_TypeDef; +//struct CAN_TypeDef; /** Specialization of CAN driver for LPC17xx and LPC40xx CAN. */ @@ -98,7 +98,7 @@ private: uint8_t state_; ///< present bus state - struct CAN_TypeDef *can_; + CAN_TypeDef *can_; int can_irqn_; int can_second_irqn_; int can_third_irqn_; From 97b0c9e7ab90e4989bf4ba0b3395e77354f56412 Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Tue, 30 Apr 2024 09:25:13 -0400 Subject: [PATCH 03/10] Minor fixes (typo). --- src/freertos_drivers/st/Stm32Can.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/freertos_drivers/st/Stm32Can.cxx b/src/freertos_drivers/st/Stm32Can.cxx index f2a7ad71e..17861a84f 100644 --- a/src/freertos_drivers/st/Stm32Can.cxx +++ b/src/freertos_drivers/st/Stm32Can.cxx @@ -152,7 +152,7 @@ Stm32Can::Stm32Can(const char *name) can_third_irqn_ = CAN1_THIRD_IRQN; #endif break; -#idef CAN2 +#ifdef CAN2 case 1: /* CAN2... */ can_ = CAN2; can_irqn_ = CAN2_IRQN; From 2944bd67cf26fd7d3de0148c1ee4ca5b53210ebe Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Tue, 30 Apr 2024 09:28:07 -0400 Subject: [PATCH 04/10] Minor fixes (IRQn_Type). --- src/freertos_drivers/st/Stm32Can.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/freertos_drivers/st/Stm32Can.hxx b/src/freertos_drivers/st/Stm32Can.hxx index abfe092b2..9f581aaec 100644 --- a/src/freertos_drivers/st/Stm32Can.hxx +++ b/src/freertos_drivers/st/Stm32Can.hxx @@ -99,9 +99,9 @@ private: uint8_t state_; ///< present bus state CAN_TypeDef *can_; - int can_irqn_; - int can_second_irqn_; - int can_third_irqn_; + IRQn_Type can_irqn_; + IRQn_Type can_second_irqn_; + IRQn_Type can_third_irqn_; /** Default constructor. */ From 85328ce041bdaab296630ebe96cc4863e30ad09a Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Tue, 30 Apr 2024 09:32:25 -0400 Subject: [PATCH 05/10] Minor fixes (L4 CAN1 def). --- src/freertos_drivers/st/Stm32Can.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/freertos_drivers/st/Stm32Can.cxx b/src/freertos_drivers/st/Stm32Can.cxx index 17861a84f..77b9bedf7 100644 --- a/src/freertos_drivers/st/Stm32Can.cxx +++ b/src/freertos_drivers/st/Stm32Can.cxx @@ -86,7 +86,9 @@ #define CAN1_IRQN CAN1_TX_IRQN #define CAN1_SECOND_IRQN CAN1_RX0_IRQn #define CAN1_THIRD_IRQN CAN1_SCE_IRQn +#ifndef CAN1 #define CAN1 CAN +#endif #define CAN_CLOCK (cm3_cpu_clock_hz) #elif defined (STM32F767xx) From f9a71b999ca02b69659350c241064f8f3e2b4cb4 Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Tue, 30 Apr 2024 09:36:08 -0400 Subject: [PATCH 06/10] Minor fixes (L4 CAN2 def). --- src/freertos_drivers/st/Stm32Can.cxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/freertos_drivers/st/Stm32Can.cxx b/src/freertos_drivers/st/Stm32Can.cxx index 77b9bedf7..f1351a624 100644 --- a/src/freertos_drivers/st/Stm32Can.cxx +++ b/src/freertos_drivers/st/Stm32Can.cxx @@ -86,11 +86,15 @@ #define CAN1_IRQN CAN1_TX_IRQN #define CAN1_SECOND_IRQN CAN1_RX0_IRQn #define CAN1_THIRD_IRQN CAN1_SCE_IRQn -#ifndef CAN1 -#define CAN1 CAN -#endif #define CAN_CLOCK (cm3_cpu_clock_hz) +#ifdef CAN2 +#define CAN2_TX_IRQN CAN2_TX_IRQn +#define CAN2_IRQN CAN2_TX_IRQN +#define CAN2_SECOND_IRQN CAN2_RX0_IRQn +#define CAN2_THIRD_IRQN CAN2_SCE_IRQn +#endif + #elif defined (STM32F767xx) #include "stm32f7xx_hal_cortex.h" From 0072cc8a30999b57937d6b2d4be32abcc3fdd870 Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Fri, 31 Jan 2025 15:59:55 -0500 Subject: [PATCH 07/10] Multiple CAN IFs on ST Micro MCUs. --- src/freertos_drivers/st/Stm32Can.cxx | 753 +++++++++++++++++++++++++++ src/freertos_drivers/st/Stm32Can.hxx | 120 +++++ 2 files changed, 873 insertions(+) create mode 100644 src/freertos_drivers/st/Stm32Can.cxx create mode 100644 src/freertos_drivers/st/Stm32Can.hxx diff --git a/src/freertos_drivers/st/Stm32Can.cxx b/src/freertos_drivers/st/Stm32Can.cxx new file mode 100644 index 000000000..14b9c6b2e --- /dev/null +++ b/src/freertos_drivers/st/Stm32Can.cxx @@ -0,0 +1,753 @@ +/** \copyright + * Copyright (c) 2015, Stuart W Baker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @file Stm32Can.cxx + * This file implements a can device driver layer specific to STM32F0xx devices. + * + * @author Stuart W. Baker + * @date 3 May 2015 + */ + +#if (!defined(ARDUINO)) || defined(ARDUINO_ARCH_STM32) + +#include "Stm32Can.hxx" + +#include +#include + +#include "can_ioctl.h" + +#include "stm32f_hal_conf.hxx" + +#if defined (STM32F072xB) || defined (STM32F091xC) + +#include "stm32f0xx_hal_cortex.h" +#define CAN1_IRQN CEC_CAN_IRQn +#define CAN1 CAN +#define CAN_CLOCK cpu_clock_hz + +#elif defined (STM32F103xB) + +#include "stm32f1xx_hal_cortex.h" +#define SPLIT_INT +#define CAN1_TX_IRQN USB_HP_CAN1_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN USB_LP_CAN1_RX0_IRQn +#define CAN1_THIRD_IRQN CAN1_SCE_IRQn + +#ifdef CAN2 +#define CAN2_TX_IRQN USB_HP_CAN2_TX_IRQn +#define CAN2_IRQN CAN2_TX_IRQN +#define CAN2_SECOND_IRQN USB_LP_CAN2_RX0_IRQn +#define CAN2_THIRD_IRQN CAN2_SCE_IRQn +#endif + +#define CAN_CLOCK (cm3_cpu_clock_hz >> 1) + +#elif defined (STM32F303xC) || defined (STM32F303xE) + +#include "stm32f3xx_hal_cortex.h" +#define SPLIT_INT +#define CAN1_TX_IRQN USB_HP_CAN_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN USB_LP_CAN_RX0_IRQn +#define CAN1_THIRD_IRQN CAN_SCE_IRQn +#define CAN1 CAN +#define CAN_CLOCK (cm3_cpu_clock_hz >> 1) + +#elif defined (STM32L431xx) || defined (STM32L432xx) + +#include "stm32l4xx_hal_cortex.h" +#define SPLIT_INT +#define CAN1_TX_IRQN CAN1_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN CAN1_RX0_IRQn +#define CAN1_THIRD_IRQN CAN1_SCE_IRQn +#define CAN_CLOCK (cm3_cpu_clock_hz) + +#ifdef CAN2 +#define CAN2_TX_IRQN CAN2_TX_IRQn +#define CAN2_IRQN CAN2_TX_IRQN +#define CAN2_SECOND_IRQN CAN2_RX0_IRQn +#define CAN2_THIRD_IRQN CAN2_SCE_IRQn +#endif + +#elif defined (STM32F767xx) + +#include "stm32f7xx_hal_cortex.h" +#define SPLIT_INT +#define CAN1_TX_IRQN CAN1_TX_IRQn +#define CAN1_IRQN CAN1_TX_IRQN +#define CAN1_SECOND_IRQN CAN1_RX0_IRQn +#define CAN1_THIRD_IRQN CAN1_SCE_IRQn +#define CAN_CLOCK (cm3_cpu_clock_hz >> 2) // 54 MHz, sysclk/4 + +#ifdef CAN2 +#define CAN2_TX_IRQN CAN2_TX_IRQn +#define CAN2_IRQN CAN2_TX_IRQN +#define CAN2_SECOND_IRQN CAN2_RX0_IRQn +#define CAN2_THIRD_IRQN CAN2_SCE_IRQn +#endif + +#ifdef CAN3 +#define CAN3_TX_IRQN CAN3_TX_IRQn +#define CAN3_IRQN CAN3_TX_IRQN +#define CAN3_SECOND_IRQN CAN3_RX0_IRQn +#define CAN3_THIRD_IRQN CAN3_SCE_IRQn +#endif + +#else +#error Dont know what STM32 chip you have. +#endif + +Stm32Can *Stm32Can::instances[MAXCANIFS] = {NULL,NULL,NULL}; + +/** Constructor. + * @param name name of this device instance in the file system + */ +Stm32Can::Stm32Can(const char *name) + : Can(name) + , state_(CAN_STATE_STOPPED) +{ + /* Get dev num (digit at the end of the devname). */ + char dev = name[strlen(name)-1]; + HASSERT(dev >= '0'); + int index = dev - '0'; +#if defined(CAN3) + HASSERT(index < 3); +#elif defined(CAN2) + HASSERT(index < 2); +#else + HASSERT(index < 1); +#endif + + /* only one instance per interface allowed */ + HASSERT(instances[index] == NULL); + + instances[index] = this; + switch (index) + { + case 0: /* CAN1... */ + can_ = CAN1; + can_irqn_ = CAN1_IRQN; +#ifdef SPLIT_INT + can_second_irqn_ = CAN1_SECOND_IRQN; + can_third_irqn_ = CAN1_THIRD_IRQN; +#endif + break; +#ifdef CAN2 + case 1: /* CAN2... */ + can_ = CAN2; + can_irqn_ = CAN2_IRQN; +#ifdef SPLIT_INT + can_second_irqn_ = CAN2_SECOND_IRQN; + can_third_irqn_ = CAN2_THIRD_IRQN; +#endif + break; +#endif +#ifdef CAN3 + case 2: /* CAN3... */ + can_ = CAN3; + can_irqn_ = CAN3_IRQN; +#ifdef SPLIT_INT + can_second_irqn_ = CAN3_SECOND_IRQN; + can_third_irqn_ = CAN3_THIRD_IRQN; +#endif + break; +#endif + default: + break; + } + + /* should already be disabled, but just in case */ + HAL_NVIC_DisableIRQ(can_irqn_); + +#if defined (STM32F030x6) || defined (STM32F031x6) || defined (STM32F038xx) \ + || defined (STM32F030x8) || defined (STM32F030xC) || defined (STM32F042x6) \ + || defined (STM32F048xx) || defined (STM32F051x8) || defined (STM32F058xx) \ + || defined (STM32F070x6) || defined (STM32F070xB) || defined (STM32F071xB) \ + || defined (STM32F072xB) || defined (STM32F078xx) \ + || defined (STM32F091xC) || defined (STM32F098xx) +#else + /* The priority of CAN interrupt is as high as possible while maintaining + * FreeRTOS compatibility. + */ + SetInterruptPriority(can_irqn_, configKERNEL_INTERRUPT_PRIORITY); + +#ifdef SPLIT_INT + HAL_NVIC_DisableIRQ(can_second_irqn_); + SetInterruptPriority(can_second_irqn_, configKERNEL_INTERRUPT_PRIORITY); + HAL_NVIC_DisableIRQ(can_third_irqn_); + SetInterruptPriority(can_third_irqn_, configKERNEL_INTERRUPT_PRIORITY); +#endif +#endif +} + +#if !defined(ARDUINO) +// +// Stm32Can::ioctl() +// +int Stm32Can::ioctl(File *file, unsigned long int key, unsigned long data) +{ + if (key == SIOCGCANSTATE) + { + *((can_state_t*)data) = state_; + return 0; + } + return -EINVAL; +} +#endif // !ARDUINO + +/** Enable use of the device. + */ +void Stm32Can::enable() +{ + /* disable sleep, enter init mode */ + can_->MCR = CAN_MCR_INRQ; + + /* Time triggered tranmission off + * Bus off state is left automatically + * Auto-Wakeup mode disabled + * automatic re-transmission enabled + * receive FIFO not locked on overrun + * TX FIFO mode on + */ + can_->MCR |= (CAN_MCR_ABOM | CAN_MCR_TXFP); + + /* Setup timing. + * 125,000 Kbps = 8 usec/bit + */ + can_->BTR = (CAN_BS1_5TQ | CAN_BS2_2TQ | CAN_SJW_1TQ | + ((CAN_CLOCK / 1000000) - 1)); + + /* enter normal mode */ + can_->MCR &= ~CAN_MCR_INRQ; + + /* Enter filter initialization mode. Filter 0 will be used as a single + * 32-bit filter, ID Mask Mode, we accept everything, no mask. + */ + can_->FMR |= CAN_FMR_FINIT; + can_->FM1R = 0; + can_->FS1R = 0x000000001; + can_->FFA1R = 0; + can_->sFilterRegister[0].FR1 = 0; + can_->sFilterRegister[0].FR2 = 0; + + /* Activeate filter and exit initialization mode. */ + can_->FA1R = 0x000000001; + can_->FMR &= ~CAN_FMR_FINIT; + + state_ = CAN_STATE_ACTIVE; + + /* enable interrupts */ + can_->IER = (CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE); // errors + can_->IER |= (CAN_IER_ERRIE | CAN_IER_FMPIE0); // error + receive + HAL_NVIC_EnableIRQ(can_irqn_); +#ifdef SPLIT_INT + HAL_NVIC_EnableIRQ(can_second_irqn_); + HAL_NVIC_EnableIRQ(can_third_irqn_); +#endif +} + +/** Disable use of the device. + */ +void Stm32Can::disable() +{ + HAL_NVIC_DisableIRQ(can_irqn_); +#ifdef SPLIT_INT + HAL_NVIC_DisableIRQ(can_second_irqn_); + HAL_NVIC_DisableIRQ(can_third_irqn_); +#endif + can_->IER = 0; + + state_ = CAN_STATE_STOPPED; + + /* disable sleep, enter init mode */ + can_->MCR = CAN_MCR_INRQ; +} + +/* Try and transmit a message. + */ +void Stm32Can::tx_msg() +{ + // If we are error passive, the last transmission ended with an error, and + // there are no free TX mailboxes, then we flush the input queue. This is a + // workaround because the STM32 CAN controller can get stuck in this state + // and never get to bus off if the TX attempts end up with no-ack (meaning + // the controller is alone on the bus). + if ((can_->ESR & CAN_ESR_EPVF) && ((can_->ESR & CAN_ESR_LEC_Msk) != 0) && + ((can_->TSR & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)) == 0)) + { + txBuf->flush(); + txBuf->signal_condition(); + return; + } + + /* see if we can send anything out */ + struct can_frame *can_frame; + + size_t msg_count = txBuf->data_read_pointer(&can_frame); + unsigned i; + + for (i = 0; i < msg_count; ++i, ++can_frame) + { + volatile CAN_TxMailBox_TypeDef *mailbox; + if (can_->TSR & CAN_TSR_TME0) + { + mailbox = can_->sTxMailBox + 0; + } + else if (can_->TSR & CAN_TSR_TME1) + { + mailbox = can_->sTxMailBox + 1; + } + else if (can_->TSR & CAN_TSR_TME2) + { + mailbox = can_->sTxMailBox + 2; + } + else + { + /* no empty mailboxes left to fill */ + break; + } + + /* setup frame */ + if (can_frame->can_eff) + { + mailbox->TIR = (can_frame->can_id << 3) | CAN_TI0R_IDE; + } + else + { + mailbox->TIR = can_frame->can_id << 21; + } + if (can_frame->can_rtr) + { + mailbox->TIR |= CAN_TI0R_RTR; + } + else + { + mailbox->TDTR = can_frame->can_dlc; + mailbox->TDLR = (can_frame->data[0] << 0) | + (can_frame->data[1] << 8) | + (can_frame->data[2] << 16) | + (can_frame->data[3] << 24); + mailbox->TDHR = (can_frame->data[4] << 0) | + (can_frame->data[5] << 8) | + (can_frame->data[6] << 16) | + (can_frame->data[7] << 24); + } + + /* request transmission */ + mailbox->TIR |= CAN_TI0R_TXRQ; + } + + if (i) + { + txBuf->consume(i); + txBuf->signal_condition(); + } + + /* enable transmit interrupt */ + can_->IER |= CAN_IER_TMEIE; +} + +/** Handle an interrupt. + */ +void Stm32Can::rx_interrupt_handler() +{ + unsigned msg_receive_count = 0; + + while (can_->RF0R & CAN_RF0R_FMP0) + { + /* rx data received */ + struct can_frame *can_frame; + size_t msg_count = rxBuf->data_write_pointer(&can_frame); + if (msg_count) + { + if (can_->sFIFOMailBox[0].RIR & CAN_RI0R_IDE) + { + /* extended frame */ + can_frame->can_id = can_->sFIFOMailBox[0].RIR >> 3; + can_frame->can_eff = 1; + } + else + { + /* standard frame */ + can_frame->can_id = can_->sFIFOMailBox[0].RIR >> 21; + can_frame->can_eff = 0; + } + if (can_->sFIFOMailBox[0].RIR & CAN_RI0R_RTR) + { + /* remote frame */ + can_frame->can_rtr = 1; + can_frame->can_dlc = 0; + } + else + { + /* data frame */ + can_frame->can_rtr = 0; + can_frame->can_dlc = can_->sFIFOMailBox[0].RDTR & CAN_RDT0R_DLC; + can_frame->data[0] = (can_->sFIFOMailBox[0].RDLR >> 0) & 0xFF; + can_frame->data[1] = (can_->sFIFOMailBox[0].RDLR >> 8) & 0xFF; + can_frame->data[2] = (can_->sFIFOMailBox[0].RDLR >> 16) & 0xFF; + can_frame->data[3] = (can_->sFIFOMailBox[0].RDLR >> 24) & 0xFF; + can_frame->data[4] = (can_->sFIFOMailBox[0].RDHR >> 0) & 0xFF; + can_frame->data[5] = (can_->sFIFOMailBox[0].RDHR >> 8) & 0xFF; + can_frame->data[6] = (can_->sFIFOMailBox[0].RDHR >> 16) & 0xFF; + can_frame->data[7] = (can_->sFIFOMailBox[0].RDHR >> 24) & 0xFF; + } + } + else + { + ++overrunCount; + } + /* release FIFO */ + can_->RF0R |= CAN_RF0R_RFOM0; + ++msg_receive_count; + } + + if (msg_receive_count) + { + /* advance the "zero copy" buffer by the number of messages received */ + rxBuf->advance(msg_receive_count); + rxBuf->signal_condition_from_isr(); + state_ = CAN_STATE_ACTIVE; + } +} + +void Stm32Can::tx_interrupt_handler() +{ + if (can_->TSR & (CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2)) + { + /* transmit request completed, should be able to send another */ + struct can_frame *can_frame; + + size_t msg_count = txBuf->data_read_pointer(&can_frame); + if (msg_count) + { + /* try and send some more CAN frames */ + unsigned i; + + for (i = 0; i < msg_count; ++i, ++can_frame) + { + volatile CAN_TxMailBox_TypeDef *mailbox; + if (can_->TSR & CAN_TSR_TME0) + { + mailbox = can_->sTxMailBox + 0; + } + else if (can_->TSR & CAN_TSR_TME1) + { + mailbox = can_->sTxMailBox + 1; + } + else if (can_->TSR & CAN_TSR_TME2) + { + mailbox = can_->sTxMailBox + 2; + } + else + { + /* no empty mailboxes left to fill */ + break; + } + + /* setup frame */ + if (can_frame->can_eff) + { + mailbox->TIR = (can_frame->can_id << 3) | CAN_TI0R_IDE; + } + else + { + mailbox->TIR = can_frame->can_id << 21; + } + if (can_frame->can_rtr) + { + mailbox->TIR |= CAN_TI0R_RTR; + } + else + { + mailbox->TDTR = can_frame->can_dlc; + mailbox->TDLR = (can_frame->data[0] << 0) | + (can_frame->data[1] << 8) | + (can_frame->data[2] << 16) | + (can_frame->data[3] << 24); + mailbox->TDHR = (can_frame->data[4] << 0) | + (can_frame->data[5] << 8) | + (can_frame->data[6] << 16) | + (can_frame->data[7] << 24); + } + + /* request transmission */ + mailbox->TIR |= CAN_TI0R_TXRQ; + } + txBuf->consume(i); + } + else + { + /* no more data left to transmit */ + can_->IER &= ~CAN_IER_TMEIE; + } + txBuf->signal_condition_from_isr(); + state_ = CAN_STATE_ACTIVE; + } +} + +/* + * Stm32Can::sce_interrupt_handler() + */ +void Stm32Can::sce_interrupt_handler() +{ + if (can_->MSR & CAN_MSR_ERRI) + { + /* error interrupt has occured */ + can_->MSR |= CAN_MSR_ERRI; // clear flag + + bool cancel_queue = false; + + if (can_->ESR & CAN_ESR_EWGF) + { + /* error warning condition */ + state_ = CAN_STATE_BUS_WARNING; + } + if (can_->ESR & CAN_ESR_EPVF) + { + /* error passive condition */ + ++softErrorCount; + state_ = CAN_STATE_BUS_PASSIVE; + cancel_queue = true; + } + if (can_->ESR & CAN_ESR_BOFF) + { + /* bus off error condition */ + ++busOffCount; + state_ = CAN_STATE_BUS_OFF; + cancel_queue = true; + } + if (cancel_queue) + { + can_->TSR |= CAN_TSR_ABRQ2; + can_->TSR |= CAN_TSR_ABRQ1; + can_->TSR |= CAN_TSR_ABRQ0; + can_->IER &= ~CAN_IER_TMEIE; + txBuf->flush(); + txBuf->signal_condition_from_isr(); + } + } +} + +extern "C" { +/** This is the interrupt handler for the can device. + */ + +//---------------------------------------------------------------------------- +// +// F072xB & F091xC +// +//---------------------------------------------------------------------------- + +#if defined (STM32F072xB) || defined (STM32F091xC) +void cec_can_interrupt_handler(void) +{ + Stm32Can::instances[0]->rx_interrupt_handler(); + Stm32Can::instances[0]->tx_interrupt_handler(); + Stm32Can::instances[0]->sce_interrupt_handler(); +} +#elif defined (STM32F103xB) || defined (STM32F303xC) || defined (STM32F303xE) +//---------------------------------------------------------------------------- +// +// F103xB, F303xC and F303E +// +//---------------------------------------------------------------------------- + +void usb_hp_can1_tx_interrupt_handler(void) +{ + Stm32Can::instances[0]->tx_interrupt_handler(); +} + +void usb_lp_can1_rx0_interrupt_handler(void) +{ + Stm32Can::instances[0]->rx_interrupt_handler(); +} + +void can1_sce_interrupt_handler(void) +{ + Stm32Can::instances[0]->sce_interrupt_handler(); +} + +#ifdef CAN2 +void usb_hp_can2_tx_interrupt_handler(void) +{ + Stm32Can::instances[1]->tx_interrupt_handler(); +} + +void usb_lp_can2_rx0_interrupt_handler(void) +{ + Stm32Can::instances[1]->rx_interrupt_handler(); +} + +void can2_sce_interrupt_handler(void) +{ + Stm32Can::instances[1]->sce_interrupt_handler(); +} + +#endif + +#elif defined(STM32F767xx) || defined(STM32L431xx) || defined(STM32L432xx) +//---------------------------------------------------------------------------- +// +// F767xx L431xx & L432xx +// +//---------------------------------------------------------------------------- + +void can1_tx_interrupt_handler(void) +{ + Stm32Can::instances[0]->tx_interrupt_handler(); +} + +void can1_rx0_interrupt_handler(void) +{ + Stm32Can::instances[0]->rx_interrupt_handler(); +} + +void can1_sce_interrupt_handler(void) +{ + Stm32Can::instances[0]->sce_interrupt_handler(); +} + +<<<<<<< HEAD +#ifdef CAN2 +void can2_tx_interrupt_handler(void) +{ + Stm32Can::instances[1]->tx_interrupt_handler(); +} + +void can2_rx0_interrupt_handler(void) +{ + Stm32Can::instances[1]->rx_interrupt_handler(); +} + +void can2_sce_interrupt_handler(void) +{ + Stm32Can::instances[1]->sce_interrupt_handler(); +} +#endif +#ifdef CAN3 +void can3_tx_interrupt_handler(void) +{ + Stm32Can::instances[2]->tx_interrupt_handler(); +} + +void can3_rx0_interrupt_handler(void) +{ + Stm32Can::instances[2]->rx_interrupt_handler(); +} + +void can3_sce_interrupt_handler(void) +{ + Stm32Can::instances[2]->sce_interrupt_handler(); +} +#endif +======= +>>>>>>> e35c58d4aba4b9d5a4dc355684a2eb1c87008f01 + +#else +#error Dont know what STM32 chip you have. +#endif + +} // extern "C" + +#endif // !ARDUINO + +#if defined(ARDUINO_ARCH_STM32) + +#include "stm32_def.h" +#include "PinAF_STM32F1.h" +#include + +void arduino_can_pinmap(PinName tx_pin, PinName rx_pin) { + __HAL_RCC_CAN1_CLK_ENABLE(); + void* can_tx = pinmap_peripheral(tx_pin, PinMap_CAN_TD); + void* can_rx = pinmap_peripheral(rx_pin, PinMap_CAN_RD); + void* can = pinmap_merge_peripheral(can_tx, can_rx); + if (can == NP) { + DIE("Could not find CAN peripheral"); + } + + GPIO_InitTypeDef GPIO_InitStruct; + + GPIO_InitStruct.Pin = STM_GPIO_PIN(tx_pin); + auto fn = pinmap_function(tx_pin, PinMap_CAN_TD); + GPIO_InitStruct.Mode = STM_PIN_MODE(fn); + GPIO_InitStruct.Pull = STM_PIN_PUPD(fn); + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; +#ifdef STM32F1xx + pin_SetF1AFPin(STM_PIN_AFNUM(fn)); +#else + GPIO_InitStruct.Alternate = STM_PIN_AFNUM(fn); +#endif /* STM32F1xx */ + HAL_GPIO_Init(set_GPIO_Port_Clock(STM_PORT(tx_pin)), &GPIO_InitStruct); + + GPIO_InitStruct.Pin = STM_GPIO_PIN(rx_pin); + fn = pinmap_function(rx_pin, PinMap_CAN_RD); + GPIO_InitStruct.Mode = STM_PIN_MODE(fn); + GPIO_InitStruct.Pull = STM_PIN_PUPD(fn); + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; +#ifdef STM32F1xx + pin_SetF1AFPin(STM_PIN_AFNUM(fn)); +#else + GPIO_InitStruct.Alternate = STM_PIN_AFNUM(fn); +#endif /* STM32F1xx */ + HAL_GPIO_Init(set_GPIO_Port_Clock(STM_PORT(rx_pin)), &GPIO_InitStruct); +} + +extern "C" { +void USB_HP_CAN_TX_IRQHandler(void) +{ + Stm32Can::instances[0]->tx_interrupt_handler(); +} + +void USB_LP_CAN_RX0_IRQHandler(void) +{ + Stm32Can::instances[0]->rx_interrupt_handler(); +} +void CEC_CAN_IRQHandler(void) +{ + Stm32Can::instances[0]->rx_interrupt_handler(); + Stm32Can::instances[0]->tx_interrupt_handler(); + Stm32Can::instances[0]->sce_interrupt_handler(); +} +void CAN1_TX_IRQHandler(void) +{ + Stm32Can::instances[0]->tx_interrupt_handler(); +} +void CAN1_RX0_IRQHandler(void) +{ + Stm32Can::instances[0]->rx_interrupt_handler(); +} +void CAN1_SCE_IRQHandler(void) +{ + Stm32Can::instances[0]->sce_interrupt_handler(); +} +} // extern "C" + +#endif // ARDUINO_ARCH_STM32 diff --git a/src/freertos_drivers/st/Stm32Can.hxx b/src/freertos_drivers/st/Stm32Can.hxx new file mode 100644 index 000000000..9f581aaec --- /dev/null +++ b/src/freertos_drivers/st/Stm32Can.hxx @@ -0,0 +1,120 @@ +/** \copyright + * Copyright (c) 2015, Stuart W Baker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @file Stm32Can.hxx + * This file implements a can device driver layer specific to STM32F0xx devices. + * + * @author Stuart W. Baker + * @date 3 May 2015 + */ + +#ifndef _FREERTOS_DRIVERS_ST_STM32F0XXCAN_HXX_ +#define _FREERTOS_DRIVERS_ST_STM32F0XXCAN_HXX_ + +#include + +#ifdef ARDUINO +#include +#include "freertos_drivers/arduino/Can.hxx" +#else +#include "freertos_drivers/common/Can.hxx" +#endif + +#include "stm32f_hal_conf.hxx" + +// Max possible number of CAN ifs across the whole STM32 -- the constructor +// will calculate the actual max for the specific chip compiling for +#define MAXCANIFS 3 + +//struct CAN_TypeDef; + +/** Specialization of CAN driver for LPC17xx and LPC40xx CAN. + */ +class Stm32Can : public Can +{ +public: + /** Constructor. + * @param name name of this device instance in the file system + */ + Stm32Can(const char *name); + + /** Destructor. + */ + ~Stm32Can() + { + } + + /** Handle an interrupt. */ + void rx_interrupt_handler(); + /** Handle an interrupt. */ + void tx_interrupt_handler(); + /** Handle an interrupt. */ + void sce_interrupt_handler(); + + /** Instance pointers help us get context from the interrupt handler(s) */ + static Stm32Can *instances[MAXCANIFS]; + +private: +#ifndef ARDUINO + /// Request an ioctl transaction. + /// @param file file reference for this device + /// @param key ioctl key + /// @param data key data + /// @return >= 0 upon success, -errno upon failure + int ioctl(File *file, unsigned long int key, unsigned long data) override; +#endif + + void enable() override; /**< function to enable device */ + void disable() override; /**< function to disable device */ + void tx_msg() override; /**< function to try and transmit a message */ + + /** one interrupt vector is shared between two CAN controllers, so we need + * to keep track of the number of controllers in use. + */ + static unsigned int intCount; + + uint8_t state_; ///< present bus state + + CAN_TypeDef *can_; + IRQn_Type can_irqn_; + IRQn_Type can_second_irqn_; + IRQn_Type can_third_irqn_; + + /** Default constructor. + */ + Stm32Can(); + + + DISALLOW_COPY_AND_ASSIGN(Stm32Can); +}; + +#ifdef ARDUINO + +extern void arduino_can_pinmap(PinName tx_pin, PinName rx_pin); + +#endif + +#endif /* _FREERTOS_DRIVERS_ST_STM32F0XXCAN_HXX_ */ From d2c0a1f18b0b650cc7442e1b7d9cb0f9bf00fd0c Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Fri, 31 Jan 2025 17:30:47 -0500 Subject: [PATCH 08/10] Fix git merge artifacts. --- src/freertos_drivers/st/Stm32Can.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/freertos_drivers/st/Stm32Can.cxx b/src/freertos_drivers/st/Stm32Can.cxx index 14b9c6b2e..516c6d660 100644 --- a/src/freertos_drivers/st/Stm32Can.cxx +++ b/src/freertos_drivers/st/Stm32Can.cxx @@ -634,7 +634,6 @@ void can1_sce_interrupt_handler(void) Stm32Can::instances[0]->sce_interrupt_handler(); } -<<<<<<< HEAD #ifdef CAN2 void can2_tx_interrupt_handler(void) { @@ -667,8 +666,6 @@ void can3_sce_interrupt_handler(void) Stm32Can::instances[2]->sce_interrupt_handler(); } #endif -======= ->>>>>>> e35c58d4aba4b9d5a4dc355684a2eb1c87008f01 #else #error Dont know what STM32 chip you have. From 13ed5588ddab942d4cef2e82e9c7be9471cad670 Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Sat, 8 Feb 2025 08:31:36 -0500 Subject: [PATCH 09/10] Fixed formatting, added comments, and added a constructor parameter to select the IF, instead of using the pathname. --- src/freertos_drivers/st/Stm32Can.cxx | 47 +++++++++++++--------------- src/freertos_drivers/st/Stm32Can.hxx | 19 +++++------ 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/freertos_drivers/st/Stm32Can.cxx b/src/freertos_drivers/st/Stm32Can.cxx index 516c6d660..05dba02ee 100644 --- a/src/freertos_drivers/st/Stm32Can.cxx +++ b/src/freertos_drivers/st/Stm32Can.cxx @@ -36,7 +36,6 @@ #include "Stm32Can.hxx" #include -#include #include "can_ioctl.h" @@ -128,14 +127,10 @@ Stm32Can *Stm32Can::instances[MAXCANIFS] = {NULL,NULL,NULL}; /** Constructor. * @param name name of this device instance in the file system */ -Stm32Can::Stm32Can(const char *name) +Stm32Can::Stm32Can(const char *name, uint8_t index) : Can(name) , state_(CAN_STATE_STOPPED) { - /* Get dev num (digit at the end of the devname). */ - char dev = name[strlen(name)-1]; - HASSERT(dev >= '0'); - int index = dev - '0'; #if defined(CAN3) HASSERT(index < 3); #elif defined(CAN2) @@ -150,36 +145,36 @@ Stm32Can::Stm32Can(const char *name) instances[index] = this; switch (index) { - case 0: /* CAN1... */ - can_ = CAN1; - can_irqn_ = CAN1_IRQN; + case 0: /* CAN1... */ + can_ = CAN1; + can_irqn_ = CAN1_IRQN; #ifdef SPLIT_INT - can_second_irqn_ = CAN1_SECOND_IRQN; - can_third_irqn_ = CAN1_THIRD_IRQN; + can_second_irqn_ = CAN1_SECOND_IRQN; + can_third_irqn_ = CAN1_THIRD_IRQN; #endif - break; + break; #ifdef CAN2 - case 1: /* CAN2... */ - can_ = CAN2; - can_irqn_ = CAN2_IRQN; + case 1: /* CAN2... */ + can_ = CAN2; + can_irqn_ = CAN2_IRQN; #ifdef SPLIT_INT - can_second_irqn_ = CAN2_SECOND_IRQN; - can_third_irqn_ = CAN2_THIRD_IRQN; + can_second_irqn_ = CAN2_SECOND_IRQN; + can_third_irqn_ = CAN2_THIRD_IRQN; #endif - break; + break; #endif #ifdef CAN3 - case 2: /* CAN3... */ - can_ = CAN3; - can_irqn_ = CAN3_IRQN; + case 2: /* CAN3... */ + can_ = CAN3; + can_irqn_ = CAN3_IRQN; #ifdef SPLIT_INT - can_second_irqn_ = CAN3_SECOND_IRQN; - can_third_irqn_ = CAN3_THIRD_IRQN; + can_second_irqn_ = CAN3_SECOND_IRQN; + can_third_irqn_ = CAN3_THIRD_IRQN; #endif - break; + break; #endif - default: - break; + default: + break; } /* should already be disabled, but just in case */ diff --git a/src/freertos_drivers/st/Stm32Can.hxx b/src/freertos_drivers/st/Stm32Can.hxx index 9f581aaec..207375945 100644 --- a/src/freertos_drivers/st/Stm32Can.hxx +++ b/src/freertos_drivers/st/Stm32Can.hxx @@ -45,12 +45,10 @@ #include "stm32f_hal_conf.hxx" -// Max possible number of CAN ifs across the whole STM32 -- the constructor -// will calculate the actual max for the specific chip compiling for +/// Max possible number of CAN ifs across the whole STM32 -- the constructor +/// will calculate the actual max for the specific chip compiling for #define MAXCANIFS 3 -//struct CAN_TypeDef; - /** Specialization of CAN driver for LPC17xx and LPC40xx CAN. */ class Stm32Can : public Can @@ -59,7 +57,7 @@ public: /** Constructor. * @param name name of this device instance in the file system */ - Stm32Can(const char *name); + Stm32Can(const char *name, uint8_t index = 0); /** Destructor. */ @@ -98,13 +96,12 @@ private: uint8_t state_; ///< present bus state - CAN_TypeDef *can_; - IRQn_Type can_irqn_; - IRQn_Type can_second_irqn_; - IRQn_Type can_third_irqn_; + CAN_TypeDef *can_; ///< CAN hardware registers for this instance (defined in the SDK). + IRQn_Type can_irqn_; ///< CAN IRQn for this instance. + IRQn_Type can_second_irqn_; ///< CAN Second IRQn (if used) for this instance. + IRQn_Type can_third_irqn_; ///< CAN Third IRQn (if used) for this instance. - /** Default constructor. - */ + /** Default constructor. */ Stm32Can(); From 240b59e1924e98537729fc0f2976942040a9dd85 Mon Sep 17 00:00:00 2001 From: Robert Heller Date: Mon, 10 Feb 2025 16:17:21 -0500 Subject: [PATCH 10/10] Fixed formatting, added comments, and added a constructor parameter to select the IF, instead of using the pathname. --- src/freertos_drivers/st/Stm32Can.hxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/freertos_drivers/st/Stm32Can.hxx b/src/freertos_drivers/st/Stm32Can.hxx index 207375945..14e2a6c85 100644 --- a/src/freertos_drivers/st/Stm32Can.hxx +++ b/src/freertos_drivers/st/Stm32Can.hxx @@ -104,7 +104,6 @@ private: /** Default constructor. */ Stm32Can(); - DISALLOW_COPY_AND_ASSIGN(Stm32Can); };