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.

CCS/TMS320F28377S: DCAN module. Code example about mask and fifo use.

Part Number: TMS320F28377S
Other Parts Discussed in Thread: TMS320F28234, C2000WARE

Tool/software: Code Composer Studio

Hi,

I'm trying to adapt a CanOpen stack that works on DSP TMS320F28234 with ecan module on the new TMS320F28377S with the DCAN module.

I'm write some basic code to interface the stack with the new device but I have a lot of problem to undestand how to setup a fifo in the receive mailbox and also how to setup the mask bit in order to hardware filter a specific device.

The following is the code that I use to set DCAN, manage Msg Interrupt and Status Interrupt:

/* values defined for 20 Mhz */
DWORD CONST tCCanSpeed[9] = {
	10000,      /*  10K bit/s,*/
	20000,      /*  20K bit/s */
	50000,      /*  50K bit/s */
	100000,     /* 100K bit/s */
	125000,     /* 125K bit/s */
	250000,     /* 250K bit/s */
	500000,     /* 500K bit/s */
	800000,     /* 800K bit/s */
	1000000     /*   1M bit/s */
};

/*--------------------------------------------------------------------*/
/*  private data                                                      */
/*--------------------------------------------------------------------*/

CAN_MSG stCanMsgBuffer;     /*!< local buffer to store one CAN message */

STATIC unsigned char ucBufferIn[8];
STATIC tCANMsgObject sMsgObjectRx;

/*--------------------------------------------------------------------*/
/*  private functions                                                 */
/*--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*/
/*  public functions                                                  */
/*--------------------------------------------------------------------*/

/*!
  Initialize the CAN controller.
  Esegue l'inizializzazione del modulo CAN e resetta tutti i messaggi

  \param bIndex selects the bit timing
*/
void gCan_CntrlInit(BYTE bIndex)
{
	BYTE i;                                                                                // Counter per scorrere i buffer da 3 a 32

	EALLOW;            /* disable protection */

	// Initializes the CAN controller after reset.
	//
	// \param ui32Base is the base address of the CAN controller.
	//
	// After reset, the CAN controller is left in the disabled state.  However,
	// the memory used for message objects contains undefined values and must be
	// cleared prior to enabling the CAN controller the first time.  This prevents
	// unwanted transmission or reception of data before the message objects are
	// configured.  This function must be called before enabling the controller
	// the first time.
	CANInit(CAN_BASIC_ADR);                                                // Initialize the CAN controller

	// Inizializza la sorgente del clock modulo CAN dal clock esterno a 20MHz
	CANClkSourceSelect(CAN_BASIC_ADR, CAN_CLK_EXT_OSC);                    // Setup CAN to be clocked by X1,X2 clock (20MHz)

	/* set baud rate */
	// Set up the bit rate for the CAN bus.  This function sets up the CAN
	// bus timing for a nominal configuration.  You can achieve more control
	// over the CAN bus timing by using the function CANBitTimingSet() instead
	// of this one, if needed.
	// In this example, the CAN bus is set to 500 kHz.  In the function below,
	// the call to SysCtlClockGet() is used to determine the clock rate that
	// is used for clocking the CAN peripheral.  This can be replaced with a
	// fixed value if you know the value of the system clock, saving the extra
	// function call.  For some parts, the CAN peripheral is clocked by a fixed
	// 8 MHz regardless of the system clock in which case the call to
	// SysCtlClockGet() should be replaced with 8000000.  Consult the data
	// sheet for more information about CAN peripheral clocking.
	CANBitRateSet(CAN_BASIC_ADR, 20000000, tCCanSpeed[bIndex]);

	// Initialize messages mailbox
	// Messages 1 -> 16 receive
	// Messages 29-30-31-32 transmit
	// Set RX message buffers
	for (i = 1; i <= 15; i++)
	{
		/* identifier zero, set AME */
		sMsgObjectRx.ui32MsgID = 0;                                                // CAN message ID - use 0

		sMsgObjectRx.ui32Flags =  MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER | MSG_OBJ_FIFO;            // enable mask and rx interrupt and FIFO

		sMsgObjectRx.ui32MsgLen = 8;

		*(unsigned long *)ucBufferIn = 0;
		sMsgObjectRx.pucMsgData = ucBufferIn;                                      // ptr to message content

		sMsgObjectRx.ui32MsgIDMask = 0x00000000UL;
		CANMessageSet(CAN_BASIC_ADR, i, &sMsgObjectRx, MSG_OBJ_TYPE_RX);
	} /* for */

	// Initialize message 16 as FIFO end
	sMsgObjectRx.ui32MsgID = 0;                                                // CAN message ID - use 0

	sMsgObjectRx.ui32Flags =  MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER;   // enable mask and rx interrupt and END FIFO

	sMsgObjectRx.ui32MsgLen = 8;

	*(unsigned long *)ucBufferIn = 0;
	sMsgObjectRx.pucMsgData = ucBufferIn;                                      // ptr to message content

	sMsgObjectRx.ui32MsgIDMask = 0x00000000UL;
	CANMessageSet(CAN_BASIC_ADR, 16, &sMsgObjectRx, MSG_OBJ_TYPE_RX);

	/* enable status interrupts on interrupt line 0 */
	/* enable message interrupts on interrupt line 1 */
	/* for bus-off, error passiv and warning level  */
	CANIntEnable(CAN_BASIC_ADR, CAN_INT_IE1 | CAN_INT_ERROR | CAN_INT_IE0);       // Interrupt line 1 enable, Status interrupt enable, Error interrupt enable, Interrupt line 0 enable

	/* connect message buffer interrupts to line 1 */
	HWREG(CAN_BASIC_ADR + CAN_O_IP_MUX21) = 0xFFFFFFFF;                            // Tutti gli interrupt delle mailbox su INT1

	/* enable message buffer interrupts */
	CANGlobalIntEnable(CAN_BASIC_ADR, CAN_GLB_INT_CANINT1 | CAN_GLB_INT_CANINT0);  // Global interrupt 0 and 1 enable

	EDIS;              /* enable protection */
}

