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.

TDA4VM: MCU2_1 CAN sgianl lost

Part Number: TDA4VM

Tool/software:

I'm testing CAN TX and RX on MCU2_1 while running our own vision app. However whenever I try to send CAN signal, signal loss happens after few minuites later.

To use CAN TX/RX on MCU2_1, fixed dts file and disabled mcan2 and enabled STB pin to active high. After then I confirmed TX/RX test between A72 main_mcan0 and MCU2_1 main_mcan2 after booting without running the vision app.  

I'm not using TIVX or OpenVX but implemented native FreeRTOS task in main.c file. Each TX and RX has their own task to run and TX task runs every 10ms using vTaskDelayUntil.

At the begining, I tried to use 32 TX buffers by setting txBufNum of MCAN_MsgRAMConfigParams. But I changed it to use only one TX buffer after going over mcan examples. 

Is there any blind spots that I couldn't recognize?

  • CAN Baudrate : 500kb/s
  • CAN Datarate  : 1Mb/s
  • Max. CAN Bus load : < 50%

Here is the CAN config code 

/* Message RAM Configuration */
#define OZ_TI_MCAN_TX_BUFF_START_ADDR              (0x0U)
#define OZ_TI_MCAN_TX_BUFF_SIZE                    (32U)
#define OZ_TI_MCAN_TX_FIFO_SIZE                    (32U)
#define OZ_TI_MCAN_RX_BUFF_START_ADDR              (0x900U)
#define OZ_TI_MCAN_FIFO_0_START_ADDR               (0x1B00U)
#define OZ_TI_MCAN_FIFO_0_NUM                      (64U)
#define OZ_TI_MCAN_FIFO_1_START_ADDR               (0x2D00U)
#define OZ_TI_MCAN_FIFO_1_NUM                      (64U)
#define OZ_TI_MCAN_TX_EVENT_START_ADDR             (0x3F00U)
#define OZ_TI_MCAN_TX_EVENT_SIZE                   (32U)
#define OZ_TI_MCAN_STD_ID_FILT_START_ADDR          (0x4000U)
#define OZ_TI_MCAN_STD_ID_FILTER_NUM               (128U)
#define OZ_TI_MCAN_EXT_ID_FILT_START_ADDR          (0x4200U)
#define OZ_TI_MCAN_EXT_ID_FILTER_NUM               (64U)

/* CAN ID MASK */
#define OZ_TI_MCAN_EXT_ID_AND_MASK          (0x1FFFFFFFU)

uint32_t mcan_base_addr = CSL_MCAN2_MSGMEM_RAM_BASE

