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.

TMDSCNCD263: How to receive multiple messages on MCAN peripheral

Part Number: TMDSCNCD263
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hello,

I have a CANalyzer connected to my AM263 Control card CAN port. I have modified the external_mcan_read_write example to:

1) Send a message on a button press

2) poll MCAN for messages if button is not pressed.

The problem is that when I run the debugger, hit a breakpoint in line 237, and send more CAN messages,  then resume the code, the MCAN peripheral discards the other messages I transmitted from my CANalyzer.

How do I use the buffer to make sure my other CAN messages are not discarded?

/*
 *  Copyright (C) 2023 Texas Instruments Incorporated
 *
 *  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.
 */

/* This example demonstrates the CAN message communication to external CAN
 * controller in with the following configuration.
 * CAN FD Message Format.
 * Message ID Type is Standard, Msg Id 0xC0.
 * MCAN is configured in Interrupt Mode.
 * MCAN Interrupt Line Number 0.
 * Arbitration Bit Rate 1Mbps.
 * Data Bit Rate 5Mbps.
 * Buffer mode is used for Tx and RX to store message in message RAM.
 * Instance MCAN1 is set as a Commander in Transmit Mode. Message is transmitted and received
 * back from external CAN controller. Once message is transmitted the example will wait for
 * recieving the messages from external PC. Have to manually transmit ten messages from external
 * PC for test to finish. When the received message id and the data matches with the transmitted
 * one, then the example is completed.
 */

#include <stdio.h>
#include <kernel/dpl/DebugP.h>
#include <kernel/dpl/AddrTranslateP.h>
#include <kernel/dpl/SemaphoreP.h>
#include <drivers/mcan.h>
#include "ti_drivers_config.h"
#include "ti_drivers_open_close.h"
#include "ti_board_open_close.h"

#define APP_MCAN_BASE_ADDR                       (CONFIG_MCAN0_BASE_ADDR)
#define APP_MCAN_INTR_NUM                        (CONFIG_MCAN0_INTR)
#define APP_MCAN_MSG_LOOP_COUNT                  (10U)
#define APP_MCAN_LOOPBACK_MODE_DISABLE           (FALSE)

/* Allocate Message RAM memory section to filter elements, buffers, FIFO */
/* Maximum STD Filter Element can be configured is 128 */
#define APP_MCAN_STD_ID_FILTER_CNT               (1U)
/* Maximum EXT Filter Element can be configured is 64 */
#define APP_MCAN_EXT_ID_FILTER_CNT               (0U)
/* Maximum TX Buffer + TX FIFO, combined can be configured is 32 */
#define APP_MCAN_TX_BUFF_CNT                     (1U)
#define APP_MCAN_TX_FIFO_CNT                     (4U)
/* Maximum TX Event FIFO can be configured is 32 */
#define APP_MCAN_TX_EVENT_FIFO_CNT               (0U)
/* Maximum RX FIFO 0 can be configured is 64 */
#define APP_MCAN_FIFO_0_CNT                      (60U)
/* Maximum RX FIFO 1 can be configured is 64 and
 * rest of the memory is allocated to RX buffer which is again of max size 64 */
#define APP_MCAN_FIFO_1_CNT                      (0U)

/* Standard Id configured in this app */
#define APP_MCAN_STD_ID                          (0xC0U)
#define APP_MCAN_STD_ID_MASK                     (0x7FFU)
#define APP_MCAN_STD_ID_SHIFT                    (18U)

#define APP_MCAN_EXT_ID_MASK                     (0x1FFFFFFFU)

/* In the CAN FD format, the Data length coding differs from the standard CAN.
 * In case of standard CAN it is 8 bytes */
static const uint8_t gMcanDataSize[16U] = {0U,  1U,  2U,  3U,
                                           4U,  5U,  6U,  7U,
                                           8U,  12U, 16U, 20U,
                                           24U, 32U, 48U, 64U};

/* Semaphore to indicate transfer completion */
static SemaphoreP_Object gMcanTxDoneSem, gMcanRxDoneSem;
static HwiP_Object       gMcanHwiObject;
static uint32_t          gMcanBaseAddr;

/* Static Function Declarations */
static void    App_mcanIntrISR(void *arg);
static void    App_mcanConfig(Bool enableInternalLpbk);
static void    App_mcanInitMsgRamConfigParams(
               MCAN_MsgRAMConfigParams *msgRAMConfigParams);
