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.

TMS320F28388D: Additional information on the CANFD TX delay compensation

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE

I am trying to get CANFD working, and I have 1Mbps framing / 2Mbps data working in both the transmit and receive directions. However when I increase the data-rate to 4Mbps, there are many CAN errors, and nothing occurs at 8Mbps. From my reading, I suspect the propagation delay from the TX-side to the RX-side, and it appears that the TDCR register can affect these errors. I have read and re-read the descriptions of these TDCO and TDCF, but there settings are still unclear. 

Does TDCO change the SSP, so increasing the TDCO will delay the RX-measurement after TX?

What does TDCF do? I know that it must be greater than TDCO to have an effect, but its actual function is unclear.

I believe I need to delay the RX-measurement after TX, as my CAN transceiver delay (for a dominant TX) is 170ns maximum. I have tried playing with these TDCO and TDCF, but there has been no apparent improvement.

Thanks,

Jim

  • Jim,

    You are right, for 170ns transceiver delay with higher data rates, you would need to enable the TDC by setting MCAN_DBTP.TDC to 1. Please confirm if you are setting this bit. 

    As given in the TRM, the SSP position is defined by the addition of TDCO+the transmitter delay measured and the TDCF defines a filter window to avoid an early SSP position due to any glitch(dominant) during the delay measurement. 

    Can you share the below details for us to understand the issue a bit more:

    1. The kind of error you are getting(bit/stuff/etc error ) 
    2. The nominal and day bit timing parameters you have used for the 4Mbps case

    Regards,
    Praveen

  • Praveen,
    Thank you for the quick reply; yes I have DBTP.TDC = 1 and the TDCF/TDCO set to the same values as in the mcan_ex2_external_loopback example.

    I am using PCANView with a PCAN USB-CANFD device, which shows no errors at 1M framing / 2M data-rate, so I think the tool is OK. However at 1M/4M, about 1/2 of the packets show BUSWARNING, BUSPASSIVE, and ESI errors reported from the CM. In addition, the CM is reporting PSR.LEC = 5, which is consistent with this propagation-error theory.

    It was clear that the resolution of TDCF/TDCO was CAN_CLK, which is 120Mhz. It is as simple as setting TDCO to 100, which would delay the RX-measurement after TX by ~830ns (100/120Mhz)?

    Do you know if anyone has got the 28388 working at 1M/8M CANFD? If these delay-compensation registers don't fix the issue, I think the next step is running the CM at 40 (or even 20)Mhz, which allows larger propagation delays.

    Thanks,
    Jim

  • Jim,

    I will get back to you on your query by Monday. In the meanwhile, if you can share the modifications you did on this example, it will help us to find out what is happening

    Regards,
    Praveen

  • Praveen,

    I have integrated the example into my 3-core application, so all of the surrounding code has changed. In addition I have a Classic-CAN channel running to support a legacy PC-application so the CAN addressing and filtering has changed from the example. I am running the CM (and the MCAN) at 120Mhz, and the initParams, configParams, and msgRAMConfigParams (except for filter numbers and FIFO mode) are all the same as the example. 

    Also 1Mbps framing / 2Mbps data is 100% reliable for both TX/RX (while at the same time running the Classic-CAN channel), so fundamentally the MCAN configuration is correct. At 1M / 4M, I attached the PCANView results, which show ~1/2 of the packets are OK (I had to disable the auto-bus-off checks to keep the CM from simply stopping after a few dozen packets). This log is my CM transmitting a packet every 10ms (no CM reception).

    I can send you my entire MCAN configuration if you want (I just did not want to bury you in code).

    Thanks,

    Jim

  • Hi,

    Not only TDC should be used for higher bit rates, but as well timequanta should be the same for both arbitration and data bitrates. 

  • Hi, can you tell me why the timequanta must be the same for both the arbitration and data-rates? I am using a common function to set this and the tsegs, which I think originates in the 28377 CAN example code, and the timequanta will change depending on the bitrate.

    Note I have an update to this problem; if I change the CM_CLK from 120Mhz to 40Mhz, this allows the timequanta (and the sample-point) to increase enough to allow the 4Mbps data-rate to work. This does not solve my problem though as this 40Mhz clock is too slow for the remaining application code. I think this proves the problem is a tx-delay / sample-point problem, so I am hoping I can get an answer to the proper usage of the TDCF and TDCO delay-compensation registers.

    Thanks,

    Jim

  • Hi Jim,

    I haven't tried CAN FD on TMS320 yet, but I'm working with CAN FD on different architecture. I saw bad results communicating identical MCU's with identical FW until I followed these recommendations https://can-newsletter.org/uploads/media/raw/5a08588dc5eef8bbdbf7113ab5537251.pdf 

    One of them is this:

    ◆ Recommendation 2: Set the BRPa bit-rate prescaler equal BRPd This leads to identical tq values in both phases. This prevents that during bit-rate switching inside the CAN FD data frame an existing quantization error can transform into a phase error.

    Now comms work well at all rates up to 8Mbps, no errors even with poor bus drivers limited to 2Mbps. Those 2Mbps drivers were soldered in demo in evaluation boards. Our production devices of course use faster bus drivers with low propagation delay. 

    Edward

  • Edward,

    Thank you for the details; that make sense. 

    2 more questions if you ca:

    1. Did you have to adjust (does you processor have) transmit-delay compensation? That was my original question to TI, as the details of this register are unclear.

    2. Do you know what bus-driver you selected? We have looked at a few, and it looks like they all (even the stated 8Mbps-compliant ones) are all ~80ns delay in the dominant path in each direction. The only way I could even get to 4Mbps was to run my CPU at a 40Mhz clock, which lengthens the time-quanta and tseg1 allowing for this delay.

    Thanks,

    Jim

  • Hi Jim,

    1. TDC setting calculated from bitrates, propagation delay etc is fine, no need to adjust it further. It was NXP MCU and so NXP calculator in the form of Excel *.xlsm. I think you can use calculated values from it for F28388 as well, just make sure that calculated settings don't cross some F28388 limits, I guess they won't. I would look for dedicated TI calculator, perhaps there exists one. 

    2. Bus driver chosen is one from ON, up to 5Mbps, propagation delay about 90ns. 250ns is fine for TDC-less bitrate up to ~3Mbps. With 90ns TDC is not required even at 5Mbps. But driver with 250ns with proper TDC operates well up to 8Mbps. 

    Edward

  • Edward,
    Thanks for your recommendations.

    Jim,

    A minor correction on the below statement: 

    "It was clear that the resolution of TDCF/TDCO was CAN_CLK, which is 120Mhz. It is as simple as setting TDCO to 100, which would delay the RX-measurement after TX by ~830ns (100/120Mhz)?"

    There is a divider between the MCANABITCLKSEL mux (which is the CMCLK in this case) and the CAN_CLK which is controlled via CLK_CFG_REGS.AUXCLKDIVSEL.MCANCLKDIV register from the C28x side. The SW function which sets this config is "SysCtl_setMCANClk(...)" under the mcan_config_c28x project. This is set as DIVBY4 by default in the example, hence the CAN_CLK is actually 120MHz/4 = 30Mhz.

    Using this divider, you can keep the application running from CM CPU at 120Mhz and let the MCAN clk run at 40Mhz.

    Regarding the TDC, the hardware measures the round trip delay using the dominant bit after FDF. The TDCO offset is added to this measurement to arrive at the final SSP point as shown below. I am checking with our expert on the actual value to be programmed in this register and will get back to you shortly.

    Regards,
    Praveen

  • Praveen,

    That is awesome. I was surprised there was no CAN_CLK divider shown in the clocking system diagrams. I think that should solve my problem. 

    Just a curiosity; the tx-delay-compensation registers should then be left the same as the example for any of these higher CANFD data-rates?

    Thanks,

    Jim

  • Jim,

    You are right. The documentation is not very explicit with respect to the divider. It is given in the registers but not in the diagram. We already have an internal ticket to fix the documentation. It should be fixed soon. 

    As I understand, the TDC offset is actually to adjust the SSP position inside the bit time. Since the bit times vary with the data rates, ideally we should recalculate the values based on the bit times. I will anyway double check on this one shortly.

    Regards,
    Praveen

  • Praveen,

    Do you have an updated CM clocking system diagram or do you have a snippet of the MCAN section you can send me? I can run the CM at 60Mhz and I have CAN-Classic and CANFD working, but if I change the MCANCLKDIV divider to /2 (to get an MCAN CLK of 60Mhz), no CAN works. This MCANCLKDIV register block is not even shown in the clocking diagram, so it is unclear where in the diagram the clock frequency is being changed. 

    To be clear, all I changed was the MCANCLKDIV (to be /2) and the frequency used to calculate the brp (from 120Mhz to 60).

    Thanks,

    Jim

  • Jim,

    Does the attached help?

    clocking_cm_mod.pdf

  • Hareesh,

    Yes thank you; that helps. I think I am so close. 

    Are you aware of any subtleties when setting MCAN_FCLK different than MCAN_ICLK? Here is what I have done:

    1. Set CM_CLK = 60Mhz and MCANCLKDIV =0 (/1), so MCAN_ICLK = MCAN_FCLK = 60Mhz; my MCAN comm works at 1Mbps (classic-mode). 

    2. Change only: CM_CLK = 120Mhz and MCANCLKDIV =1 (/2), so MCAN_ICLK = 120Mhz and MCAN_FCLK = 60Mhz. No CAN works (still classic mode)

    In both of these examples, my code produces the same brp, tseg1, tseg2, and sjw, which should be OK because in both examples, the bit-clock is 60Mhz. 

    I don't see any other MCAN registers affected by the clock, and I am only testing classic-CAN here, so there are no FD complexities. Any suggestions?

    Thanks,

    Jim

  • Jim,

    As captured in the spec, the MCAN_FCLK has to be less than or equal to the MCAN_ICLK. This is the only requirement. I will try this out at our end as well.

    Have you tried other divider values? Is it something you are seeing only with MCANCLKDIV = 1?

    Regards,
    Praveen

  • It was still a little unclear where MCAN_ICLK and MCAN_FCLK are in the clocking diagram, but I believe MCAN_ICLK is CM.MCANA.SYSCLK and MCAN_FCLK is MCAN BitClock on the diagram. Also I have MCANABITCLKSEL = 0, so I think by definition, FCLK is <= ICLK because of the MCANDLKDIV register.

    I tried 40Mhz and 60Mhz, both of which I have working if the MCANDLKDIV=0 (ICLK = FCLK). 

    Thanks,

    Jim

  • Jim,

    You are correct about the MCAN_ICLK and MCAN_FCLK. This is captured in the Table45-2 in the spec.

    With CM_CLK = 120Mhz, and MCANCLKDIV =1 (/2), (i.e MCAN_ICLK = 120Mhz and MCAN_FCLK = 60Mhz), I am seeing successful transfers with both  classic CAN and CAN-FD frames at 1Mbps bit rate.

    I have used the below timing parameters:

        bitTimes.nomRatePrescalar   = 0x2U; // Nominal Baud Rate Pre-scaler.
        bitTimes.nomTimeSeg1        = 0xEU; // Nominal Time segment before sample point.
        bitTimes.nomTimeSeg2        = 0x3U; // Nominal Time segment after sample point.
    

    Can you share your timing parameters?

    Regards,
    Praveen

  • Praveen,

    My BRP, TSEG1, and TSEG2 were a little different, but I changed the value to yours; there was no change to my outcome. 

    With AUXPLLRAWCLK=60Mhz and MCANCLKDIV=0, I believe MCAN_ICLK and MCAN_FCLK both = 60Mhz, and CAN-classic works.

    Changing only these 2 items: AUXPLLRAWCLK=120Mhz and MCANCLKDIV=1, I believe now MCAN_ICLK = 120Mhz and FCLK=60Mhz, CAN-Classic doesn't work. 

    Did you have to change any other MCAN code between these 2 experiments?

    Thanks,

    Jim

  • Jim,

    No, I havent changed code between both the settings.

    Can you share your code? If it is not possible to share the full code, please share only the changes that you have made on top of the c2000ware example

    Regards,
    Praveen

  • Jim,

    I am attaching the c2000ware example code which I have used for my testing. It is working at my end for 1Mbps in both FD mode=0 & 1

    mcan_ex2_external_loopback.c
    //#############################################################################
    //
    // FILE:   mcan_ex2_external_loopback.c
    //
    // TITLE:  MCAN External Loopback with Interrupt
    //
    //! \addtogroup driver_example_cm_list
    //! <h1> MCAN External Loopback with Interrupt </h1>
    //!
    //! This example shows the MCAN External Loopback functionality. The external
    //! loopback is done between two MCAN Controllers. As there is only one MCAN
    //! that exist this example can be changed to make MCAN Transmit or Receive
    //! based on define selected. The GPIOs of MCAN should be connected to a CAN
    //! Transceiver
    //! 
    //! Before running this example, please run the mcan_config_c28x example
    //! It will initialize the clock, configure the GPIOs.
    //!
    //! Selection of Mode : A define has to be selected to make the MCAN to
    //! transmit or receive.
    //!  - TRANSMIT - MCAN to Transmit messages.
    //!  - RECEIVE  - MCAN to Receive Messages.
    //!
    //! Run the example as with RECEIVE Define on one MCAN Controller before
    //! running it as Transmit.  
    //!
    //! \b Hardware \b Required \n
    //!  - A C2000 board with CAN transceiver
    //!
    //! \b External \b Connections \n
    //!  - MCAN is on GPIO30 (MCANRXA) and GPIO31 (MCANTXA)
    //!
    //! \b Watch \b Variables \n
    //!  - isrIntr0Flag - The flag has initial value as no. of messages to be
    //!                   transmitted and its value decrements after a message is
    //!                   transmitted. 
    //!  - isrIntr1Flag - The flag has initial value as no. of messages that are
    //!                   received and its value decrements after a message is
    //!                   successfully received.
    //!  - error - Checks if there is an error that occurred when the data was
    //!            sent using internal loopback
    //!
    //
    //#############################################################################
    // $TI Release: F2838x Support Library v3.02.00.00 $
    // $Release Date: Tue May 26 17:21:56 IST 2020 $
    // $Copyright:
    // Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //#############################################################################
    
    //
    // Include Files
    //
    #include "cm.h"
    #include "inc/stw_types.h"
    #include "inc/stw_dataTypes.h"
    
    //
    // Select one of the Modes.
    //
    #define TRANSMIT
    //#define RECEIVE
    
    //
    // Defines.
    //
    #define NUM_OF_MSG                    (10U)
    #define MCAN_STD_ID_FILT_START_ADDR   (0U)
    #define MCAN_STD_ID_FILTER_NUM        (1U)
    #define MCAN_EXT_ID_FILT_START_ADDR   (48U)
    #define MCAN_EXT_ID_FILTER_NUM        (1U)
    #define MCAN_TX_EVENT_START_ADDR      (100U)
    #define MCAN_TX_EVENT_SIZE            (NUM_OF_MSG)
    #define MCAN_TX_EVENT_WATERMARK       (NUM_OF_MSG/2)
    #define MCAN_TX_BUFF_START_ADDR       (148U)
    #define MCAN_TX_BUFF_SIZE             (NUM_OF_MSG)
    #define MCAN_TX_FIFO_SIZE             (NUM_OF_MSG)
    #define MCAN_FIFO_0_START_ADDR        (548U)
    #define MCAN_FIFO_0_NUM               (NUM_OF_MSG)
    #define MCAN_FIFO_0_WATERMARK         (NUM_OF_MSG)
    #define MCAN_FIFO_1_START_ADDR        (748U)
    #define MCAN_FIFO_1_NUM               (NUM_OF_MSG)
    #define MCAN_FIFO_1_WATERMARK         (NUM_OF_MSG)
    #define MCAN_RX_BUFF_START_ADDR       (948U)
    #define MCAN_EXT_ID_AND_MASK          (0x1FFFFFFFU)
    #define MCAN_TS_PRESCALAR             (0xB0)
    
    #define MCAN_TX_BUFF_ELEM_SIZE       (MCAN_ELEM_SIZE_64Bytes)
    #define MCAN_RX_BUFF_ELEM_SIZE       (MCAN_ELEM_SIZE_64Bytes)
    #define MCAN_RX_FIFO0_ELEM_SIZE      (MCAN_ELEM_SIZE_64Bytes)
    #define MCAN_RX_FIFO1_ELEM_SIZE      (MCAN_ELEM_SIZE_64Bytes)
    
    //
    // Global Variables.
    //
    volatile uint32_t isrIntr0Flag = NUM_OF_MSG;
    volatile uint32_t isrIntr1Flag = NUM_OF_MSG;
    volatile uint32_t isrIntrTSFlag = 1U;
    int32_t     error = 0;
    MCAN_TxBufElement txMsg[NUM_OF_MSG];
    MCAN_RxBufElement rxMsg[NUM_OF_MSG], rxMsg1;
    int32_t loopCnt = 0U;
    
    
    //
    // Function Prototype.
    //
    static void MCANConfig(void);
    static void MCANIntrConfig(void);
    static void MCANIntr0ISR(void);
    static void MCANIntr1ISR(void);
    
    void main()
    {
    #ifdef RECEIVE
        int32_t dataCnt;
    #endif
        int i = 0;
        uint32_t numOfMsg = NUM_OF_MSG;
        volatile uint32_t mode = 0U;
        uint32_t dataBytes = 8;
        
        //
        // Switching on the peripheral.
        //
        CM_init();
    
        //
        // Reset the peripheral.
        //
        SysCtl_resetPeripheral(SYSCTL_PERIPH_RES_MCAN_A);
    
        //
        // CrossBar and ISR Configuration.
        //
        MCANIntrConfig();
        
        //
        // Initialize message to transmit.
        //
        for(loopCnt = 0U ; loopCnt < numOfMsg ; loopCnt++)
        {
            txMsg[loopCnt].id       = (0x0);
            txMsg[loopCnt].id       = (loopCnt) << 16U;
            txMsg[loopCnt].id       |= (0xFF);
            txMsg[loopCnt].rtr      = 0U;
            txMsg[loopCnt].xtd      = 1U;
            txMsg[loopCnt].esi      = 0U;
            txMsg[loopCnt].dlc      = 15U;
            txMsg[loopCnt].brs      = 0U;
            txMsg[loopCnt].fdf      = 1U;
            txMsg[loopCnt].efc      = 1U;
            txMsg[loopCnt].mm       = 0xAAU;
            txMsg[loopCnt].data[i]  = 0x1;
            for(i = 1; i < dataBytes; i++)
            {
                txMsg[loopCnt].data[i]  = txMsg[loopCnt].data[i-1] + 1;
            }
            i = 0;
        }
        for(loopCnt = 0U ; loopCnt < numOfMsg ; loopCnt++)
        {
            rxMsg[loopCnt].id = 0U;
            rxMsg[loopCnt].rtr = 0U;
            rxMsg[loopCnt].xtd = 0U;
            rxMsg[loopCnt].esi = 0U;
            rxMsg[loopCnt].rxts = 0U;
            rxMsg[loopCnt].dlc = 0U;
            rxMsg[loopCnt].brs = 0U;
            rxMsg[loopCnt].fdf = 0U;
            rxMsg[loopCnt].fidx = 0U;
            rxMsg[loopCnt].anmf = 0U;
            for(i = 0; i < dataBytes; i++)
            {
                rxMsg[loopCnt].data[i]  = 0;
            }
        }
    
        //
        // Configure the MCAN Module.
        //
        MCANConfig();
        
    #ifdef TRANSMIT
        //
        // This is transmitter side application.
        //
         
        // 
        // Enable Interrupts.
        //
        MCAN_enableIntr(MCAN0_BASE, MCAN_INTR_MASK_ALL,1);
        MCAN_enableIntr(MCAN0_BASE, MCAN_INTR_SRC_RES_ADDR_ACCESS|
                        MCAN_INTR_SRC_TIMESTAMP_WRAPAROUND,0);
        
        //
        // Select Interrupt Line.
        //
        MCAN_selectIntrLine(MCAN0_BASE, MCAN_INTR_MASK_ALL,
                            MCAN_INTR_LINE_NUM_0);
        
        //
        // Enable Interrupt Line.
        //
        MCAN_enableIntrLine(MCAN0_BASE, MCAN_INTR_LINE_NUM_0, 1U);
        
        //
        // Enable Transmission interrupt.
        //
        for(loopCnt = 0U ; loopCnt < numOfMsg ; loopCnt++)
        {
            MCAN_txBufTransIntrEnable(MCAN0_BASE, loopCnt,1);
        
            //
            // Write message to Message RAM.
            //
            MCAN_writeMsgRam(MCAN0_BASE, MCAN_MEM_TYPE_BUF, loopCnt,
                             &txMsg[loopCnt]);
        }
        
        //
        // Add request for all transmission.
        //
        HWREG(MCAN0_BASE + MCAN_TXBAR) = 0x000003FF;
                    
        //
        // Wait till the flag becomes zero and all the messages are transmitted.
        //
        while(isrIntr0Flag)
        {
        }
    #endif
    #ifdef RECEIVE
        //
        // This is receiver side application.
        // 
    
        //
        // Enable Interrupts.
        //
        MCAN_enableIntr(MCAN0_BASE, MCAN_INTR_MASK_ALL,1);
        MCAN_enableIntr(MCAN0_BASE, MCAN_INTR_SRC_RES_ADDR_ACCESS|
                        MCAN_INTR_SRC_TIMESTAMP_WRAPAROUND,0);
        
        //
        // Select Interrupt Line.
        //
        MCAN_selectIntrLine(MCAN0_BASE, MCAN_INTR_MASK_ALL,
                            MCAN_INTR_LINE_NUM_1);
        //
        // Enable Interrupt Line.
        //
        MCAN_enableIntrLine(MCAN0_BASE, MCAN_INTR_LINE_NUM_1, 1U);
        
        //
        // Wait till the interrupt flag becomes zero.
        //
        while(isrIntr1Flag)
        {
        }
    
        for(loopCnt = 0U ; loopCnt < numOfMsg;loopCnt++)
        {
            MCAN_readMsgRam(MCAN0_BASE, MCAN_MEM_TYPE_FIFO, 0U,
                            MCAN_RX_FIFO_NUM_1, &rxMsg1);
            MCAN_writeRxFIFOAck(MCAN0_BASE, MCAN_RX_FIFO_NUM_1,
                                loopCnt);
            rxMsg[loopCnt] = rxMsg1;
        }
                    
        for(loopCnt = 0U ; loopCnt < numOfMsg ; loopCnt++)
        {
    
            if (rxMsg[loopCnt].id  != txMsg[loopCnt].id)
            {
                error++;
            }
            if (rxMsg[loopCnt].rtr != txMsg[loopCnt].rtr)
            {
                error++;
            }
            if (rxMsg[loopCnt].xtd != txMsg[loopCnt].xtd)
            {
                error++;
            }
            if (rxMsg[loopCnt].esi != txMsg[loopCnt].esi)
            {
                error++;
            }
            if (rxMsg[loopCnt].dlc != txMsg[loopCnt].dlc)
            {
                error++;
            }
            if (rxMsg[loopCnt].brs != txMsg[loopCnt].brs)
            {
                error++;
            }
            if (rxMsg[loopCnt].fdf != txMsg[loopCnt].fdf)
            {
                error++;
            }
            
            if (loopCnt > 0)
            {
                if (rxMsg[loopCnt].rxts > rxMsg[loopCnt-1].rxts)
                {
                }
                else
                {
                    error++;
                }
            }
    
            for (dataCnt = 0U ; dataCnt < dataBytes ; dataCnt++)
            {
                if (rxMsg[loopCnt].data[dataCnt]!=
                    txMsg[loopCnt].data[dataCnt])
                {
                    error++;
                }
            }
        }
    #endif
        if (error != 0)
        {
            //
            // Stop if there is an error.
            //
            __asm("   bkpt #0");
        }
        
        //
        // Stop Application.
        //
        __asm("   bkpt #0");
    }
    
    static void MCANIntrConfig(void)
    {
        Interrupt_registerHandler(INT_MCANSS_0,&MCANIntr0ISR);
        Interrupt_enable(INT_MCANSS_0);
        Interrupt_registerHandler(INT_MCANSS_1,&MCANIntr1ISR);
        Interrupt_enable(INT_MCANSS_1);
        Interrupt_enableInProcessor();
    }
    static void MCANConfig(void)
    {
        uint32_t fdoe;
        MCAN_RevisionId revId;
        MCAN_InitParams initParams;
        MCAN_ConfigParams configParams;
        MCAN_MsgRAMConfigParams    msgRAMConfigParams;
        MCAN_StdMsgIDFilterElement stdFiltelem;
        MCAN_ExtMsgIDFilterElement extFiltelem;
        MCAN_BitTimingParams       bitTimes;
    
        //
        // Initialize MCAN Init parameters.
        //
        initParams.fdMode            = 0x1U; // FD operation disabled.
        initParams.brsEnable         = 0x1U; // Bit rate switching for
                                             // transmissions enabled.
        initParams.txpEnable         = 0x1U; // Transmit pause enabled.
        initParams.efbi              = 0x0U; // Edge filtering disabled.
        initParams.pxhddisable       = 0x0U; // Protocol exception handling enabled.
        initParams.darEnable         = 0x1U; // Automatic retransmission of messages
                                             // not transmitted successfully enabled.
        initParams.wkupReqEnable     = 0x1U; // Wakeup request is enabled.
        initParams.autoWkupEnable    = 0x1U; // Auto-Wakeup is enabled.
        initParams.emulationEnable   = 0x1U; // Emulation/Debug Suspend is enabled.
        initParams.tdcEnable         = 0x1U; // Transmitter Delay Compensation is
                                             // enabled.
        initParams.wdcPreload        = 0xFFU; // Start value of the Message RAM
                                              // Watchdog Counter preload.
     
        //
        // Transmitter Delay Compensation parameters.
        //
        initParams.tdcConfig.tdcf    = 0xAU;
        initParams.tdcConfig.tdco    = 0x6U;
        
        //
        // Initialize MCAN Config parameters.
        // 
        configParams.monEnable       = 0x0U; // Bus Monitoring Mode is disabled.
        configParams.asmEnable       = 0x0U; // Normal CAN operation.
        configParams.tsPrescalar       = 0x2U; // Prescaler Value.
        configParams.tsSelect          = 0x2U; // Timestamp counter value.
        configParams.timeoutSelect     = MCAN_TIMEOUT_SELECT_CONT;
        // Time-out counter source select.
        configParams.timeoutPreload    = 0xFFFFU;// Start value of the Timeout
                                                 // Counter.
        configParams.timeoutCntEnable  = 0x0U; // Time-out Counter is disabled.
        configParams.filterConfig.rrfs = 0x1U; // Reject all remote frames with
                                               // 29-bit extended IDs.
        configParams.filterConfig.rrfe = 0x1U; // Reject all remote frames with
                                               // 11-bit standard IDs.
        configParams.filterConfig.anfe = 0x1U; // Accept in Rx FIFO 1.
        configParams.filterConfig.anfs = 0x1U; // Accept in Rx FIFO 1.
    
        //
        // 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.flesa                = MCAN_EXT_ID_FILT_START_ADDR;
        // Extended ID Filter List Start Address.
        msgRAMConfigParams.lse                  = MCAN_EXT_ID_FILTER_NUM;
        // List Size: Extended ID.
        msgRAMConfigParams.txStartAddr          = MCAN_TX_BUFF_START_ADDR;
        // Tx Buffers Start Address.
        msgRAMConfigParams.txBufNum             = MCAN_TX_BUFF_SIZE;
        // Number of Dedicated Transmit Buffers.
        msgRAMConfigParams.txFIFOSize           = MCAN_TX_FIFO_SIZE;
        // Tx FIFO/Queue.
        msgRAMConfigParams.txBufMode            = 0U;
        msgRAMConfigParams.txBufElemSize        = MCAN_ELEM_SIZE_64BYTES;
      // Tx Buffer Element Size.
        msgRAMConfigParams.txEventFIFOStartAddr = MCAN_TX_EVENT_START_ADDR;
        // Tx Event FIFO Start Address.
        msgRAMConfigParams.txEventFIFOSize      = MCAN_TX_BUFF_SIZE;
        // Event FIFO Size.
        msgRAMConfigParams.txEventFIFOWaterMark = MCAN_TX_EVENT_WATERMARK;
        // Level for Tx Event FIFO watermark interrupt.
        msgRAMConfigParams.rxFIFO0startAddr     = MCAN_FIFO_0_START_ADDR;
        // Rx FIFO0 Start Address.
        msgRAMConfigParams.rxFIFO0size          = MCAN_FIFO_0_NUM;
        // Number of Rx FIFO elements.
        msgRAMConfigParams.rxFIFO0waterMark     = MCAN_FIFO_0_WATERMARK;
        msgRAMConfigParams.rxFIFO0OpMode        = 0U;
        msgRAMConfigParams.rxFIFO1startAddr     = MCAN_FIFO_1_START_ADDR;
        // Rx FIFO1 Start Address.
        msgRAMConfigParams.rxFIFO1size          = MCAN_FIFO_1_NUM;
        // Number of Rx FIFO elements.
        msgRAMConfigParams.rxFIFO1waterMark     = MCAN_FIFO_1_WATERMARK;
        // Level for Rx FIFO 1 watermark interrupt.
        msgRAMConfigParams.rxFIFO1OpMode        = 0U; // FIFO blocking mode.
        msgRAMConfigParams.rxBufStartAddr       = MCAN_RX_BUFF_START_ADDR;
        // Rx Buffer Start Address.
        msgRAMConfigParams.rxBufElemSize        = MCAN_ELEM_SIZE_64BYTES;
        // Rx Buffer Element Size.
        msgRAMConfigParams.rxFIFO0ElemSize      = MCAN_ELEM_SIZE_64BYTES;
        // Rx FIFO0 Element Size.
        msgRAMConfigParams.rxFIFO1ElemSize      = MCAN_ELEM_SIZE_64BYTES;
        // Rx FIFO1 Element Size.
        
        //
        // Initialize Tx Buffer Configuration parameters.
        //
        stdFiltelem.sfid2              = 0x0U; // Standard Filter ID 2.
        stdFiltelem.sfid1              = 0x4U; // Standard Filter ID 1.
        stdFiltelem.sfec               = 0x7U; // Store into Rx Buffer or as
                               // debug message, configuration of SFT[1:0] ignored.
        stdFiltelem.sft                = 0x0U; // Range filter from SFID1 to SFID2.
        
        //
        // Initialize Tx Buffer Configuration parameters.
        //
        extFiltelem.efid2  = (0x9U << 16U);
        extFiltelem.efid2 |= 0xFFU;
        extFiltelem.efid1  = (0x0U << 16U);
        extFiltelem.efid1 |= 0xFFU;
        extFiltelem.efec   = 0x6U;
        extFiltelem.eft    = 0x0U;
    
        //
        // Initialize bit timings.
        //
        bitTimes.nomRatePrescalar   = 0x1FU; // Nominal Baud Rate Pre-scaler.
        bitTimes.nomTimeSeg1        = 0x1U; // Nominal Time segment before sample point.
        bitTimes.nomTimeSeg2        = 0x1U; // Nominal Time segment after sample point.
        bitTimes.nomSynchJumpWidth  = 0x0U; // Nominal (Re)Synchronization Jump Width Range.
        bitTimes.dataRatePrescalar  = 0x3U; // Data Baud Rate Pre-scaler.
        bitTimes.dataTimeSeg1       = 0x1U; // Data Time segment before sample point.
        bitTimes.dataTimeSeg2       = 0x1U; // Data Time segment after sample point.
        bitTimes.dataSynchJumpWidth = 0x0U; // Data (Re)Synchronization Jump Width.
    
        //
        // Get MCANSS Revision ID
        //
        MCAN_getRevisionId(MCAN0_BASE, &revId);
    
        fdoe = MCAN_isFDOpEnable(MCAN0_BASE);
        if(TRUE == fdoe)
        {
            //
            // CAN-FD operation is enabled.
            //
        }
        else
        {
            //
            // CAN-FD operation is disabled.
            //
        }
        
        //
        // Wait for memory initialization to happen.
        //
        while(FALSE == MCAN_isMemInitDone(MCAN0_BASE))
        {
        }
        
        //
        // Put MCAN in SW initialization mode.
        //
        MCAN_setOpMode(MCAN0_BASE, MCAN_OPERATION_MODE_SW_INIT);
        
        //
        // Wait till MCAN is not initialized.
        //
        while (MCAN_OPERATION_MODE_SW_INIT != MCAN_getOpMode(MCAN0_BASE))
        {}
       
        //
        // Initialize MCAN module.
        //
        MCAN_init(MCAN0_BASE, &initParams);
        
        //
        // Configure MCAN module.
        //
        MCAN_config(MCAN0_BASE, &configParams);
     
        //
        // Disable external timeStamp overflow interrupt.
        //
        MCAN_extTSEnableIntr(MCAN0_BASE,1);
    
        //
        // Configure TimeStamp Counter.
        //
        MCAN_extTSCounterConfig(MCAN0_BASE, MCAN_TS_PRESCALAR);
    
        //
        // Configure Bit timings.
        //
        MCAN_setBitTime(MCAN0_BASE, &bitTimes);
        
        //
        // Set Extended ID Mask.
        //
        MCAN_setExtIDAndMask(MCAN0_BASE, MCAN_EXT_ID_AND_MASK);
        
        //
        // Configure Message RAM Sections
        //
        MCAN_msgRAMConfig(MCAN0_BASE, &msgRAMConfigParams);
        
        //
        // Configure Standard ID filter element
        //
        MCAN_addStdMsgIDFilter(MCAN0_BASE, 0U, &stdFiltelem);
        
        //
        // Configure Extended ID filter element
        //
        MCAN_addExtMsgIDFilter(MCAN0_BASE, 0U, &extFiltelem);
    
        //
        // Enable external counter.
        //
        MCAN_extTSCounterEnable(MCAN0_BASE, 1U);
    
        //
        // Take MCAN out of the SW initialization mode
        //
        MCAN_setOpMode(MCAN0_BASE, MCAN_OPERATION_MODE_NORMAL);
        
        while (MCAN_OPERATION_MODE_NORMAL != MCAN_getOpMode(MCAN0_BASE))
        {
            
        }
    }
    
    static void MCANIntr0ISR(void)
    {
        uint32_t intrStatus;
    
        intrStatus = MCAN_getIntrStatus(MCAN0_BASE);
        MCAN_clearIntrStatus(MCAN0_BASE, intrStatus);
        
        if (MCAN_INTR_SRC_TRANS_COMPLETE == (intrStatus &
             MCAN_INTR_SRC_TRANS_COMPLETE))
        {
            //
            // Decrement the flag after each message is transmitted.
            //
            isrIntr0Flag--;
        }
        else
        {
            //
            // Stop the application if error occurs.
            //
            __asm("   bkpt #0");
        }
    
    }
    
    static void MCANIntr1ISR(void)
    {
        uint32_t intrStatus;
    
        intrStatus = MCAN_getIntrStatus(MCAN0_BASE);
        MCAN_clearIntrStatus(MCAN0_BASE, intrStatus);
        if(MCAN_INTR_SRC_RX_FIFO1_NEW_MSG ==
                (intrStatus & MCAN_INTR_SRC_RX_FIFO1_NEW_MSG))
        {
            //
            // Decrement the flag after each message is received.
            //
            isrIntr1Flag--;
        }
        else
        {
            //
            // Stop the application if error occurs.
            //
            __asm("   bkpt #0");
        }
    }
    

    The clock configs from C28x side are:

    CM_CLK = 120Mhz (AUXPLL locked at 120Mhz, with CMCLKDIV=BY1)

    MCAN_CLK = 60Mhz (MCANBITCLKSEL=AUXPLLCLK with MCANCLKDIV = BY2 )

    Can you please try this out?

    Please let me know if you would want the C28x modifications as well.

    Regards,
    Praveen

  • Praveen,

    Yes please send me the C28x modifications as well. I am going to start fresh with the mcan_ex2_external_loopback to see if I can get it working on my board. 

    Does this example actually require 2 28388D boards connected together, or can I compile this example with TRANSMIT defined and the board transmits to a PCAN device?

    Thanks,

    Jim

  • Praveen,

    Never mind for now about the C28x example application; maybe we will get back to that, but I think I am on to something. It occurred to me that I should be able to measure these clock changes physically on the CAN bus, by looking at the actual CAN bit-width time, so I did the following:

    1) With CM_CLK = MCAN_CLK = 120Mhz, everything works, so I have MCAN-classic transmitting at 1Mbps, and the bit-width on the scope is correctly 1us.

    2) I changed ONLY --- CPU1:AUXCLKDIVSEL.MCANCLKDIV from 0 to 1; what I expected to happen is my 1Mbps transmissions would look like 500Kbs, because the actual MCAN is clocked at half the rate; surprisingly, my MCAN is still transmitting at 1Mbps -- MCANCLKDIV=1 had no effect on the MCAN. 

    3) I then changed CPU1:AUXCLKDIVSEL.MCANCLKDIV from 1 to 2, and the CAN-bus bit-width changed to ~333Kbps; it almost looks like MCANCLKDIV=1 does not do anything; is that possible?

    I will keep playing with this, and I will let you know what I find.

    Thanks,

    Jim

  • Praveen,

    Here's an update -- there appears to be a bug in my aux-clock-set code that does not properly reconfigure the MCANCLKDIV within the debugger. The code above that did not work -- does work after loading the code and power cycling. 

    So hopefully one last question -- does TI have code or a spreadsheet to properly set the arbitration and data bit times (up to 8Mbps) versus the MCAN clock rate? I found a DCAN-CANBTR.xlsx spreadsheet and some code (function CAN_setBitTiming) in E2E for a different processor, which works at 120Mhz MCAN clock, but it is failing now with my MCAN_CLK = 24Mhz. 

    Thanks,

    Jim

  • Jim,

    That is good to hear.

    Regarding the timing calculator spreadsheet, We are working on getting a similar one for MCAN and will update you on the timelines. For now, you can use the bit rate calculation tool from Peak systems . Please be aware the value to be programmed into the registers should be 1 less than the actual timing values

    Regards,
    Praveen

  • Jim,

    I hope all your queries are answered. If so, please close this thread by clicking "Verify answer" on the reply.

    Regards,
    Praveen

  • Praveen,

    Do you know how the PCAN-tool generated numbers relate to the CM/TI-required numbers? I am using my working 40Mhz-MCAN_CLK and 1M/4M arb/data-rate as a guide:

    In my application, the bit-time = (TS1+TS2+3) * (BRP+1/freq).

    arb-values = (5+2+3) * 4/40M = 1us

    data-values = (5+2+3) *1/40M = 0.25us (I know my arb-brp != data-brp, but I will get back to that)

    PCAN arb-values (BRP/TS1/TS2/SJW) = 1/19/20/20

    PCAN data-values (BRP/TS1/TS2/SJW) = 1/4/5/5

    PCAN doesn't give their equation; I guessed at: bit-time = (TS1+TS2+1) * BRP/freq, which works -- so do I take the PCAN TSeg1/TSeg2 numbers and subtract 1 from each? It would make the equations align, but I am guessing here.

    Also should I use the PCAN SJW numbers as is, or subtract 1, or ?

    Thanks,

    Jim

  • Jim,

    You are correct.

    As I indicated in my previous post, we should subtract one from the value that we derive out of the PCAN software. This is true for SJW as well.

    Regards,
    Praveen

  • Praveen,

    I have a little progress (finally). I am able to use the PCAN-tool values to work at 1MArb/2MegData (at 40Mhz). Note there is a limitation in the TI-library that seems like a mistake -- in hw_mcanss.h the nominal bit-time values are artificially limited to less than the NBTP register is capable of. These constants are labeled "User defined ranges", but it seems like a bug to arbitrarily limit the register settings.

    So I have the PCAN-tool 1MArb/2MegData (at 40Mhz) working, but when I try to use the PCAN-tool 1MArb/4MegData (at 40Mhz), they don't work. I am using mostly the same values as the mcan_ex2_external_loopback example, which has the transmitter-delay compensator enabled -- should it be?

    Also I left the various PCAN-tool options as default (like nominal/data sample-points) -- should they be?

    I attached my mcan.c; if you have a file-difference tool, the configuration is very similar to mcan_ex2_external_loopback.c

    Thanks,

    Jimmcan.c

  • Jim,

    I see your point on the hw_mcanss.h. Let me check with our software experts on this.

    Regarding the timing values, using the values from the file you have attached, the nominal/data sample points is coming around to 50%. It is generally advisable to have higher sampling point(>75%). Can you try higher sample points?

    Regards,
    Praveen

  • Praveen,

    The 80% data-sample-points (the only value available at 40Mhz) worked better, but packet-error-rate is ~20%, which suggests there is a small sweet-spot of the configured values. Can you give me any guidance as to how to select values? It would take forever to change the MCAN_CLK through all possible values AND try all possible PCAN-tool values.

    The only equation I know is the the bit-time equation = (TS1+TS2+3) * (BRP+1)/MCAN_CLK, but this does not account for the sample-points, bit-rate deviation, and bit-duration options the PCAN-tool provides. Are there some additional equations that can help find this small window of working values?

    Thanks,

    Jim

  • Jim,

    I am attaching the link to the bit rate calculator App note that was developed for DCAN :Link.  You can use that as a reference. 

    At 4Mbps, the phy roundtrip delay will also start contributing. As discussed in the start of this thread, it is better to enable the TDC.

    Regards,
    Praveen

  • Praveen,

    I had seen that bit-rate-calculator app-note and spreadsheet, but it is for CAN-classic only so it has limited use. Do you know if TI will be updating this spreadsheet to support 4/8Meg data-rates for CANFD? I would be happy to test anything TI has.

    Regarding the TDC, we have come full-circle on my original questions; it is unclear how the TDCO/TDCF register values are determined. Here are my questions from that first post:

    Does TDCO change the SSP, so increasing the TDCO will delay the RX-measurement after TX?

    What does TDCF do? I know that it must be greater than TDCO to have an effect, but its actual function is unclear.

    I believe I need to delay the RX-measurement after TX, as my CAN transceiver delay (for a dominant TX) is 170ns maximum. I have tried playing with these TDCO and TDCF, but there has been no apparent improvement.

    Jim

  • Praveen,
    Let me try to approach this problem differently. My on-board CAN-transceiver has a combined latency of 170ns, so my sample-point (SP) must be set greater than that, correct?

    Also if my configured-SP is >= 170ns, I should not need transmit-delay-compensation?

    I have 2 sets of 1Meg/4Meg values -- one set I derived (that has ~1% PER{Packet Error Rate}) and one set from PCAN (with ~20% PER).

    My PER values come from a directly-connected (usb-to-can) PCANFD with less than 1ft of cabling.

    I am hoping that if I can understand why the PCAN values are less reliable, I can use that information to determine how to set the 1Meg/8Meg values.

    Considering only the data values (which should be OK, right?). All of these are at 40Mhz MCAN_CLK.
    My register values are BRP/TS1/TS2/SJW = 0/5/2/2
    TQ = 25ns
    SP = (7*25) = 175ns

    PCAN register values are BRP/TS1/TS2/SJW = 0/6/1/1
    TQ = 25ns
    SP = (8*25) = 200ns

    If my calculations are correct above, the longer SP works less reliably, even though it is <=80% which is recommended.

    My values have twice the SJW -- do you think that is the value that is making my values better?

    Note my values do not have the same nominal/data BRP as recommended, but I want to get there. So if anything my values should be less reliable?

    Is there something else to consider when evaluating these 2 sets of numbers?

    Thanks,
    Jim

  • Hi jim,

    I'm attaching an experimental MCAN bit timing parameter calculator. It computes the NBTP(B-23) and DBTP(B-42) register values based on the desired bit rate. Can you see if this helps.

    Regards,

    YashwantCAN_BitTimingCalculatorMCAN.xls