int32_t mcan_hw_init(void)
{
    int32_t status = 0;
    MCAN_DBG_PRINT(">>>>\n");

    uint32_t                   fdoe;
    MCAN_RevisionId            revId;
    MCAN_InitParams            initParams;
    MCAN_ConfigParams          configParams;
    MCAN_MsgRAMConfigParams    msgRAMConfigParams;
    MCAN_StdMsgIDFilterElement stdFiltelem;
    MCAN_BitTimingParams       bitTimes;
    
    // board init
#if defined (SOC_AM65XX) || defined (SOC_J721E) || defined (SOC_AM64X) || defined (SOC_J721S2) || defined (SOC_J784S4)
    Board_initCfg   boardCfg;
    Board_STATUS    boardStatus;

    boardCfg = BOARD_INIT_MODULE_CLOCK |
               BOARD_INIT_PINMUX_CONFIG;
    status = Board_init(boardCfg);
    if (status != BOARD_SOK) {
        MCAN_ERR_PRINT("Unable to initialize MCAN HW !!!\n");
    }
#endif

    // Set MCAN base address
    uint32_t mcan_base_addr = OZ_MCAN_BASE_ADDR;

    /* Initialize MCAN Init params */
    initParams.fdMode          = 0x1U;
    initParams.brsEnable       = 0x1U;
    initParams.txpEnable       = 0x0U;
    initParams.efbi            = 0x0U;
    initParams.pxhddisable     = 0x0U;
    initParams.darEnable       = 0x1U;
    initParams.wkupReqEnable   = 0x1U;
    initParams.autoWkupEnable  = 0x1U;
    initParams.emulationEnable = 0x1U;
    initParams.emulationFAck   = 0x0U;
    initParams.clkStopFAck     = 0x0U;
    initParams.wdcPreload      = 0xFFU;
    initParams.tdcEnable       = 0x1U;
    initParams.tdcConfig.tdcf  = 0xAU;
    initParams.tdcConfig.tdco  = 0x6U;
    /* Initialize MCAN Config params */
    configParams.monEnable         = 0x0U;
    configParams.asmEnable         = 0x0U;
    configParams.tsPrescalar       = 0xFU;
    configParams.tsSelect          = 0x0U;
    configParams.timeoutSelect     = 0x0U;
    configParams.timeoutPreload    = 0xFFFFU;
    configParams.timeoutCntEnable  = 0x0U;
    configParams.filterConfig.rrfs = 0x1U;
    configParams.filterConfig.rrfe = 0x1U;
    configParams.filterConfig.anfe = 0x1U;
    configParams.filterConfig.anfs = 0x1U;
    /* Initialize Message RAM Sections Configuration Parameters */
    msgRAMConfigParams.flssa                = OZ_TI_MCAN_STD_ID_FILT_START_ADDR;
    msgRAMConfigParams.lss                  = OZ_TI_MCAN_STD_ID_FILTER_NUM;
    msgRAMConfigParams.flesa                = OZ_TI_MCAN_EXT_ID_FILT_START_ADDR;
    msgRAMConfigParams.lse                  = OZ_TI_MCAN_EXT_ID_FILTER_NUM;

    msgRAMConfigParams.txStartAddr          = OZ_TI_MCAN_TX_BUFF_START_ADDR;
    msgRAMConfigParams.txBufNum             = OZ_TI_MCAN_TX_BUFF_SIZE;
    msgRAMConfigParams.txFIFOSize           = 0U;
    msgRAMConfigParams.txBufMode            = 0U;
    msgRAMConfigParams.txBufElemSize        = MCAN_ELEM_SIZE_64BYTES;
    msgRAMConfigParams.txEventFIFOStartAddr = OZ_TI_MCAN_TX_EVENT_START_ADDR;
    msgRAMConfigParams.txEventFIFOSize      = OZ_TI_MCAN_TX_BUFF_SIZE;
    msgRAMConfigParams.txEventFIFOWaterMark = 0U;

    msgRAMConfigParams.rxFIFO0startAddr     = OZ_TI_MCAN_FIFO_0_START_ADDR;
    msgRAMConfigParams.rxFIFO0size          = OZ_TI_MCAN_FIFO_0_NUM;
    msgRAMConfigParams.rxFIFO0waterMark     = 0U;
    msgRAMConfigParams.rxFIFO0OpMode        = 0U;
    msgRAMConfigParams.rxFIFO1startAddr     = OZ_TI_MCAN_FIFO_1_START_ADDR;
    msgRAMConfigParams.rxFIFO1size          = OZ_TI_MCAN_FIFO_1_NUM;
    msgRAMConfigParams.rxFIFO1waterMark     = 0U;
    msgRAMConfigParams.rxFIFO1OpMode        = 0U;
    msgRAMConfigParams.rxBufStartAddr       = OZ_TI_MCAN_RX_BUFF_START_ADDR;
    msgRAMConfigParams.rxBufElemSize        = MCAN_ELEM_SIZE_64BYTES;
    msgRAMConfigParams.rxFIFO0ElemSize      = MCAN_ELEM_SIZE_64BYTES;
    msgRAMConfigParams.rxFIFO1ElemSize      = MCAN_ELEM_SIZE_64BYTES;
    /* Initialize Tx Buffer Config params */
    stdFiltelem.sfid2 = (0x7U << 6U);
    stdFiltelem.sfid1 = 0x4U;
    stdFiltelem.sfec  = 0x7U;
    stdFiltelem.sft   = 0x0U;

    /* Initialize bit timings */
    bitTimes.nomRatePrescalar   = 0xFU;
    bitTimes.nomTimeSeg1        = 0x5U;
    bitTimes.nomTimeSeg2        = 0x2U;
    bitTimes.nomSynchJumpWidth  = 0x0U;

    bitTimes.dataRatePrescalar  = 0x7U;
    bitTimes.dataTimeSeg1       = 0x5U;
    bitTimes.dataTimeSeg2       = 0x2U;
    bitTimes.dataSynchJumpWidth = 0x0U;

    /* Get MCANSS Revision ID */
    MCAN_getRevisionId(mcan_base_addr, &revId);
    
    /* Enable Auto wakeup */
    fdoe = MCAN_isFDOpEnable(mcan_base_addr);
    if ((uint32_t)TRUE == fdoe) {
        MCAN_INFO_PRINT("CAN-FD operation is enabled through E-Fuse.\n");
    }
    else {
        MCAN_INFO_PRINT("CAN-FD operation is disabled through E-Fuse.\n");
    }

    /* wait for memory initialization to happen */
    while (FALSE == MCAN_isMemInitDone(mcan_base_addr))
    {}
    MCAN_setOpMode(mcan_base_addr, MCAN_OPERATION_MODE_SW_INIT);
    while (MCAN_OPERATION_MODE_SW_INIT != MCAN_getOpMode(mcan_base_addr))
    {}
    /* Initialize MCAN module */
    MCAN_init(mcan_base_addr, &initParams);
    /* Configure MCAN module */
    MCAN_config(mcan_base_addr, &configParams);
    /* Configure Bit timings */
    status = MCAN_setBitTime(mcan_base_addr, &bitTimes);
    if (status != STW_SOK) {
        MCAN_ERR_PRINT("Bit Timing Configuration failed\n");
    }

    /* Set Extended ID Mask */
    MCAN_setExtIDAndMask(mcan_base_addr, OZ_TI_MCAN_EXT_ID_AND_MASK);
    /* Configure Message RAM Sections */
    MCAN_msgRAMConfig(mcan_base_addr, &msgRAMConfigParams);
    /* Configure Standard ID filter element */
    MCAN_addStdMsgIDFilter(mcan_base_addr, 0U, &stdFiltelem);
    /* Take MCAN out of the SW initialization mode */

    // Loop Back
    MCAN_lpbkModeEnable(mcan_base_addr, MCAN_LPBK_MODE_INTERNAL, FALSE);

    MCAN_setOpMode(mcan_base_addr, MCAN_OPERATION_MODE_NORMAL);
    while (MCAN_OPERATION_MODE_NORMAL != MCAN_getOpMode(mcan_base_addr))
    {}
    /* Enable Interrupts */
    MCAN_enableIntr(mcan_base_addr, MCAN_INTR_MASK_ALL, (uint32_t)TRUE);
    MCAN_enableIntr(mcan_base_addr, MCAN_INTR_SRC_RES_ADDR_ACCESS, (uint32_t)FALSE);

    /* Select Interrupt Line */
    MCAN_selectIntrLine(mcan_base_addr,
                        MCAN_INTR_MASK_ALL,
                        MCAN_INTR_LINE_NUM_1);

    /* Enable Interrupt Line */
    MCAN_enableIntrLine(mcan_base_addr,
                        MCAN_INTR_LINE_NUM_1,
                        1U);

    // Enable Interrupt
    status = mcan_rx_register_interrupt(4); // CSL_MCAN0_MSGMEM_RAM_BASE
    if (status != 0) {
        MCAN_ERR_PRINT("Unable to reigster interrupt in MCAN !!!");
    }

    MCAN_DBG_PRINT("<<<<\n");
    return status;
}

