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.

AM2634: SBL CAN issue

Part Number: AM2634
Other Parts Discussed in Thread: AM2632, UNIFLASH

Hi there.

I would like to use SBL uni-flash boot function via CAN on AM2632 and we reference the example of TI supported “sbl_qspi” to add CAN function. But there is one problem I confuse about now. We found this API will be triggered twice in one task cycle. In this case, we create a 10ms task to test the CAN Tx function. However, this MCAN-writeMsgRam function has a wrong action while we use CAN tool to check the behavior.

As follows, it was expected to send once every 10ms. Consequently, it becomes a bit weird. These two sent times accord to 10ms. In other words, it must be triggered twice in a cycle time. But it is wrong.

On the other hand, we try to have an experiment using XDS200 to download the .out file to the AM2632. We set a breakpoint on the MCAN-writeMsgRam function so that we can check if it really does twice in one cycle. It results that this function was triggered twice in this situation. We attach the film on youtube.  www.youtube.com/watch

Could you guys please have a look at this problem? 

many thanks

  • Hi Jay,

    Looks like the MCAN-writeMsgRam() gets called in two different places: in ApiCan_SendMessage and in HHCan0TxTest. Is this the problem?

    Best regards,

    Ming

  • Hi mate. Your point has no doubt. We checked these places and there is only one place using the MCAN-writeMsgRam function so we set a breakpoint to see what happened. It shows a double trigger at line 400. As mentioned previously, the debug steps show in the video from 0:31 to 0:36. 

    thank you and BR,

    Jay

  • Hi Jay,

    It means the HHCAN_Handler() get called two times in 10ms, right? Who is calling HHCAN_Handler(). I assume it is called in the Timer interrupt. Is it possible that it also get called in the CAN TX interrupt?

    Best regards,

    Ming

  • Hi there,

    I have already simplified our code to check the issue. The “HHCAN_Handler” is implemented once per 10ms. The CAN module setup is almost the same as SDK, and it is fine in other projects we used. The difference here is this project is “SBL”. So I attach my main code here please help me to figure out the problem.

  • Hi Jay,

    I do not understand why you put the following code section inside the while loop in main:

    Bootloader_profileAddProfilePoint("System_init");

    Drivers_open();
    Bootloader_profileAddProfilePoint("Drivers_open");

    DebugP_log("\r\n");
    DebugP_log("Starting QSPI Bootloader ... \r\n");

    status = Board_driversOpen();
    DebugP_assert(status == SystemP_SUCCESS);
    Bootloader_profileAddProfilePoint("Board_driversOpen");

    Best regards,

    Ming

  • Hi Ming Wei,

    Sorry for providing the wrong version. 

    As follows the picture is the correct one the same as the footage.

    This paragraph about the bootloader series is based on the sample code.

    We have checked this issue with these steps but it still remains.

    Thank you and BR,

    Jay

  • Hi Jay,

    From the source code you provided, the only two functions in question are: TBM_PollData() and TBM_Handler(). Can you provide the code for those two functions? One possibility is that the TBM_PollData may be TRUE more than 100 times per second. The other possibility is that TBM_Handler() also calls MCAN_writeMsgRam somehow.

    Best regards,

    Ming

  • Hi Ming Wei,

    The config of TBM is set in the systemconfig.

    Furthermore, the relative functions are as follows. (timebase)

    /*******************************************************************************/
    /* NEC Interrupt Vector Define */
    /*******************************************************************************/
    //#pragma	interrupt INTTM50	Timebase_Routine
    //#pragma	interrupt INTTMH1	CycleWakeUp_Routine
    
    /*******************************************************************************/
    /* Header File Includes*/
    /*******************************************************************************/ 
    
    
    //#include "TI_Define.h"
    //#include "DF_Value.h"
    
    #include <stdio.h>
    
    #include <kernel/dpl/ClockP.h>
    #include <kernel/dpl/DebugP.h>
    #include <kernel/dpl/SystemP.h>
    #include <drivers/soc.h>
    #include <kernel/dpl/AddrTranslateP.h>
    #include "ti_dpl_config.h"
    #include "ti_drivers_config.h"
    #include "HHtimebase.h"
    #include "DF_Value.h"
    
    //#define CONFIG_TIMER0_INT_NUM                       (CONFIG_TIMER0_INT_NUM)
    #define APP_MCAN_INTR_NUM                        (CONFIG_MCAN0_INTR)
    #define APP_MCAN_MSG_LOOP_COUNT                  (10U)
    
    void myClockCallback(void *args);
    /*******************************************************************************/
    /* Private Typedef Structure*/
    /*******************************************************************************/
    typedef struct
    {
        DF_U08	T1msFlag	;     /* Flag for 1ms   */
    	DF_U08	T10msFlag	;     /* Flag for 10ms  */
    	DF_U08	T50msFlag	;     /* Flag for 50ms  */
        DF_U08	T100msFlag	;     /* Flag for 100ms */
    
    	DF_U32	T10msTimer	;
    	DF_U32	T50msTimer	;
        DF_U32	T100msTimer	;
    
    	DF_U32	DelayCount	;
    
    
    }TS_TIMEBASE_DATA;
    
    /*******************************************************************************/
    /* Private Variable Definition*/
    /*******************************************************************************/
    static TS_TIMEBASE_DATA	tbmData = {0};
    
    uint32_t gOneShotCount = 0;
    uint32_t gPeriodicCount = 0;
    
    /*******************************************************************************/
    /* Public Function Definition*/
    /*******************************************************************************/
    
    /*******************************************************************************/
    /* Function name: TBM_Init()*/
    /* Description	: Initialize TimeBase Module Data*/
    /* Parameters	: N.A  */
    /* Returns		: N.A*/
    /* Remark		: N.A*/
    /*******************************************************************************/
    void TBM_Init(void)
    {
        tbmData.T1msFlag = DF_CLEAR;
        tbmData.T10msFlag = DF_CLEAR;
        tbmData.T50msFlag = DF_CLEAR;
        tbmData.T100msFlag = DF_CLEAR;
    
    	tbmData.T10msTimer = 10;
    	tbmData.T50msTimer = 5;
        tbmData.T100msTimer = 2;
    }
    
    /*******************************************************************************/
    /* Function name: TBM_Handler()*/
    /* Description	: Handler TimeBase Module Data*/
    /* Parameters	: N.A*/
    /* Returns		: N.A*/
    /* Remark		: N.A*/
    /*******************************************************************************/
    void TBM_Handler(void)
    {
    
        //DebugP_log("TBM_Handler ...\r\n");
    	/* Clear All Timer Base Flags */
    	tbmData.T1msFlag = DF_CLEAR;
    	tbmData.T10msFlag = DF_CLEAR;
    	tbmData.T50msFlag = DF_CLEAR;
    	tbmData.T100msFlag = DF_CLEAR;
    	/* Clear WatchDog Timer*/
    	//WDOG_Refresh(WDOG);
    
    	/* Handle 50 ms */
    	tbmData.T50msTimer--;
    	if (tbmData.T50msTimer == DF_CLEAR)
    	{
    		tbmData.T50msFlag = DF_ON;
    		/* Reset 50ms Timer*/
    		tbmData.T50msTimer = 5;
    		/* Handle 100 ms */
    		tbmData.T100msTimer--;
    		if (tbmData.T100msTimer == DF_CLEAR)
    		{
    			tbmData.T100msFlag = DF_ON;
    			/* Reset 100ms Timer*/
    			tbmData.T100msTimer = 2;
    		}	
    	}
    
    }
    
    
    DF_BOOL TBM_PollData(TE_TIMEBASE_TYPE inType)
    {
        switch (inType)
        {  
    		case TBM_10ms:
    			return (tbmData.T10msFlag);
    		case TBM_50ms:
    			return (tbmData.T50msFlag);
    		case TBM_100ms:
    			return (tbmData.T100msFlag);
    		default:
    			return DF_OFF;
        }
    	return DF_OFF;
    }
    
    /*******************************************************************************/
    /* Function name: TBM_Delay(LS_U16 value)*/
    /* Description	: Delay function.*/
    /* Parameters	: LS_U16 value, timebase = 1 ms*/
    /* Returns		: N.A*/
    /* Remark		: N.A*/
    /*******************************************************************************/
    void TBM_Delay(DF_U16 value)/*timebase 10ms*/
    {
        tbmData.DelayCount = DF_CLEAR;
        while (tbmData.DelayCount < value)
        {
    		if ((tbmData.DelayCount%20) == 0)
    		{
    	//		WDOG_Refresh(WDOG);
    		}
        }
    }
    
    /*******************************************************************************/
    /* Interrupt Routine Definition*/
    /*******************************************************************************/
    
    volatile unsigned int SwTimer=0;
    unsigned char PollingTask10ms=0;
    unsigned char PollingTask100ms=0;
    unsigned char PollingTask1000ms=0;
    
    uint32_t gTimerCount = 0;
    uint32_t gpioFlag_timer = 0;
    
    void HHClockCallback(void *args)
    {
    
        uint32_t *value = (uint32_t*)args;
    
        (*value)++; /* increment number of time's this callback is called */
        DebugP_log("value %d ...\r\n", (*value));
        SwTimer++;
        if(SwTimer>10000)
        {SwTimer=1;}
    
        if((SwTimer%10)==0)
        {PollingTask10ms=1;}
    
        if((SwTimer%100)==0)
        {PollingTask100ms=1;}
    
        if((SwTimer%1000)==0)
        {PollingTask1000ms=1;}
    
    
        //PRINTF("Timebase_Routine: %d\r\n", tbmData.T1msFlag);
        /* Handle 10 ms */
        tbmData.T10msTimer-- ;
        if (tbmData.T10msTimer == DF_CLEAR)
        {
            tbmData.T10msFlag = DF_ON;
            /* Reset 10ms Timer */
            tbmData.T10msTimer = 10;
        }
    }
    
    
    

    By the way, We have changed the CAN function to GPIO function in 10ms as well. Conversely, it performs once in 10ms correctly.

  • Hi Jay,

    It boils down to the following function:

    void HHCan0TxTest(void)
    {

       tican0data.status = MCAN_txBufAddReq(tican0data.gMcanBaseAddr, tican0data.bufNum);

       /* Configure Tx Msg to transmit */
       App_mcan1ConfigTxMsg(&tican0msgdata.txMsg);

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

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

    }

    Can you count how many times MCAN_writeMsgRam() gets called in 10ms and how many HHCan0TxTest() gets called in 10ms?

    How does the MCAN TX interrupt handled (the ISR code)?

    Best regards,

    Ming

  • Hi Ming Wei,

    The HHCan0TxTest(void) gets called once in 10ms. MCAN_writeMsgRam() was expected to be called once. However it gets calleds twice in HHCan0TxTest(void) in 10ms. As the footage showing, MCAN_writeMsgRam() actives two times in HHCan0TxTest(void) in 10ms.

    We user the same MCAN TX interrupt handler in other normal projects and it works properly.

    Thank you and BR,

    Jay

  • Hi Ming Wei,

    We try to join the GPIO function with CAN Tx function and MCANISR. The pictures shown below are results.

    The first one is CAN TX and mcanISR are called at the same time period.

    The second one and the third one are the IO and CAN comparison. We check that CAN signal is sent twice and the IO is only triggered once.

    Our modifications as shown below.

    On the one hand, we check the ISR and CANTx_handler both were expected to our figure. On the other hand, the MCAN_writeMsgRam function still seems to be strange. Could you please check the SBL sample why it cannot use the CAN function normally or where should we need to modify our code.

    Thank you and BR,

    Jay

  • Hi Ming Wei

    Have any idea for this CAN TX twice time issue?

    BR

    JAY

  • Hi Jay,

    Ming asked me to help with this issue.

    I read through the thread and my understanding is as follows:

    • You're trying to replace the UART in SBL UART Uniflash with CAN
    • MCAN Tx occurs at twice the frequency you expect (2 times in 10 msec vs 1 time)
    • You have a couple of test programs which demonstrate the problem.

    The first test program configure a timer for 10 period and polls for timer period completion in an infinite loop. On timer period completion, the program:

    • executes a timer handler
    • toggles a debug GPIO
    • executes the MCAN Tx function

    The second test program takes a MCAN Tx interrupt. In the MCAN Tx ISR, the program:

    • toggles a debug GPIO
    • executes the MCAN Tx function

    Oscilloscope captures show:

    • the GPIO toggles every timer period (10 msec)
    • the MCAN Tx occurs twice back-to-back

    The MCAN configuration is similar to SDK examples. Also, this configuration works in other MCAN example code. It only behaves this way in your modified SBL example.

    Can you please confirm my understanding is correct?

    Your test results seem to indicate MCAN_writeMsgRam() is called only once is 10 msec, but that MCAN Tx occurs twice for a single call to MCAN_writeMsgRam().

    Can you share example code (entire CCS project) that clearly demonstrates the problem which executes on an AM263x CC?

    Regards,
    Frank

  • Hi Frank 

    Your understanding is correct!

    BR

    JAY

  • Jay,

    Thanks, I'll take a look at get back with you.

    Regards,
    Frank

  • Hi Frank

    Have any update for this thread?

    BR

    JAY

  • Hi Jay,

    My apologies for taking so long to respond. Is this issue resolved?

    Regards,
    Frank

  • Hi Frank

    This issue resolved by Sunil Kumar M S

    BR

    Jay

  • Jay,

    Ok, thanks much. I'll close this thread for now.

    Regards,
    Frank