STM32的bxCAN的主要特点有: l 支持CAN协议2.0A和2.0B主动模式 l 波特率最高达1Mbps l 支持时间触发通信 l 具有3个发送邮箱 l 具有3级深度的2个接收FIFO l 可变的过滤器组(最多28个) 在STM32互联型产品中,带有2个CAN控制器,而我们使用的STM32F103ZET6属于增强型,不是互联型,只有1个CAN控制器。双CAN的框图如图30.1.10所示: 图30.1.10 双CAN框图 从图中可以看出两个CAN都分别拥有自己的发送邮箱和接收FIFO,但是他们共用28个滤波器。通过CAN_FMR寄存器的设置,可以设置滤波器的分配方式。 STM32的标识符过滤是一个比较复杂的东东,它的存在减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。 STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供: ● 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位 ● 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位 此外过滤器可配置为,屏蔽位模式和标识符列表模式。 在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。 而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。 通过CAN_FMR寄存器,可以配置过滤器组的位宽和工作模式,如图30.1.11所示: 图30.1.11 过滤器组位宽模式设置 为了过滤出一组标识符,应该设置过滤器组工作在屏蔽位模式。 为了过滤出一个标识符,应该设置过滤器组工作在标识符列表模式。 应用程序不用的过滤器组,应该保持在禁用状态。 过滤器组中的每个过滤器,都被编号为(叫做过滤器号,图30.1.11中的n)从0开始,到某个最大数值-取决于过滤器组的模式和位宽的设置。 举个简单的例子,我们设置过滤器组0工作在:1个32为位过滤器-标识符屏蔽模式,然后设置CAN_F0R1=0XFFFF0000,CAN_F0R2=0XFF00FF00。其中存放到CAN_F0R1的值就是期望收到的ID,即我们希望收到的映像(STID+EXTID+IDE+RTR)最好是:0XFFFF0000。而0XFF00FF00就是设置我们需要必须关心的ID,表示收到的映像,其位[31:24]和位[15:8]这16个位的必须和CAN_F0R1中对应的位一模一样,而另外的16个位则不关心,可以一样,也可以不一样,都认为是正确的ID,即收到的映像必须是0XFFxx00xx,才算是正确的(x表示不关心)。 关于标识符过滤的详细介绍,请参考《STM32参考手册》的22.7.4节(431页)。接下来,我们看看STM32的CAN发送和接收的流程。 CAN发送流程 CAN发送流程为:程序选择1个空置的邮箱(TME=1)à设置标识符(ID),数据长度和发送数据à设置CAN_TIxR的TXRQ位为1,请求发送à邮箱挂号(等待成为最高优先级)à预定发送(等待总线空闲)à发送à邮箱空置。整个流程如图30.1.12所示: 图30.1.12 发送邮箱 上图中,还包含了很多其他处理,不强制退出发送(ABRQ=1)和发送失败处理等。通过这个流程图,我们大致了解了CAN的发送流程,后面的数据发送,我们基本就是按照此流程来走。接下来再看看CAN的接收流程。 CAN接收流程 CAN接收到的有效报文,被存储在3级邮箱深度的FIFO中。FIFO完全由硬件来管理,从而节省了CPU的处理负荷,简化了软件并保证了数据的一致性。应用程序只能通过读取FIFO输出邮箱,来读取FIFO中最先收到的报文。这里的有效报文是指那些正确被接收的(直到EOF都没有错误)且通过了标识符过滤的报文。前面我们知道CAN的接收有2个FIFO,我们每个滤波器组都可以设置其关联的FIFO,通过CAN_FFA1R的设置,可以将滤波器组关联到FIFO0/FIFO1。 CAN接收流程为:FIFO空à收到有效报文à挂号_1(存入FIFO的一个邮箱,这个由硬件控制,我们不需要理会)à收到有效报文à挂号_2à收到有效报文à挂号_3à收到有效报文à溢出。 这个流程里面,我们没有考虑从FIFO读出报文的情况,实际情况是:我们必须在FIFO溢出之前,读出至少1个报文,否则下个报文到来,将导致FIFO溢出,从而出现报文丢失。每读出1个报文,相应的挂号就减1,直到FIFO空。CAN接收流程如图30.1.13所示: 图30.1.13 FIFO接收报文 FIFO接收到的报文数,我们可以通过查询CAN_RFxR的FMP寄存器来得到,只要FMP不为0,我们就可以从FIFO读出收到的报文。
|