XCP的移植(2)

本篇文章主要介绍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);
}

  • 8
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: Vector xcp 是一种用于汽车电子控制单元(ECU)之间进行通信的协议。移植 Vector xcp 即将该协议应用到特定的硬件平台上,以实现不同ECU之间的通信。 Vector xcp协议主要用于汽车诊断和标定(program的替代词)应用。它可以通过CAN、FlexRay、以太网等通信总线传输数据,并通过诸如汽车电子控制单元调试器等工具进行监测和控制。 移植Vector xcp协议需要以下步骤: 1. 了解目标硬件平台的通信总线接口。根据硬件平台的特点,选择适当的通信总线接口来实现Vector xcp协议的数据传输。 2. 确定协议的通信速率和通信模式。根据硬件平台的性能和需求,配置Vector xcp协议的通信速率和通信模式,以保证通信的稳定和高效。 3. 移植协议的核心功能。根据Vector xcp协议的规范和文档,将其核心功能移植到目标硬件平台上,以实现ECU之间的通信。 4. 进行测试和调试。通过使用相关的工具和设备,对移植后的Vector xcp协议进行测试和调试,以确保其功能的正确性和稳定性。 5. 优化和改进。根据实际应用需求,对移植后的Vector xcp协议进行优化和改进,以提高通信的性能和可靠性。 总结来说,移植Vector xcp协议需要对硬件平台进行适配,并将协议功能移植到目标平台上,以实现不同ECU之间的通信。通过测试和优化,可以确保协议在目标平台上的稳定和高效运行。 ### 回答2: Vector XCP(CAN交互模块)是Vector公司的一款CAN 总线通信工具,用于将上位机与车辆之间进行数据通信。移植Vector XCP的过程通常涉及以下几个步骤。 首先,需要了解移植的目标平台的硬件和软件环境。这包括处理器架构、操作系统、编译器和硬件接口等。然后,根据目标平台的特性,对Vector XCP的源代码进行修改和适配。这可能涉及将硬件接口层和驱动程序移植到目标平台上。 其次,进行编译和构建。根据目标平台的编译器和构建工具,修改Vector XCP的构建脚本,并进行编译和链接。 接下来,需要考虑与目标平台的通信接口的适配。Vector XCP使用CAN总线作为通信介质,需要通过CAN接口与车辆进行数据交互。因此,需要根据目标平台的CAN控制器和驱动程序,对Vector XCP的通信模块进行适配。 最后,进行测试和验证。移植后的Vector XCP需要进行测试,以确保它在目标平台上的功能和性能都符合预期。这包括测试通信性能、数据传输的准确性和稳定性等。 总结起来,移植Vector XCP需要了解目标平台的特性,对源代码进行修改和适配,进行编译和构建,适配通信接口,并进行测试和验证。通过这些步骤,可以成功地将Vector XCP移植到目标平台上,实现与车辆之间的数据通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_34309267

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值