And this is the TX function which is called every 10msec and main function I modified.

The 'avpMain' is the function that has the 'mcan_tx'  function.

static int32_t mcan_tx(OzAvpPathControlOutput* data)
{
    int32_t status = 0;
    int32_t remains;
    int32_t buf_num;
    uint32_t buf_idx;
    volatile uint32_t i;

    MCAN_TxBufElementNoCpy tx_msg;

    tx_msg.rtr = 0U;
    tx_msg.xtd = 0U;
    tx_msg.esi = 0U;
    tx_msg.brs = 1U;
    tx_msg.fdf = 0U;
    tx_msg.efc = 0U;
    tx_msg.mm = 0xAAU;

    // write messages to buffer
    int32_t msg_idx = 0;
    while (msg_idx < data->num_frame) {
        remains = data->num_frame - msg_idx;
        buf_num = (remains > OZ_TI_MCAN_TX_BUFF_SIZE) ? OZ_TI_MCAN_TX_BUFF_SIZE : remains;

        for (buf_idx = 0U; buf_idx < (uint32_t)buf_num; buf_idx++) {
        
            // make can_message
            tx_msg.id = (uint32_t)((uint32_t)(data->acan_frame[msg_idx].can_id) << 18U);
            tx_msg.dlc = (uint32_t)data->acan_frame[msg_idx].can_dlc;
            tx_msg.data = data->acan_frame[msg_idx].data;

            // tx
            MCAN_writeMsgRamNoCpy(gMcanBaseAddr, MCAN_MEM_TYPE_BUF, buf_idx, &tx_msg);

            // waiting for Tr complete
            const uint32_t buf_bit_mask = (1U << 1);
            uint32_t buf_tx_status = 1;
            int32_t watchdog_count = 0x1FFFFF;
            do {
                uint32_t tx_status = MCAN_getTxBufReqPend(gMcanBaseAddr);
                buf_tx_status = tx_status & buf_bit_mask;
                watchdog_count--;
            } while ((buf_tx_status != 0U) && (watchdog_count > 0));

            if (watchdog_count == 0) {
                VX_PRINT(VX_ZONE_ERROR, "Watchdog timer expired!\n");
                return -1;
            }

            status = MCAN_txBufAddReq(gMcanBaseAddr, buf_idx);
            if (status != 0) {
                printf("Error in Adding Transmission Request...\n");
                return -1;
            }

            for (i = 0; i < OZ_AVP_PATH_CAN_TX_DELAY_COUNT; i++) {
            }

            // Checking for Errors
            MCAN_ProtocolStatus protStatus;
            MCAN_getProtocolStatus(gMcanBaseAddr, &protStatus);
            if (((MCAN_ERR_CODE_NO_ERROR == protStatus.lastErrCode) ||
                 (MCAN_ERR_CODE_NO_CHANGE == protStatus.lastErrCode)) &&
                ((MCAN_ERR_CODE_NO_ERROR == protStatus.dlec) ||
                 (MCAN_ERR_CODE_NO_CHANGE == protStatus.dlec)) &&
                (0U == protStatus.pxe)) {
            }
            else {
                printf("Error in transmission...\n");
            }

            msg_idx++;
        }

    }

    return status;
}



