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