This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28069: CAN Rx Frame "lost"

Part Number: TMS320F28069


Hello there,

I've been running several tests on my system and it seems that randomly I am missing a frame.

My system is slave on the bus. The eCAN module is configured in SCC mode. Mailboxes 6-9 are set in reception, 10-15 in transmission.

What I've observed during my tests is that the frame is properly sent by the master (spy on the bus confirms the frame presence).

Then on firmware side, I am sending an ascii character to UART when the reception interrupt is called for the corresponding Rx Mailboxes (6-9). I can observe that I do not write this byte neither on my terminal, so I guess something is either wrong on CAN Transceiver or in the configuration of my CAN.

The issue is really random. Any ideas for investigation or any guessing would be more than welcome on that topics.

Regards,

Celine

  • You are saying that you actually saw the frame on the bus, but it was not received in the eCAN. Since this is a random phenomenon, I wouldn’t suspect the hardware at this point. The only reason I can think of is the receive mailbox not properly configured to accept this frame. If you are using acceptance mask filtering, please check the value of the LAM registers. Or check if the message was copied into the mailbox RAM, but the interrupt did not trigger (possibly due to incorrect interrupt configuration at that point in time).
  • Hello Hareesh,

    Thanks for your feedback.

    I don't suspect the mailbox configuration as the lost frame ID is received properly most of the time so the filtering is fine.

    I suspect as you said that the interrupt does not trigger, but it is not really clear for me how to check this point.

    Also, I am not confident in the way the interrupt flags are cleared as there is several level. It might be the problem.

    Done at interrupt reception: ECanaRegs.CANMIM.all = ECanaRegs.CANMIM.all & (~mbx_bit);  /* Disable Rx mailbox */

                                                 PieCtrlRegs.PIEACK.all |= PIEACK_GROUP9;

    Done when processing the mailbox content in thread context: ECanaRegs.CANRMP.all |= bit; /* Clear Interrupt Flag */
                                                                                                      ECanaRegs.CANMIM.all |= bit;  /* Re-enable Rx mailbox */

    The interrupt initialisation is done this way:

    PieVectTable.ECAN0INTA = &cana_sys_isr;
    PieCtrlRegs.PIEIER9.bit.INTx5 = 1;
    PieVectTable.ECAN1INTA = &cana_mbx_isr;
    PieCtrlRegs.PIEIER9.bit.INTx6 = 1;

    with the callback defined as follow

    interrupt void cana_mbx_isr(void)
    {

    union CANGIF1_REG gif1;
    volatile struct MBOX *p_mbox = &ECanaMboxes.MBOX0;
    uint32_t mbx_bit;
    gif1.all = ECanaRegs.CANGIF1.all;
    mbx_bit = ((uint32_t)1)<<gif1.bit.MIV1;
    p_mbox = &(p_mbox[gif1.bit.MIV1]);
    EALLOW;
    ECanaRegs.CANMIM.all = ECanaRegs.CANMIM.all & (~mbx_bit);
    EDIS;
    if( l_rx_cb[m] != 0 )
    l_rx_cb[m](gif1.bit.MIV1);

    PieCtrlRegs.PIEACK.all |= PIEACK_GROUP9;
    }

    and l_rx_cb[x]

    void can_rx_callback( uint16_t mailbox )
    {
    // message will be processed inside canopen manager context
    can_msg_evt_t* pe = Q_NEW( can_msg_evt_t, SIG_CANMSG );
    pe->data = mailbox;
    QActive_postFIFO( g_ao_canopen, (QEvent*)pe);

    }

    Finally, at reception of the message in the thread context, I read the content of the mailbox

    void can_read_msg( uint16_t mbx, canmsg_t* msg )
    {
    volatile struct MBOX *p_mbox = 0;
    uint16_t prev_int_status;
    uint32_t bit = ((uint32_t)1)<<mbx;
    char msg2[50];
    p_mbox = &(ECanaMboxes.MBOX0) + mbx;

    EALLOW;
    ECanaRegs.CANRMP.all |= bit; /* Clear Interrupt Flag */
    ECanaRegs.CANMIM.all |= bit; /* Re-enable Rx mailbox */
    EDIS;

    if (ECanaRegs.CANRML.all & bit)
    {
    LOG("can_read_msg %d lost\r\n",bit);
    }

    msg->id = p_mbox->MSGID.bit.STDMSGID;/* copy message ID */
    msg->len = p_mbox->MSGCTRL.bit.DLC;/* copy message length */
    msg->rtr = p_mbox->MSGCTRL.bit.RTR;/* copy message RTR bit */
    msg->data[0] = p_mbox->MDL.byte.BYTE0;
    msg->data[1] = p_mbox->MDL.byte.BYTE1;
    msg->data[2] = p_mbox->MDL.byte.BYTE2;
    msg->data[3] = p_mbox->MDL.byte.BYTE3;
    msg->data[4] = p_mbox->MDH.byte.BYTE4;
    msg->data[5] = p_mbox->MDH.byte.BYTE5;
    msg->data[6] = p_mbox->MDH.byte.BYTE6;
    msg->data[7] = p_mbox->MDH.byte.BYTE7;
    }

  • How do you ensure that the message was not overwritten? Have you enabled the RML interrupt?
    Since you do not use mailboxes 0 thru 5, have you tried configuring these mailboxes for reception to ensure that no received message ever gets over-written?

    Do you use the OPC mechanism?

    Have you verified if the message is correctly copied in the mailbox RAM?

    You may also want to use the mailbox time-out mechanism to alert you if a message is not received within a particular time. Note that is applicable only when a message is not received at all, not when a message is received but the interrupt did not fire for some reason (which I suspect to be the case here).

    In SPRUH18G, section 1.7 clearly explains the various conditions that must be satisfied for the interrupt to be taken by the CPU. It also has some cautions that need to be adhered to. Pay special attention to Fig 1-94 and sections 1.7.3.1 through 1.7.3.3.

    Please see SPRA876B for some debug tips and also program examples.
  • Hello Hareesh,
    thanks for your answer and your link. I did have a look at them but unfortunately I still have my issue.

    I have enabled the RML interrupt. I do read check the CANRML register when reading the mailbox to check if there is no lost message

    /* Check if the mailbox lost flag is not set */
    if (ECanaRegs.CANRML.all & bit)

    Mailboxes 0 to 5 are used and set for SYNC and NMT. I have three mailboxes set for reception of those specific messages. I've added some debug and only Mailbox 9 is used, the two others are never used so this is not about lack of mailboxes. To check that part anyway, I've enabled the OPC mechanism for the two first one and disabled for the last one so it should fired an interrupt in case of issue. I don't received that neither.

    EALLOW;
    can_mask_6_15( 0xFF03FFFF);

    can_mbx( 6, RX, OP_OFF, STD_MSGID(AME_ON,canopen_id)); // last mbox protection should be off to fire interrupt
    for( i=7; i<=LAST_RX_MBX; i++ )
    can_mbx(i, RX, OP_ON, STD_MSGID(AME_ON,canopen_id));

    Finally, I've concluded that the message is received and copied in the RAM but the interrupt is not fired.
    I am confused about some examples I have read as interrupts are disabled before the mailbox reading. If I understood properly the datasheet, then the mailbox for which I received the interrupt is disabled while the corresponding flag in RMP has not been cleared, also I've removed te configuration of ECanaRegs.CANMIM.all when rx interrupt is raised.

    Below is my code now. I am sure there is still something wrong, but can't figure it out.

    When an interrupt is triggered for a reception mailboxes, cana_mbx_isr() is called. Then, can_rx_callback(ECanaRegs.CANGIF1.bit.MIV1) is called and a message SIG_CANMSG is sent in the interrupt context to the canopen task. The mailbox will be read in the canopen task context using can_read_msg(). Could this delay of mailbox reading be the root cause, if so, I don't understand why as the mailbox should not be overwritten because of the OPC mechanism and other Rx mailboxes should be used. I am pretty confident this is then not the case.

    ********************************************************************************************
    ******************************* Initialisation *******************************************
    ********************************************************************************************

    void can_module_init( uint16_t canopen_id, uint16_t bitrate )
    {
    int i =0;
    can_init( bitrate );

    EALLOW;
    can_mask_0_2( MASK_NMT_ERR_CTRL );

    can_mbx( 0, RX, OP_OFF, STD_MSGID( AME_ON,0x700) );
    can_mbx( 1, RX, OP_ON, STD_MSGID( AME_ON,0x700) );
    can_mbx( 2, RX, OP_ON, STD_MSGID( AME_ON,0x700) );

    // mailboxes 3-5 are for receiving canopen NMT, SYNC & Time Stamps
    can_mbx( 3, RX, OP_OFF, STD_MSGID( AME_OFF,0x00)); // NMT
    can_mbx( 4, RX, OP_ON, STD_MSGID( AME_OFF,0x00)); // NMT
    can_mbx( 5, RX, OP_ON, STD_MSGID( AME_OFF,0x00)); // NMT

    /* Mailboxes 6-9 are for receiving canopen node messages */
    EALLOW;
    can_mask_6_15( 0xFF03FFFF); // 1111 1111 0000 0011 1111 1111 1111 1111

    can_mbx( 6, RX, OP_OFF, STD_MSGID(AME_ON,canopen_id)); // last mbox protection should be off to fire interrupt
    for( i=7; i<=LAST_RX_MBX; i++ )
    can_mbx(i, RX, OP_ON, STD_MSGID(AME_ON,canopen_id));

    //mailboxes 10-15 are TX
    for( i=FIRST_TX_MBX; i<=LAST_TX_MBX; i++ )
    can_mbx( i, TX, OP_OFF, 0);

    can_interrupts(can_sys_callback, can_rx_callback );

    EDIS;
    }


    void can_interrupts( can_sys_callback_t sys_cb, can_rx_callback_t rx_cb )
    {
    volatile struct ECAN_REGS *p_can_regs;
    EALLOW;

    p_can_regs = &ECanaRegs;
    l_sys_cb[0] = sys_cb;
    l_rx_cb[0] = rx_cb;

    PieVectTable.ECAN0INTA = &cana_sys_isr;
    PieCtrlRegs.PIEIER9.bit.INTx5 = 1;
    PieVectTable.ECAN1INTA = &cana_mbx_isr;
    PieCtrlRegs.PIEIER9.bit.INTx6 = 1;

    /* These registers allow the CPU to identify the interrupt source. */
    p_can_regs->CANGIF0.all = 0xFFFFFFFF;
    p_can_regs->CANGIF1.all = 0xFFFFFFFF;
    p_can_regs->CANMIL.all = 0xFFFFFFFF; // all mailboxes generate interrupts on line 1
    // set global (module, not mailboxes) interrupts line to 0 and enable both lines
    p_can_regs->CANGIM.all = (uint32_t)(INT_SCC_ALL|0x3);
    IER |= M_INT9;

    EDIS;
    }

    ********************************************************************************************
    ******************************* Callbacks *********************************************
    ********************************************************************************************

    #define SYS_ISR_INTERNALS(REGS, m)\
    union CANGIF1_REG gif1;\
    gif1.all = ECanaRegs.CANGIF1.all;\
    if( REGS.CANGIF0.all & INT_ABORT_ACK) {\
    if(l_sys_cb[m]!=0) l_sys_cb[m](INT_ABORT_ACK,gif1.bit.MIV1);\
    REGS.CANAA.all = 0xFFFFFFFF;\
    }\
    else\
    if( REGS.CANGIF0.all & INT_WRITE_DENIED ) {\
    if(l_sys_cb[m]!=0) l_sys_cb[m](INT_WRITE_DENIED,gif1.bit.MIV1);\
    REGS.CANGIF0.all &= INT_WRITE_DENIED;\
    }\
    else\
    if( REGS.CANGIF0.all & INT_WAKEUP ) {\
    if(l_sys_cb[m]!=0) l_sys_cb[m](INT_WAKEUP,gif1.bit.MIV1);\
    REGS.CANGIF0.all &= INT_WAKEUP; /* Clear interrupt flag bit */\
    }\
    else\
    if( REGS.CANGIF0.all & INT_RECV_MSG_LOST ) {\
    if(l_sys_cb[m]!=0) l_sys_cb[m](INT_RECV_MSG_LOST,gif1.bit.MIV1);\
    REGS.CANGIF0.all &= INT_RECV_MSG_LOST; /* Clear interrupt flag bit */\
    REGS.CANRMP.all = 0xFFFFFFFF;\
    }\
    else\
    if( REGS.CANGIF0.all & INT_BUS_OFF ) {\
    if(l_sys_cb[m]!=0) l_sys_cb[m](INT_BUS_OFF,gif1.bit.MIV1);\
    REGS.CANGIF0.all &= INT_BUS_OFF;\
    }\
    else\
    if( REGS.CANGIF0.all & INT_ERR_PASSIVE ) {\
    if(l_sys_cb[m]!=0) l_sys_cb[m](INT_ERR_PASSIVE,gif1.bit.MIV1);\
    REGS.CANGIF0.all &= INT_ERR_PASSIVE;\
    }\
    else\
    if( REGS.CANGIF0.all & INT_WARN_LEVEL ) {\
    if(l_sys_cb[m]!=0) l_sys_cb[m](INT_WARN_LEVEL,gif1.bit.MIV1);\
    REGS.CANGIF0.all &= INT_WARN_LEVEL;\
    }

    #pragma CODE_SECTION(cana_sys_isr, "ramfuncs");
    interrupt void cana_sys_isr(void)
    {
    SYS_ISR_INTERNALS(ECanaRegs,0);

    IER |= M_INT9; // Enable INT9
    EINT;
    PieCtrlRegs.PIEACK.bit.ACK9 = 1; // Enables PIE to drive a pulse into the CPU
    }

    #pragma CODE_SECTION(cana_mbx_isr, "ramfuncs");
    interrupt void cana_mbx_isr(void)
    {
    IER |= M_INT9;
    PieCtrlRegs.PIEACK.bit.ACK9 = 1; // Enables PIE to drive a pulse into the CPU
    EINT;

    l_rx_cb[0](ECanaRegs.CANGIF1.bit.MIV1);
    }

    void can_rx_callback( uint16_t mailbox )
    {
    /* acknowledge to interrupt done in cana_mbx_isr */

    // message will be processed inside canopen manager context
    can_msg_evt_t* pe = Q_NEW( can_msg_evt_t, SIG_CANMSG );
    pe->data = mailbox;
    QActive_postFIFO( g_ao_canopen, (QEvent*)pe);
    }

    void can_read_msg( uint16_t mbx, canmsg_t* msg )
    {
    volatile struct MBOX *p_mbox = 0;
    uint16_t prev_int_status;
    uint32_t bit = ((uint32_t)1)<<mbx;
    uint16_t i=0;
    p_mbox = &(ECanaMboxes.MBOX0) + mbx;

    /* Check if the mailbox lost flag is not set */
    if (ECanaRegs.CANRML.all & bit)
    {
    while(1);
    }

    EALLOW;
    ECanaRegs.CANRMP.all |= bit; /* Clear Interrupt Flag */
    EDIS;

    msg->id = p_mbox->MSGID.bit.STDMSGID; /* copy message ID */
    msg->len = p_mbox->MSGCTRL.bit.DLC; /* copy message length */
    msg->rtr = p_mbox->MSGCTRL.bit.RTR; /* copy message RTR bit */
    msg->data[0] = p_mbox->MDL.byte.BYTE0;
    msg->data[1] = p_mbox->MDL.byte.BYTE1;
    msg->data[2] = p_mbox->MDL.byte.BYTE2;
    msg->data[3] = p_mbox->MDL.byte.BYTE3;
    msg->data[4] = p_mbox->MDH.byte.BYTE4;
    msg->data[5] = p_mbox->MDH.byte.BYTE5;
    msg->data[6] = p_mbox->MDH.byte.BYTE6;
    msg->data[7] = p_mbox->MDH.byte.BYTE7;

    if (ECanaRegs.CANRMP.all & bit)
    {
    while(1);
    }
    }