static uint8_t gTskStackMain[8*1024]
__attribute__ ((section(".bss:taskStackSection")))
__attribute__ ((aligned(8192)))
    ;

static uint8_t gTskStackAvp[256*1024]
__attribute__ ((section(".bss:taskStackAvpSection")))
__attribute__ ((aligned(8192)))
    ;

static uint8_t gTskStackCANRx[256*1024]
__attribute__ ((section(".bss:taskStackCANRxSection")))
__attribute__ ((aligned(8192)))
    ;

int main(void)
{
    TaskP_Params tskParams;
    TaskP_Handle task;
    TaskP_Params tskAvpPrams;
    TaskP_Handle task_avp;
    TaskP_Params tskCANRxPrams;
    TaskP_Handle task_CANRx;
    MCAN_BitTimingParams bitTimes;
    /* This is for debug purpose - see the description of function header */
    StartupEmulatorWaitFxn();

    OS_init();


    TaskP_Params_init(&tskParams);
    tskParams.priority = 8u;
    tskParams.stack = gTskStackMain;
    tskParams.stacksize = sizeof (gTskStackMain);
    task = TaskP_create(&appMain, &tskParams);

    if( NULL == task )
    {
        OS_stop();
    }
#ifdef USE_AVP

    TaskP_Params_init(&tskAvpPrams);
    tskAvpPrams.priority = 10u;
    tskAvpPrams.stack = gTskStackAvp;
    tskAvpPrams.stacksize = sizeof (gTskStackAvp);
    tskAvpPrams.name = "task_avp";
    task_avp = TaskP_create(&avpMain, &tskAvpPrams);
    
    if( NULL == task_avp )
    {
        OS_stop();
    }

    TaskP_Params_init(&tskCANRxPrams);
    tskCANRxPrams.priority = 9u;
    tskCANRxPrams.stack = gTskStackCANRx;
    tskCANRxPrams.stacksize = sizeof (gTskStackCANRx);
    tskCANRxPrams.name = "task_CANRx";
    task_CANRx = TaskP_create(&avpACANRx, &tskCANRxPrams);

    if( NULL == task_CANRx )
    {
        OS_stop();
    }

    mcan_hw_init();

#endif
    OS_start();

    return 0;
}