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.

TMS320F280039C: MCAN - Not working at rates > 3Mbps

Part Number: TMS320F280039C
Other Parts Discussed in Thread: LAUNCHXL-F280039C, TCAN332, ISO1042

Tool/software:

Hi,

I have the problem that I cannot run CANFD at higher datarates than 3Mbps on my controller and a F280039C Eval Board or 4Mbps in between two F280039C Eval Boards with a very short cable (< 10cm) in both setups. I am using a CANFD example which I extended a little, so that I can choose the baudrate and trigger a message when I want. So everything works fine with 3Mbps, but my board already has a problem at 3Mbps and the two EVAL boards at 4Mbps. At 3Mbps I can also make the cable 1m long and I dont't face any issues in both setups. My own boards uses an isolated CANFD compatible transceiver, the ISO1042QDWVRQ1, so that is more or less the only difference, the firmware is the same on both boards.

About the Hardware:

CANFD Transceiver on my custom board (Note that I already removed the 10pF caps for testing):

Note that on the custom board, TX and RX of the transceiver are S50 impedance matched lines and only a few centimeter. The output of the driver is also only a few centimeter and close to 120Ohm differential and 60Ohm single end. Use of good design practice are guaranteed (continous GND plane, impedance matching etc,).

What I measured:

I measured the TX line on the EVAL board and the RX line on the other EVAL board / my custom board with an oscilloscope and it looks like the following for a 1 byte payload message (Not the measurements are not done with a spring probe):

EVAL to EVAL (working fine):



EVAL to Custom (Not working):



So from a signal point of view, I think it looks fine. In the end, it looks like there is no ACK from the receiving node.

About the firmware:

I used the MCAN_BitTimingCalculator.xls from TI to calculate the timings for different frequencies. Both controller use an external 10ppm tolerance 20Mhz crystal and running at 120MHz. 


Registers:

CANFD Timing:

#ifdef USE_500KBAUDPS
    //DIV3 -->500kBit (1Mbit/s data rate) --> Look at the timing calculator, put in 120Mhz, DIV3 etc. then look at Drierlib / Syscfg Inputs below in the .xlsx --> should output the values below!!!
    bitTimes.nomRatePrescalar   = 3U; // Nominal Baud Rate Pre-scaler
    bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
    bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
    bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
    bitTimes.dataRatePrescalar  = 1U; // Data Baud Rate Pre-scaler
    bitTimes.dataTimeSeg1       = 9U; // Data Time segment before SP
    bitTimes.dataTimeSeg2       = 8U; // Data Time segment after SP
    bitTimes.dataSynchJumpWidth = 8U; // Data SJW
#endif

#ifdef USE_1MBAUDPS
    //DIV1 --> 1MBaudps --> 2Mbit/s data rate
    bitTimes.nomRatePrescalar   = 4U; // Nominal Baud Rate Pre-scaler
    bitTimes.nomTimeSeg1        = 11U; // Nominal Time segment before SP
    bitTimes.nomTimeSeg2        = 10U; // Nominal Time segment after SP
    bitTimes.nomSynchJumpWidth  = 10U; // Nominal SJW
    bitTimes.dataRatePrescalar  = 2U; // Data Baud Rate Pre-scaler
    bitTimes.dataTimeSeg1       = 9U; // Data Time segment before SP
    bitTimes.dataTimeSeg2       = 8U; // Data Time segment after SP
    bitTimes.dataSynchJumpWidth = 8U; // Data SJW
#endif

#ifdef USE_1_5MBAUDPS
    //DIV1 --> 1.5MBaudps --> 3Mbit/s data rate
    bitTimes.nomRatePrescalar   = 3U; // Nominal Baud Rate Pre-scaler
    bitTimes.nomTimeSeg1        = 10U; // Nominal Time segment before SP
    bitTimes.nomTimeSeg2        = 7U; // Nominal Time segment after SP
    bitTimes.nomSynchJumpWidth  = 7U; // Nominal SJW
    bitTimes.dataRatePrescalar  = 1U; // Data Baud Rate Pre-scaler
    bitTimes.dataTimeSeg1       = 10U; // Data Time segment before SP
    bitTimes.dataTimeSeg2       = 7U; // Data Time segment after SP
    bitTimes.dataSynchJumpWidth = 7U; // Data SJW
#endif

#ifdef USE_2MBAUDPS
    //DIV1 --> 2MBaudps --> 4Mbit/s data rate
    bitTimes.nomRatePrescalar   = 2U; // Nominal Baud Rate Pre-scaler
    bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
    bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
    bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
    bitTimes.dataRatePrescalar  = 1U; // Data Baud Rate Pre-scaler
    bitTimes.dataTimeSeg1       = 6U; // Data Time segment before SP
    bitTimes.dataTimeSeg2       = 6U; // Data Time segment after SP
    bitTimes.dataSynchJumpWidth = 5U; // Data SJW

#endif