static void    App_mcanEnableIntr(void);
static void    App_mcanConfigTxMsg(MCAN_TxBufElement *txMsg);
static void    App_mcanInitStdFilterElemParams(
                                  MCAN_StdMsgIDFilterElement *stdFiltElem,
                                  uint32_t bufNum);
void mcanEnableTransceiver(void);
static void GPIO_bankIsrFxn(void *args);

uint32_t            gGpioBaseAddr = GPIO_PUSH_BUTTON_BASE_ADDR;
HwiP_Object         gGpioHwiObject;
volatile bool   gGpioIntrDone = false;

void mcan_external_read_write_main(void *args)
{
    int32_t                 status = SystemP_SUCCESS;
    HwiP_Params             hwiPrms;
    MCAN_TxBufElement       txMsg;
    MCAN_ProtocolStatus     protStatus;
    MCAN_RxBufElement       rxMsg;
    MCAN_RxNewDataStatus    newDataStatus;
    MCAN_ErrCntStatus       errCounter;
    uint32_t                i, bufNum, fifoNum, bitPos = 0U;

    int32_t         retVal;
    uint32_t        pinNum, intrNum, buttonNum;     // GPIO STUFF
    uint32_t        waitCount = 5;

    /* INITIALIZE MCAN */
    mcanEnableTransceiver();

    DebugP_log("[MCAN] Application started... Please read or write ...\r\n");

    /* Construct Tx/Rx Semaphore objects */
    status = SemaphoreP_constructBinary(&gMcanTxDoneSem, 0);
    DebugP_assert(SystemP_SUCCESS == status);
    status = SemaphoreP_constructBinary(&gMcanRxDoneSem, 0);
    DebugP_assert(SystemP_SUCCESS == status);

    /* Register interrupt */
    HwiP_Params_init(&hwiPrms);
    hwiPrms.intNum      = APP_MCAN_INTR_NUM;
    hwiPrms.callback    = &App_mcanIntrISR;
    status              = HwiP_construct(&gMcanHwiObject, &hwiPrms);
    DebugP_assert(status == SystemP_SUCCESS);

    /* Assign MCAN instance address */
    gMcanBaseAddr = (uint32_t) AddrTranslateP_getLocalAddr(APP_MCAN_BASE_ADDR);

    /* Configure MCAN module, Enable External LoopBack Mode */
    App_mcanConfig(APP_MCAN_LOOPBACK_MODE_DISABLE);

    /* Enable Interrupts */
    App_mcanEnableIntr();
    /* MCAN INITIALIZED */

    /* INITIALIZE GPIO */
    pinNum          = GPIO_PUSH_BUTTON_PIN;
    intrNum         = CSLR_R5FSS0_CORE0_INTR_GPIO_INTRXBAR_OUT_14;
    buttonNum       = 1;

    /* Address translate */
    gGpioBaseAddr = (uint32_t) AddrTranslateP_getLocalAddr(gGpioBaseAddr);

    /* Register pin interrupt */
    HwiP_Params_init(&hwiPrms);
    hwiPrms.intNum   = intrNum;
    hwiPrms.callback = &GPIO_bankIsrFxn;
    hwiPrms.args     = (void *) pinNum;
    /* GPIO interrupt is a pulse type interrupt */
    hwiPrms.isPulse  = TRUE;
    retVal = HwiP_construct(&gGpioHwiObject, &hwiPrms);
    DebugP_assert(retVal == SystemP_SUCCESS );
    /* GPIO INITIALIZED */

    DebugP_log("Starting Test...\n");
    DebugP_log("Press SW1 to transmit message. Otherwise, wait for message.");

    while(1)
    {
        if(gGpioIntrDone)
        {
            /* Configure Tx Msg to transmit */
            App_mcanConfigTxMsg(&txMsg);

            /* Select buffer number, 32 buffers available */
            bufNum = 0U;
            /* Enable Transmission interrupt for the selected buf num,
             * If FIFO is used, then need to send FIFO start index until FIFO count */
            status = MCAN_txBufTransIntrEnable(gMcanBaseAddr, bufNum, (uint32_t)TRUE);
            DebugP_assert(status == CSL_PASS);

            /* Write message to Msg RAM */
            MCAN_writeMsgRam(gMcanBaseAddr, MCAN_MEM_TYPE_BUF, bufNum, &txMsg);

            /* Add request for transmission, This function will trigger transmission */
            status = MCAN_txBufAddReq(gMcanBaseAddr, bufNum);
            DebugP_assert(status == CSL_PASS);

            /* Wait for Tx completion */
            SemaphoreP_pend(&gMcanTxDoneSem, SystemP_WAIT_FOREVER);

            MCAN_getProtocolStatus(gMcanBaseAddr, &protStatus);
            /* Checking for Tx Errors */
            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))
            {
                 DebugP_assert(FALSE);
            }
            gGpioIntrDone = false;
        }
        else
        {
            /* Wait for Rx completion */
            // SemaphoreP_pend(&gMcanRxDoneSem, 10);

            /* Checking for Rx Errors */
            // MCAN_getErrCounters(gMcanBaseAddr, &errCounter);
            /*DebugP_assert((0U == errCounter.recErrCnt) &&
                          (0U == errCounter.canErrLogCnt));*/

            /* Get the new data staus, indicates buffer num which received message */
            MCAN_getNewDataStatus(gMcanBaseAddr, &newDataStatus);
            MCAN_clearNewDataStatus(gMcanBaseAddr, &newDataStatus);

            /* Select buffer and fifo number, Buffer is used in this app */
            bufNum = 0;
            fifoNum = MCAN_RX_FIFO_NUM_0;

            bitPos = (1U << bufNum);
            if (bitPos == (newDataStatus.statusLow & bitPos))
            {
                MCAN_readMsgRam(gMcanBaseAddr, MCAN_MEM_TYPE_BUF, bufNum, fifoNum, &rxMsg);
            }
        }
        //ClockP_usleep(2000);
    }


    /* De-Construct Tx/Rx Semaphore objects */
    HwiP_destruct(&gMcanHwiObject);
    SemaphoreP_destruct(&gMcanTxDoneSem);
    SemaphoreP_destruct(&gMcanRxDoneSem);
    MCAN_reset(gMcanBaseAddr);

    DebugP_log("Test Finished");

    Board_driversClose();
    Drivers_close();

    return;
}

