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

OS_ERR_FIFO_OVF when CAN data received

Hi everybody

I use SAM7x512 and RL-ARM OS.
here, OS has 7 tasks and one of them is for CAN receiver. OS_TICK is 1000 and OS_STKSIZE is 1024. and 500000 is my CAN baudrate(my board is just receiver and transmitter is a KVASER PCI CAN Interface).

speed of data transmission is my problem.

when for example transmitter side of CAN bus send a packet per 10ms or more there is know any problem but when I try to increase the speed after some packet (about 200 messages or more) I will get OS_ERR_FIFO_OVF in os_error function. but when I disable the CAN task all other task are working as well.

note: When the system is getting crash and doesn't do any tasks but it's not in os_error function in debug mode with ulink2 sometimes task of CAN in "RTX task and system" -> "stack load" shows "under flow" and after that it calls os_error (in usual states it's about 3% of stack usage)

I tried such works:

1. increase OS_STKSIZE
2. increase OS_FIFOSZ
3. increase CAN_No_ReceiveObjects
4. chaning the OS_TICK

but nothing happened

Does anyone know what I should do?

Parents
  • Hi
    I've used exactly CAN_SAM7X.c which is in keil examples
    here is the CAN IRQ ISR:

    
    
    static void CAN_IRQHandler (void) __irq  {
      U32 ch;
      CAN_msg *ptrmsg;
      struct _AT91S_CAN_MB *MailBox;
      U32 i, int_status, int_ch, int_mask;
    
      int_mask   = CAN_PTR->CAN_IMR;
      CAN_PTR->CAN_IDR = 0xFF;                /* Disable CAN interrupts          */
      int_status = CAN_PTR->CAN_SR & int_mask;
    
      int_ch = int_status & tx_mailboxes;
      if (int_ch) {                         /* Transmission interrupt occured    */
        tx_mailboxes &= ~int_ch;              /* Tx on channel is inactive       */
        int_mask     &= ~int_ch;              /* Clear interrupt mask for Tx     */
    
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Find mailbox that caused Tx int */
          if (int_ch & i) break;
          i <<= 1;
        }
    
        MailBox = table_mailbox_addr[ch-1];   /* Mailbox address                 */
        MailBox->CAN_MB_MMR=AT91C_CAN_MOT_DIS;/* Disable mailbox until next write*/
          /* If there is a message in the mailbox ready for send, read the
             message from the mailbox and send it                                */
          if (isr_mbx_receive (MBX_tx_ctrl[CTRL0], (void **)&ptrmsg) != OS_R_OK) {
            CAN_hw_wr (CTRL, ptrmsg);
            _free_box(CAN_mpool, ptrmsg);
        } else {
          isr_sem_send(wr_sem[CTRL0]);        /* Return a token back to semaphore*/
        }
      }
    
      int_ch = int_status & rx_mailboxes;
      if (int_ch) {                         /* Reception    interrupt occured    */
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Read all pending received msgs  */
          if (int_ch & i) {
            MailBox = table_mailbox_addr[ch-1];   /* Mailbox address             */
    
            /* If the mailbox isn't full read the message from the hardware and
               send it to the message queue                                      */
            if (os_mbx_check (MBX_rx_ctrl[CTRL0]) > 0)  {
              ptrmsg = _alloc_box (CAN_mpool);
              if (ptrmsg) CAN_hw_rd (CTRL, ch, ptrmsg);   /* Read received msg   */
              MailBox->CAN_MB_MCR = AT91C_CAN_MTCR;       /* release mailbox     */
              if (ptrmsg) isr_mbx_send (MBX_rx_ctrl[CTRL0], ptrmsg);
            }
          }
          i <<= 1;
        }
      }
    
      CAN_PTR->CAN_IER          = int_mask;               /* Enable CAN interrupt*/
      AT91C_BASE_AIC->AIC_ICCR  = CAN_INT_CLR;            /* Clear interrupt flag*/
      AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR;  /* End of interrupt*/
    }
    
    
    
    

    then to process the data in separated task I made it in this way:

    
    
    U32 ch;
    CAN_msg *ptrmsg;
    struct _AT91S_CAN_MB *MailBox;
    U32 i, int_status, int_ch, int_mask;
    
    
    
    void CAN_process(void) {
    while (1) {
    os_evt_wait_or (0x0001, 0xffff); // Wait until ISR triggers an event
    
    if (int_ch) {                         /* Transmission interrupt occured    */
        tx_mailboxes &= ~int_ch;              /* Tx on channel is inactive       */
        int_mask     &= ~int_ch;              /* Clear interrupt mask for Tx     */
    
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Find mailbox that caused Tx int */
          if (int_ch & i) break;
          i <<= 1;
        }
    
        MailBox = table_mailbox_addr[ch-1];   /* Mailbox address                 */
        MailBox->CAN_MB_MMR=AT91C_CAN_MOT_DIS;/* Disable mailbox until next write*/
          /* If there is a message in the mailbox ready for send, read the
             message from the mailbox and send it                                */
          if (isr_mbx_receive (MBX_tx_ctrl[CTRL0], (void **)&ptrmsg) != OS_R_OK) {
            CAN_hw_wr (CTRL, ptrmsg);
            _free_box(CAN_mpool, ptrmsg);
        } else {
          isr_sem_send(wr_sem[CTRL0]);        /* Return a token back to semaphore*/
        }
      }
    
      int_ch = int_status & rx_mailboxes;
      if (int_ch) {                         /* Reception    interrupt occured    */
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Read all pending received msgs  */
          if (int_ch & i) {
            MailBox = table_mailbox_addr[ch-1];   /* Mailbox address             */
    
            /* If the mailbox isn't full read the message from the hardware and
               send it to the message queue                                      */
            if (os_mbx_check (MBX_rx_ctrl[CTRL0]) > 0)  {
              ptrmsg = _alloc_box (CAN_mpool);
              if (ptrmsg) CAN_hw_rd (CTRL, ch, ptrmsg);   /* Read received msg   */
              MailBox->CAN_MB_MCR = AT91C_CAN_MTCR;       /* release mailbox     */
              if (ptrmsg) isr_mbx_send (MBX_rx_ctrl[CTRL0], ptrmsg);
            }
          }
          i <<= 1;
        }
      }
    }
    }
    
    
    
    
    static void CAN_IRQHandler (void) __irq  {
    
    
      int_mask   = CAN_PTR->CAN_IMR;
      CAN_PTR->CAN_IDR = 0xFF;                /* Disable CAN interrupts          */
      int_status = CAN_PTR->CAN_SR & int_mask;
    
      int_ch = int_status & tx_mailboxes;
    
      isr_evt_set (0x0001, CAN_process_TID);
    
      CAN_PTR->CAN_IER          = int_mask;               /* Enable CAN interrupt*/
      AT91C_BASE_AIC->AIC_ICCR  = CAN_INT_CLR;            /* Clear interrupt flag*/
      AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR;  /* End of interrupt*/
    }
    
    

    maybe I should do something else in IRQ ...

    and the connection of CAN, here is just for receiving data and I don't have send routine.

    note: I tried to fully disable CAN peripheral in Ethernet IRQ.
    note: when I increased the fifo size of OS, about 1 to 3 minutes I can receive data (1 message per 1ms) and after that program will call os_error with error code=2 (fifo ovf) and sometimes the program will call PAbt_Handler or hardly ever DAbt_Handler. (these two handlers maybe due to fifo ovf but they occur rarely)

    another question:
    when the transmitter side before lunching my device send messages, program will crash on os_sem_init (wr_sem[ctrl0], 1); in CAN_init function.
    how can I prevent it?

    I have question a lot, excuse me

    thanks again for your responses

