欢迎光临散文网 会员登陆 & 注册

IMX6ULL与STM32F103的CAN通信实现

2022-12-22 09:48 作者:17投47中  | 我要投稿

在上一篇博文中,我们利用USBCAN设备及其上位机软件,测试了一块以IMX6ULL为核心芯片的开发板的CAN通信收发功能,了解了在Linux应用层基于套接字实现CAN网络应用的基本方法。本次我们将USBCAN替换为一块以STM32F103ZET6为核心芯片的开发板,尝试实现双机之间的CAN通信基本功能。

  • 硬件连接

在硬件上,两个板子各自均只留出1路CAN接口,只需将两个CAN接口的CAN_H与CAN_L对应连接起来即可。由于CAN信号是两根线的差分信号,故不需要再连接其它。两板的CAN收发器均采用经典的TJA1050,器件连接的原理图如下。用线连好后双机的CAN通信连接示意图如下。芯片内部集成的CAN控制器与外接的CAN收发器交换CAN报文数据,收发器是控制器与物理总线的中间媒介,负责在控制器的逻辑电平和总线的差分信号间做转换。而CAN控制器的具体行为由相关寄存器的状态决定,需要我们编写程序来控制。两个收发器之间的CAN_H和CAN_L两条线的两段之间,需要各自接一个120Ω的电阻,由原理图可见板载已经接入了该电阻,无需额外接入。两个板子连接的实物图如下。

  • 驱动层实现

这里所说的驱动层,是从Linux系统体系的角度而言的。Linux具有明显的内核与应用层之分,对底层硬件的驱动程序是内核的组成部分,在应用层控制硬件工作的流程中充当了一种“中间件”的作用,对上提供相关接口供应用层调用,对下通过操作寄存器等真正操控硬件的行为。但对于STM32裸机的开发方式来说,程序并不需要明确划分哪些部分属于app、哪些属于driver,所有的代码是可以放在一起的。我们本次的开发基于ST官方提供的标准库,所以这里把基于标准库封装开发所得的用于实现STM32的CAN外设基本功能的接口,称为STM32的CAN“驱动层”。

[1]IMX6ULL

为驱动IMX6ULL上的CAN外设,首先要找到描述该设备硬件信息的设备树,其中外设引脚信息和控制器描述信息是必不可少的。我们在内核源码/arch/arm/boot/dts/目录下找到有关该CAN外设的设备树代码如下:

上面CAN控制器的status为disabled,表示不可用,需要改成okay才能正常使用。一般我们不会直接去修改原控制器的默认设置,而是采用“追加”的方式更改属性值,如下为对flexcan1硬件信息的追加补充:

这样设备树的配置基本就完成了,然后需要使能IMX6ULL的flexcan驱动。一般而言,NXP在官方提供的内核里已经集成了多种类型外设的驱动,如果仅仅使用基础通信等基本功能而不涉及复杂需求的实现,那么大多数情况下直接使能内核自带驱动后就可以了。在内核源码顶层目录下执行内核配置make menuconfig,依次进入Networking support、CAN bus subsystem support、CAN Device Driver,找到Support for Freescale FLEXCAN based chips选项,编译类型选成编译为内核一部分即built-in,如下:

保存设置后CAN驱动的编译选项就存在了编译配置文件中,再编译内核就能使上面的设备树配置和驱动配置生效了,将生成的Image和dtb文件载入IMX6ULL开发板,即可看到系统中的CAN设备,如下。在/sys/class/net/目录下的can0即为我们配置的外设,查看其控制器设备树的status可见值为okay,和我们设置的一样。

[2]STM32F103ZET6

要使用STM32F103的CAN外设,我们需要考虑这些方面:①引脚配置,要考虑CAN_RX和CAN_TX所在引脚号、GPIO的时钟使能、GPIO参数如何配置等;②CAN控制器配置,包括CAN外设时钟使能、CAN工作模式、波特率、接收FIFO属性等;③CAN过滤器配置,主要决定CAN的接收策略;④CAN外设的接收和发送接口;⑤在需要利用CAN中断的场合,还应该配置NVIC和CAN中断类型。后面和IMX6ULL交互时需要用到CAN接收中断,所以我们本次需要配置中断。基于ST提供的标准库,可以将上述几方面开发成自己的接口,即为所谓的CAN“驱动层”。我们开发的接口主要代码如下:

上面代码中,CAN接收中断号定义在文件stm32f10x.h中的枚举类型IRQn_Type,该类型规定了STM32F10x的所有中断号。CAN接收中断服务函数的名称定义在启动文件start_up_stm32f10x_hd.s中。在CAN控制器配置函数中,设定了禁止FIFO锁定模式,意味着FIFO溢出时新接收的报文会覆盖旧的报文而不会被丢弃。由时间参数的设定可以得出,CAN波特率即为36MHz/(8*(1+5+3))=500kbps。在CAN过滤器的配置中,采用了32位掩码模式,根据ID为0x123和掩码为0xFFFF可知,这里设定了仅接受ID为0x123的报文,并且为标准ID和数据帧。使能了FIFO0的消息挂起中断,即该邮箱中接收到消息就进入CAN接收服务函数。在CAN_SendTxMsg接口中,调用了库函数CAN_Transmit进行发送,该函数返回有效的邮箱号或表示无可用邮箱的标志。利用库函数CAN_TransmitStatus检查发送状态是否为完成。

  • 应用层实现

我们设计一个非常简单的双机交互流程,如下:

IMX6这边首先发送ID为x0123的CAN报文,STM32接收到后回复ID为0x456的CAN报文,IMX6收到后继续发送0x123,然后重复这个过程。

[1]IMX6ULL

关于IMX6ULL的CAN通信应用层的基本知识,可参考之前的博文《imx6ull开发板的CAN通信》,这里不详细说明了。我们设置2个线程分别处理发送和接收任务,发送线程在收到报文后延时2秒发送,两个线程之间使用简单的标志位同步。应用层代码如下:

[2]STM32F103ZET6

STM32侧的接收是在CAN接收中断服务函数中完成的,在文件stm32f10x_it.c中添加如下代码:

有报文到来则FIFO0的消息挂起中断触发,调用库函数CAN_Receive实现接收,并且通过简单的标志位通知主函数消息收到。接收缓冲区和通知标志均在主函数中声明。主函数循环检测该标志,如检测到被置1则通过串口把收到的数据打印出来,并立即发送报文给IMX6ULL。主函数的主要代码如下:

  • 结果

两边编译成功后烧写到各自板子中,启动IMX6侧的应用进程,可以看到STM32侧打印的串口消息和IMX6侧进程打印的接收消息如下。可以看出STM32成功接收到了ID为0x123的标准数据帧,每次接收8字节0x01到0x08,IMX6ULL侧成功接收到了ID为0x456的标准数据帧,每次接收8字节:0x78、0x89、0x9a、0xab、0xbc、0xcd、0xde和0xef。


IMX6ULL与STM32F103的CAN通信实现的评论 (共 条)

分享到微博请遵守国家法律