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.

TMS320F280025C: CANBUS Tx interrupt

Part Number: TMS320F280025C
Other Parts Discussed in Thread: C2000WARE

Tool/software:

Hi everyone!
I'm here to share a problem I'm facing in dealing with canbus tx interrupt.

I'm using the F280025C launchpad which has one canbus channel CANA and two possible interrupt lines linked with it (CANINT0 and CANINT1).

I setup the peripheral and interrupt table in order to trigger:
Rx - CANINT0
Tx - CANINT1

Moreover, regarding the interface registers, I chose to use IF1 for trasmission purposes and IF2 for receiving.
I enabled both the TxIE, RxIE bitfileds and the global interrupt lines for canbus.

Concerning receiving interrupt everything works fine, trasmission always fails when i try to send a canbus message (I've been using a can analyzer as other node).

Literally it's as if nothing happens.

After that, I tried to exclude the Rx interrupt (line 0) from the code and focus on the Tx only (line 1). 

By debugging the canbus registers themselves I could see a very strange thing: the trasmission line which is triggered is 0 (which is supposed to be linked to Rx from the setup).
I couldn't figure it out why.

Then, another very strange thing is that the IPEN_21 register identifies the correct message object, the TxOk bit is high and LEC one doesn't show any warnings.
In this case the tx interrupt is generated but there's no way to clean it by the usual way (IntClrPnd = 1). Indeed, the tx interrupt is entered endlessly.

Why does the Tx interrupt gets triggered just as I exclude the Rx one?
Can anyone help me out with this?.


I attach some of the code i've been writing about, hoping it's useful to catch the issue.
Let me know please :)

Elia

========================================
PIE SETUP

========================================

EALLOW;

PieVectTable.CANA0_INT = &cana_rx_isr;
PieVectTable.CANA1_INT = &cana_tx_isr;

PieCtrlRegs.PIEIER9.bit.INTx6 = 1; 
PieCtrlRegs.PIEIER9.bit.INTx5 = 1;
//PieCtrlRegs.PIEIER9.bit.INTx6 = 1;

IER |= M_INT9; 
EDIS;




========================================
INITIALIZATION

========================================

void InitCAN(void)
{
int16_t iMsg;

//
// Place CAN controller in init state, regardless of previous state. This
// will put controller in idle, and allow the message object RAM to be
// programmed.
//
CanaRegs.CAN_CTL.bit.Init = 1;
CanaRegs.CAN_CTL.bit.CCE = 1;
CanaRegs.CAN_CTL.bit.SWR = 1; // Software Reset (si attiva solo se Init è settato)

//
// Wait for busy bit to clear
//
while(CanaRegs.CAN_IF1CMD.bit.Busy) // c'è un trasferimento in corso tra interface register e la ram
{
}

//
// Clear the message value bit in the arbitration register. This indicates
// the message is not valid and is a "safe" condition to leave the message
// object. The same arb reg is used to program all the message objects.
//

CanaRegs.CAN_IF1CMD.bit.DIR = 1; // 0 read, 1 write : 0 legge dalla mailbox verso l'interface register, 1 viceversa
CanaRegs.CAN_IF1CMD.bit.Arb = 1; // Arbitration bits (Identifier + Dir + Xtd + MsgVal) trasferiti da IF -> MAILBOX (se write, viceversa se read)
CanaRegs.CAN_IF1CMD.bit.Control = 1; // Control bits come sopra

CanaRegs.CAN_IF1ARB.all = 0;

CanaRegs.CAN_IF1MCTL.all = 0;

CanaRegs.CAN_IF2CMD.bit.DIR = 1;
CanaRegs.CAN_IF2CMD.bit.Arb = 1;
CanaRegs.CAN_IF2CMD.bit.Control = 1;

CanaRegs.CAN_IF2ARB.all = 0;

CanaRegs.CAN_IF2MCTL.all = 0;

//
// Loop through to program all 32 message objects
//
for(iMsg = 1; iMsg <= 32; iMsg+=2)
{
//
// Wait for busy bit to clear
//
while(CanaRegs.CAN_IF1CMD.bit.Busy)
{
}

//
// Initiate programming the message object
//
CanaRegs.CAN_IF1CMD.bit.MSG_NUM = iMsg;

//
// Wait for busy bit to clear
//
while(CanaRegs.CAN_IF2CMD.bit.Busy)
{
}

//
// Initiate programming the message object
//
CanaRegs.CAN_IF2CMD.bit.MSG_NUM = iMsg + 1;
}

CanaRegs.CAN_IF1CMD.bit.DATA_A = 1;
CanaRegs.CAN_IF1CMD.bit.DATA_B = 1;

CanaRegs.CAN_IF2CMD.bit.DATA_A = 1;
CanaRegs.CAN_IF2CMD.bit.DATA_B = 1;

//
// Acknowledge any pending status interrupts.
//
volatile uint32_t discardRead = CanaRegs.CAN_ES.all; // ERROR and STATUS registers


}