/*!
  Put a CAN message on the bus.
  \param ptMsg pointer to buffer
  \return NO_ERR transmission in progress,
		  WAIT_ERR no transmission cause of inhibit time,
		  BUSY_ERR no transmission cause of other transmission in progress
*/
BYTE gCan_SendMsg(CAN_MSG MEM_AREA *ptMsg)
{
	BYTE  ReturnCode = NO_ERR;

	unsigned long ulStatus;
	tCANMsgObject sMsgObjectTx;
	tMsgObjType   MsgType;
	unsigned char ucBufferOut[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

	if(ptMsg == 0)
	{
		ReturnCode = NO_ERR;
	} // if
	else
	{
		sMsgObjectTx.ui32Flags = MSG_OBJ_TX_INT_ENABLE;

		// copy message data bytes
		ucBufferOut[0] = ptMsg->bDb[0];
		ucBufferOut[1] = ptMsg->bDb[1];
		ucBufferOut[2] = ptMsg->bDb[2];
		ucBufferOut[3] = ptMsg->bDb[3];
		ucBufferOut[4] = ptMsg->bDb[4];
		ucBufferOut[5] = ptMsg->bDb[5];
		ucBufferOut[6] = ptMsg->bDb[6];
		ucBufferOut[7] = ptMsg->bDb[7];

		sMsgObjectTx.ui32MsgID = ptMsg->qbId.dw;                       // CAN message COB-ID
		sMsgObjectTx.ui32MsgIDMask = 0;                                // no mask needed for TX
		sMsgObjectTx.ui32MsgLen = ptMsg->Dlc;                          // set DLC and RTR flag
		sMsgObjectTx.pucMsgData = ucBufferOut;                         // ptr to message content
		if(ptMsg->Rtr)
		{
			sMsgObjectTx.ui32Flags |= MSG_OBJ_REMOTE_FRAME;            // Set remote frame
			MsgType = MSG_OBJ_TYPE_TX_REMOTE;                          // Set Msg Type
		}
		else
			MsgType = MSG_OBJ_TYPE_TX;                                 // Set Msg Type

		// Read the controller TX status.
		ulStatus = CANStatusGet(CAN_BASIC_ADR, CAN_STS_TXREQUEST);

		if((ulStatus & 0x80000000UL) == 0)
		{
			// Send using Object 32
			// Il messaggio viene configurato e messo in trasmissione dalla funzione CANMessageSet()
			CANMessageSet(CAN_BASIC_ADR, 32, &sMsgObjectTx, MsgType);  // Send message on bus using Object 32
		}
		else if((ulStatus & 0x40000000UL) == 0)
		{
			// Send using Object 31
			// Il messaggio viene configurato e messo in trasmissione dalla funzione CANMessageSet()
			CANMessageSet(CAN_BASIC_ADR, 31, &sMsgObjectTx, MsgType);  // Send message on bus using Object 31
		}
		else if((ulStatus & 0x20000000UL) == 0)
		{
			// Send using Object 30
			// Il messaggio viene configurato e messo in trasmissione dalla funzione CANMessageSet()
			CANMessageSet(CAN_BASIC_ADR, 30, &sMsgObjectTx, MsgType);  // Send message on bus using Object 30
		}
		else if((ulStatus & 0x10000000UL) == 0)
		{
			// Send using Object 29
			// Il messaggio viene configurato e messo in trasmissione dalla funzione CANMessageSet()
			CANMessageSet(CAN_BASIC_ADR, 29, &sMsgObjectTx, MsgType);  // Send message on bus using Object 29
		}
		else
		{
			ReturnCode = BUSY_ERR;                                     // OUT: busy error
		}
	}

	return ReturnCode;                                                 // OUT: ReturnCode
}

/*!
  \brief CAN message buffer ISR.

  The CAN receive/transmit interrupt service routine.

  This function is connected to DCAN interrupt 1
*/
__interrupt void gCan_MsgIntHandler(void)
{
	BYTE bBNr;                                 	/* message buffer number */
#if ID_FILTER != 0
	WORD wId;                                  	/* received identifier */
#endif											/* ID_FILTER */

	unsigned long ulCanINT;
	unsigned long ulCanES;
	unsigned long ulCanNDAT_21;
	unsigned long ulCanIPEN_21;

	// Set interrupt priority:
	volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
	IER |= M_INT9;
	IER	&= MINT9;                           // Set "global" priority
	PieCtrlRegs.PIEIER9.all &= MG9_6;       // Set "group"  priority
	PieCtrlRegs.PIEACK.all = 0xFFFF;        // Enable PIE interrupts
	__asm("  NOP");
	EINT;

	// Debug interrupt counter
	IrqMsgRicevuti++;

	// Read the CAN interrupt status to find the cause of the interrupt
	ulCanINT = CANIntStatus(CAN_BASIC_ADR, CAN_INT_STS_CAUSE);
	ulCanINT = (ulCanINT >> 16) & 0xFFFF;

	while (ulCanINT)
	{
		// Read the controller status.  This will return a field of status
		// error bits that can indicate various errors.  Error processing
		// is not done in this example for simplicity.  Refer to the
		// API documentation for details about the error status bits.
		// The act of reading this status will clear the interrupt.  If the
		// CAN peripheral is not connected to a CAN bus with other CAN devices
		// present, then errors will occur and will be indicated in the
		// controller status.
		ulCanES = CANStatusGet(CAN_BASIC_ADR, CAN_STS_CONTROL);
		ulCanES = ulCanES;

		// Read New Datas bits
		ulCanNDAT_21 = CANStatusGet(CAN_BASIC_ADR, CAN_STS_NEWDAT);
		// Read Interrupt pending bits
		ulCanIPEN_21 = CANStatusGet(CAN_BASIC_ADR, CAN_STS_IPEN);
	
		for (bBNr = 1; (bBNr <= 32) && (ulCanIPEN_21 != 0); bBNr++)
		{
			if(ulCanIPEN_21 & 0x0001L)            	// If interrupt pending
			{
				if(bBNr >= 29)                   	// Transmit interrupt ?
				{
					// Transmit interrupt - last transmission successful
					bFirstMsgTrans = TRUE;
					bCanStatus |= CAN_STS_TX_OK;

					// Clear the message object interrupt.
					CANIntClear(CAN_BASIC_ADR, bBNr);

					// Debug: increase sended messages counter 
					Rcantx++;
				}
				else if(ulCanNDAT_21 & 0x0001L)   	// Receive interrupt ?
				{
					// Get the received message and clear interrutp pending flag
					CANMessageGet(CAN_BASIC_ADR, bBNr, &sMsgObjectRx, true);
					// Clear the message object interrupt.
					CANIntClear(CAN_BASIC_ADR, bBNr);

					// N.B. This do-while cycle is only used to jump at end with "continue" instruction
					//      Is executed only 1 time because the while argument is "false"
					do
					{
#if ID_FILTER != 0
						// 29 bit identifier not allowed
						if(sMsgObjectRx.ui32Flags & MSG_OBJ_EXTENDED_ID)
						{
							// release receive buffer
							continue;
						} // if

						// get identifier
						wId = (WORD)(sMsgObjectRx.ui32MsgID & 0x07FF);

						// check identifier
						if(gCB_PreCheckIdStd(wId) == FALSE)
						{
							// release receive buffer
							continue;
						} // if

						// standard frame received
						stCanMsgBuffer.Ext = 0;

						// copy COB ID
						stCanMsgBuffer.qbId.dw = wId;
#else
						// Check 29 bit identifier
						if(sMsgObjectRx.ui32Flags & MSG_OBJ_EXTENDED_ID)
						{
							// Extended frame received
							stCanMsgBuffer.Ext = 1;
							// get COB ID
							//stCanMsgBuffer.qbId.dw = ReadDword(CAN_MID + CAN_TX_BUF
							//                                   + bBNr * CAN_MSG_OFFSET
							//                                   + CAN_BASIC_ADR) & 0x1FFFFFFFUL;
							stCanMsgBuffer.qbId.dw = (sMsgObjectRx.ui32MsgID & 0x1FFFFFFFUL);
						} // if
						else
						{
							// Standard frame received
							stCanMsgBuffer.Ext = 0;
							// Get COB ID
							stCanMsgBuffer.qbId.dw = (sMsgObjectRx.ui32MsgID & 0x07FF);
						} // else
#endif // ID_FILTER

						// Get RTR
						stCanMsgBuffer.Rtr = ((sMsgObjectRx.ui32Flags & MSG_OBJ_REMOTE_FRAME) ? 1 : 0);

						// Get DLC
						stCanMsgBuffer.Dlc = (BYTE)(sMsgObjectRx.ui32MsgLen & 0x0F);

						// Check DLC
						if(stCanMsgBuffer.Dlc > 8)
						{
							stCanMsgBuffer.Dlc = 8;
						} // if

						// copy message data bytes
						stCanMsgBuffer.bDb[0] = sMsgObjectRx.pucMsgData[0];
						stCanMsgBuffer.bDb[1] = sMsgObjectRx.pucMsgData[1];
						stCanMsgBuffer.bDb[2] = sMsgObjectRx.pucMsgData[2];
						stCanMsgBuffer.bDb[3] = sMsgObjectRx.pucMsgData[3];
						stCanMsgBuffer.bDb[4] = sMsgObjectRx.pucMsgData[4];
						stCanMsgBuffer.bDb[5] = sMsgObjectRx.pucMsgData[5];
						stCanMsgBuffer.bDb[6] = sMsgObjectRx.pucMsgData[6];
						stCanMsgBuffer.bDb[7] = sMsgObjectRx.pucMsgData[7];

						if(sMsgObjectRx.ui32Flags & MSG_OBJ_DATA_LOST)
						{
							// release receive buffer
							// Set EMCY overrun flag
							fEmcyOverrun = TRUE;
							continue;
						} // if

						// put message to storage location
						gCB_CanBufferMsg(&stCanMsgBuffer);

					} while (0);    // Do while
				}
				else               // Spurious interrupt
				{
					// Spurious interrupt handling can go here.
					CANIntClear(CAN_BASIC_ADR, CAN_INT_INT0ID_STATUS);
				}  // if
			}  // if

			ulCanNDAT_21 >>= 1;
			ulCanIPEN_21 >>= 1;
		} // for
	
		// Read the CAN interrupt status to find the cause of the interrupt
		ulCanINT = CANIntStatus(CAN_BASIC_ADR, CAN_INT_STS_CAUSE);
		ulCanINT = (ulCanINT >> 16) & 0xFFFF;
	}

	DINT;

	CANGlobalIntClear(CANA_BASE, CAN_GLB_INT_CANINT1);

	PieCtrlRegs.PIEIER9.all = TempPIEIER;
}

/*!
  \brief CAN error ISR.

  The CAN error interrupt service routine.

  This function is connected to DCAN interrupt 0
*/
__interrupt void gCan_SysIntHandler(void)
{
	unsigned long ulCanINT;
	unsigned long ulCanES;

	// Set interrupt priority:
	volatile Uint16 TempPIEIER = PieCtrlRegs.PIEIER9.all;
	IER |= M_INT9;
	IER	&= MINT9;                       // Set "global" priority
	PieCtrlRegs.PIEIER9.all &= MG9_5;   // Set "group"  priority
	PieCtrlRegs.PIEACK.all = 0xFFFF;    // Enable PIE interrupts
	__asm("  NOP");
	EINT;

	// Debug interrupt counter
	IrqSysRicevuti++;

	// Read the CAN interrupt status to find the cause of the interrupt
	ulCanINT = CANIntStatus(CAN_BASIC_ADR, CAN_INT_STS_CAUSE);
	ulCanINT = ulCanINT;

	// Read the controller status.  This will return a field of status
	// error bits that can indicate various errors.  Error processing
	// is not done in this example for simplicity.  Refer to the
	// API documentation for details about the error status bits.
	// The act of reading this status will clear the interrupt.  If the
	// CAN peripheral is not connected to a CAN bus with other CAN devices
	// present, then errors will occur and will be indicated in the
	// controller status.
	ulCanES  = CANStatusGet(CAN_BASIC_ADR, CAN_STS_CONTROL);

	if(ulCanES & CAN_STATUS_EWARN)
	{
		// warning level interrupt
		bCanStatus |= CAN_STS_WARNING;
		// no bus-off detected
		bCanStatus &= ~CAN_STS_BUS_OFF;
	} // if

	if(ulCanES & CAN_STATUS_EPASS)
	{
		// warning level interrupt
		bCanStatus |= CAN_STS_WARNING;
		// no bus-off detected
		bCanStatus &= ~CAN_STS_BUS_OFF;
	} // if

	if(ulCanES & CAN_STATUS_BUS_OFF)
	{
		// bus-off interrupt
		bCanStatus |= CAN_STS_BUS_OFF;
		// leave warning level
		bCanStatus &= ~CAN_STS_WARNING;
	} // If

	// Increase CAN error counter
	Rcanerr++;

	DINT;
	CANGlobalIntClear(CANA_BASE, CAN_GLB_INT_CANINT0);

	PieCtrlRegs.PIEIER9.all = TempPIEIER;
}

--------
My problems are the follow:
1) Fifo doesn't work as I expected: all messages are stored in the first mailbox and if the interrupt code doesn't read data in short time, an overrun error is generated.
2) Mask doesn't work as I expected: if I don't put the MSG_OBJ_USE_ID_FILTER switch in the sMsgObjectRx.ui32Flags no messages are received by DCAN. I have to put the MSG_OBJ_USE_ID_FILTER and set the mask
to 0x00000000 to be able to receive messages from the bus.
3) If I want to hardware filter the CanOpen objects NMT=0x00, SYNC=0x80, EMCY=0x81, RxPDO1=0x181, TxPDO1=0x201, RxPDO2=0x281, TxPDO2=0x301, RxPDO3=0x381, TxPDO3=0x401,
RxPDO4=0x481, TxPDO4=0x501, TxSDO=0x581, RxPDO=0x601, NMTerr=0x701, I don't understand why but the RxPDO=0x601 isn't received at all.

Is there someone that can help me and say if the code that I'm using has any bug, expecially in the rx fifo setup, and where I can find any example of code other that the very little example that I found in the
F2837xS_examples_Cpu1 directory?

Last but not least, why I can't see the CAN registers value using CodeComposerStudio 8.3?
Values displayed into the DCAN registers windows is not a valid value.

Thank you for your attention
Regards

Giuseppe