打印
[资料分享与下载]

使用KE驱动库中KE06 CAN Demo的遇到几个问题和说明

[复制链接]
1255|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
追逐浪花|  楼主 | 2015-9-22 14:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

        在KE06驱动库中提供了CAN的使用例程,但是在使用过程中了发现几个比较典型的问题,并且这几个问题在论坛和community中也有很多网友问到,此处总结分享出来,希望能够对大家有所帮助。

        硬件平台:FRDM-KE06 + ZLG USB CAN

        软件平台:CW10.6 + KEXX_DRIVERS_V1.2.1_DEVD中CAN_Node1_demo

        问题背景:KE06 CAN_Node1_demo的目的是使用两块FRDM-KE06板互连,对发数据,程序运行正常。当客户的需求是验证同时使用KE06的三个发送FIFO会不会出现丢包的状况,于是只能使用USBCAN去抓数据,于是发现如下几个问题。


        问题1. USBCAN无法接收数据以及波特率设置计算的误解

        在CAN_Node1_demo中,尽管两块板收发正常,但是如果用户使用USBCAN去调试,却发现无法接收数据,从示波器查看TX引脚,所以判断原因就应该在于波特率的设置。

        程序默认波特率设置如下,但是其波特率具体是多少呢,从注释中看到Baud_RATE被定义为:

 BAUD_RATE_CLOCK/(BAUD_RATE_BRP+1)/ (BAUD_RATE_SJW+1)/(3 + BAUD_RATE_TSEG1+ BAUD_RATE_TSEG2)

        但事实上这个计算公式错误的,正确的计算应该如下。Baud_RATE的计算和BAUD_RATE_SJW没有关系,具体原因可以参考CAN的技术手册,这个注释对用户产生了很大的误解,导致波特率总是设置不正确。

        Baud_RATE=BAUD_RATE_CLOCK/(BAUD_RATE_BRP+1)/(3 + BAUD_RATE_TSEG1+ BAUD_RATE_TSEG2)

        按照这个公式计算,得到Baud_RATE=20000000/1/(3+9+6)=555555,所以USBCAN无法接收到任何数据。


        Demo默认波特率设置代码:

define BAUD_RATE_SJW         SJW_3TQ /*!< 1 set Synchronization Jump Width. */

#define BAUD_RATE_BRP         0 /*!< 1 Baud Rate Prescaler */     

#define BAUD_RATE_SAMP      0 /*!< 0-One sample per bit, 1-three sample per bit. */

#define BAUD_RATE_TSEG1      TSEG_10  /*!< Time Segment 1*/

#define BAUD_RATE_TSEG2      TSEG_7  /*!< Time Segment 2*/

#define BAUD_RATE_CLOCK      2000000L/*!< clock source for MSCAN*/

#define Baud_RATE                     BAUD_RATE_CLOCK/(BAUD_RATE_BRP+1)/ (BAUD_RATE_SJW+1)/(3 + BAUD_RATE_TSEG1+ BAUD_RATE_TSEG2)  //易引起误解段


相关帖子

沙发
追逐浪花|  楼主 | 2015-9-22 14:57 | 只看该作者
按照以上公式,Baud_RATE=BAUD_RATE_CLOCK/(BAUD_RATE_BRP+1)/(3 + BAUD_RATE_TSEG1+ BAUD_RATE_TSEG2)

设置波特率100K,需要做的修改如下:
 #define BAUD_RATE_SJW         SJW_3TQ /*!< 1 set Synchronization Jump Width. */

#define BAUD_RATE_BRP         9 /*!< 1 Baud Rate Prescaler */     

#define BAUD_RATE_SAMP      0 /*!< 0-One sample per bit, 1-three sample per bit. */

#define BAUD_RATE_TSEG1      TSEG_12  /*!< Time Segment 1*/

#define BAUD_RATE_TSEG2      TSEG_7  /*!< Time Segment 2*/

#define BAUD_RATE_CLOCK      2000000L/*!< clock source for MSCAN*/

#define Baud_RATE                     BAUD_RATE_CLOCK/(BAUD_RATE_BRP+1)//(3 + BAUD_RATE_TSEG1+ BAUD_RATE_TSEG2)

经过以上修改后,KE06板和上位CANTEST软件收发正常。



问题2. 可以接受扩展帧数据,但无法接收标准帧