#ifdef USE_3MBAUDPS
    //DIV1 --> 3MBaudps --> 3Mbit/s data rate
    bitTimes.nomRatePrescalar   = 3U; // Nominal Baud Rate Pre-scaler
    bitTimes.nomTimeSeg1        = 5U; // Nominal Time segment before SP
    bitTimes.nomTimeSeg2        = 2U; // Nominal Time segment after SP
    bitTimes.nomSynchJumpWidth  = 2U; // Nominal SJW
    bitTimes.dataRatePrescalar  = 3U; // Data Baud Rate Pre-scaler
    bitTimes.dataTimeSeg1       = 5U; // Data Time segment before SP
    bitTimes.dataTimeSeg2       = 2U; // Data Time segment after SP
    bitTimes.dataSynchJumpWidth = 2U; // Data SJW
#endif

#ifdef USE_4MBAUDPS //Needs 2 termination resistors
    //DIV1 --> 4MBaudps --> 4Mbit/s data rate
    bitTimes.nomRatePrescalar   = 1U; // Nominal Baud Rate Pre-scaler
    bitTimes.nomTimeSeg1        = 7U; // Nominal Time segment before SP
    bitTimes.nomTimeSeg2        = 5U; // Nominal Time segment after SP
    bitTimes.nomSynchJumpWidth  = 5U; // Nominal SJW
    bitTimes.dataRatePrescalar  = 1U; // Data Baud Rate Pre-scaler
    bitTimes.dataTimeSeg1       = 7U; // Data Time segment before SP
    bitTimes.dataTimeSeg2       = 5U; // Data Time segment after SP
    bitTimes.dataSynchJumpWidth = 5U; // Data SJW
#endif

#ifdef USE_5MBAUDPS //Needs 2 termination resistors
    //DIV1 --> 5MBaudps --> 5Mbit/s data rate
    bitTimes.nomRatePrescalar   = 0U; // Nominal Baud Rate Pre-scaler
    bitTimes.nomTimeSeg1        = 3U; // Nominal Time segment before SP
    bitTimes.nomTimeSeg2        = 2U; // Nominal Time segment after SP
    bitTimes.nomSynchJumpWidth  = 2U; // Nominal SJW
    bitTimes.dataRatePrescalar  = 0U; // Data Baud Rate Pre-scaler
    bitTimes.dataTimeSeg1       = 3U; // Data Time segment before SP
    bitTimes.dataTimeSeg2       = 2U; // Data Time segment after SP
    bitTimes.dataSynchJumpWidth = 2U; // Data SJW
#endif

