Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STM32 CAN Error Handling #644

Merged
merged 7 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 86 additions & 25 deletions src/freertos_drivers/st/Stm32Can.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@

#include <stdint.h>

#include "can_ioctl.h"

#include "stm32f_hal_conf.hxx"

#if defined (STM32F072xB) || defined (STM32F091xC)
Expand All @@ -53,6 +55,7 @@
#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 CAN_CLOCK (cm3_cpu_clock_hz >> 1)

Expand All @@ -63,6 +66,7 @@
#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 CAN1_SCE_IRQn
#define CAN_CLOCK (cm3_cpu_clock_hz >> 1)

#elif defined (STM32L431xx) || defined (STM32L432xx)
Expand All @@ -72,6 +76,7 @@
#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 CAN_CLOCK (cm3_cpu_clock_hz)

#elif defined (STM32F767xx)
Expand All @@ -82,6 +87,7 @@
#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 CAN_CLOCK (cm3_cpu_clock_hz >> 2) // 54 MHz, sysclk/4

#else
Expand All @@ -95,6 +101,7 @@ Stm32Can *Stm32Can::instances[1] = {NULL};
*/
Stm32Can::Stm32Can(const char *name)
: Can(name)
, state_(CAN_STATE_STOPPED)
{
/* only one instance allowed */
HASSERT(instances[0] == NULL);
Expand All @@ -119,10 +126,25 @@ Stm32Can::Stm32Can(const char *name)
#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
bakerstu marked this conversation as resolved.
Show resolved Hide resolved
}

//
// 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;
}

/** Enable use of the device.
*/
void Stm32Can::enable()
Expand Down Expand Up @@ -162,11 +184,15 @@ void Stm32Can::enable()
CAN->FA1R = 0x000000001;
CAN->FMR &= ~CAN_FMR_FINIT;

state_ = CAN_STATE_ACTIVE;

/* enable interrupts */
CAN->IER = (/*CAN_IER_ERRIE |*/ CAN_IER_BOFIE | CAN_IER_FMPIE0);
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
}

Expand All @@ -177,9 +203,12 @@ 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;
}
Expand Down Expand Up @@ -261,30 +290,6 @@ void Stm32Can::rx_interrupt_handler()
{
unsigned msg_receive_count = 0;

if (CAN->ESR & CAN_ESR_BOFF)
{
/* bus off error condition */
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();
}
#if 0
if (CAN->MSR & CAN_MSR_ERRI)
{
/* error condition */
CAN->TSR |= CAN_TSR_ABRQ2;
CAN->TSR |= CAN_TSR_ABRQ1;
CAN->TSR |= CAN_TSR_ABRQ0;
CAN->IER &= ~CAN_IER_TMEIE;
CAN->MSR &= ~CAN_MSR_ERRI;
txBuf->flush();
txBuf->signal_condition_from_isr();
++softErrorCount;
}
#endif
while (CAN->RF0R & CAN_RF0R_FMP0)
{
/* rx data received */
Expand Down Expand Up @@ -339,6 +344,7 @@ void Stm32Can::rx_interrupt_handler()
/* 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;
}
}

Expand Down Expand Up @@ -413,9 +419,48 @@ void Stm32Can::tx_interrupt_handler()
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
balazsracz marked this conversation as resolved.
Show resolved Hide resolved

if (CAN->ESR & CAN_ESR_EWGF)
{
/* error warning condition */
state_ = CAN_STATE_BUS_WARNING;
CAN->ESR &= ~CAN_ESR_EWGF;
}
if (CAN->ESR & CAN_ESR_EPVF)
{
/* error passive condition */
++softErrorCount;
state_ = CAN_STATE_BUS_PASSIVE;
CAN->ESR &= ~CAN_ESR_EPVF;
}
if (CAN->ESR & CAN_ESR_BOFF)
{
/* bus off error condition */
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();
++busOffCount;
state_ = CAN_STATE_BUS_OFF;
CAN->ESR &= ~CAN_ESR_BOFF;
}
}
}

extern "C" {
/** This is the interrupt handler for the can device.
Expand All @@ -426,6 +471,7 @@ 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)

Expand All @@ -439,6 +485,11 @@ 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();
}

#elif defined(STM32F767xx) || defined(STM32L431xx) || defined(STM32L432xx)

void can1_tx_interrupt_handler(void)
Expand All @@ -451,6 +502,11 @@ void can1_rx0_interrupt_handler(void)
Stm32Can::instances[0]->rx_interrupt_handler();
}

void can1_sce_interrupt_handler(void)
{
Stm32Can::instances[0]->sce_interrupt_handler();
}

#else
#error Dont know what STM32 chip you have.
#endif
Expand Down Expand Up @@ -515,6 +571,7 @@ 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)
{
Expand All @@ -524,6 +581,10 @@ 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
Expand Down
11 changes: 11 additions & 0 deletions src/freertos_drivers/st/Stm32Can.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,20 @@ public:
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[1];

private:
/// 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;

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 */
Expand All @@ -79,6 +88,8 @@ private:
*/
static unsigned int intCount;

uint8_t state_; ///< present bus state

/** Default constructor.
*/
Stm32Can();
Expand Down