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