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;
}
}