static void GPIO_bankIsrFxn(void *args)
{
    uint32_t    pinNum = (uint32_t) args;
    uint32_t    bankNum =  GPIO_GET_BANK_INDEX(pinNum);
    uint32_t    intrStatus, pinMask = GPIO_GET_BANK_BIT_MASK(pinNum);

    /* Get and clear bank interrupt status */
    intrStatus = GPIO_getBankIntrStatus(gGpioBaseAddr, bankNum);
    GPIO_clearBankIntrStatus(gGpioBaseAddr, bankNum, intrStatus);

    /* Per pin interrupt handling */
    if(intrStatus & pinMask)
    {
        gGpioIntrDone = true;
    }
}

static void App_mcanConfig(Bool enableInternalLpbk)
{
    MCAN_StdMsgIDFilterElement stdFiltElem[APP_MCAN_STD_ID_FILTER_CNT] = {0U};
    MCAN_InitParams            initParams = {0U};
    MCAN_ConfigParams          configParams = {0U};
    MCAN_MsgRAMConfigParams    msgRAMConfigParams = {0U};
    MCAN_BitTimingParams       bitTimes = {0U};
    uint32_t                   i;

    /* Initialize MCAN module initParams */
    MCAN_initOperModeParams(&initParams);
    /* CAN FD Mode and Bit Rate Switch Enabled */
    initParams.fdMode          = TRUE;
    initParams.brsEnable       = TRUE;

    /* Initialize MCAN module Global Filter Params */
    MCAN_initGlobalFilterConfigParams(&configParams);

    /* Initialize MCAN module Bit Time Params */
    /* Configuring default 1Mbps and 5Mbps as nominal and data bit-rate resp */
    MCAN_initSetBitTimeParams(&bitTimes);

    /* Initialize MCAN module Message Ram Params */
    App_mcanInitMsgRamConfigParams(&msgRAMConfigParams);

    /* Initialize Filter element to receive msg, should be same as tx msg id */
    for (i = 0U; i < APP_MCAN_STD_ID_FILTER_CNT; i++)
    {
        App_mcanInitStdFilterElemParams(&stdFiltElem[i], i);
    }
    /* wait for memory initialization to happen */
    while (FALSE == MCAN_isMemInitDone(gMcanBaseAddr))
    {}

    /* Put MCAN in SW initialization mode */
    MCAN_setOpMode(gMcanBaseAddr, MCAN_OPERATION_MODE_SW_INIT);
    while (MCAN_OPERATION_MODE_SW_INIT != MCAN_getOpMode(gMcanBaseAddr))
    {}

    /* Initialize MCAN module */
    MCAN_init(gMcanBaseAddr, &initParams);
    /* Configure MCAN module Gloabal Filter */
    MCAN_config(gMcanBaseAddr, &configParams);
    /* Configure Bit timings */
    MCAN_setBitTime(gMcanBaseAddr, &bitTimes);
    /* Configure Message RAM Sections */
    MCAN_msgRAMConfig(gMcanBaseAddr, &msgRAMConfigParams);
    /* Set Extended ID Mask */
    MCAN_setExtIDAndMask(gMcanBaseAddr, APP_MCAN_EXT_ID_MASK);

    /* Configure Standard ID filter element */
    for (i = 0U; i < APP_MCAN_STD_ID_FILTER_CNT; i++)
    {
        MCAN_addStdMsgIDFilter(gMcanBaseAddr, i, &stdFiltElem[i]);
    }
    if (TRUE == enableInternalLpbk)
    {
        MCAN_lpbkModeEnable(gMcanBaseAddr, MCAN_LPBK_MODE_INTERNAL, TRUE);
    }

    /* Take MCAN out of the SW initialization mode */
    MCAN_setOpMode(gMcanBaseAddr, MCAN_OPERATION_MODE_NORMAL);
    while (MCAN_OPERATION_MODE_NORMAL != MCAN_getOpMode(gMcanBaseAddr))
    {}

    return;
}

