 LPC2378 CAN semaphore bug Robert Harris LPC2368 using RTX I've spent several days tracking down a problem where the CAN would stop transmitting after a time period - usually after exactly 31845 packets - which is 0x5555. I found that CAN_hw_tx_empty was returning CAN_TX_BUSY_ERROR, but then the CAN interrupt was never transmitting the message waiting in the mailbox. Next I looked at the wr_sem semaphore, and found that the token count was increasing with every successful transmission. Eventually the token count was rolling from 0xFFFF to 0x0000, which would cause CAN_hw_tx_empty to fail. Now I see 0x5555 x 3 = 0xFFFF. Next I found that the wr_sem semaphore was being sent 2 - 3 times from the interrupt runtine. Looking at the CAN_ISR function it seems that the semaphore is sent every interrupt if the CAN TX hardware is free. This is a bug, because the interrupt is called for receive, as well as TX for the other controller.
if (CAN1GSR & (1 << 3)) {
if (isr_mbx_receive (MBX_tx_ctrl[0], (void **)&ptrmsg) != OS_R_OK) {
CAN_hw_wr (1, ptrmsg);
_free_box(CAN_mpool, ptrmsg);
} else {
isr_sem_send(wr_sem[0]); /* Return a token back to semaphore */
}
}
Adding an additional test for the type of interrupt fixed the problem:
// If the CAN has transmitted
if(CAN1ICR & (1<<1))
{
// If the CAN hardware is ready to transmit
if(CAN1GSR & (1 << 3))
{
// See if there are any messages to send
if(isr_mbx_receive(MBX_tx_ctrl[0], (void **)&ptrmsg) != OS_R_OK)
{
CAN_hw_wr(1, ptrmsg);
_free_box(CAN_mpool, ptrmsg);
}
else
{
// Release semaphore token
isr_sem_send(wr_sem[0]);
}
}
}
Hope that this saves someone else 3 days of their life.
|