Skip to content

Commit

Permalink
Workaround for stm32can stuck in error passive state (#726)
Browse files Browse the repository at this point in the history
Under some circumstances the stm32 CAN controller can get stuck in error passive state and never hit bus off state even though there is no other bus participant. This PR changes the queuing and error handling logic to detect this state and drop the transmit queue entries.

The specific condition is when there is an operational can transceiver, but there is no other bus participant, meaning that all transmit attempts end up with no-ack error. In this situation the TEC rises to 128, the device goes error passive, but the TEC does not get incremented any further.

Removes flag clear statements for error flags in the ESR register, because these flags are not writeable (can not be cleared in software).

===

* Cancel messages in the queue when we are in error passive mode.

* Cancels the transmit queue for both error passive and bus off states.
Removes flag clear statements for error flags in the ESR register,
because these flags are not writeable (can not be cleared in software).
  • Loading branch information
balazsracz authored Aug 19, 2023
1 parent 9552334 commit 53f3ab7
Showing 1 changed file with 22 additions and 5 deletions.
27 changes: 22 additions & 5 deletions src/freertos_drivers/st/Stm32Can.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,19 @@ void Stm32Can::disable()
*/
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;

Expand Down Expand Up @@ -435,31 +448,35 @@ void Stm32Can::sce_interrupt_handler()
/* 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;
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;
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();
++busOffCount;
state_ = CAN_STATE_BUS_OFF;
CAN->ESR &= ~CAN_ESR_BOFF;
}
}
}
Expand Down

0 comments on commit 53f3ab7

Please sign in to comment.