This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC2378 CAN semaphore bug

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.

Parents Reply Children
No data