========================================
CAN ENABLE

========================================

void CAN_Enable(void){

//
// Enable the CAN for operation.
//
CanaRegs.CAN_CTL.bit.DAR = 1; // Disable automatic retransmission

CanaRegs.CAN_CTL.bit.Test = 0; // Enable test mode and select external loopback
CanaRegs.CAN_TEST.bit.EXL = 0; // External Loopback

CanaRegs.CAN_CTL.bit.IE0 = 1; // Abilito interrupt
CanaRegs.CAN_GLB_INT_EN.bit.GLBINT0_EN = 1;

CanaRegs.CAN_CTL.bit.IE1 = 1;
CanaRegs.CAN_GLB_INT_EN.bit.GLBINT1_EN = 1;

CanaRegs.CAN_CTL.bit.Init = 0; // Enable the CAN for operation (0 processa i messaggi normalmente)


}

========================================
TX MAILBOX SETUP

========================================

void CAN_Mailbox_Setup_TX(uint32_t objID, uint32_t msgID, uint16_t dlc)
{
//
// Use Shadow variable for IF1CMD. IF1CMD should be written to in
// single 32-bit write.
//
union CAN_IF1CMD_REG CAN_IF1CMD_SHADOW;

//
// Wait for busy bit to clear.
//
while(CanaRegs.CAN_IF1CMD.bit.Busy)
{
}

//
// Clear and Write out the registers to program the message object.
//
CAN_IF1CMD_SHADOW.all = 0;
CanaRegs.CAN_IF1MSK.all = 0;
CanaRegs.CAN_IF1ARB.all = 0;
CanaRegs.CAN_IF1MCTL.all = 0;

//
// Set the Control, Mask, and Arb bit so that they get transferred to the
// Message object.
//
CAN_IF1CMD_SHADOW.bit.Control = 1;
CAN_IF1CMD_SHADOW.bit.Arb = 1;
CAN_IF1CMD_SHADOW.bit.Mask = 1;
CAN_IF1CMD_SHADOW.bit.DIR = 1;

CanaRegs.CAN_IF1ARB.bit.Dir = 1; // se non lo forzo ad 1 manda un messaggio vuoto (remote frame RTR)
CanaRegs.CAN_IF1MCTL.bit.TxIE = 1;
//
// Set Message ID (this example assumes 11 bit ID mask)
//
CanaRegs.CAN_IF1ARB.bit.ID = (msgID << CAN_MSG_ID_SHIFT);
CanaRegs.CAN_IF1ARB.bit.MsgVal = 1;

//
// Set the data length since this is set for all transfers. This is
// also a single transfer and not a FIFO transfer so set EOB bit.
//
CanaRegs.CAN_IF1MCTL.bit.DLC = dlc;
CanaRegs.CAN_IF1MCTL.bit.EoB = 1;

//
// Transfer data to message object RAM
//
CAN_IF1CMD_SHADOW.bit.MSG_NUM = objID;
CanaRegs.CAN_IF1CMD.all = CAN_IF1CMD_SHADOW.all;
}

========================================
TX INTERRUPT HANDLING

========================================