Reply
  • Hi
    I've used exactly CAN_SAM7X.c which is in keil examples
    here is the CAN IRQ ISR:

    
    
    static void CAN_IRQHandler (void) __irq  {
      U32 ch;
      CAN_msg *ptrmsg;
      struct _AT91S_CAN_MB *MailBox;
      U32 i, int_status, int_ch, int_mask;
    
      int_mask   = CAN_PTR->CAN_IMR;
      CAN_PTR->CAN_IDR = 0xFF;                /* Disable CAN interrupts          */
      int_status = CAN_PTR->CAN_SR & int_mask;
    
      int_ch = int_status & tx_mailboxes;
      if (int_ch) {                         /* Transmission interrupt occured    */
        tx_mailboxes &= ~int_ch;              /* Tx on channel is inactive       */
        int_mask     &= ~int_ch;              /* Clear interrupt mask for Tx     */
    
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Find mailbox that caused Tx int */
          if (int_ch & i) break;
          i <<= 1;
        }
    
        MailBox = table_mailbox_addr[ch-1];   /* Mailbox address                 */
        MailBox->CAN_MB_MMR=AT91C_CAN_MOT_DIS;/* Disable mailbox until next write*/
          /* If there is a message in the mailbox ready for send, read the
             message from the mailbox and send it                                */
          if (isr_mbx_receive (MBX_tx_ctrl[CTRL0], (void **)&ptrmsg) != OS_R_OK) {
            CAN_hw_wr (CTRL, ptrmsg);
            _free_box(CAN_mpool, ptrmsg);
        } else {
          isr_sem_send(wr_sem[CTRL0]);        /* Return a token back to semaphore*/
        }
      }
    
      int_ch = int_status & rx_mailboxes;
      if (int_ch) {                         /* Reception    interrupt occured    */
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Read all pending received msgs  */
          if (int_ch & i) {
            MailBox = table_mailbox_addr[ch-1];   /* Mailbox address             */
    
            /* If the mailbox isn't full read the message from the hardware and
               send it to the message queue                                      */
            if (os_mbx_check (MBX_rx_ctrl[CTRL0]) > 0)  {
              ptrmsg = _alloc_box (CAN_mpool);
              if (ptrmsg) CAN_hw_rd (CTRL, ch, ptrmsg);   /* Read received msg   */
              MailBox->CAN_MB_MCR = AT91C_CAN_MTCR;       /* release mailbox     */
              if (ptrmsg) isr_mbx_send (MBX_rx_ctrl[CTRL0], ptrmsg);
            }
          }
          i <<= 1;
        }
      }
    
      CAN_PTR->CAN_IER          = int_mask;               /* Enable CAN interrupt*/
      AT91C_BASE_AIC->AIC_ICCR  = CAN_INT_CLR;            /* Clear interrupt flag*/
      AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR;  /* End of interrupt*/
    }
    
    
    
    

    then to process the data in separated task I made it in this way:

    
    
    U32 ch;
    CAN_msg *ptrmsg;
    struct _AT91S_CAN_MB *MailBox;
    U32 i, int_status, int_ch, int_mask;
    
    
    
    void CAN_process(void) {
    while (1) {
    os_evt_wait_or (0x0001, 0xffff); // Wait until ISR triggers an event
    
    if (int_ch) {                         /* Transmission interrupt occured    */
        tx_mailboxes &= ~int_ch;              /* Tx on channel is inactive       */
        int_mask     &= ~int_ch;              /* Clear interrupt mask for Tx     */
    
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Find mailbox that caused Tx int */
          if (int_ch & i) break;
          i <<= 1;
        }
    
        MailBox = table_mailbox_addr[ch-1];   /* Mailbox address                 */
        MailBox->CAN_MB_MMR=AT91C_CAN_MOT_DIS;/* Disable mailbox until next write*/
          /* If there is a message in the mailbox ready for send, read the
             message from the mailbox and send it                                */
          if (isr_mbx_receive (MBX_tx_ctrl[CTRL0], (void **)&ptrmsg) != OS_R_OK) {
            CAN_hw_wr (CTRL, ptrmsg);
            _free_box(CAN_mpool, ptrmsg);
        } else {
          isr_sem_send(wr_sem[CTRL0]);        /* Return a token back to semaphore*/
        }
      }
    
      int_ch = int_status & rx_mailboxes;
      if (int_ch) {                         /* Reception    interrupt occured    */
        i = 1;
        for (ch = 1; ch < MAX_OBJ+1; ch++) {  /* Read all pending received msgs  */
          if (int_ch & i) {
            MailBox = table_mailbox_addr[ch-1];   /* Mailbox address             */
    
            /* If the mailbox isn't full read the message from the hardware and
               send it to the message queue                                      */
            if (os_mbx_check (MBX_rx_ctrl[CTRL0]) > 0)  {
              ptrmsg = _alloc_box (CAN_mpool);
              if (ptrmsg) CAN_hw_rd (CTRL, ch, ptrmsg);   /* Read received msg   */
              MailBox->CAN_MB_MCR = AT91C_CAN_MTCR;       /* release mailbox     */
              if (ptrmsg) isr_mbx_send (MBX_rx_ctrl[CTRL0], ptrmsg);
            }
          }
          i <<= 1;
        }
      }
    }
    }
    
    
    
    
    static void CAN_IRQHandler (void) __irq  {
    
    
      int_mask   = CAN_PTR->CAN_IMR;
      CAN_PTR->CAN_IDR = 0xFF;                /* Disable CAN interrupts          */
      int_status = CAN_PTR->CAN_SR & int_mask;
    
      int_ch = int_status & tx_mailboxes;
    
      isr_evt_set (0x0001, CAN_process_TID);
    
      CAN_PTR->CAN_IER          = int_mask;               /* Enable CAN interrupt*/
      AT91C_BASE_AIC->AIC_ICCR  = CAN_INT_CLR;            /* Clear interrupt flag*/
      AT91C_BASE_AIC->AIC_EOICR = AT91C_BASE_AIC->AIC_EOICR;  /* End of interrupt*/
    }
    
    

    maybe I should do something else in IRQ ...

    and the connection of CAN, here is just for receiving data and I don't have send routine.

    note: I tried to fully disable CAN peripheral in Ethernet IRQ.
    note: when I increased the fifo size of OS, about 1 to 3 minutes I can receive data (1 message per 1ms) and after that program will call os_error with error code=2 (fifo ovf) and sometimes the program will call PAbt_Handler or hardly ever DAbt_Handler. (these two handlers maybe due to fifo ovf but they occur rarely)

    another question:
    when the transmitter side before lunching my device send messages, program will crash on os_sem_init (wr_sem[ctrl0], 1); in CAN_init function.
    how can I prevent it?

    I have question a lot, excuse me

    thanks again for your responses

Children
  • Hi
    about that part of my code in previous post (with isr_evt_set) when I was debugging I found that the program never pass "os_evt_wait_or (0x0001, 0xffff)" (the program has called isr_evt_set but nothing happened after that)

    what's wrong with it?

  • Hi

    after a long while I could found what the problem was.


    * Try to speed up general interrupt handling.

    as you can see in my sample code (2 messages before) the developer of that code has used mailbox to send a new packet to can_receive fuction and can_receive function use mailbox wait to get a new message through OS mailbox

    here I try to omit it and instead, referesh a global variable and flag to be aware in main routine that new message has been received

    everything is OK without any OVF on FIFO; dAbt and pAbt

    I think because the number of intterupts in Ethernet and CAN are too high the only way to cope such a problem is just speed up my ISR routine as Tamir Michael said.

    thanks again

    well done

  • I'm not sure I agree with your analysis. Yes, interrupts should always be as fast as possible. And they should clear out the data and leave the hardware in a stable state. You just may not get your queues full and leave data still in the hardware.

    Another issue the ISR makes use of os_mbx_check() instead of isr_mbx_check().