static void App_mcanConfigTxMsg(MCAN_TxBufElement *txMsg)
{
    uint32_t i;

    /* Initialize message to transmit */
    MCAN_initTxBufElement(txMsg);
    /* Standard message identifier 11 bit, stored into ID[28-18] */
    txMsg->id  = ((APP_MCAN_STD_ID & MCAN_STD_ID_MASK) << MCAN_STD_ID_SHIFT);
    txMsg->dlc = MCAN_DATA_SIZE_2BYTES; /* Payload size is 64 bytes */
    txMsg->fdf = TRUE; /* CAN FD Frame Format */
    txMsg->xtd = FALSE; /* Extended id not configured */
    txMsg->data[0] = 0b11001100;
    txMsg->data[1] = 0b00000111;
    return;
}

static void App_mcanInitStdFilterElemParams(MCAN_StdMsgIDFilterElement *stdFiltElem,
                                            uint32_t bufNum)
{
    /* sfid1 defines the ID of the standard message to be stored. */
    stdFiltElem->sfid1 = APP_MCAN_STD_ID;
    /* As buffer mode is selected, sfid2 should be bufNum[0 - 63] */
    stdFiltElem->sfid2 = bufNum;
    /* Store message in buffer */
    stdFiltElem->sfec  = MCAN_STD_FILT_ELEM_BUFFER;
    /* Below configuration is ignored if message is stored in buffer */
    stdFiltElem->sft   = MCAN_STD_FILT_TYPE_RANGE;

    return;
}

static void App_mcanInitMsgRamConfigParams(MCAN_MsgRAMConfigParams
                                           *msgRAMConfigParams)
{
    int32_t status;

    MCAN_initMsgRamConfigParams(msgRAMConfigParams);

    /* Configure the user required msg ram params */
    msgRAMConfigParams->lss = APP_MCAN_STD_ID_FILTER_CNT;
    msgRAMConfigParams->lse = APP_MCAN_EXT_ID_FILTER_CNT;
    msgRAMConfigParams->txBufCnt = APP_MCAN_TX_BUFF_CNT;
    msgRAMConfigParams->txFIFOCnt = APP_MCAN_TX_FIFO_CNT;
    /* Buffer/FIFO mode is selected */
    msgRAMConfigParams->txBufMode = MCAN_TX_MEM_TYPE_BUF;
    msgRAMConfigParams->txEventFIFOCnt = APP_MCAN_TX_EVENT_FIFO_CNT;
    msgRAMConfigParams->rxFIFO0Cnt = APP_MCAN_FIFO_0_CNT;
    msgRAMConfigParams->rxFIFO1Cnt = APP_MCAN_FIFO_1_CNT;
    /* FIFO blocking mode is selected */
    msgRAMConfigParams->rxFIFO0OpMode = MCAN_RX_FIFO_OPERATION_MODE_BLOCKING;
    msgRAMConfigParams->rxFIFO1OpMode = MCAN_RX_FIFO_OPERATION_MODE_BLOCKING;

    status = MCAN_calcMsgRamParamsStartAddr(msgRAMConfigParams);
    DebugP_assert(status == CSL_PASS);

    return;
}