// Devo riuscire a farlo funzionare!
__interrupt void cana_tx_isr(void){

dbg.can_tx++;
#if 0
while(!CanaRegs.CAN_ES.bit.TxOk){
}
#endif

#if 0
if(!CanaRegs.CAN_ES.bit.TxOk){
CanaRegs.CAN_ES.bit.TxOk = 0;
GpioDataRegs.GPATOGGLE.bit.GPIO31 = 1;
comando_feeder = 0;
}
#endif

if((CanaRegs.CAN_IPEN_21 && (1 << (CAN_TX_LOCK-1))) && (CanaRegs.CAN_INT.bit.INT1ID == CAN_TX_LOCK)){
GpioDataRegs.GPATOGGLE.bit.GPIO31 = 1;

CanaRegs.CAN_IF1CMD.bit.ClrIntPnd = 1;
}


//volatile uint32_t status = CanaRegs.CAN_ES.all; // ERROR and STATUS registers
CanaRegs.CAN_GLB_INT_CLR.bit.INT1_FLG_CLR = 1;
PieCtrlRegs.PIEACK.bit.ACK9 = 1;

}







  • Hi Elia,

    When inserting code in the post the next time, please use the option "Insert -> </>Code" on below toolbar when replying.  This makes the post more organized and keeps the boundary between the contents and code part which is easier to read and you can make line# references in the code.

    When using both CAN interrupt lines, register CAN_IP_MUX21 has to configured to map the mailboxes (total of 32) to the corresponding interrupt line.  I do not see the CAN_IP_MUX21 configuration in your code.

    Regards,

    Joseph

  • Hi Joseph,
    I'm sorry for the code part, next time I'll follow your instructions, I appreciated it!
    Thank you for the interrupt suggestion, I completely lost that register.
    As soon as I get back to my project I'll give you updates but I hope this one solves it.

    I keep a door open because it also happened that the IntPnd flag wasn't set the times tx interrupt was triggered.

    But nevermind, you hint is precious!
    Have a nice weekend

    Elia

  • Hi Joseph,
    Now I can correctly trigger tx interrupt.. the problem I mentioned before is remaining.

    The tx interrupt gets triggered and then I have to clear it up in order to move on.
    By diving into the debugging. the problems are:
    - the IntPen register in CAN_IF1_MCTL doesn't go to 1. So this command CanaRegs.CAN_IF1CMD.bit.ClrIntPnd = 1; has no effect

    - CanaRegs.CAN_GLB_INT_CLR.bit.INT1_FLG_CLR = 1; doesn't take such register to 1 (seen from the debugging)

    Basically I'm not able to clear the interrupt, so I permanently stay inside the routine without any exiting chance.

    Dou you any clue regarding this?
    This time I'll attach the isr code in the proper section.

    __interrupt void cana_tx_isr(void){
    
        dbg.can_tx++;
    
    
        if((CanaRegs.CAN_IPEN_21 && (1 << (CAN_TX_LOCK-1))) && (CanaRegs.CAN_INT.bit.INT1ID == CAN_TX_LOCK)){
            GpioDataRegs.GPATOGGLE.bit.GPIO31 = 1;
    
            CanaRegs.CAN_IF1CMD.bit.ClrIntPnd = 1;
        }
    
        CanaRegs.CAN_IF1CMD.bit.ClrIntPnd = 1;
    
        CanaRegs.CAN_GLB_INT_CLR.bit.INT1_FLG_CLR = 1;
        PieCtrlRegs.PIEACK.bit.ACK9 = 1;
    
    }


    Bye
    Elia 

  • Hi Elia,

    I strongly encourage you to look at the available examples in our C2000Ware.  The coding style you have adopted is what we call the bitfield type where you assign the bit values directly to the bit fields.  Our C2000Ware code uses driverlib coding, which is a more efficient coding method as it also involves several checks to make sure the location written to and value is valid.

    For CAN, there are several receive and transmit examples that illustrate how to handle the ISR and clear the interrupts properly.  For example, the below snippet is how a CAN interrupt is handled and cleared using the CAN_clearInterruptStatus() API:

    //*****************************************************************************
    //
    // CAN_clearInterruptStatus
    //
    //*****************************************************************************
    void
    CAN_clearInterruptStatus(uint32_t base, uint32_t intClr)
    {
        //
        // Check the arguments.
        //
        ASSERT(CAN_isBaseValid(base));
        ASSERT((intClr == CAN_INT_INT0ID_STATUS) ||
               ((intClr >= 1U) && (intClr <= 32U)));
    
        if(intClr == (uint32_t)CAN_INT_INT0ID_STATUS)
        {
            //
            // Simply read and discard the status to clear the interrupt.
            //
            HWREGH(base + CAN_O_ES);
        }
        else
        {
            //
            // Wait to be sure that this interface is not busy.
            //
            while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) ==
                  CAN_IF1CMD_BUSY)
            {
            }
    
            //
            // Only change the interrupt pending state by setting only the
            // CAN_IF1CMD_CLRINTPND bit.
            //
            // Send the clear pending interrupt command to the CAN controller.
            //
            HWREG_BP(base + CAN_O_IF1CMD) = ((uint32_t)CAN_IF1CMD_CLRINTPND |
                                            (intClr & CAN_IF1CMD_MSG_NUM_M));
    
            //
            // Wait to be sure that this interface is not busy.
            //
            while((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) ==
                  CAN_IF1CMD_BUSY)
            {
            }
        }
    }
    

    Note that prior to clearing the interrupt, there is a check done with the CAN to check if IF1CMD is busy.

    Regards,

    Joseph