CH32-CAN发送管理

1 CAN发送邮箱

CH32共有三个CAN发送邮箱,在检测到总线空闲时交发送,但需要注意的是,有可能会发送失败,有可能因为仲裁失败从而导致失败,也有可能是其它错误,原则上bxCAN将自动重发,但bxCAN也可以配置不自动重发。正因为如此,发送邮箱中有可能同时存在多个需要发送的报文,一旦出现这种情况,那么发送邮箱中的多个报文又将是谁先发送谁后发送呢?有两种模式:ID模式和FIFO模式。ID模式由报文的ID值决定,即ID值越小,优先级越高,另一种FIFO模式,顾名思义,即为消息队列方式,谁先到谁先发送,此种模式下三个邮箱与接收FIFO类似。

下图是发送邮箱的状态图:

 

                                                               

由上图可知,发送邮箱共有四种状态,空状态,挂号状态,预定发送状态(scheduled),发送状态。

发送报文的流程为:应用程序选择1个空发送邮箱;设置标识符,数据长度和待发送数据;然后对CANx_TXMIRy寄存器的TXRQ位置’1’,来请求发送。TXRQ位置’1’后,邮箱就不再是空邮箱;而一旦邮箱不再为空,软件对邮箱寄存器就不再有写的权限。TXRQ位置1后,邮箱马上进入挂号状态,并等待成为最高优先级的邮箱,参见发送优先级。一旦邮箱成为最高优先级的邮箱,其状态就变为预定发送状态。一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。一旦邮箱中的报文被成功发送后,它马上变为空邮箱;硬件相应地对CANx_TSTATR寄存器的RQCP和TXOK位置1,来表明一次成功发送。
如果发送失败,由于仲裁引起的就对CANx_TSTATR寄存器的ALST位置’1’,由于发送错误引起的就对TERR位置’1’。

2 发送优先级

          如之前所述,如果三个邮箱中同时存在多个待发送的报文时,此时存在一个问题,即先送哪个邮箱中的报文好呢?此时,存在一个发送优先级的问题。此时,非空发送邮箱进入发送仲裁,发送仲裁有两种策略:ID模式和FIFO模式。

  • ID模式:当有超过1个发送邮箱在挂号时,发送顺序由邮箱中报文的标识符决定。根据CAN协议,标识符数值最低的报文具有最高的优先级。如果标识符的值相等,那么邮箱号小的报文先被发送。此模式通过对CAN主控寄存器CANx_CTLR的TXFP位清0来设置。
  • FIFO模式:通过对CANx_CTLR寄存器(CAN主控寄存器)的TXFP位置’1’,可以把发送邮箱配置为发送FIFO。在该模式下,发送的优先级由发送请求次序决定。该模式对分段发送很有用。

3 取消发送

发送邮箱中待发送的报文在正常发送成功之前也可以中途取消,通过对CANx_TSTATR寄存器的ABRQ位置’1’,可以中止发送请求。

  • 当发送邮箱处于挂号或预定状态时:发送请求马上就被中止了。
  • 当发送邮箱处于发送状态时:

         那么中止请求可能导致2种结果:

                    1:如果邮箱中的报文被成功发送,那么邮箱变为空邮箱,并且CANx_TSTATR寄存器(CAN发送状态寄存器)的TXOK位被硬件置’1’;

                    2:如果邮箱中的报文发送失败了,那么邮箱变为预定状态,然后发送请求被中止,邮箱变为空邮箱且TXOK位被硬件清’0’。

       因此,不管如何,一旦取消发送,那么在发送操作结束后,邮箱都会变为空邮箱。

     标准库中的取消发送函数如下:

                                                          

 

4 自动重传模式

该模式主要用于满足CAN标准中,时间触发通信选项的需求。通过对CANx_CTLR寄存器的NART位置’1’,来让硬件工作在该模式(禁止自动重传)。
在该模式下,发送操作只会执行一次。如果发送操作失败了,不管是由于仲裁丢失或出错,硬件都不会再自动发送该报文。
在一次发送操作结束后,硬件认为发送请求已经完成,从而对CANx_TSTATR寄存器的RQCP位置’1’,同时发送的结果反映在TXOK、ALST和TERR位上。

5 发送邮箱的组成

三个发送邮箱的结构与接收FIFO的邮箱类似,发送邮箱也是由四个寄存器组成:发送邮箱标识符寄存器(CANx_TXMIRy),发送邮箱长度和时间戳寄存器(CANx_TXMDTRy),发送邮箱低字节数据寄存器(CANx_TXMDLRy),发送邮箱高字节寄存器(CANx_TXMDHRy)。

代码如下:此处为标准ID配置

u8 CAN_Send_Msg( u8 *msg, u8 len )
{
u8 mbox;
u16 i = 0;

CanTxMsg CanTxStructure;

CanTxStructure.StdId = 0x317;//设置标准CAN ID  
CanTxStructure.IDE = CAN_Id_Standard;  //设置IDE为标准CAN ID 
CanTxStructure.RTR = CAN_RTR_Data;//数据帧
CanTxStructure.DLC = len;

for( i=0; i<len; i++ )
{
CanTxStructure.Data[i] = msg[i];
}

mbox = CAN_Transmit(CAN1, &CanTxStructure);

i = 0;

while( ( CAN_TransmitStatus( CAN1, mbox ) != CAN_TxStatus_Ok ) && (i < 0xFFF) )
{
i++;
}

if( i == 0xFFF )
{
return 1;
}
else
{
return 0;
}
}

posted @ 2024-06-27 13:53  WCH_CH32  阅读(83)  评论(0编辑  收藏  举报