Any idea, what could cause that? In the end, the EVAL boards should also be able to run at 5Mbps, but they dont. So I still think this is a firmware issue and not a hardware issue (the ISO1042QDWVRQ1 has more delay, so this might be the difference). When I try to send with >3Mbps from my board or > 4Mbps from the EVAL board, I dont get a CAN frame, just down and up again after a few 100 ns.

  • Hi Hans,

    Based on the 500kbps bit timings snippet, I am assuming that SYSCLK is running at 120MHz and MCAN is running at 40MHz, which is similar to the SW examples.  The 40Mhz MCAN speed is defined by the API function  SysCtl_setMCANClk(SYSCTL_MCANCLK_DIV_3).  Please confirm if this the correct.  Also please note that in MCAN, there are two bit timings to satisfy.  The first one is the NOM (or nominal) bit rate which is the bit rate from start of frame, arbitration bits, control bits, DLC and BRS (bit rate switching).  After BRS, the bit rate switches to data rate, which can be much faster than the nominal rate.

    Nominal rate can only go as high as 1Mbps for MCAN but the data rate can go up to 5Mbps.  I see that some of the nominal bit timings in your snippet go beyond 1Mbps.  Please use below equation for both nominal and data bit rates:

           Bit rate = (MCAN CLK / (RatePrescaler + 1))/(TimeSeg1 + TimeSeg2 + 3)

    Given that MCAN CLK is 40MHz, and using the bit rate formula above, here are the values to use for a nominal rate of 1Mbps and data rate of 5Mbps:

           nomRatePrescaler = 1U;

           nomTimeSeg1 = 9U;

           nomTimeSeg2 = 8U;

           dataRatePrescaler = 0U;

           dataTimeSeg1 = 3U;

           dataTimeSeg2 = 2U;

    Regards,

    Joseph

  • Hi Joseph,

    Thank you for your response. I forgot to commit the DIV, yes for 500kbps it is SYSCTL_MCANCLK_DIV_3, for the rest of the timings, it is SYSCTL_MCANCLK_DIV_1 and so the MCAN clk is 120MHz.

    Oh I tought that also the nominal bit time can go as high as the data bitrate, thanks for the clarification. Still I am facing issues, now even at 3Mbps, but only when I try to send from the custom board. At 4Mbps it also happen between two EVAL boards, so not even close to 5Mbps with such a short cable.



    Custom (yellow TX) to Eval (blue TX):

    Eval (blue TX) to Custom (yellow TX):

    The exact same 64byte message is sent, once from the Custom to the Eval PCB and then vis versa. It seems. It seems, that the F280039C of the custom board is not even trying to send out the message, but I really don't see what could cause that. At 2Mbps it works perfectly.

    I adjusted the normal bitrate as you mentioned and used again the .xlsx from TI to calcualte the baud rates (using a SYSCTL_MCANCLK_DIV_2 in the following):

    #ifdef USE_3MBAUDPS
        //DIV2 --> 1MBaudps nominal (max nominal speed is 1MBaudps) --> 3Mbit/s data rate
        bitTimes.nomRatePrescalar   = 2U; // Nominal Baud Rate Pre-scaler
        bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
        bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
        bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
        bitTimes.dataRatePrescalar  = 0U; // Data Baud Rate Pre-scaler
        bitTimes.dataTimeSeg1       = 9U; // Data Time segment before SP
        bitTimes.dataTimeSeg2       = 8U; // Data Time segment after SP
        bitTimes.dataSynchJumpWidth = 8U; // Data S
    #endif
    
    #ifdef USE_4MBAUDPS //Needs 2 termination resistors
        //DIV2 --> 1MBaudps nominal (max nominal speed is 1MBaudps) --> 4Mbit/s data rate
        bitTimes.nomRatePrescalar   = 2U; // Nominal Baud Rate Pre-scaler
        bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
        bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
        bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
        bitTimes.dataRatePrescalar  = 0U; // Data Baud Rate Pre-scaler
        bitTimes.dataTimeSeg1       = 6U; // Data Time segment before SP
        bitTimes.dataTimeSeg2       = 6U; // Data Time segment after SP
        bitTimes.dataSynchJumpWidth = 5U; // Data S
    #endif
    
    #ifdef USE_5MBAUDPS //Needs 2 termination resistors
        //DIV2 --> 1MBaudps nominal (max nominal speed is 1MBaudps) --> 5Mbit/s data rate
        bitTimes.nomRatePrescalar   = 2U; // Nominal Baud Rate Pre-scaler
        bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
        bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
        bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
        bitTimes.dataRatePrescalar  = 0U; // Data Baud Rate Pre-scaler
        bitTimes.dataTimeSeg1       = 5U; // Data Time segment before SP
        bitTimes.dataTimeSeg2       = 4U; // Data Time segment after SP
        bitTimes.dataSynchJumpWidth = 4U; // Data S
    #endif

    Setup Eval Boards:



  • Hi Hans,

    MCAN CLK can only be set from 20MHz to 80MHz as limitation to the IP.  Clocking at 120MHz is outside of the operating spec of the MCAN module.  For this case, you are limited to div by 2, 3, 4 and 5.  Try reducing the MCAN clock to the spec values.  5Mbps should be easily attainable with your setup as long as clock spec is not violated.

    Regards,

    Joseph

  • Hi Joseph, I already used a DIV2, so 60MHz clock signal, but that alone did not work. I added now an external propagation delay of 130ns, that worked so far with the eval boards, they can now go up to 5Mbps. My custom board with the isolated CANFD Transceiver does now only work up to 4Mbps, also with a external propagation delay of 200ns I do not reach the 5Mbps, the controller just gives out the signals from above. I don't really now what causes that, but it seems impossible to get 5Mbps with the isolated CAN transceiver. The ISO1042QDWVRQ1 at least states it can handle rates up to 5Mbps.



    MCAN_BitTimingCalculator.xlsx:

  • Hi Han,

    Sorry, i skipped that part about the div2 in your response above.  Would you please try a div3 such that the MCAN CLK is 40MHz and use below nom and data timings and see if you can get 1Mbps/5Mbps nom/data rate?

           nomRatePrescaler = 1U;

           nomTimeSeg1 = 9U;

           nomTimeSeg2 = 8U;

           dataRatePrescaler = 0U;

           dataTimeSeg1 = 3U;

           dataTimeSeg2 = 2U;

    Thanks,

    Joseph

  • Hi Joseph, sorry for the late reply. I could now test it, it does not change anything. I only get faster speeds when I account for the transceiver delay. I really don't see what else it could be.

    I adjusted the bus length to 70m in the .xslx at that let it work with 4Mbps, but still not 5Mbps.

  • Hi Hans,

    I'm checking some online forums and have seen common answer that upper cable length limit to attain 5Mbps is 40m.  With shorter cable length, would you be able to scope CAN_L and CAN_H terminals on the receiving end ( and do a math difference for the actual CAN frame waveform)?  Would want to inspect the waveform of the transmitted frame to see if there are any distortions or noise. 

    Thanks,

    Joseph

  • Hi Joseph,

    I attached the plots of CAN_L and CAN_N for 3Mbps and 5Mbps. You can see, that at 5Mbps, somehow the CAN_L and CAN_H looks like floating.

    Yellow: CANL, Light Blue: CANH, Dark Blue: TX from Sender.

    3Mbps:

    5Mbps:

  • Hi Hans,

    Can you double check on your timings again?  In the 5Mbps, one bit width seems to be ~1us.  It should be ~200ns.  Also, instead of the blue trace from the TX, can you instead do a math operation on the waveform and display CAN_H - CAN_L or get the scope on the receiving node on the CANRX side?  The differential waveform from the receiving end transceiver will produce the CANRX waveform for the receiving node.

    Also can you inspect the MCAN_PSR register contents on both transmitting and receiving nodes to see what errors might have occurred during the transaction?

    Regards,

    Joseph

  • Hi Joseph, 

    The MCAN runs with 1Mbps nominal and 5Mbps data rate, so what you see above is the nominal rate for arbitration, then when changing to the data rate, it seems to fail (not one pulse is sent). 

    I probed now directly the RX input now on the receiver node with the blue trace, no change to the old one:

    About the PSR Register:

    Transmitter Node:


    Receiver Node:

    The timing are correct, I am using the DIV3 and the timings from the .xlsx:

    Edit:

    Here is also a plot at 3Mbps, you see now when the arbitration phase ends, it switches correctly to 333ns cycle time:

    Regards,

    Hans

  • Hi Hans,

    Ok, that explains the 1us bit time on the 5Mbps rate.  The PSR register is not telling us anything useful.  Can we back up on the original information you shared?

    My own boards uses an isolated CANFD compatible transceiver, the ISO1042QDWVRQ1, so that is more or less the only difference, the firmware is the same on both boards.

    In the picture, it seems that you were using LAUNCHXL-F280039C but the schematics of that LaunchPad is using TCAN332DR:

    Was there a modification done on your launchpad to change the TCAN332 to the isolated transceiver ISO1042QDWVRQ1 or is this an entirely different hardware that you have been using?  I've tested several applications with TCAN332 and did not see any issues meeting 5Mbps rates.

    Thanks,

    Joseph

  • Hi Joseph,

    Thanks for the investigation. Can you share the code with me you used for testing? Because I could not run it faster than 3Mbps between the two original LAUNCHXL-F280039C without the delay modifications

    The Osci Plots from the last few messages are between an EVAL and our custom test board with the ISO1042, so it is our own design, fully oriented on the EVAL board (same components the F280039C, incl. CLK). Layout should not be the problem, overall we used S50 impedance matching and for the CANL, CANH D120, continous GND plane etc. And overall it more seems like one CAN node seems to miss a edge or something like that. 

  • //
    // Include Files
    //
    #include "driverlib.h"
    #include "device.h"
    #include "inc/stw_types.h"
    #include "inc/stw_dataTypes.h"
    #include <string.h>
    
    //
    // Defines.
    //
    #define NUM_OF_MSG                      (1U)
    #define MCAN_STD_ID_FILTER_NUM          (1U)
    #define MCAN_EXT_ID_FILTER_NUM          (0U)
    #define MCAN_FIFO_0_NUM                 (0U)
    #define MCAN_FIFO_0_ELEM_SIZE           (MCAN_ELEM_SIZE_64BYTES)
    #define MCAN_FIFO_1_NUM                 (0U)
    #define MCAN_FIFO_1_ELEM_SIZE           (MCAN_ELEM_SIZE_64BYTES)
    #define MCAN_RX_BUFF_NUM                (10U)
    #define MCAN_RX_BUFF_ELEM_SIZE          (MCAN_ELEM_SIZE_64BYTES)
    #define MCAN_TX_BUFF_SIZE               (NUM_OF_MSG)
    #define MCAN_TX_FQ_SIZE                 (0U)
    #define MCAN_TX_BUFF_ELEM_SIZE          (MCAN_ELEM_SIZE_64BYTES)
    #define MCAN_TX_EVENT_SIZE              (0U)
    
    //
    //  Defining Starting Addresses for Message RAM Sections,
    //  (Calculated from Macros based on User defined configuration above)
    //
    #define MCAN_STD_ID_FILT_START_ADDR     (0x0U)
    #define MCAN_EXT_ID_FILT_START_ADDR     (MCAN_STD_ID_FILT_START_ADDR + ((MCAN_STD_ID_FILTER_NUM * MCANSS_STD_ID_FILTER_SIZE_WORDS * 4U)))
    #define MCAN_FIFO_0_START_ADDR          (MCAN_EXT_ID_FILT_START_ADDR + ((MCAN_EXT_ID_FILTER_NUM * MCANSS_EXT_ID_FILTER_SIZE_WORDS * 4U)))
    #define MCAN_FIFO_1_START_ADDR          (MCAN_FIFO_0_START_ADDR + (MCAN_getMsgObjSize(MCAN_FIFO_0_ELEM_SIZE) * 4U * MCAN_FIFO_0_NUM))
    #define MCAN_RX_BUFF_START_ADDR         (MCAN_FIFO_1_START_ADDR + (MCAN_getMsgObjSize(MCAN_FIFO_1_ELEM_SIZE) * 4U * MCAN_FIFO_1_NUM))
    #define MCAN_TX_BUFF_START_ADDR         (MCAN_RX_BUFF_START_ADDR + (MCAN_getMsgObjSize(MCAN_RX_BUFF_ELEM_SIZE) * 4U * MCAN_RX_BUFF_NUM))
    #define MCAN_TX_EVENT_START_ADDR        (MCAN_TX_BUFF_START_ADDR + (MCAN_getMsgObjSize(MCAN_TX_BUFF_ELEM_SIZE) * 4U * (MCAN_TX_BUFF_SIZE + MCAN_TX_FQ_SIZE)))
    
    //Other
    #define MCAN_BUS_OFF_CNTR_ms            (100)
    #define MCAN_BUS_LOCK_ERR_CNTR_ms       (200)
    
    #define MCAN_TX_MESSAGE_BUFFERS         (1)
    #define MCAN_RX_MESSAGE_BUFFERS         (1)
    
    #define MCAN_DATA_BUFFER_SIZE           (64U) //Need to be the same as ELEM SIZE
    #define MCAN_DATA_ELEM_SIZE             (MCAN_ELEM_SIZE_64BYTES)
    
    #ifdef IS_NODE_1
    // CAN ID for TX
    #define LL_MCAN_TX_ADDR 0x01
    
    // CAN ID for RX
    #define LL_MCAN_RX_ADDR 0x00
    #else
    // CAN ID for TX
    #define LL_MCAN_TX_ADDR 0x00
    // CAN ID for RX
    #define LL_MCAN_RX_ADDR 0x01
    #endif
    
    //#define USE_2MBAUDPS
    //#define USE_4MBAUDPS
    #define USE_5MBAUDPS
    
    //#define USE_1_BYTE_PAYLOAD
    #define USE_64_BYTE_PAYLOAD
    
    #define USE_MCAN_WITH_ISR
    
    //*******************************************************************************************************************************************//
    // Global Structs
    //*******************************************************************************************************************************************//
    typedef struct
    {
        uint32_t mcan_err_cntr;
        uint16_t mcan_dlc_length;
        uint16_t mcan_rx_msg_cntr;
        uint16_t mcan_is_rx;
        uint32_t mcan_rx_id;
    } MCAN_RX_Handler_t;
    
    //*******************************************************************************************************************************************//
    // Variables
    //*******************************************************************************************************************************************//
    MCAN_RxBufElement rxMsg;
    MCAN_TxBufElement txMsg;
    MCAN_ProtocolStatus protStatus;
    
    bool send_test_msg = false;
    bool send_continous_test_msg = false;
    
    volatile MCAN_RX_Handler_t mcan_handler;
    
    // Lookup table for CAN FD DLC to data length mapping
    volatile uint16_t dlc_to_length[16] =
    {
            0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64
    };
    
    uint8_t msg[64] = {0};
    
    volatile uint32_t mcan_recovery_counter = 0;
    volatile uint32_t mcan_bus_lock_counter = 0;
    volatile uint32_t mcan_rx_message_counter = 0;
    volatile uint32_t mcan_isr_cntr = 0;
    volatile uint32_t intrStatus = 0;
    
    //Counter for bus off recovery
    uint32_t mcan_bus_off_recovery_counter = 0;
    
    //Counter for TX messages
    uint32_t mcan_tx_message_counter = 0;
    uint32_t mcan_tx_status = 0;
    
    uint32_t mcan_cccr_status = 0;
    
    //Flag for bus off lock
    bool bus_off_lock = true;
    
    uint32_t time_cntr_ms = 0;
    
    //*******************************************************************************************************************************************//
    // Local ISR
    //*******************************************************************************************************************************************//
    __interrupt void MCANIntr1ISR(void);
    
    
    //*******************************************************************************************************************************************//
    // Local Function Prototype
    //*******************************************************************************************************************************************//
    /**
     * @brief: Sends a MCAN Message
     */
    static void MCANTxMessage(uint16_t *data, uint16_t len);
    
    /**
     * @brief: Process of the MCAN
     */
    static void MCANProcess();
    
    /**
     * @brief: Test message
     */
    static void MCAN_SEND_TEST_MSG();
    
    /**
     * @brief: Receives a MCAN Message
     */
    static void MCANRxMessages();
    
    /**
     * @brief: Configure MCAN
     */
    static void MCANConfig(void);
    
    /**
     * @brief: This function will configure X-BAR for MCAN interrupts.
     */
    static void MCANIntrConfig(void);
    
    
    //*******************************************************************************************************************************************//
    // Global Functions
    //*******************************************************************************************************************************************//
    void main()
    {
    
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Initialize GPIO and unlock the GPIO configuration registers
        //
        Device_initGPIO();
    
    
        // GPIO4->MCAN TX on EVAL Board Only
        GPIO_setPinConfig(GPIO_4_MCAN_TX);
        GPIO_setDirectionMode(4, GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(4, GPIO_PIN_TYPE_STD);
    
    
        GPIO_setPinConfig(GPIO_5_MCAN_RX);
        GPIO_setDirectionMode(5, GPIO_DIR_MODE_IN);
        GPIO_setPadConfig(5, GPIO_PIN_TYPE_STD);
    
        //Configure the MCAN
        MCANConfig();
    
        //Buffer declaration
        uint16_t i = 0;
        for(i = 0; i < 64; i++)
        {
            msg[i] = i;
        }
    
    
        while(1)
        {
            MCANProcess();
        }
    
    }
    
    //*******************************************************************************************************************************************//
    // Static Functions
    //*******************************************************************************************************************************************//
    
    /* Defined on top of this file */
    static void MCANProcess()
    {
        //Check for messages to receive:
        MCANRxMessages();
    
        /* Wait 1ms */
        DEVICE_DELAY_US(1000);
    
        /* Do something */
        if(send_test_msg)
        {
            send_test_msg = false;
            MCAN_SEND_TEST_MSG();
        }
        else if(send_continous_test_msg)
        {
            MCAN_SEND_TEST_MSG();
        }
    }
    
    /**
     * @brief: Defined on top of this file
     */
    static void MCAN_SEND_TEST_MSG()
    {
        //Send the message
    #ifdef USE_1_BYTE_PAYLOAD
        MCANTxMessage(msg, 1);
    #else
        MCANTxMessage(msg, 64);
    #endif
    }
    
    /* Defined on top of this file */
    static void MCANTxMessage(uint16_t *data, uint16_t len)
    {
        //
        // Check for correct length
        //
        if(len > MCAN_DATA_BUFFER_SIZE)
        {
            return;
        }
    
        //Count tx
        mcan_tx_message_counter++;
    
        //
        //copy
        //
        memcpy(&txMsg.data[0], data, len);
    
        //
        // Write message to Message RAM.
        //
        MCAN_writeMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, 0U,
                         &txMsg);
    
        //
        // Add transmission request for Tx buffer 0
        //
        mcan_tx_status = MCAN_txBufAddReq(MCANA_DRIVER_BASE, 0U);
    
        //
        // Wait till the frame is successfully transmitted (and ACKnowledged)
        // "Tx Buffer Transmission Occurred" register is polled.
        //
        while(MCAN_getTxBufReqPend(MCANA_DRIVER_BASE))
        {
        }
    }
    
    /* Defined on top of this file */
    static void MCANRxMessages()
    {
        if(mcan_handler.mcan_is_rx == 1)
        {
            //Reset flag
            mcan_handler.mcan_is_rx = 0;
    
            //
            if(rxMsg.dlc < 16)
            {
                mcan_handler.mcan_dlc_length = dlc_to_length[rxMsg.dlc];
    
                //Number of MSG
                mcan_handler.mcan_rx_msg_cntr++;
            }
        }
    }
    
    /* Defined on top of this file */
    static void MCANIntrConfig(void)
    {
        Interrupt_initModule();
        Interrupt_initVectorTable();
    
        Interrupt_register(INT_MCANA_1,&MCANIntr1ISR);
        Interrupt_enable(INT_MCANA_1);
    
        Interrupt_enableGlobal();
    }
    
    static void MCANConfig(void)
    {
        MCAN_InitParams initParams;
        MCAN_MsgRAMConfigParams    msgRAMConfigParams;
        MCAN_StdMsgIDFilterElement stdFiltelem;
        MCAN_BitTimingParams       bitTimes;
    
        //
        //  Initializing all structs to zero to prevent stray values
        //
        memset(&initParams, 0, sizeof(initParams));
        memset(&msgRAMConfigParams, 0, sizeof(msgRAMConfigParams));
        memset(&stdFiltelem, 0, sizeof(stdFiltelem));
        memset(&bitTimes, 0, sizeof(bitTimes));
    
        //
        // Configure the divisor for the MCAN bit-clock
        //
        SysCtl_setMCANClk(SYSCTL_MCANCLK_DIV_3); //SYSCLK = 120MHz, DIV2 = 60MHz, DIV3 = 40MHz
    
    #ifdef USE_MCAN_WITH_ISR
        //
        // ISR Configuration.
        //
        MCANIntrConfig();
    #endif
    
        //
        // Reset Buffer
        //
        uint16_t j = 0;
    
    
        //Write also for handler
        mcan_handler.mcan_rx_id = LL_MCAN_RX_ADDR;
    
        //
        // Initialize message to receive
        //
        rxMsg.id = LL_MCAN_RX_ADDR;
        rxMsg.rtr = 0U;
        rxMsg.xtd = 0U;
        rxMsg.esi = 0U;
        rxMsg.rxts = 0U;   // Rx Timestamp
        rxMsg.dlc = 0U;
        rxMsg.brs = 0U;
        rxMsg.fdf = 0U;
        rxMsg.fidx = 0U;   // Filter Index
                                  // (of matching Rx acceptance filter element)
        rxMsg.anmf = 0U;   // Accepted Non-matching Frame
    
        j = 0;
        for(j = 0; j < MCAN_DATA_BUFFER_SIZE; j++)  // Initialize receive buffer to 0
        {
            rxMsg.data[j]  = 0;
        }
    
        //
        // Initialize message to transmit.
        //
        txMsg.id       = ((uint32_t)(LL_MCAN_TX_ADDR)) << 18U; // STDID[28:18] --> CAN Message Address = (0xADDR) << 18U
        txMsg.rtr      = 0U;   // RTR = 0 (Data frame)
        txMsg.xtd      = 0U;   // XTD = 0 (11-bit standard identifier)
        txMsg.esi      = 0U;
    #ifdef USE_1_BYTE_PAYLOAD
        txMsg.dlc      = 1U; //15U;  // 64 bytes // 8U = 8Byte
    #else
        txMsg.dlc      = 15U; //15U;  // 64 bytes // 8U = 8Byte
    #endif
    
        txMsg.fdf      = 1U;   // Frame transmitted in CAN FD format
        txMsg.brs      = 1U;   // Bit-rate switching enabled
        txMsg.efc      = 1U;   // Store TX events
        txMsg.mm       = 0xAAU;
    
        j = 0;
        for(j = 0; j < MCAN_DATA_BUFFER_SIZE; j++)
        {
            txMsg.data[j]  = 0;
        }
    
    
        //
        // Configure MCAN initialization parameters
        //
        initParams.fdMode            = 0x1U; // FD operation enabled.
        initParams.brsEnable         = 0x1U; // Bit rate switching enabled
    
        //
        // Transmitter Delay Compensation parameters.
        //
        initParams.tdcConfig.tdcf    = 0xAU;
        initParams.tdcConfig.tdco    = 0x6U;
    
        //
        // Initialize Message RAM Sections Configuration Parameters
        //
        msgRAMConfigParams.txStartAddr          = MCAN_TX_BUFF_START_ADDR;
        // Tx Buffers Start Address.
    
        msgRAMConfigParams.txBufNum             = MCAN_TX_BUFF_SIZE;
        // Number of Dedicated Transmit Buffers.
    
        msgRAMConfigParams.txBufMode            = 0U;
    
        msgRAMConfigParams.txFIFOSize           = MCAN_TX_FQ_SIZE;
        // Number of Tx FIFO or Tx Queue Elements
    
        msgRAMConfigParams.txBufElemSize        = MCAN_TX_BUFF_ELEM_SIZE;
        // Tx Buffer Element Size.
    
        //
        // Initialize Message RAM Sections Configuration Parameters
        //
        msgRAMConfigParams.flssa                = MCAN_STD_ID_FILT_START_ADDR;
        // Standard ID Filter List Start Address.
        msgRAMConfigParams.lss                  = MCAN_STD_ID_FILTER_NUM;
        // List Size: Standard ID.
        msgRAMConfigParams.rxBufStartAddr       = MCAN_RX_BUFF_START_ADDR;
        // Rx Buffer Start Address.
        msgRAMConfigParams.rxBufElemSize        = MCAN_RX_BUFF_ELEM_SIZE;
        // Rx Buffer Element Size.
    
        //
        // Initialize bit timings. --> Speed up to 5Mbps --> See MCAN_BitTimingCalculator.xls --> See nominal and data bit timing --> two different sections in the .xls
        //
    #ifdef USE_2MBAUDPS
        bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
        bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
        bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
        bitTimes.nomRatePrescalar   = 1U; // Nominal Baud Rate Pre-scaler
    
        bitTimes.dataTimeSeg1       = 9U; // Data Time segment before SP
        bitTimes.dataTimeSeg2       = 8U; // Data Time segment after SP
        bitTimes.dataSynchJumpWidth = 8U; // Data S
        bitTimes.dataRatePrescalar  = 0U; // Data Baud Rate Pre-scaler
    #endif
    
    #ifdef USE_4MBAUDPS //Needs 2 termination resistors --> Propagation Delay of 200ns
        bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
        bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
        bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
        bitTimes.nomRatePrescalar   = 1U; // Nominal Baud Rate Pre-scaler
    
        bitTimes.dataTimeSeg1       = 4U; // Data Time segment before SP
        bitTimes.dataTimeSeg2       = 3U; // Data Time segment after SP
        bitTimes.dataSynchJumpWidth = 3U; // Data S
        bitTimes.dataRatePrescalar  = 0U; // Data Baud Rate Pre-scaler
    #endif
    
    #ifdef USE_5MBAUDPS //Needs 2 termination resistors --> --> Propagation Delay of 200ns
        bitTimes.nomTimeSeg1        = 9U; // Nominal Time segment before SP
        bitTimes.nomTimeSeg2        = 8U; // Nominal Time segment after SP
        bitTimes.nomSynchJumpWidth  = 8U; // Nominal SJW
        bitTimes.nomRatePrescalar   = 1U; // Nominal Baud Rate Pre-scaler
    
        bitTimes.dataTimeSeg1       = 3U; // Data Time segment before SP
        bitTimes.dataTimeSeg2       = 2U; // Data Time segment after SP
        bitTimes.dataSynchJumpWidth = 2U; // Data S
        bitTimes.dataRatePrescalar  = 0U; // Data Baud Rate Pre-scaler
    #endif
    
        //
        // Wait for memory initialization to happen.
        //
        while(FALSE == MCAN_isMemInitDone(MCANA_DRIVER_BASE))
        {
        }
    
        //
        // Put MCAN in SW initialization mode.
        //
        MCAN_setOpMode(MCANA_DRIVER_BASE, MCAN_OPERATION_MODE_SW_INIT);
    
        //
        // Wait till MCAN is not initialized.
        //
        while (MCAN_OPERATION_MODE_SW_INIT != MCAN_getOpMode(MCANA_DRIVER_BASE))
        {}
    
        //
        // Initialize MCAN module.
        //
        MCAN_init(MCANA_DRIVER_BASE, &initParams);
    
        //
        // Configure Bit timings.
        //
        MCAN_setBitTime(MCANA_DRIVER_BASE, &bitTimes);
    
        //
        // Configure Message RAM Sections
        //
        MCAN_msgRAMConfig(MCANA_DRIVER_BASE, &msgRAMConfigParams);
    
        //
        // Initialize Rx Buffer Configuration parameters.
        //
        stdFiltelem.sfec               = 0x7U; // Store into Rx Buffer
                                               // configuration of SFT[1:0] ignored
    
        //
        // Configuring SFID2[10:9] = 0 to store message in RX Buffer
        // SFID2[5:0] defines which RX Buffer element received message
        // will be stored into (among upto 64 buffer elements)
        // Frames matching different filter elements cannot be
        // configured to be stored in the same buffer element
        // i.e. SFID2[5:0] HAS to be distinct for every filter element
        //
    
    
        //
        // Configure Standard ID filter element 0
        //
        stdFiltelem.sfid2              = 0;//0x0U; // Standard Filter ID 0. --> Buffer NUmber
        stdFiltelem.sfid1              = LL_MCAN_RX_ADDR; //0x0U; // CAN Msg Addr
    
        MCAN_addStdMsgIDFilter(MCANA_DRIVER_BASE, 0U, &stdFiltelem);
    
        //
        // Take MCAN out of the SW initialization mode
        //
        MCAN_setOpMode(MCANA_DRIVER_BASE, MCAN_OPERATION_MODE_NORMAL);
    
        while (MCAN_OPERATION_MODE_NORMAL != MCAN_getOpMode(MCANA_DRIVER_BASE))
        {
    
        }
    
    #ifdef USE_MCAN_WITH_ISR
        //
        // Enable Interrupts.
        //
        MCAN_enableIntr(MCANA_DRIVER_BASE, MCAN_INTR_MASK_ALL, 1U);
    
        //
        // Select Interrupt Line.
        //
        MCAN_selectIntrLine(MCANA_DRIVER_BASE, MCAN_INTR_MASK_ALL, MCAN_INTR_LINE_NUM_1);
    
        //
        // Enable Interrupt Line.
        //
        MCAN_enableIntrLine(MCANA_DRIVER_BASE, MCAN_INTR_LINE_NUM_1, 1U);
    #endif
    }
    
    //*******************************************************************************************************************************************//
    // ISR
    //*******************************************************************************************************************************************//
    /**
     * @brief: This is Interrupt Service Routine for MCAN interrupt 1.
     */
    __interrupt void MCANIntr1ISR(void)
    {
    
        MCAN_RxNewDataStatus newData;
    
        intrStatus = MCAN_getIntrStatus(MCANA_DRIVER_BASE);
    
        //
        // Clear the interrupt Status.
        //
        MCAN_clearIntrStatus(MCANA_DRIVER_BASE, intrStatus);
    
        //
        //  Clearing the interrupt lineNum
        //
        MCAN_clearInterrupt(MCANA_DRIVER_BASE, 0x2);
    
        //
        //  Check to see if the interrupt is caused by a message being
        //  received in dedicated RX Buffers
        //
        if((MCAN_IR_DRX_MASK & intrStatus) == MCAN_IR_DRX_MASK)
        {
            //
            // Read the NewData registers
            //
            MCAN_getNewDataStatus(MCANA_DRIVER_BASE, &newData);
    
            //  If message is received in buffer element 0
            if((newData.statusLow & (1UL << 0)) != 0)
            {
                MCAN_readMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, 0U, //0U for Buffer 0 read
                              0, &rxMsg);
    
                mcan_handler.mcan_is_rx = 1;
    
                mcan_rx_message_counter++;
            }
            //
            //  Clearing the NewData registers
            //
            MCAN_clearNewDataStatus(MCANA_DRIVER_BASE, &newData);
        }
        else if((MCAN_IR_TEFL_MASK & intrStatus) == MCAN_IR_TEFL_MASK)
        {
            //TX
        }
        else
        {
            mcan_handler.mcan_err_cntr++;
        }
    
        mcan_isr_cntr++;
    
        //
        // Acknowledge this interrupt located in group 9
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    }
    

    I tested the attached programm, which is copy/paste from the RX/TX examples from the MCAN examples and 2Mbps are working, 4Mbps and 5Mbps are not working between two new EVAL boards. I really don't see what is going on here

  • Hi Hans,

    I'm still working on this. I'm getting another Launchpad to test this out.  Give me a day to secure my set up.

    Regards,

    Joseph

  • Hi Joseph,

    Any news from you? I still could not resolve the issue.

    Thanks,

    Hans

  • Hi Hans,

    Apologies for my delayed response.  I have been swamped with other projects however looking back at the PSR status, it seems that there is an indication of a bit error during transmission.  During transmission, MCAN receives the frame back through the RX pin and compares against the transmitted data.  The DLEC error reported seems like it this is caused by the received bit not the same as the transmitted bit and this can happen at higher baud rates if the propagation delay is not accounted for.  The MCAN has a Transmission Delay Compensation where it allows the MCAN to compensate for the transmission delay.  Refer to section 29.5.4.

    Please try to implement the transmission delay compensation by enabling setting tdcEnable bit (initParams.tdcEnable = 1) and configure the values of tdco and tdcf.

    Regards,

    Joseph

  • Hi Joseph,

    You definitely should add this flag in the examples. Thanks for your help.