XCP的移植(2)
程序员文章站
2024-01-16 22:07:46
...
本篇文章主要介绍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
}
}
注意:此处根据芯片不同写不同的candriver
3.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);
}
上一篇: FreeModbus的移植