本篇文章主要介绍CAN driver和xcp的交互。 1.首先是对XCP使用ID进行初始化(在main函数)
XCPCANInit(0x200,0x300,0x301,0x302,0x303);函数原型如下:
void XCPCANInit (uint16 cro_id, uint16 dto_id, uint16 daq0_id, uint16 daq1_id, uint16 daq2_id) { uint8_t i; CAN_C.MCR.R = 0x5000003F; // Put in Freeze Mode & enable all 32 message buffers CAN_C.CR.R = 0x01c90002;//0x01920004; // 500K&12M OSC for Monaco EVB // CAN_C.CR.B.LPB = 1; // Loopback mode for test ... for (i=0; i<32; i++) { // MPC563x: init 32 message buffers CAN_C.BUF[i].CS.B.CODE = 0; // Inactivate all message buffers } CAN_C.BUF[CRO_BUF_N].CS.B.IDE = 0; // MB0 will look for a standard ID CAN_C.BUF[CRO_BUF_N].ID.B.STD_ID = cro_id; // MB0 will be used as CRO CAN_C.BUF[CRO_BUF_N].CS.B.CODE = 4; // MB0 set to RX EMPTY CAN_C.BUF[DTO_BUF_N].CS.B.CODE = 8; // MB1 served for CTO, set to TX INACTIVE CAN_C.BUF[DTO_BUF_N].CS.B.IDE = 0; CAN_C.BUF[DTO_BUF_N].ID.B.STD_ID = dto_id; // MB1 will be used as CTO CAN_C.BUF[DTO_BUF_N].CS.B.RTR = 0; // Data frame, not remote Tx request frame CAN_C.BUF[DTO_BUF_N].CS.B.LENGTH = 8; CAN_C.BUF[DAQ0_BUF_N].CS.B.CODE = 8; CAN_C.BUF[DAQ0_BUF_N].CS.B.IDE = 0; CAN_C.BUF[DAQ0_BUF_N].ID.B.STD_ID = daq0_id; // MB2 will be used as CTO CAN_C.BUF[DAQ0_BUF_N].CS.B.RTR = 0; // Data frame, not remote Tx request frame CAN_C.BUF[DAQ0_BUF_N].CS.B.LENGTH = 8; CAN_C.BUF[DAQ1_BUF_N].CS.B.CODE = 8; CAN_C.BUF[DAQ1_BUF_N].CS.B.IDE = 0; CAN_C.BUF[DAQ1_BUF_N].ID.B.STD_ID = daq1_id; // MB3 will be used as CTO CAN_C.BUF[DAQ1_BUF_N].CS.B.RTR = 0; // Data frame, not remote Tx request frame CAN_C.BUF[DAQ1_BUF_N].CS.B.LENGTH = 8; CAN_C.BUF[DAQ2_BUF_N].CS.B.CODE = 8; CAN_C.BUF[DAQ2_BUF_N].CS.B.IDE = 0; CAN_C.BUF[DAQ2_BUF_N].ID.B.STD_ID = daq2_id; // MB4 will be used as CTO CAN_C.BUF[DAQ2_BUF_N].CS.B.RTR = 0; // Data frame, not remote Tx request frame CAN_C.BUF[DAQ2_BUF_N].CS.B.LENGTH = 8; CAN_C.BUF[BOOTLOADER_BUF_RX_N].CS.B.IDE = 0; CAN_C.BUF[BOOTLOADER_BUF_RX_N].ID.B.STD_ID = BOOTLOADER_DN_ID; CAN_C.BUF[BOOTLOADER_BUF_RX_N].CS.B.CODE = 4; //CAN_C.BUF[BOOTLOADER_BUF_RX_N].CS.B.RTR = 0; // Data frame, not remote Tx request frame //CAN_C.BUF[BOOTLOADER_BUF_RX_N].CS.B.LENGTH = 8; //CAN_C.BUF[BOOTLOADER_BUF_TX_N].CS.B.CODE = 8; //CAN_C.BUF[BOOTLOADER_BUF_TX_N].CS.B.IDE = 0; //CAN_C.BUF[BOOTLOADER_BUF_TX_N].ID.B.STD_ID = BOOTLOADER_DN_ID; // MB4 will be used as CTO //CAN_C.BUF[BOOTLOADER_BUF_TX_N].CS.B.RTR = 0; // Data frame, not remote Tx request frame //CAN_C.BUF[BOOTLOADER_BUF_TX_N].CS.B.LENGTH = 8; CAN_C.RXGMASK.R = 0x1FFFFFFF; // Global acceptance mask CAN_C.IMRL.B.BUF00M = 1; // Enable MB0 interrupt; CAN_C.IMRL.B.BUF01M = 1; // Enable MB1 interrupt; CAN_C.IMRL.B.BUF02M = 1; // Enable MB2 interrupt; CAN_C.IMRL.B.BUF03M = 1; // Enable MB3 interrupt; CAN_C.IMRL.B.BUF04M = 1; // Enable MB4 interrupt; CAN_C.IMRL.B.BUF05M = 1; // Enable MB4 interrupt; INTC_InstallINTCInterruptHandler(CanBuf5ISR, 181, 10); INTC_InstallINTCInterruptHandler(CanBuf4ISR, 180, 10); INTC_InstallINTCInterruptHandler(CanBuf3ISR, 179, 10); INTC_InstallINTCInterruptHandler(CanBuf2ISR, 178, 10); INTC_InstallINTCInterruptHandler(CanBuf1ISR, 177, 10); INTC_InstallINTCInterruptHandler(CanBuf0ISR, 176, 10); SIU.PCR[87].R = 0x0E20; // MPC565x: Configure pad as CNTXC, open drain SIU.PCR[88].R = 0x0D00; // MPC565x: Configure pad as CNRXC CAN_C.MCR.R = 0x0000003F; // Negate FlexCAN C halt state for 32 MB }2.CAN发送函数(XCP调用)
void XCP_FN_TYPE XcpCan_DoTransmit( uint sessionId, uint channelId ) { XcpCan_SessionCfg_t* const pSessionCfg = XcpCan_SessionCfgs + sessionId; XcpCan_ChannelCfg_t* const pChannelCfg = pSessionCfg->pChannelCfgs + channelId; Xcp_StatePtr32 const pCanPos = &( pSessionCfg->pQueuePositions[ channelId ].ctCanPos ); XcpCan_QueueBuf_t* const pQueueBuffer = pSessionCfg->pQueueBuffers + *pCanPos; Xcp_StatePtr8 const pQueueBufState = pSessionCfg->pQueueBufferStates + *pCanPos; uint8 *pdat; uint8 i; /* Find the CAN msg ID which has been configured for the specified channel. This is not entirely straightforward, * since the msg ID of a dynamic DAQ list can be set at runtime. * * We assume that a DAQ CAN channel index can be translated to the equivalent DAQ list ID by subtracting XCP_FIRST_DAQ_CHANNEL. */ uint32 configuredMsgId = pChannelCfg->msgId; #ifdef XCP_ENABLE_DYNDAQ if( channelId >= XCP_FIRST_DAQ_CHANNEL && Xcp_SessionConfigs[ sessionId ].maxDynDaqLists > 0 && pSessionCfg->pDynDaqMsgIds[ channelId - XCP_FIRST_DAQ_CHANNEL ] != XCPCAN_INVALID_MSGID ) { /* The current channel is associated with a dynamic DAQ list, and the list has a msg ID which was configured * at runtime. */ configuredMsgId = pSessionCfg->pDynDaqMsgIds[ channelId - XCP_FIRST_DAQ_CHANNEL ]; } #endif /* XCP_ENABLE_DYNDAQ */ /* Note that the CAN DLC is encoded in the top nibble of bufferState. */ //for(i=0; i< 8; i++) //{ //can_data[i] = (uint8 *)pQueueBuffer->msgBuffer++; //} //pdat = (Xcp_StatePtr8)pQueueBuffer->msgBuffer; XcpApp_CanTransmit( pChannelCfg->msgObjId, configuredMsgId, (*pQueueBufState) >> 4, (Xcp_StatePtr8)pQueueBuffer->msgBuffer ); /* Clear the queue buffer associated with the transmitted message. */ pQueueBuffer->msgBuffer[0] = 0; pQueueBuffer->msgBuffer[1] = 0; /* Set buffer to free */ *pQueueBufState = XCP_TXRXFREE; /* Advance the current CAN buffer in the queue for the channel, wrapping if necessary. */ if( *pCanPos != pChannelCfg->idxEnd ) { ++( *pCanPos ); } else { *pCanPos = pChannelCfg->idxStart; } }里边调用 XcpApp_CanTransmit 函数
void XcpApp_CanTransmit( XcpCan_MsgObjId_t msgObjId, uint32 msgId, uint numBytes, Xcp_StatePtr8 pBytes ) { uint8 cnt; uint8 BufN; uint8 *msg; uint16 TxID; uint8 length; uint8_t i,j; BufN = (uint8)msgObjId; TxID = (uint16)msgId; length = numBytes; if (XcpTransCrmPossible(BufN)) { CAN_C.BUF[BufN].CS.B.IDE = 0; // Use standard ID length CAN_C.BUF[BufN].CS.B.RTR = 0; // Data frame, not remote Tx request frame CAN_C.BUF[BufN].CS.B.LENGTH = numBytes; CAN_C.BUF[BufN].ID.B.STD_ID = TxID; // Transmit ID msg = pBytes; for(i=0;i<8;i++) { dat[i] = *msg++; } for (cnt=0,j=0;cnt<8;cnt++,j++) { CAN_C.BUF[BufN].DATA.B[cnt] = dat[j];//*pBytes++; //*msg++; } CAN_C.BUF[BufN].CS.B.SRR = 1; // Tx frame (not req'd for standard frame) CAN_C.BUF[BufN].CS.B.CODE =0xC; // Activate msg. buf. to transmit data frame } } 注意:此处根据芯片不同写不同的candriver3.CAN接收函数(XCP调用)
static void CanBuf0ISR(void) { uint32 dummy; uint8 cnt; RxCode = CAN_C.BUF[CRO_BUF_N].CS.B.CODE; // Read CODE, ID, LENGTH, DATA, TIMESTAMP Rec_Id = CAN_C.BUF[CRO_BUF_N].ID.B.STD_ID; length=(uint8)CAN_C.BUF[CRO_BUF_N].CS.B.LENGTH; for (cnt=0; cnt<8; cnt++) { tmpRevData[cnt] = CAN_C.BUF[CRO_BUF_N].DATA.B[cnt]; } dummy = CAN_C.BUF[CRO_BUF_N].CS.B.TIMESTAMP; dummy = CAN_C.TIMER.R; // Read TIMER to unlock message buffers CAN_C.IFRL.B.BUF00I = 1; // clear interrupt XcpCan_RxCallback(Rec_Id, length, (uint8*)&tmpRevData[0]); }CAN中断根据不同的底层来匹配,通过 XcpCan_RxCallback(Rec_Id, length, (uint8*)&tmpRevData[0])函数和协议有所交互. 具体函数如下
void XCP_FN_TYPE XcpCan_RxCallback( uint32 msgId, uint8 msgLen, uint8* pMsgData ) { Xcp_StatePtr32 pCtCanPos; uint channelId; uint sessionId; XcpCan_SessionCfg_t* pSessionCfg = XcpCan_SessionCfgs; Xcp_StatePtr8 pQueueBufState; #ifdef XCP_ENABLE_STIM uint pidOffEnabled; uint32 configuredMsgId; XcpCan_ChannelCfg_t* pChannelCfg; Xcp_DaqConfig_t* pDaqCfg; Xcp_Daq_t* pDaqState; #endif /* XCP_ENABLE_STIM */ /* Search all CAN channels for all sessions to try to identify the CAN channel to which the RX message belongs. */ for( sessionId = 0; sessionId < XCP_NUM_SESSIONS; ++sessionId ) { /* Is the CAN message is a broadcast CMD_GET_SLAVE_ID? */ if( msgId == pSessionCfg->broadcastMsgId && pMsgData[0] == XCP_CMD_TRANSPORT_LAYER_CMD && pMsgData[1] == XCPCAN_CMD_GET_SLAVE_ID ) { channelId = XCP_RX_CMD_CHANNEL; break; } /* Is the CAN message a command? Note that it is not sufficient just to check the message's PID since the message * could be: * - a command message destined for another session; * - a PID_OFF STIM message, with no valid PID. */ else if( pMsgData[0] >= XCP_PID_CMD_LAST && msgId == pSessionCfg->pChannelCfgs[ XCP_RX_CMD_CHANNEL ].msgId ) { /* The CAN message belongs to the XCP_RX_CMD_CHANNEL channel. */ channelId = XCP_RX_CMD_CHANNEL; break; } #ifdef XCP_ENABLE_STIM else { /* The CAN message does not contain a command, therefore it must contain a STIM DTO packet. * We search the CAN channels associated with STIM lists to find the channel to which the RX message belongs. * * Throughout, we assume that: * - A CAN channel index can be translated to the equivalent DAQ list ID by subtracting XCP_FIRST_DAQ_CHANNEL. * - The first STIM CAN channel has index XcpCan_SessionCfg_t::firstRxStimChannel. * - The last STIM CAN channel has index XcpCan_SessionCfg_t::numChannels - 1. */ channelId = pSessionCfg->firstRxStimChannel; pChannelCfg = pSessionCfg->pChannelCfgs + channelId; pDaqState = Xcp_SessionConfigs[ sessionId ].pDaqStates + channelId - XCP_FIRST_DAQ_CHANNEL; pDaqCfg = Xcp_SessionConfigs[ sessionId ].pDaqConfigs + channelId - XCP_FIRST_DAQ_CHANNEL; for( ; channelId < pSessionCfg->numChannels; ++channelId ) { /* Skip the current channel if it corresponds to a DAQ list which is not running or is not a STIM list. */ if( ( XCP_DAQLISTMODE_RUNNING | XCP_DAQLISTMODE_DIRECTION ) != ( pDaqState->daqListMode & ( XCP_DAQLISTMODE_RUNNING | XCP_DAQLISTMODE_DIRECTION ) ) ) { ++pChannelCfg; ++pDaqState; ++pDaqCfg; continue; } /* Find the CAN msg ID which has been configured for the current channel. This is not entirely straightforward, * since the msg ID of a dynamic DAQ list can be set at runtime.*/ configuredMsgId = pChannelCfg->msgId; #ifdef XCP_ENABLE_DYNDAQ if( pSessionCfg->pDynDaqMsgIds && pSessionCfg->pDynDaqMsgIds[ channelId - XCP_FIRST_DAQ_CHANNEL ] != XCPCAN_INVALID_MSGID ) { /* The current channel is associated with a dynamic DAQ list, and the list has a msg ID which was configured * at runtime. */ configuredMsgId = pSessionCfg->pDynDaqMsgIds[ channelId - XCP_FIRST_DAQ_CHANNEL ]; } #endif /* XCP_ENABLE_DYNDAQ */ if( configuredMsgId == msgId ) { /* We have found a CAN channel which shares the same message ID as the RX message. * If: * - the current channel is associated with a DAQ list configured for PID_OFF mode, or * - the current channel is not associated with a DAQ list configured for PID_OFF mode, and * the PID of the RX message is within the PID range of the DAQ list associated with the * current channel, * then the RX message belongs to the current channel.*/ pidOffEnabled = pDaqState->daqListMode & XCP_DAQLISTMODE_PIDOFF; if( pidOffEnabled || ( !pidOffEnabled && pMsgData[0] >= pDaqCfg->firstPid && pMsgData[0] < ( pDaqCfg->firstPid + pDaqCfg->numOdt ) ) ) { /* The CAN message belongs to the current STIM channel. */ break; } } ++pChannelCfg; ++pDaqState; ++pDaqCfg; } if( channelId < pSessionCfg->numChannels ) { /* The inner loop successfully identified the STIM channel which is associated with the RX message. */ break; } } #endif /* XCP_ENABLE_STIM */ ++pSessionCfg; } if(sessionId == XCP_NUM_SESSIONS ) { /* The RX message is not associated with any of our CAN channels. */ return; } pSessionCfg = XcpCan_SessionCfgs + sessionId; pCtCanPos = &( pSessionCfg->pQueuePositions[ channelId ].ctCanPos ); pQueueBufState = pSessionCfg->pQueueBufferStates + *pCtCanPos; /* Copy the received message to the current CAN buffer for the channel, if the current CAN buffer is free. */ if( *pQueueBufState == XCP_TXRXFREE ) { /* We could just copy msgLen bytes of data into the current CAN buffer for the channel, but we take advantage of the * following facts to copy the data in a multiple of whichever block size the current target finds most convenient: * - msgLen is <= 8 * - the buffer has 8 bytes of space; * - the buffer is aligned on a natural boundary. */ if( msgLen % XCP_MEM_BLOCK_SIZE ) { /* Round msgLen up to the next multiple of XCP_MEM_BLOCK_SIZE. */ msgLen += XCP_MEM_BLOCK_SIZE - ( msgLen % XCP_MEM_BLOCK_SIZE ); } /* msgLen is now guaranteed to be a multiple of XCP_MEM_BLOCK_SIZE. */ Xcp_MemCopy( (Xcp_StatePtr8)pSessionCfg->pQueueBuffers[ *pCtCanPos ].msgBuffer, pMsgData, msgLen ); /* Set current queue buffer to XCP_RXDATA */ *pQueueBufState = XCP_RXDATA; /* Last buffer in queue? */ if( *pCtCanPos != pSessionCfg->pChannelCfgs[ channelId ].idxEnd ) { /* next queue buffer */ ++( *pCtCanPos ); } else { /* Back to queue start */ *pCtCanPos = pSessionCfg->pChannelCfgs[ channelId ].idxStart; } } return; }DAQ 列表通过如下中断调用
static void CanBuf1ISR(void) { CAN_C.IFRL.B.BUF01I = 1; // clear interrupt XcpCan_TxCallback(1); } static void CanBuf2ISR(void) { CAN_C.IFRL.B.BUF02I = 1; // clear interrupt XcpCan_TxCallback(2); } static void CanBuf3ISR(void) { CAN_C.IFRL.B.BUF03I = 1; // clear interrupt XcpCan_TxCallback(3); }