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.

AM335x: CAN Interface 2 - no valid message number set in the INT register (offset 10h)



We are using on an AM335x both CAN interfaces. On the CAN interface 2 we have the problem, that the INT register (offset = 10h) has sometimes after a powerfail always no valid message (0 is set) number set after an interrupt.

The problem is from powerfail to powerfail different. When it is working after a powerfail,  we have no further problems. The CAN interface 1 is working always fine. We have the same interrupt handler for interface 1 and 2 and we are using INT0 for DCAN1 and DCAN2.

In the interrupt handler all interrupts will be disabled in the CTL register.

...

/* Interrupt line 0 disable */

/* Interrupt line 1 disable */

DCANIntLineDisable (base, (DCAN_INT_LINE0 | DCAN_INT_LINE1));

/* Status change interrupt disable */

/* Error interrupt disable */

DCANIntDisable (base, (DCAN_STATUS_CHANGE_INT | DCAN_ERROR_INT));

...

In the CAN eventhandler we poll the INT Register for a valid message number, make the message handling for receive and transmit and when the INT Register value ist 0 we enable the saved  interrupts again in the CTL register.

register values:

DCAN0            0x481cc000   DCAN1 0x481d0000

CTL Register:  0x0000160e                0x0000160e

 

Do you have an idea to solve the problem ?

  • Hi Klaus,

    What software are you using?

  • Hi Biser,

    Thanks for your help.

    We are using the DCAN API from TI, and an own implementation for the CAN driver working with the OS vxWorks. Our interrupt handler function is doing the same as the interrupt handler on a linux can driver (d_can_interrupts).

    Best regards

    Klaus

     

  • There is no DCAN related Errata Advisory for the AM335X. Since you say that this is a sporadic issue it seems to me that it's not software related, but rather due to some external factor - voltages ramp-up time, parasitic signals on the DCAN lines, something in this direction. Have you compared the two interfaces with a scope during power-on?

  • We have checked the voltage ramp-up time and also the DCAN lines. Also the CAN Interface 1 is working in the same time while the CAN Interface 2 has the problem with a valid messagenumber in the INT register.

    There is no valid messagenumber (=0 set ) in the INT register for transmitted or received CAN frames on the can bus, which can be checked over the RxOk and TxOk bits in the ES Register.

    Best regards

    Klaus

     

  • Maybe this is a stupid question, but are you checking all 16 bits of Int0ID[15:0]? There is a possible value 0x8000 = Error and status register value is not 0x07.

  • The value of the INT register is definitive 0 while the RxOk or TxOk bits in the ES register is set.

    Look to the counters in the attached file  

    
    				
    				CAN1	    CAN2
    	irqA:       00791726  00006979			incremented by the hwIsrHandler
    	iRx:        00380750  00000000			incremented by the EventHandler if msgnum=RX
    	iTx:        00823592  00000000			incremented by the EventHandler if msgnum=TX
    	iOx:        00000000  00000000			incremented by the EventHandler if msgnum=other
    	iZero:      00791726  00006979			incremented by the EventHandler if msgnum=0
        rxok:       00380749  00006947			incremented by the EventHandler if ES register RxOk=1
        txok:       00411720  00000032			incremented by the EventHandler if ES register TxOk=1
    	
    
    
    
    
    static void hwIsrHandler
        (
        DDVXCNAM335XDEV * pInst
        )
    {
    	if (pInst)
    	{
    		pInst->irqA++;
    
    	    /* disable and save the interrupt states */
    	    pInst->svCmd = hwBusDisableInterrupt (pInst->hw.base);
    	    
    		RtkSendTaskEvent(pInst->notifyTID, pInst->notifyEvt);
    	}
    }
    
    
    EventHandler:
    /* == read event ==========================================================	*/
    static DM_ERROR				ioControlReadEvent
    (
    	DDVXCNAM335XDEV			*pInst,		/* device instance					*/
    	LPVOID					*pInp,		/* input buffer						*/
    	ULONG					sInp,		/* size of input buffer				*/
    	DDCAN_Typ				*pOut,		/* output buffer					*/
    	ULONG					sOut,		/* size of output buffer			*/
    	LPULONG					pDone		/* out: number of used out bytes	*/
    )
    {
    	DM_ERROR				stat = ERR_DD_IOCTL;
    	UINT32             		registerEs;		/* ES Register (offset = 04h) */
    	UINT32             		registerInt;	/* INT Register (offset = 10h)  */
    	int 					work_done = 0;
    	UINT8               	intid[2];
    	UINT8               	msgNum = 0;	/* channel index */
    	UINT32					ifArb;		/* Arbitration Register */
    	UINT32					ifMctl;		/* Message Control Register */
    
    	(void)pInp;	(void)sInp;
    	
    	*pDone = 0;
    	
    	if ((0 != pOut) && (sizeof(DDCAN_Typ) == sOut))
    	{
    		stat = ERR_DDCAN_NODATA;
    		
    		registerEs = DCANErrAndStatusRegInfoGet (pInst->hw.base);
    		pInst->hw.regEs = registerEs;
    		
    		/* status events have the highest priority */
    		if (registerEs & DCAN_IN_LOCAL_PWR_DWN_MODE)
    			{
    				/*
    				 * Application request for setting DCAN to local
    				 * power-down mode was successful. DCAN is in
    				 * local power-down mode.
    				 */
    				pInst->pwdown++;
    			}
    		if (registerEs & DCAN_INITIATED_SYSTEM_WKUP)
    			{
    				/*
    				 * DCAN has initiated a wake up of the system due to
    				 * dominant CAN bus while module power down.
    				 * This bit will be reset if error and status register is read.
    				 */
    				pInst->syswakeup++;
    			}
    		if (registerEs & DCAN_PARITY_ERR_DETECTED)
    			{
    				/*
    				 * The parity check mechanism has detected a
    				 * parity error in the Message RAM.
    				 * This bit will be reset if error and status register is read.
    				 */
    				pInst->pariterror++;
    			}
    		if (registerEs & DCAN_MOD_IN_BUS_OFF_STATE)
    			{
    				/* The CAN module is in bus-off state. */
    				pInst->busOff++;
    				if ((pInst->lstErrState & DCAN_MOD_IN_BUS_OFF_STATE) == 0)
    				{
    					/* first event */
    					pInst->lstErrState |= DCAN_MOD_IN_BUS_OFF_STATE; 
    					err2ddc(pOut, DDC_ERROR_BUSOFF);
    					
    					hwBusOff(&pInst->hw);
    					
    					stat = ERR_OK;
    					work_done = 1;
    				}
    			}
    		if (registerEs & DCAN_ERR_WARN_STATE_RCHD)
    			{
    				/*
    				 * At least one of the error counters has
    				 * reached the error warning limit of 96.
    				 */
    				pInst->bwarn++;
    				if ((pInst->lstErrState & DCAN_ERR_WARN_STATE_RCHD) == 0)
    				{
    					/* first event */
    					pInst->lstErrState |= DCAN_ERR_WARN_STATE_RCHD; 
    					err2ddc(pOut, DDC_ERROR_WARNING);
    					stat = ERR_OK;
    					work_done = 1;
    				}
    				/* hwbusOff -> dann kommt kein echter BusOFF IRQ mehr 
    				 * hwBusOff(&pInst->hw);
    				 */
    
    			}
    		if (registerEs & DCAN_CORE_IN_ERR_PASSIVE)
    			{
    				/*
    				 * The CAN core is in the error passive state
    				 * as defined in the CAN Specification.
    				 */
    				pInst->passerror++;
    				
    				/* hwbusOff -> dann kommt kein echter BusOFF IRQ mehr 
    				 * hwBusOff(&pInst->hw);
    				 */
    
    			}
    		if (registerEs & DCAN_RXD_MSG_SUCCESSFULLY)
    			{
    				/* A message has been successfully received */
    				pInst->rxPending = 1;
    				pInst->rxok++;
    				
    				hwBusOn(&pInst->hw);
    
    				/* reset lstErrState */
    				pInst->lstErrState = ERRSTATE_RESET;
    			}
    		if (registerEs & DCAN_TXD_MSG_SUCCESSFULLY)
    			{
    				/* A message has been successfully transmitted (error free and acknowledged by at least one other node) */
    				pInst->txPending = 1;
    				pInst->txok++;
    
    				hwBusOn(&pInst->hw);
    				
    				/* reset lstErrState */
    				pInst->lstErrState = ERRSTATE_RESET;
    			}
    		if ((registerEs & DCAN_ES_LEC) != 0 && (registerEs != DCAN_ES_LEC))
    			{
    				pInst->hw.lecErr = registerEs & DCAN_ES_LEC;
    				if ((pInst->lstErrState & ((registerEs & DCAN_ES_LEC))) == 0)
    				{
    					/* first event */
    					pInst->lstErrState |= ((registerEs & DCAN_ES_LEC)); 
    					switch (pInst->hw.lecErr)
    					{
    					case DCAN_LST_ERRCODE_STUFF_ERR:
    						err2ddc(pOut, DDC_ERROR_STUFF);
    						pInst->lecStuff++;
    						break;
    
    					case DCAN_LST_ERRCODE_FORM_ERR:
    						err2ddc(pOut, DDC_ERROR_FORM);
    						pInst->lecForm++;
    						break;
    
    					case DCAN_LST_ERRCODE_ACK_ERR:
    						err2ddc(pOut, DDC_ERROR_ACK);
    						pInst->lecAck++;
    						break;
    
    					case DCAN_LST_ERRCODE_BIT1_ERR:
    						err2ddc(pOut, DDC_ERROR_BIT1);
    						pInst->lecBit1++;
    						break;
    
    					case DCAN_LST_ERRCODE_BIT0_ERR:
    						err2ddc(pOut, DDC_ERROR_BIT0);
    						pInst->lecBit0++;
    						break;
    
    					case DCAN_LST_ERRCODE_CRC_ERR:
    						err2ddc(pOut, DDC_ERROR_CRC);
    						pInst->lecCrc++;
    						break;
    					}
    
    					stat = ERR_OK;
    					work_done = 1;
    				}
    			}
    		if (!work_done)
    		{
    			registerInt = DCANIntRegStatusGet(pInst->hw.base, (DCAN_INT_LINE0_STAT | DCAN_INT_LINE1_STAT) );
    			intid[0] = (registerInt & DCAN_INT_LINE1_STAT) >> 16;
    			intid[1] = (registerInt & DCAN_INT_LINE0_STAT) & 0xFF;
    #if DEBUG
    			if((registerInt >= D_CAN_MSG_OBJ_RX_FIRST) && (registerInt <= D_CAN_MSG_OBJ_RX_LAST))
    				pInst->iRx++;
    			else if((registerInt >= D_CAN_MSG_OBJ_TX_FIRST) && (registerInt <= D_CAN_MSG_OBJ_TX_LAST))
    				pInst->iTx++;
    			else if (registerInt == 0)
    				pInst->iZero++;
    			else
    				pInst->iOx++;
    #endif
    			if (registerInt)
    			{
    				if (intid[0])
    					msgNum = intid[0];
    				else if (intid[1])
    					msgNum = intid[1];
    			}
    			else if (!msgNum && pInst->pollRxMsgNum)
    				msgNum = pInst->pollRxMsgNum;   /* no interrrupt source -> poll receive messages */
    			
    			if (msgNum)
    			{
    				if((msgNum >= D_CAN_MSG_OBJ_RX_FIRST) && (msgNum <= D_CAN_MSG_OBJ_RX_LAST))
    				{
    					/* first handling for RX frames */
    					
    					/* (1) Technical Reference Manual - AM335x ARM� Cortex� 
    					 * Received messages with identifiers matching to a FIFO buffer are stored into a message object 
    					 * of this FIFO buffer, starting with the message object with the lowest message number          
    					 * poll RX messages from RX first, independent from the Interrupt Register value */  
    					for (msgNum = D_CAN_MSG_OBJ_RX_FIRST; msgNum < D_CAN_MSG_OBJ_RX_LAST; msgNum++ )
    					{
    						/* Read a message object from CAN message RAM to Interface register */
    						DCANCommandRegSet(pInst->hw.base, (DCAN_DAT_A_ACCESS | DCAN_DAT_B_ACCESS | 
    													DCAN_TXRQST_ACCESS | DCAN_CLR_INTPND | 
    													DCAN_ACCESS_CTL_BITS | DCAN_ACCESS_ARB_BITS | 
    													DCAN_ACCESS_MSK_BITS | DCAN_MSG_READ), 
    													msgNum, DCAN_IF1_REG);
    
    
    				....
    

     

  • Klaus,

    1. Can you define what exactly happens during this powerfail? Is this an entire board power failure, etc

    2. What happens immediately after this powerfail? Does the board automatically recover and boot up again?

    3. If so, do you see activity on the CAN2 bus when the problem occurs?

    4. Does the bus topology look the same for both CAN1 & CAN2? 

    5. To be clear, when you say you're using TI API are you referring to Linux or starterware API?

    Regards,

    Tyler

  • Hello Tyler,

    We have the problem also, when we restart the target with a software reset.

    We have the same activity on both CAN interfaces.

    The Bus topology is the same on both CAN interfaces. There is only one CAN node on each bus.

    We are using vxWorks as OS.

    In the meantime we have found a workaround for the CAN interface 2 problem. We made some sleeps (ms) in the initialization of the CAN driver beetween the access to the CAN controller registers.

    Regards,

    Klaus

  • Klaus,

    Can you provide the instruction sequence you're using for initialization along with the locations that you placed these delays that resolved the problem?

    -Tyler

  • Hello Tyler,

    We have to init functions, first hwInit() and after hwStart() called by a target restart. See to the attached file.

    regards,

    Klaus

     

     

  • Klaus,

    Are all of the delay loops you inserted in your code required for you to get the correct behavior? Have you tried removing them one at a time to try and narrow down where exactly the delay fixes the issue?

    -Tyler

  • Ok, i will do it next week and will give you an information.

    Thanks,

    klaus

     

     

  • The DCANMsgRAMInit()  API delivered by the "Quick Start Guide Starter Ware 02.00.xx " from Texas Instruments  did not wait for the CONTROL_DCAN_RAMINIT_DCAN0_RAMINIT_DONE bit as documented in Technical Reference Manual AM335x ARM® Cortex.

    23.3.8.1.3 DCAN RAM Hardware Initialization

    The memory hardware initialization for the DCAN module is enabled in the device control register (DCAN_RAMINIT) which initializes the RAM with zeros and sets parity bits accordingly. Wait for the RAMINIT_DONE bit to be set to ensure successful RAM initialization. Ensure the clock to the DCAN module is enabled before starting this initialization...

    /**

    * \brief   This function initializes the DCAN message RAM.

    *

    * \param   instanceNum       The DCAN instance to be used.

    *

    * \return  None.

    *

    */

    void DCANMsgRAMInit(unsigned int instanceNum)

    {

    if(1 == instanceNum)

        {

            HWREG(SOC_CONTROL_REGS + CONTROL_DCAN_RAMINIT) |=

                 CONTROL_DCAN_RAMINIT_DCAN0_RAMINIT_START;

        }

    else

        {

    return;

       }

    }

    Modification:

    void DCANMsgRAMInit(unsigned int instanceNum)

    {

    if(1 == instanceNum)

        {

            HWREG(SOC_CONTROL_REGS + CONTROL_DCAN_RAMINIT) |=

                  CONTROL_DCAN_RAMINIT_DCAN0_RAMINIT_START;

        while(!(HWREG(SOC_CONTROL_REGS + CONTROL_DCAN_RAMINIT) &

                            CONTROL_DCAN_RAMINIT_DCAN0_RAMINIT_DONE));

       }

    else if(2 == instanceNum)

        {

           HWREG(SOC_CONTROL_REGS + CONTROL_DCAN_RAMINIT) |=

                  CONTROL_DCAN_RAMINIT_DCAN1_RAMINIT_START;

        while(!(HWREG(SOC_CONTROL_REGS + CONTROL_DCAN_RAMINIT) &

                        CONTROL_DCAN_RAMINIT_DCAN1_RAMINIT_DONE));

        }

    }

  • Klaus,

    I'm glad you were able to locate the problem and develop a solution. Your modified function looks good to me and I've let the STARTERWARE team know about this bug so that is will be resolved in the next release.

    -Tyler

  • Hello,

    I'm porting the dcanTxRx example on the ICE board, changing from DCAN1 to DCAN0.

    I tried adding the control of the RAMINIT_DONE bit in the DCANMsgRAMInit, as requested by the TRM, but the cycle loops endless and the bit is never set. 

    All the initializiations have been done following the example.

    What could be wrong?

    Best Regards.

        Gianpiero

  • Hello Gianpiero,

    With our target it works how it is documented in the Technical Reference Manual AM335x ARM® Cortex. But i hope we get more informations from the STARTERWARE team, which was informed by Tyler

    Best regards

    Klaus

     

     

     

  • To everyone who are interested in.

    The problem was related to the fact that the ARM was set in user mode by the initialization of the compiler (_c_int00). That prevented the application from changing the value of the dcan_raminit register. In order to change this register, the Arm has to be set in privileged mode.

    Using the dcanTxRx.cmd linker command file solved the problem.

    Best regards.

         Gianpiero

    P.S.

    Of course, it was not uartTxRx but dcanTxRx.

    Gianpiero Lamborghini said:

    Hello,

    I'm porting the UartTxRx example on the ICE board, changing from DCAN1 to DCAN0.

    I tried adding the control of the RAMINIT_DONE bit in the DCANMsgRAMInit, as requested by the TRM, but the cycle loops endless and the bit is never set. 

    All the initializiations have been done following the example.

    What could be wrong?

    Best Regards.

        Gianpiero