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.

TMS320F2808: CAN Bus timeout inconsistency

Part Number: TMS320F2808

I have a circuit that is happy when both CAN devices are the same baud rate. I have now setup the end device to have a different baud rate at startup to purposefully cause a timeout of the CAN tx message. I feel there is something missing in my 'resetting' of the timeout as the code only works every other time.

What I mean is when F2808 is 20Kbps and end device is 1Mbps, the first time, the F2808 CAN Tx timesout and then moves to a function to update the baudrate to 1Mbps and then the rest of the CAN messages are processed as expected. I then stop the execution and then restart the same code, the F2808 start at 20Kbps, CAN message timesout, switches to 1Mbps but the next message fails but I can't trace why. I then restart the code and the same baud process executes but this time it works as expected. Every other CPU reset it works as expected but every other reset fails. 

Seems as if some flag during the failed state is reset when the next CPU reset is issued but I can't seem to find it.

What are some of the key flags to ensure is cleared during a CAN tx timeout, and how do I reset them?

Or should I abort the Tx message before trying to change baud rate (or send another message any time a TO occurs)?

PMDresult CAN_SendCmdMsg(struct CAN_CONFIG* cancfg, Uint16 bytecount, Uint16* bytes)
{
    PMDresult result = PMD_NOERROR;
    cancfg->TX_MBOX->MSGCTRL.bit.DLC = bytecount;
    // add bytes to mailbox
    StuffMailbox(cancfg, bytecount, &bytes[0]);

    /* Clear the "Time Stamp Counter"  */
    EALLOW;
    ECanaRegs.CANTSC = 0;
    EDIS;

    ECanRegsShadow.CANTRS.all = 0;
    ECanRegsShadow.CANTRS.all = cancfg->TX_BIT;     // Set TRS for mailbox under test
    ECanaRegs.CANTRS.all = ECanRegsShadow.CANTRS.all;
    //
    // Wait for TAn bits to be set
    // TODO Set timeouts on all do..while
    //
    ECanRegsShadow.CANTA.all = ECanaRegs.CANTA.all;
    do
    {
        ECanRegsShadow.CANTOS.all = ECanaRegs.CANTOS.all;
        ECanRegsShadow.CANTA.all = ECanaRegs.CANTA.all;
    } while((ECanRegsShadow.CANTA.all & cancfg->TX_BIT) == 0 && // Wait for TAx = 1 (Successful CAN transmit)
            (ECanRegsShadow.CANTOS.all & cancfg->TX_BIT) == 0); // TOS = 1 when timeout occurred
    /* Service a timeout? */
    if((ECanRegsShadow.CANTOS.all & cancfg->TX_BIT) == cancfg->TX_BIT)
    {
        // timeout occurred so clear the bit and move on
        ECanRegsShadow.CANTOC.all = ECanaRegs.CANTOC.all;
        ECanRegsShadow.CANTOC.all = cancfg->TX_BIT;
        ECanaRegs.CANTOC.all = ECanRegsShadow.CANTOC.all;
        // CANTOC should be clear now
        result = PMD_ERR_Timeout;
    }

    ECanRegsShadow.CANTA.all = 0;
    ECanRegsShadow.CANTA.all = cancfg->TX_BIT;         // Clear tx bit
    ECanaRegs.CANTA.all = ECanRegsShadow.CANTA.all;

    return result;
}

    /*
    * This bit globally enables all interrupts for the ECAN0INT line if the corresponding masks are set.
    */
    ECanRegsShadow.CANGIM.all = ECanRegsShadow.CANGIM.all;
    ECanRegsShadow.CANGIM.bit.I0EN = 1;   // Enable eCAN0INT
    ECanRegsShadow.CANGIM.bit.I1EN = 0;   // Disable eCAN1INT
    ECanRegsShadow.CANGIM.bit.MTOM = 1;   // Enable mailbox timeouts
    ecanregs->CANGIM.all = ECanRegsShadow.CANGIM.all;

    /*
     * Setup transmit and receive timeouts
     * Limit-value of the time-stamp counter (TSC) 100 clocks / uSec
     *    TSC is incremented by bit clock so it is independent of bit per second
     */
    ECanaMOTORegs.MOTO[INIT_TX_CANMBOX] = 0x400;
    ECanaMOTORegs.MOTO[INIT_RX_CANMBOX] = 0x400;
    ECanaMOTORegs.MOTO[AZ_TX_CANMBOX]   = 0x400;
    ECanaMOTORegs.MOTO[AZ_RX_CANMBOX]   = 0x400;
    /* Enable time-out function for the mailboxes */
    ECanaRegs.CANTOC.all = MAILBOX0BIT | MAILBOX5BIT | MAILBOX16BIT | MAILBOX21BIT;
    /* Clear the "Time Stamp Counter"  */
    ECanaRegs.CANTSC = 0;

  • Not sure if this helps but I am seeing in the 1st message of GetID(), the power cycle that works, the F2808 is producing an ACK after the request but on the power cycle that fails, there is no ACK but the message frames are identical. Not sure why the F2808 would not send ACK. Any thoughts? (The connected device will always output 2 bytes after every message received as status bytes.)

  • Jeffrey,

                    Mismatched bit-rates should quickly take the transmitting node to bus-off. Do you see that? When node enters BO, CCR bit should be set. If you see this happening, you could use that instead of a time-out condition. I am bit unclear on what you are trying to do. 

    In your second post, you are talking about an ACK, but ACK from who? If the 2808 is transmitting, it is the other node that would generate the ACK. What you interpret as ACK may be the ACK delimiter, not the ACK itself. Remember the ACK field consists of two bits. The transmitter puts out a 1, which is overridden by a receiver which puts out a 0. This is followed by a 0, which is the ACK delimiter. 

    Please read sections 3.1 & 3.2 of www.ti.com/lit/spra876  and section 2.1 of  www.ti.com/lit/spra890.

  • I will look into the Bus off in a bit - thanks for that

    UPDATE - The only bits in the CANES register are the ACKE and SMA (which I expect based on breakpoint?)

    As for the second part, I suspect the missing ACK is from the F2808. The F2808 queries (tx 0x605) the 58113 for an ID and then the 58113 replies (tx 0x585). So the first message is F2808 tx and the next message is from the 58113 responding so it is txing and the F2808 is rxing. That is why I suspected the F2808 is not providing the ACK.

  • When the bit-rates are the same, each node correctly acknowledges the transmission from the other node, so there are no H/W issues in your setup. 

    When the bit-rates are mis-matched, the communication will not get very far since the receiver won't be able to interpret the traffic on the bus and would destroy the on-going transmission with error frames. The transmission won't even reach the ACK phase. 

    If, in a normal communication setup (matching bit-rates), if the transmitter does not receive an ACK, ACKE bit will indeed be set. In a mis-matched bit-rate setting, some other error bit should be set in CANES. 

    Your understanding on SMA bit is correct.

  • Please note that at the time of the images, the bit rates are the same. This is after the F2808 tx timeout experienced.

    Are you recommending that the timeouts not be utilized until bit timing matches - use a timeout instead?

  • Considering your network works fine under normal circumstances (i.e. when the bit-rate is identical), the receiving node must provide an ACK, unless it is in bus-off condition. I don't know how you handle recovery from bus-off. It could either be automatic (ABO=1) or done manually by clearing CCR (ABO=0).

    Are you recommending that the timeouts not be utilized until bit timing matches - use a timeout instead?

    Sorry, I don't understand the question. It sounds contradictory.

  • I am asking if you would recommend leaving the CAN tx/rx timeout features off until both devices are set to the same baud rate?

    Also, I would appreciate knowledge on how to recover from a timeout if it is experienced so the the CAN bus can remain alive if it was just a glitch.

  • Jeffrey,

        Perhaps it would be more time efficient to discuss over a call. Will reach out privately.

  • This seems to be directly associated with the timeout register. Originally I set up all the timeout registers in the CAN_Init(). To overcome this lack of ACK from TI, I moved the the following code to prior to testing the CANRMP for receive time outs and prior to setting the CANTRS bit for the transmit timeouts:

        /* Enable and clear the "Time Stamp Counter"  */
        EALLOW;
        ECanRegsShadow.CANTOC.all = ECanaRegs.CANTOC.all;
        ECanRegsShadow.CANTOC.all |= (Uint32)(1 << mbox);
        ECanaRegs.CANTOC.all = ECanRegsShadow.CANTOC.all; // Set the time out enable
        ECanaRegs.CANTSC = 0; // Reset the time out counter
        ECanaRegs.CANGIF0.all  = 0xFFFFFFFF; /* Clear all interrupt flag bits */
        EDIS;

    The MTOM and MOTO registers are still declared in the CAN_Init().

    I then added the following code to immediately after setting the CANRMP value for receive time outs and immediately after the setting of the CANTA for the transmit time outs:

        /* Disable and clear the "Time Stamp Counter"  */
        EALLOW;
        ECanRegsShadow.CANTOC.all = ECanaRegs.CANTOC.all;
        ECanRegsShadow.CANTOC.all &= ~(Uint32)(1 << mbox); // Disable specific time out
        ECanaRegs.CANTOC.all = ECanRegsShadow.CANTOC.all;
        ECanaRegs.CANTSC = 0; // Reset the time out counter
        EDIS;

    The ability to recover from a CAN time out seems to be lacking in documentation, and I haven't found much to support any of the other global interrupts recovery - ability to keep the CAN bus active after the global issue. Any help here would be greatly appreciated.

  • Jeffrey,

         I just wrote a test case and verified that bit-rate switch per se is not the issue. I transmit a frame at 1 Mbps from a TI MCU to the bus analyzer, which is correctly received. I then reconfigure the MCU (and the bus analyzer) to 50 kbps and let the bus analyzer transmit a frame @ 50 kbps, which is correctly received by the MCU. 

    I'll be travelling starting this evening. Will get back to you on your last post by Monday.

  • I agree the bit rate change is not the issue but thanks for confirming that. :-) Nice to get a second opinion!

  • Let me look at your code snippet and get back to you. It would be likely Monday or Tuesday. Thank you for your patience.