1 前言
本文将针对客户在使用Cube库时CAN2不能产生接收中断进行分析。
2 问题描述
客户使用的是STM32F105,同时用到了CAN1与CAN2,使用cube库,但有个奇怪的现象,CAN1能正常工作,CAN2却无**常产生接收中断,CAN1与CAN2的代码几乎没有什么差别。
3 重现问题
实验使用STM3210C-EVAL评估板,这款板子有同时将CAN1和CAN2引出,此板上的MCU为STM32F107VC,与客户所用到的STM32F105只多了个Ethernet外设,其他无差别,正适合用来验证此问题。
3.1 工程制作
使用cubemx生成工程,cubemx得配置如下图:
配置波特率为500K,自动离线使能。
0
|
|
|
|
点击生产代码,在main函数内的/* USER CODE BEGIN 2 */与/* USER CODE END 2 */添加:
|
|
|
|
|
在main函数内的/* USER CODE BEGIN 3 */与/* USER CODE END 3 */添加:
|
|
|
|
|
3.2 测试重现问题现象
使用ZLG的USBCAN-2E-U盒子与STM3210C-EVAL评估板以及PC连接进行测试:
在调试下,在PC端软件CANTest下都能看到CAN1与CAN2发送的数据,这说明连接上是完全没有问题的,但是,在调试CAN接收时,在CAN2的接收中断处设置断点,使用PC端软件CAN_Test向CAN2发送数据发现并不能产生中断,而对比CAN1时,发现CAN1却可以产生接收中断。
|
|
|
|
|
4 问题分析
仔细对比CAN1与CAN2的代码,发现并没有什么不同之处。仔细思考一下,由于CAN接收中断是与CAN过滤器有关,因此,着重对比CAN1与CAN2设置过滤器时的代码差异。
CAN1设置过滤器代码如下:
而CAN1设置过滤器代码如下:
看来好像没有什么不妥的地方,基本差不多,只不过调用HAL_CAN_ConfigFilter函数配置过滤器传入的第一个参数一个是&hcan1,一个是&hcan2,
查看参考手册,对比CAN1与CAN2的差别:
在参考手册的24.4节中对CAN的功能介绍时有下面一段话:
|
|
|
|
|
上面一段话的意思是说,CAN1是作为主,而CAN2做为从,做为从的CAN2不能直接访问这个专用的512bytes的SRAM,而只能通过作为主的CAN1来间接访问,且CAN1与CAN2是共享这个专用的512bytes的SRAM。打开图222,如下所示:
如上图可知,CAN1与CAN2共用过滤器(Acceptance Filters),CAN2是通过CAN1的Memory Access Controler来访问过滤器的。过滤器共有28个,占用512专用字节其中一部分。
接着在数据手册中查下内存映射,如下图所示:
|
|
|
|
|
可知,CAN1的地址为:
然后查看bxCAN的寄存器,在参考手册的24.9.5节中,发现有这么一段话:
也就是说,从偏移地址0x200开始到0x31C之间的寄存器只存在于CAN1中,在CAN2中并不存在,那么这些都是些什么寄存器呢?
查看参考手册的CAN寄存器映射表,如下内容所示:
|
|
|
|
|
可知这些都是CAN过滤器相关的寄存器,可知离CAN1起始地址0x4000 6400偏移0x200~0x320之间是CAN过滤器寄存器的地址,且这些过滤器由CAN1和CAN2共享,且最重要的一点信息是,离CAN2起始地址0x4000 6800偏移0x200~0x320之间是没有寄存器的,这个非常重要!
再回过头来看CAN2过滤器的设置代码:
这几行设置过滤器的代码到底是将参数设置到CAN1偏移0x200~0x320之间还是CAN2偏移的0x200~0x320之间?这个问题要弄清楚,非常重要的!继续看HAL_CAN_ConfigFilter函数内:
|
|
|
|
|
由上代码可知,设置的参数实际上是设置到传入的句柄hcan的示例Instance下的成员FS1R,sFilterRegister[]中去了,查看这些成员的定义:
由以上代码可知,HAL_CAN_ConfigFilter函数实际上就是对传入的CAN起始地址偏移0x200~0x320之间的过滤器相关寄存器进行参数设置,但是,对于CAN2来说,实际并不存在这个这些寄存器,因此不会生效。这个可以在调试过程中查看CAN2寄存器值来验证,如下图:
在运行过HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig)之后,CAN2相关的过滤器还是没有变化,进一步说明此函数对于CAN2来说是无效的。
|
|
|
|
|
那么要解决这个问题,该如何修改呢?很明显,通过CAN1来设置即可。CAN1和CAN2共享过滤器,但设置过滤器时可以通过CAN1的偏移来访问过滤器,这么说来,也可以将这个理解为CAN1作为“主”的确切含义吧。
修改后如下:
在CAN2中断设置断点,使用PC端软件CANTest向STM3210C-EVAL评估板的CAN2通道发送数据进行测试验证:
如上图可见,CAN2的接收中断已经可以正常捕获到了。
|
|
|
|
|
5 横向扩展
此问题是在使用Cube库下时发现的,那么标准库是否也会存在同样的问题?
其实,在使用标准库下,在设置过滤器时,并不需要传入CAN1或CAN2的句柄,因此也就不会这这种问题,如下基于标准库的示例代码:
在函数CAN_FilterInit中,内部自始至终操作的都是CAN1,如下所示:
因此,不会出现在Cube库下出现的问题。
|
|
|
|
|
6 总结
此文所描述的问题之会出现在使用Cube库的情况下,且基本覆盖包含双CAN的所有系列,在使用HAL函数HAL_CAN_ConfigFilter配置过滤器时,将第一个参数固定指向CAN1的句柄就可以了。
|
|
|
|
|