在例程代码中KE06对CAN数据读取是通过接收中断 MSCAN_RxProcessing中调用CAN_ReadOneFrameFromBuf函数实现的,具体代码如下,红色字体是对扩展帧帧ID的拆解接收,而没有对标准帧帧ID的接收。
 uint8_t CAN_ReadOneFrameFromBuff(MSCAN_Type *pCANx,MSCAN_FramePtr pRxFrame)

{

。。。。。。。。。。。。。。。。。

  if(CAN_IsRxBuffFull(pCANx))

  {

  sIDR1.Bytes = CAN_ReadIDR1Reg(pCANx);

  sIDR3.Bytes = CAN_ReadIDR3Reg(pCANx);

  pRxFrame->bIsExtOrStand = sIDR1.IDR1.R_TEIDE;

  pRxFrame->bIsRemoteFrame = sIDR3.IDR3.ERTR;

  pRxFrame->ID_Type.ExtID.EID28_21 = CAN_ReadIDR0Reg(pCANx);

  pRxFrame->ID_Type.ExtID.EID20_18 = sIDR1.IDR1.EID20_18_OR_SID2_0;

  pRxFrame->ID_Type.ExtID.EID17_15 = sIDR1.IDR1.EID17_15;

  pRxFrame->ID_Type.ExtID.EID14_7 = CAN_ReadIDR2Reg(pCANx);

  pRxFrame->ID_Type.ExtID.EID6_0 = sIDR3.IDR3.EID6_0;

      

  pRxFrame->DLR = pCANx->RDLR&0x0F;

   。。。。。。。。。。。。。。。。。。

  }

使用特权

评论回复
板凳
追逐浪花|  楼主 | 2015-9-22 14:58 | 只看该作者
所以,添加对标准帧的接收代码,如下红色字体。更改后,把sMSCANConfig.u32IDMR0和sMSCANConfig.u32IDMR1更改为0xFFFF FFFF(ignore)后,通过上位机段发送的任何ID的标准帧都可以被正常接收。
 uint8_t CAN_ReadOneFrameFromBuff(MSCAN_Type *pCANx,MSCAN_FramePtr pRxFrame)

{

。。。。。。。。。。。。。。。。

  if(CAN_IsRxBuffFull(pCANx))

  {

  sIDR1.Bytes = CAN_ReadIDR1Reg(pCANx);

  sIDR3.Bytes = CAN_ReadIDR3Reg(pCANx);

  pRxFrame->bIsExtOrStand = sIDR1.IDR1.R_TEIDE;

  pRxFrame->bIsRemoteFrame = sIDR3.IDR3.ERTR;



  if(pRxFrame->bIsExtOrStand)

  {   

  pRxFrame->ID_Type.ExtID.EID28_21 = CAN_ReadIDR0Reg(pCANx);

  pRxFrame->ID_Type.ExtID.EID20_18 = sIDR1.IDR1.EID20_18_OR_SID2_0;

  pRxFrame->ID_Type.ExtID.EID17_15 = sIDR1.IDR1.EID17_15;

  pRxFrame->ID_Type.ExtID.EID14_7 = CAN_ReadIDR2Reg(pCANx);

  pRxFrame->ID_Type.ExtID.EID6_0 = sIDR3.IDR3.EID6_0;

  }

  else

  {            

  pRxFrame->ID_Type.StandID.EID2_0 = sIDR1.IDR1.EID20_18_OR_SID2_0;

  pRxFrame->ID_Type.StandID.EID10_3 = CAN_ReadIDR0Reg(pCANx);

  }

  pRxFrame->DLR = pCANx->RDLR&0x0F;

  。。。。。。。。。。。。。。。。。。  }

问题3. sCANTxItemInfo.u32DataLength的含义和长度设置

在代码中,CAN数据的发送流程是,先填充发送数据,然后通过CAN_SendItemToBuffer函数把这些数据写入到Buffer队列,即u8DataBuff[MAX_DATA_LENGTH]中,最后再在 CAN_CheckSendBufferFrame中调用CAN_LoadOneFrameToBuff依次把Buffer队列的数据发送出去。

最后这个函数就牵涉到帧个数的概念,通俗来讲就是一次向CAN的硬件Buffer传送的几个帧,具体长度的指定会在初始化时由sCANTxItemInfo.u32DataLength 设定,具体函数如下。从字面来理解,这个参数就是设置每次发送的长度,举例说,假设要发送100个数据,可以设置每次的发送长度是20,发送5次,也可以是50个数据,发送两次。所以很容易错误认为可以随便设置u32DataLength,但事实上这样设置会导致发送数据的丢失。
 //Initialize the Tx information

sCANTxItemInfo.bIsExtOrStand = 1;

sCANTxItemInfo.bIsRemoteFrame = 0;

sCANTxItemInfo.ID_Type.ID = NODE_ID1;

sCANTxItemInfo.u32DataLength = 24;

for(i=0;i<24;i++)

{

  sCANTxItemInfo.u8DataBuff[i] = i;

}

使用特权

评论回复
地板
追逐浪花|  楼主 | 2015-9-22 14:59 | 只看该作者
原因在于,u32DataLength的设置受限于KE06 Buffer的深度,KE06包含发送有3个Buffer(每个Buffer对应8个字节),截图如下。 如果设置的发送长度大于24(24=3个bufferx每个buffer 8个字节),将有可能导致发送数据丢失。 发送数据的代码如下,会先获取那个发送邮箱为空,然后launch 发送。刚好能够完成由于发送帧Buffer的长度为CAN_BUFFER_LENGTH=16,所以如果向这个Buffer写入的速度很快。当然这个即便在u32DataLength设置为24时也有可能出现问题,需要用户去控制Buffer的写入速度。

无论如何,考虑到CAN的邮箱深度为3,最好不要设置u32DataLength大于24个字节。
 uint8_t CAN_LoadOneFrameToBuff(MSCAN_Type *pCANx,MSCAN_RegisterFramePtr pFrameBuff)

{

。。。。。。。。。。。。。。。。。。。。。

  //get the empty transmitter buffer

  u8TransmitterEmptyFlag = CAN_GetTransmitterBufferEmptyFlag(MSCAN);

  if(u8TransmitterEmptyFlag == TRANSMITTER_TX_NO_EMPTY)

  {

       return FALSE;

  }

DisableInterrupts;

  // select transmitter buffer

  CAN_TxBuffSelect(pCANx,u8TransmitterEmptyFlag);

  //don't copy  time stamps, so here Sub 2 byter

  memcpy((void *)&pCANx->TEIDR0,(void *)pFrameBuff,sizeof(MSCAN_RegisterFrameType)-2);



  CAN_LaunchTransmitBuffer(pCANx,CAN_GetTxBuffSelect(pCANx));

。。。。。。。。。。。。。。。。。。

  return TRUE;

}

问题4. 接收数据丢失的判断

前文提到,demo中发送和接收帧Buffer的个数为CAN_BUFFER_LENGTH=16(对应的Buffer大小为16个8字节),所以发送端的数据传送太多,而接收端未来得及读取时,就会导致数据溢出丢弃。当传输速度快时,这种问题很难避免,但是往往用户需要知道什么时候出现了这种问题,那该如何去判断呢?

很显然,出现溢出时应该是RX的帧Buffer没有空闲空间,即u8RxFrameBufferFreeLength=0时,所以如下红色Printf函数处添加标记通知溢出即可,然后再在应用层做其他处理。

使用特权

评论回复
5
追逐浪花|  楼主 | 2015-9-22 14:59 | 只看该作者
 void MSCAN_RxProcessing( void )

{

    u32RxInterruptCounter ++;

    if(CAN_IsRxBuffFull(MSCAN))

    {

    if(u8RxFrameBufferFreeLength!=0)

        {

            CAN_ReadOneFrameFromBuff(MSCAN,&sRxFrame[u8RxFrameBufferIndex++]);

            if(u8RxFrameBufferIndex>=CAN_BUFFER_LENGTH)

            {

                u8RxFrameBufferIndex = 0;

            }

            u8RxFrameBufferFreeLength--;





        }

        else

        {

            //receive frame buffer is full, clear buffer in MSCAN

            // clear receiver full flag

            CAN_ClearRXF_Flag(MSCAN);

            printf("receive frame buffer is full, may lost frame!\r\n"); //YNN

        }

    }

}

使用特权

评论回复
6
FSL_TICS_ZJJ| | 2015-9-22 15:07 | 只看该作者
楼主总结的很到位,的确是目前KE06 can代码存在的问题。

使用特权

评论回复
7
风的样子| | 2015-9-22 17:13 | 只看该作者
楼主讲的真是详细啊,谢谢分享

使用特权

评论回复
8
Roderman_z| | 2015-9-22 20:08 | 只看该作者
分析的很透彻,确实有这方面的问题存在

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

256

帖子

1

粉丝