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.

C2000 CAN Interrupt stops after about 1M telegrams



Hi folks

We encountered a problem with the C2812's CAN peripheral.
After happily receiving telegrams for more than an hour, suddenly the interrupt stops being called.

When I debug the controller, I can see that CANRMP has 0x00000002 in it, and  CANGIF0.15 is also set. But the interrupt is not called.

When I then acknowledge the RMP by writing 0x02 to it with the emulator, the interrupt starts to work again as soon as the next telegram arrives.

It seems that after the processing of incoming telegrams in the ISR, another one arrives before the ISR is left. And if not all telegrams are handled and the ISR is left, the interrupt never seems to be called again. But how can I assure that no telegram arrives in the time between the processing of the telegrams and the end of the ISR?

I seem to misunderstand something - but what?

Any help is really appreciated!

Regards, Daniel

  • Here comes some more information.

    The register values of CAN and PIEIER9 in the state where the interrupt is not called anymore. In the meantime I have separated the interrupts into two ISRs, one for RX mailboxes, and one for TX mailboxes in the hope it would help somehow, but it didn't.

    You can see that CANGIF0.15 is set, and CANGIM.0 is also set.  But the corresponding interrupt flag in PIEIFR9 is not set. What can be the reason for that?

    Here comes some code:

    The ISR

    /*---------------------------------------------------------------------------*/
    interrupt void cco_rxInterruptHandler (void)
    {
    cobj_t obj;
    UNSIGNED8 last_selected_can = SelectedCan;
    UNSIGNED8 len;
    UNSIGNED32 id;
    volatile UNSIGNED16 status;
    volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;

    //Other Interrupts with higher priority may interrupt this one
    IER |= M_INT9; // Set "global" priority
    IER &= MINT9;
    PieCtrlRegs.PIEIER9.all &= MG95; // Set "group" priority
    PieCtrlRegs.PIEACK.all = 0xFFFF; // Enable PIE interrupts
    EINT;


    while (ECanaRegs.CANGIF0.all & (1UL<<15)) //dh changed if to while to handle all currently active interrupts
    {
    obj = ECanaRegs.CANGIF0.all & 0x1F;

    id = getId(obj);
    len = getLength(obj,TRUE);

    if (cco_getData(obj, RxBuff) == OK)
    {
    if (RxIntHandler)
    RxIntHandler(obj, id, len, RxBuff);
    }
    }

    cco_can_select(last_selected_can);

    DELAY_US(30);

    // Restore registers saved:
    DINT;
    PieCtrlRegs.PIEIER9.all = TempPIEIER;
    }

    /*---------------------------------------------------------------------------*/
    SIGNED16 cco_getData (cobj_t obj, UNSIGNED8 *destrBuff)
    {
    SIGNED16 ret;

    if ((obj < CAN_OBJ_COUNT) && CanObj[obj].valid)
    {
    if (crd_msg(obj, destrBuff, NULL)) // is Message Buffer full ?
    ret = OK;
    else
    ret = B_EMPTY;
    }
    else
    {
    ret = B_ERROR;
    }

    return ret;
    }

    /*---------------------------------------------------------------------------*/
    static BOOLEAN crd_msg (cobj_t obj, UNSIGNED8 *dbuff, UNSIGNED8 *rlen)
    {
    BOOLEAN ret = FALSE;
    UNSIGNED8 len;
    UNSIGNED32 mask = (1UL<<obj);
    UNSIGNED8 sbuff[MAX_CAN_DATA_LEN];
    SIGNED16 testcnt = 0;
    UNSIGNED32 mdl;
    UNSIGNED32 mdh;

    if (ECanaRegs.CANRMP.all & mask)
    {
    memset(sbuff,0,sizeof(sbuff));

    INT_DISABLE(); // bi 2009-09-10 to avoid problems when guarding was reading message while a sync message was sent
    cco_globalInt(FALSE);

    do { // we have to repeat this if clearing of RMP bit does not work. That means an incoming message overwrote the one we were reading.
    ECanaRegs.CANRMP.all = mask;

    len = getLength(obj,FALSE);
    len = min(len,CanObj[obj].len);

    CanDoubleRead(&mdl,&(((EcanMbox_t*)(&ECanaMboxes))+obj)->MDL.all);
    CanDoubleRead(&mdh,&(((EcanMbox_t*)(&ECanaMboxes))+obj)->MDH.all);
    } while((ECanaRegs.CANRMP.all & mask) && (testcnt++ < 10));

    cco_globalInt(TRUE);

    sbuff[0] = (mdl>>24) & 0xFF;
    sbuff[1] = (mdl>>16) & 0xFF;
    sbuff[2] = (mdl>> 8) & 0xFF;
    sbuff[3] = (mdl ) & 0xFF;
    sbuff[4] = (mdh>>24) & 0xFF;
    sbuff[5] = (mdh>>16) & 0xFF;
    sbuff[6] = (mdh>> 8) & 0xFF;
    sbuff[7] = (mdh ) & 0xFF;

    memcpy(dbuff,sbuff,len);

    if (rlen)
    *rlen = len;

    ret = TRUE;
    INT_ENABLE();
    }

    return ret;
    }

    /*---------------------------------------------------------------------------*/
    void cco_globalInt (FLAG enable)
    {
    volatile UNSIGNED32 tmp,tmp2;
    EALLOW;
    tmp = 0x01 | 0x02; // I0EN & I1EN - Bit
    tmp2 = ECanaRegs.CANGIM.all;
    if (enable) {
    tmp = tmp | tmp2;
    ECanaRegs.CANGIM.all = tmp; // I0EN - Interrupt Enable
    } else {
    tmp = (~tmp) & tmp2;
    ECanaRegs.CANGIM.all = tmp; // I0EN - Interrupt Disable
    }
    EDIS;
    }

  • Hi;

    Not sure if it also solves your problem, but I would recommend proceeding exactly in following order:

    ***  'EINT' must be placed before the 'PieCtrlRegs...' and (if used) 'CANTOS' must be set TWICE with another instruction in between to guarantee the interrupt's response consistency!  ***

    Tested millions of times... Good luck.

    Ibrahim.


    #define TMR_TMO e.CANGIF0.bit.MTOF0 // Can Timer Timeout Flag
    #define TMR_OVF   e.CANGIF0.bit.TCOF0       // Timestamp Counter Overflow Flag

    interrupt void ECAN0INTA_ISR(void) // Buraya kaydırılan kesmeler:
    { VU16 tier=PieCtrlRegs.PIEIER9.all; // 1) TMR_OVF: Taşmada TSC ve TMR_CMP arasında eşgüdüm sağlanır
    U32 m; U08 miv; // 2) TMR_TMO: MOTO[13] Eşlemde gereken görevler yerine getirilir
    volatile struct ECAN_REGS *c=&ECanaRegs, e; // **DİKKAT:sizeof(ECAN_REGS)=52 --> "e" stack´ten 52W ister?
    IER|=M_INT9; IER&=MINT9; PieCtrlRegs.PIEIER9.all&=MG95; // Küresel ve kümesel öncelikleri ayarla
    EINT; PieCtrlRegs.PIEACK.all=0xFFFF; // PIE kesmelerine izin ver :: Sıralamayı bozma!
    e.CANGIF0.all=c->CANGIF0.all; e.CANTOS.all =c->CANTOS.all; // ..
    miv=e.CANGIF0.bit.MIV0; m=~(1UL<<miv); // Bayrağın kaynağı (0x00002000 olması beklenir)
    if(TMR_OVF){ csts.tmr_ovfl=1; TMR_OVF=1; c->CANGIF0.all=e.CANGIF0.all; } // bclr_TCOF Timestamp Counter Overflow Flag
    if(TMR_TMO){ csts.tmr_dspt=1; c->CANTOS.all=m; // DİKAAAAAAAAT --> Yalnız burada silmek yetmiyor.. Kesme bir daha patlamıyor!
    cnt_prv=TMR_CNT; c->CANTOS.all=m; } // HEMEN ATLAMA --> İKİ KEZ SİLİNCE ANCAK GERÇEKLEŞİYOR :) 50µs´de 33x10^6 kez denendi
    DINT; PieCtrlRegs.PIEIER9.all=tier; }



  • Hi Ibrahim

    Thanks for your proposal, I will try it!

    I have the order of the commands out of the examples from Ti, so I hoped they were okay.
    We don't have any timeout interrupts active, so I don't think we need CANTOS at all. 

    Thanks and regards,
    Daniel 

  • Hello

    As I have found the problem in the meantime, I want to give a feedback here.

    It was a bug in our SCI implementation. Our SCI driver had a function to force an interrupt. This was implemented by a write to the PIEIFR9 register, using Ti's .bit modify function: PieCtrlRegs.PIEIFR9.bit.INTx2 = 1;

    This of course is not allowed, because it reads the register, modifies the temp value and then writes it back. That means, when an interrupt happens during this process on another bit than the one we want to modify, it will be overwritten immediately. 
    As the CAN interrupt is on the same group as the SCI interrupt, this explains the malfunction of the CAN interrupt.

    Regards, 
    Daniel