static void App_mcanEnableIntr(void)
{
    MCAN_enableIntr(gMcanBaseAddr, MCAN_INTR_MASK_ALL, (uint32_t)TRUE);
    MCAN_enableIntr(gMcanBaseAddr,
                    MCAN_INTR_SRC_RES_ADDR_ACCESS, (uint32_t)FALSE);
    /* Select Interrupt Line 0 */
    MCAN_selectIntrLine(gMcanBaseAddr, MCAN_INTR_MASK_ALL, MCAN_INTR_LINE_NUM_0);
    /* Enable Interrupt Line */
    MCAN_enableIntrLine(gMcanBaseAddr, MCAN_INTR_LINE_NUM_0, (uint32_t)TRUE);

    return;
}

static void App_mcanIntrISR(void *arg)
{
    uint32_t intrStatus;

    intrStatus = MCAN_getIntrStatus(gMcanBaseAddr);
    MCAN_clearIntrStatus(gMcanBaseAddr, intrStatus);

    if (MCAN_INTR_SRC_TRANS_COMPLETE ==
        (intrStatus & MCAN_INTR_SRC_TRANS_COMPLETE))
    {
        SemaphoreP_post(&gMcanTxDoneSem);
    }

    /* If FIFO0/FIFO1 is used, then MCAN_INTR_SRC_DEDICATED_RX_BUFF_MSG macro
     * needs to be replaced by MCAN_INTR_SRC_RX_FIFO0_NEW_MSG/
     * MCAN_INTR_SRC_RX_FIFO1_NEW_MSG respectively */
    if (MCAN_INTR_SRC_DEDICATED_RX_BUFF_MSG ==
        (intrStatus & MCAN_INTR_SRC_DEDICATED_RX_BUFF_MSG))
    {
        SemaphoreP_post(&gMcanRxDoneSem);
    }

    return;
}

Thanks,

David Martinez

  • Hello David,

    This could be due to MCAN module configuration, the SS_CTRL.DBGSUSP_FREE register bitfield determines if debug-suspend is honored or not during operation. Could you check the value of the corresponding bit?

    Similarly, there is also an RTIGCTRL.COS register bitfield. Could you check the value of this, to see if counters are configured to suspend in debug mode?

    Best Regards,

    Zackary Fleenor

  • Hello,

    SS_CTRL.DBGSUSP_FREE = 1

    RTIGCTRL.COS = 0

    I found RTIGCTRL.COS values in these registers. I'm supposed to be focusing on RTI0 right? (I am using core 0).

    Best,

    David Martinez

  • Hello,

    I found on sysconfig that RTI0 is being used as the clock instance for MCAN. Since RTI0.RTIGCTRL.COS = 0, I think this might be causing the extra CAN messages to be discarded.

    i added the following line to try to change this bit. Is this correct? The bit value is not changing when running, so I think the BASE_ADDRESS is incorrect but I do not know how to find the base address of RTI0.

    RTIG_setStallMode(CONFIG_MCAN0_BASE_ADDR, RTI_GC_STALL_MODE_OFF);

    Best,

    David Martinez

  • Hello David,

    I think your assumption may be correct here.

    This looks like the correct function, but incorrect base address.

    You should use the following base address defined in mcu_plus_sdk_am263x_09_xx_xx_xx/source/drivers/hw_include/am263x/cslr_soc_baseaddress.h file.

    #define CSL_RTI0_U_BASE                  (0x52180000ul)

    Best Regards,

    Zackary Fleenor

  • Hey Zackary,

    I added this line today to my code, but I did not see any differences.

    RTIG_setStallMode(CSL_RTI0_U_BASE, RTI_GC_STALL_MODE_OFF);

    I verified in the registers these settings: 

    SS_CTRL.DBGSUSP_FREE = 1

    RTIGCTRL.COS = 1

    When I hit a breakpoint at line 237, send 5 more messages, I expect to hit the same breakpoint 5 more times but I do not. I only hit the breakpoint one more time. Should I be doing something with bufNum or fifoNum to see the rest of the messages?

  • Hey David,

    Thank you for providing this information. Sorry to hear your issue still persists. I am looping in another expert to provide additional feedback and help close the loop. Please allow some time for them to familiarize themselves with the situation and they will get back to you as soon as possible.

    Best Regards,

    Zackary Fleenor

  • Hello David,
    Please give me some time to go through the application. I will try to reproduce this locally. Is there any extra setup required that I should be aware of?

    Best,
    Aswathi