2016-06-08 02:32 AM
Hi,
I have a problem with CAN after a bus-off condition. When CAN state changes to bus-off, I set the CAN operation mode to SLEEP mode. After a few 100 ms I try to bring the CAN bus into NORMAL mode again and then the Interrupts are activated again. But it seems like the ESR register isn't cleard before CAN starts working and so I get a bus-off interrupt immediately after a restart... this is a never ending cycle. 1) Bus-Off Interrupt occurs 2) Disable CAN-Interrupts 3) Set Sleep-Mode (clear INRQ, set SLEEP in MCR Register) 4) Wait for SLAK bit set 5) Reset TX and RX Mailboxes/FIFOs, Clear all pending Interrupts 6) Wait for a few 100 ms 7) Enter Init-Mode (clear SLEEP, set INRQ, in MCR Register) 8) Wait for INAK Bit set 9) Enter Normal-Mode (clear SLEEP, clear INRQ in MCR Register) 10) Wait for INAK Bit cleared 11) Enable CAN-Interrupts 12) ---> SCE Interrupt --> BOFF Flag set --> Back to 1) When I put an ASSERT((can->ESR & BOFF_BIT) == 0) immediately after 10), the assertion fails. But if put a breakpoint at the assertion and I check the register, all bits are cleared. And when I resume, it starts working as expected. The Code for changing the CAN-Mode:
static tCanStatus SetCanMode(tCAN * can, tCanMode mode)
{
uint32_t timeout = TIMEOUT_VALUE;
if (mode == CAN_MODE_INIT)
{
can->MCR = (uint32_t)((can->MCR & (uint32_t)(~(uint32_t)CAN_MCR_SLEEP)) | CAN_MCR_INRQ);
while (((can->MSR & CAN_MODE_MASK) != CAN_MSR_INAK) && (timeout != 0))
timeout--;
if ((can->MSR & CAN_MODE_MASK) != CAN_MSR_INAK)
return CAN_STATUS_ERROR;
}
else if (mode == CAN_MODE_NORMAL)
{
can->MCR &= (uint32_t)(~(CAN_MCR_SLEEP | CAN_MCR_INRQ));
while (((can->MSR & CAN_MODE_MASK) != 0) && (timeout != 0))
timeout--;
if ((can->MSR & CAN_MODE_MASK) != 0)
return CAN_STATUS_ERROR;
configASSERT((can->ESR & 0x04) == 0); // Fails after a bus-off
}
else if (mode == CAN_MODE_SLEEP)
{
can->MCR = (uint32_t)((can->MCR & (uint32_t)(~(uint32_t)CAN_MCR_INRQ)) | CAN_MCR_SLEEP);
while (((can->MSR & CAN_MODE_MASK) != CAN_MSR_SLAK) && (timeout != 0))
timeout--;
if ((can->MSR & CAN_MODE_MASK) != CAN_MSR_SLAK)
return CAN_STATUS_ERROR;
}
return CAN_STATUS_OK;
}
#canbus #can #stm32
2016-06-08 06:32 AM
Hi WernerPrbk,
Check the optimization of your project. Try to put it to optimize for speed. Tell me if that resolve your problem. -Hannibal-2016-06-10 11:18 AM
Hi and thank you for your response.
I already figured out that the problem was the synchronization to the bus. After a Bus-Off condition you have to enter and leave the Init-Mode and then (in Normal-Mode again) you have to wait (about 11 x 128 bit times) until the CAN Interface has synchronized with the bus. During this time, the BOFF Flag is still set and generates Interrupts, if activated. I solved the problem with a reset of the CAN Interface after a Bus-Off event, but i guess waiting until the BOFF Flag is cleared is also OK (but it may take several miliseconds...). The notes in the datasheet were somewhat confusing and i just misinterpreted it...2016-06-13 08:23 AM
Hello again,
i just recognized that a reset (set RESET to 1 in CAN->MCR) isn't helping - the errors are still set... Is there no other way to clear the errors without losing the filter settings?