ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Zynq Linux下AXI-CAN实战:从Vivado到SocketCAN完整打通

Zynq Linux下AXI-CAN实战:从Vivado到SocketCAN完整打通 做Zynq的人迟早都会碰到CAN通信的需求但真正上手的时候很多人会愣一下Zynq的PS端并没有原生CAN控制器想用CAN就得往PL里挂IP核要么用SPI转CAN的小板子凑合要么就直接上Xilinx官方的AXI-CAN软核。这个“基于Zynq在Linux下的AXI-CAN实战”的坑我踩过不少从Vivado画Block Design到PetaLinux生成设备树再到应用层SocketCAN收发报文整个链路一环扣一环任何一个地方没对齐都容易卡住。这篇文章我就把这套完整打法整理出来给需要在Zynq Linux环境下跑CAN通信的朋友一份可以直接照做的实操参考。我自己做的时候也有过很痛苦的阶段一会儿设备树中断号对不上导致驱动加载失败一会儿总线波特率和收发器对不上错误帧哗哗往下掉。这些东西文档里写得零散网上帖子各说各话真正从零到通要折腾好几天。这篇东西就是把那些坑提前帮你趟一遍顺便把背后为什么要这么配的逻辑讲清楚。1. 整体方案设计与选型思路1.1 为什么Zynq上选AXI-CAN而不是其他方案先说结论在Zynq的Linux系统里做CAN用Xilinx的AXI-CAN IP核是最正规、最省心的一条路没有之一。Zynq-7000系列的PS端集成了不少外设但唯独CAN控制器没有放进去这个历史遗留问题导致我们只能向PL要资源。AXI-CAN就是Xilinx提供的CAN控制器软核挂在AXI-Lite总线上通过寄存器映射方式被CPU访问本质上是把完整的CAN协议控制器逻辑用FPGA资源实现了。有人会问那我用MCP2515这种SPI接口的CAN控制器行不行行是行但那纯属没办法的时候才用的备选方案。SPI转CAN本质上就是一颗独立CAN控制器通过SPI总线跟Zynq通信CPU要不停地轮询SPI去读缓冲一条报文的开销远大于硬件集成方案。而且MCP2515只有两个接收缓冲报文稍微一密集就容易丢帧。AXI-CAN直接挂在高速AXI总线上通过中断通知CPU有报文到达收发数据的吞吐量和实时性都高一个量级。虽然会占一点PL资源一个AXI-CAN实例加上收发FIFO也就用几千个LUT对Zynq-7020这类芯片来说根本不算事。还有一种做法是用PL侧的软核处理器跑裸机程序跟PS侧Linux通过共享内存通信这种架构复杂度过高维护成本大除非有特殊需求否则不建议。从软件生态来看Linux内核自带SocketCAN框架CAN设备在系统里就是一张网络接口卡can0用标准socket读写就能收发CAN报文配合can-utils命令行工具调试起来非常方便这对应用层开发来说简直是降维打击。综合下来AXI-CAN Linux SocketCAN就是Zynq上做CAN通信的黄金组合。1.2 整个数据通路是怎么转起来的理解这整套方案不能只看某一个环节得把数据从CAN总线上到Linux应用里的完整路径看清楚。CAN收发器芯片比如TJA1050把总线上的差分电平转换成TTL电平的TX/RX信号接到Zynq的PL引脚上。PL里的AXI-CAN IP核内部实现了完整的CAN协议控制器逻辑包括位时序同步、报文仲裁、错误检测、CRC校验等这部分的逻辑跟一颗独立的CAN控制器芯片内部干的活儿本质上是一样的只是用FPGA可编程逻辑搭出来的。AXI-CAN IP核通过AXI-Lite从机接口连接PS端的GP Master端口这样ARM Cortex-A9处理器就能通过内存映射方式访问AXI-CAN内部的寄存器比如控制寄存器、状态寄存器、报文发送缓冲区和接收缓冲区。当总线上来了一帧报文AXI-CAN把报文存进内部接收FIFO同时拉高中断信号中断信号接到PS端的GIC通用中断控制器GIC触发CPU执行中断处理函数。Linux内核里的xilinx_can驱动收到中断后从寄存器读出报文包装成Linux网络子系统标准的sk_buff结构向上抛给SocketCAN协议栈。SocketCAN核心把这些报文交给应用层注册的socket应用层的read()函数就能拿到这帧数据了。反方向发送报文就是完全对称的流程应用层调用write()把数据塞进socketSocketCAN底层调用驱动注册的ndo_start_xmit函数驱动把数据写入AXI-CAN的发送缓冲区设置发送请求位IP核自动完成CAN协议封装和发送。这套通路里各个层级的职责非常清晰物理层是收发器芯片链路层是AXI-CAN IP核驱动层是xilinx_can协议接口层是SocketCAN。这样把每一层的边界画清楚以后后面遇到问题排查起来就有方向感了而不是瞎猜。2. 硬件侧设计与Vivado工程搭建2.1 Block Design里的关键配置打开Vivado创建好Zynq工程后首先添加Zynq7 Processing System IP核。因为要用到AXI-Lite接口和中断必须把PS侧的S AXI GP0接口打开同时打开中断控制器这里建议保持默认的F2P中断或者直接把PL-PS中断端口勾选上。然后搜索AXI CAN把Xilinx的AXI CAN IP核拖进Block Design里双击打开配置界面。AXI CAN IP核的配置界面有几个关键选项值得注意。第一个是Enable CAN 2.0B这个建议勾上因为CAN 2.0B向下兼容2.0A既能发标准帧也能发扩展帧实用性最强。第二个是采样点相关的位时序参数这里要稍微动点脑子。CAN协议规定每一位的时间要拆分成同步段、传播段、相位缓冲段1和相位缓冲段2波特率取决于总线时钟频率和分频系数。AXI-CAN核会有一个输入时钟通常是PS侧FCLK0提供的比如100MHz在IP核里需要配置同步跳转宽度、时间段1、时间段2和分频系数这几项配置值直接决定了最终的总线波特率。我的习惯是先用CAN波特率计算器算出采样点最合理的组合比如500kbps总线采样点推荐在75%到87.5%之间然后反推分频系数。第三个重要配置是接收FIFO的深度在IP核界面上可以直接改Receive FIFO Depth我一般设置成32或者64。为什么在意这个深度因为CAN总线上报文是异步到达的如果CPU正在处理其他中断而没来得及读走FIFO里的数据深一点的FIFO能吸收突发流量减少丢帧概率。FIFO太浅一旦总线繁忙丢帧几乎是必然的这个在高负载CAN网络中是非常常见的问题。发送FIFO一般保持默认值就行。连完自动连接让Vivado帮你接好AXI总线和时钟复位后要手动把AXI-CAN的中断输出连接到PS端的中断输入端口上。在Address Editor里记住分配给AXI-CAN的寄存器起始地址默认通常会是0x43C00000这个地址后面写设备树时要用。最后记得给AXI-CAN的TX和RX两个引脚做外部引出加mark_debug也行做成顶层端口后分配实际的FPGA引脚到CAN收发器芯片上。2.2 硬件PCB层面的注意事项软件上配好了不代表硬件就能跑通CAN物理层的一些细节如果没处理好后面的调试会让你痛不欲生。首先CAN收发器芯片的输出端CANH和CANL之间必须接一个120Ω的终端电阻这个电阻的作用是匹配总线阻抗、消除信号反射。很多新手忽略这个电阻或者以为多接几个设备就不需要了结果就是总线上的信号反射严重通信时好时坏错误帧频发。记住CAN总线两端各需要一个120Ω电阻如果这个节点正好在总线的一端就必须接上。TX和RX信号线从Zynq引脚到收发器之间的路径要尽量短走线保持等长避免形成天线效应导致辐射干扰。收发器电源端的去耦电容要靠近芯片引脚放置典型值是100nF加10μF组合。如果工作在工业环境推荐直接用带隔离的CAN收发器模块比如ISO1050隔离耐压能避免地环路引起的通信异常。我之前在一个电机控制项目上就因为收发器地和控制器地之间有电位差导致总线一直报错后来换了隔离收发器才彻底解决。另外CAN收发器的RS引脚是斜率控制脚如果总线速率不高且走线较短可以接一个10kΩ电阻到地降低压摆率能明显减少电磁辐射。还有一点要提醒Zynq的PL引脚供电电压要跟CAN收发器的IO电平匹配。主流收发器是3.3V或5V供电如果收发器的IO逻辑电平跟PL引脚的Bank电压不一致需要加电平转换。最省事的做法是选3.3V供电的收发器直接跟Zynq的HP Bank或HR Bank对接。3. Linux驱动层适配与设备树编写3.1 内核配置与PetaLinux工程搭建硬件平台对齐了接下来进入Linux侧。我习惯用PetaLinux来管理Zynq的Linux工程它能把内核、设备树、根文件系统和Bootloader打包到一起。创建工程后用petalinux-config命令进入配置界面然后在Device Drivers - Network device support - CAN bus subsystem support里确认下面这几项都勾上CAN Device Drivers - Xilinx CAN以及CAN_USB、CAN_RAW、CAN_BCM等协议支持。其中CAN_RAW是必须的应用层收发报文全靠它。还需要在File systems里确认内核支持devtmpfs这个通常默认就有。另一个常用的配置手段是直接用内核的defconfig在文件系统里手动把CONFIG_CAN_XILINX_CANy写进去。要注意的是老版本内核里这个驱动叫xilinx_can新版本内核把Xilinx准备合并到candev框架里的驱动改名为xilinx_canfd之类但Zynq-7000场景下用的还是经典驱动名称配置选项在LogicAll CAN drive这个路径下也能找到。根据自己的内核版本确认具体选项名这个不复杂。配置好以后petalinux-build编译整个工程每次修改设备树或者内核选项后重新build一次用生成的image.ub和BOOT.BIN做SD卡启动。启动后进入系统首先要确认内核是否真的加载了CAN驱动模块用lsmod看有没有xilinx_can模块或者直接用dmesg | grep can能看到驱动注册信息就说明内核侧基本没问题了。3.2 设备树节点怎么改设备树是Zynq Linux下AXI-CAN能否正常工作的关键这里常见的坑非常多。PetaLinux在petalinux-config -c device-tree里维护设备树源文件或者更直接一点在项目目录的subsystems/linux/device-tree目录下修改system-user.dtsi把自定义的节点追加进去。一个典型的AXI-CAN设备树节点长这样amba { axi_can_0: axi-can43c00000 { compatible xlnx,axi-can-1.00.a; reg 0x43c00000 0x10000; interrupts 0 29 4; interrupt-parent intc; clocks clkc 15; clock-names can_clk; tx-fifo-depth 32; rx-fifo-depth 32; }; };这里每个字段都对应了一段容易出问题的逻辑。compatible字符串必须跟驱动源码里of_match_table匹配xilinx_can驱动里注册的compatible就是xlnx,axi-can-1.00.a一个字符都不能错。reg里的地址要和Vivado Address Editor里分配的一致这个地址会做成ioremap映射如果写错了驱动访问的就是一片不存在的内存挂死或者报错都算轻的。interrupts字段很关键格式是中断类型 中断号 触发方式其中中断类型0表示SPI共享外设中断中断号和Vivado里连接到PS中断端口的具体编号有对应关系一般是29或者30具体要根据Block Design生成的中断ID来填写。触发方式4表示高电平触发FPGA中断默认就是高电平有效。中断号如果填错了驱动在request_irq时可能会失败或者更隐蔽——中断根本不会触发报文收不到。clocks属性指定源时钟必须指向PS的FCLK节点比如clkc 15对应FCLK0。如果这个时钟没配好驱动内部的波特率计算会基于错误的时钟频率导致实际波特率和设定值偏差巨大总线直接通信失败。tx-fifo-depth和rx-fifo-depth这两个属性对应Vivado里配置的FIFO深度驱动会读取这个值来分配缓冲区大小必须和硬件设计保持一致。3.3 驱动是如何工作起来的xilinx_can驱动的核心逻辑其实不算复杂但理解它有助于排查问题。设备匹配成功后驱动的probe函数会执行ioremap把寄存器物理地址映射成虚拟地址然后通过clk_prepare_enable打开参考时钟接着读取device tree里的FIFO深度配置并分配DMA或普通内存缓冲区。驱动还会通过netdev结构注册一个网络接口并填充net_device_ops结构体里面有ndo_open对应ifconfig can0 up、ndo_stop对应ifconfig can0 down、ndo_start_xmit发送报文三个核心回调。在ndo_open里驱动会做CAN控制器的初始化包括设置波特率寄存器、清空FIFO、使能中断最后调用netif_start_queue让上层可以开始发数据。波特率设置过程会根据ip link命令传入的bitrate和sample-point参数结合时钟频率重新计算位时序寄存器值并写入硬件。所以你会发现如果设备树里时钟配错了做出来的波特率永远不对。接收路径上中断处理函数会读取中断状态寄存器确认是不是RX FIFO非空中断然后从数据寄存器连续读取报文内容把CAN ID、长度和数据组装成can_frame结构再封装成sk_buff交给网络协议栈。整个过程在中断上下文里执行所以处理速度非常快。我在实际调试中有个体会如果驱动加载了但ifconfig -a看不见can0接口十有八九是设备树节点没有被匹配上先在/sys/firmware/devicetree/base/目录下找找有没有你的节点没有就是设备树问题有的话再看看驱动是否编译进内核。通过这种方式可以快速定位软件层面的问题。4. 应用层SocketCAN实战与代码示例4.1 启用CAN接口与常用命令Linux下的CAN接口用起来像操作一张普通网卡但又有自己的特点。首先要安装can-utils工具包它提供了candump、cansend、cansend、canbusload等一系列调试命令。启用一个CAN接口的过程看起来很简单但顺序很重要ip link set can0 down ip link set can0 type can bitrate 500000 sample-point 0.75 ip link set can0 up第一行先把接口置为down状态这是很多新手会忽略的。刚上电的can0接口如果之前被配置过可能处于一个奇怪的状态必须先down再改参数。第二行配置CAN协议参数bitrate设为500kbps采样点设为75%。第三行把接口up起来这时候CAN控制器就开始监听总线了。执行完这三行命令后可以用ip -details link show can0查看接口状态如果看到“ERROR-ACTIVE”字样说明CAN控制器已经正常同步到总线上了可以开始通信。如果显示“ERROR-PASSIVE”或者“BUS-OFF”那就说明物理层有问题基本可以断定收发器、终端电阻或者波特率不匹配。用candump can0监听总线在另一个节点上周期性发报文如果能收到数据整个链路就算通了。发送报文也很简单cansend命令的格式是接口名加CAN ID加数据CAN ID和数据之间用#号分隔cansend can0 123#DEADBEEF cansend can0 1FF#0102030405060708上面第一条发了一帧标准帧ID是0x123数据是4个字节。第二条也是标准帧发了8字节数据。如果想发扩展帧可以在ID后面加个R比如cansend can0 1FFFFFFF#00这个就表示29位扩展ID。cansend还支持周期发送用-i参数指定间隔时间这个功能在调试总线负载时特别好用。4.2 写一个自己的CAN收发程序命令行工具能验证链路但真正做产品还是得写自己的应用代码。Linux下的SocketCAN编程比很多人想象中简单因为它用的就是标准socket接口会TCP编程的人学基本零成本。下面这段代码是我实际项目里用过的收发程序精简版逻辑很清楚适合拿来当模板。#include stdio.h #include stdlib.h #include string.h #include unistd.h #include fcntl.h #include sys/socket.h #include net/if.h #include sys/ioctl.h #include linux/can.h #include linux/can/raw.h int main(void) { int s; struct sockaddr_can addr; struct ifreq ifr; struct can_frame frame; int nbytes; // 1. 创建SocketCAN套接字 s socket(PF_CAN, SOCK_RAW, CAN_RAW); if (s 0) { perror(socket); return -1; } // 2. 指定要绑定的CAN接口 strcpy(ifr.ifr_name, can0); if (ioctl(s, SIOCGIFINDEX, ifr) 0) { perror(ioctl); close(s); return -1; } addr.can_family AF_CAN; addr.can_ifindex ifr.ifr_ifindex; // 3. 绑定套接字到can0 if (bind(s, (struct sockaddr *)addr, sizeof(addr)) 0) { perror(bind); close(s); return -1; } // 4. 发送一帧标准帧 frame.can_id 0x123; frame.can_dlc 4; frame.data[0] 0xDE; frame.data[1] 0xAD; frame.data[2] 0xBE; frame.data[3] 0xEF; nbytes write(s, frame, sizeof(frame)); if (nbytes ! sizeof(frame)) { perror(write); close(s); return -1; } printf(send: id0x%X dlc%d\n, frame.can_id, frame.can_dlc); // 5. 阻塞接收一帧 nbytes read(s, frame, sizeof(frame)); if (nbytes 0) { printf(recv: id0x%X dlc%d data, frame.can_id, frame.can_dlc); for (int i 0; i frame.can_dlc; i) printf(%02X , frame.data[i]); printf(\n); } close(s); return 0; }这段代码的结构值得拆开细讲。socket(PF_CAN, SOCK_RAW, CAN_RAW)创建原始CAN套接字PF_CAN是协议族SOCK_RAW表示接收所有CAN报文第三个参数CAN_RAW代表使用CAN_RAW协议。绑定之前一定要先通过ioctl拿到can0接口的ifindex索引这是Linux下所有网络接口编程的通用套路。发送报文时直接往socket里write一个struct can_frame结构体这个结构体在linux/can.h里定义字段里can_id存放CAN ID如果ID最高位是CAN_EFF_FLAG则表示29位扩展帧CAN_RTR_FLAG表示远程帧。接收同理read返回后直接解析结构体里的数据。要注意的是write和read操作的是同一个socket因此这个程序收发都会工作。在实际项目中接收数据如果不想阻塞程序主流程可以把这个socket设置成非阻塞模式或者用select/poll/epoll来监听再或者开一个独立线程专门做read然后把数据通过队列交给业务处理模块。CAN总线的特点是流量不可控接收侧必须要做成独立任务避免影响其他业务逻辑。4.3 用回环模式做离线自测设备装在没有其他CAN节点的环境里怎么验证链路答案是使用CAN控制器的回环模式。回环模式下控制器发送的报文不会上总线而是直接在内部绕回接收路径这相当于自己发给自己非常适合验证驱动和软件链路是否正常。启用回环模式也很简单ip link set can0 down ip link set can0 type can bitrate 500000 loopback on ip link set can0 up candump can0 cansend can0 123#DEADBEEF执行后candump如果能打印出ID为0x123的那帧报文就说明驱动接收路径是通的问题出在更下面的物理层。说句实在话做CAN调试尤其应该先测回环再上真实总线这个顺序能帮你省下大半天的排查时间。我遇到过一上来就接总线怎么调都不通的情况结果一测回环发现驱动完全没问题赶紧回头检查收发器和终端电阻几下就定位了。回环测试通过后记得关掉loopback用ip link set can0 down ip link set can0 type can loopback off恢复标准模式。否则后续接总线测试时发现数据能发能收但总线上别人就是看不见你的报文那准是回环开关忘关了。5. 调试经验与常见问题排查手册5.1 我踩过的那些坑从零到把Zynq的AXI-CAN跑通我前前后后踩过不少坑这里挑几个有代表性的说说给大家做个参照。第一个印象最深的是设备树中断号填错的问题。Vivado Block Design生成的地址映射和中断分配如果不仔细看连接关系很容易把中断号搞错。当时我在一个项目里配完设备树启动后ifconfig -a能看到can0up也没问题但cansend发送总是报错接收更是完全没动静。排查了半天最后用dmesg看内核日志才发现request_irq返回了-EINVAL。检查了设备树的中断号跟Vivado里生成的实际中断ID一对发现少了一位改过来就正常了。第二个是时钟频率引发的波特率漂移。Xilinx CAN IP核对参考时钟频率有严格要求我之前在一款板卡上用了PS的FCLK1输出100MHz作为CAN参考时钟设备树里也正确地引用了这个时钟但CAN总线上两台设备波特率明明是相同的500k就是通信不稳定错误帧比例很高。后来用示波器量CAN_TX引脚的波形发现一位的实际时间比500k对应的时间长了大约20%仔细一查是PetaLinux配置时钟时把FCLK1改成了80MHz设备树里写的还是100MHz驱动算分频系数的时候拿100MHz算而硬件实际跑在80MHz波特率自然就偏了。从此我养成一个习惯每次改完时钟配置后先cat /sys/kernel/debug/clk/clk_summary确认实际频率。第三个坑是收发器供电电压导致的通信异常。当时用了5V供电的CAN收发器但Zynq的PL引脚电平是3.3V虽然数据手册上说5V兼容但实际运行起来总线错误比较多摸一下收发器芯片还有点微热。最后在收发器输出端加了电平转换电路才彻底解决。所以硬件设计阶段电平匹配一定要想清楚不能想当然。5.2 典型问题速查表这里整理一份我在项目里遇到过的典型问题清单方便遇到类似现象时快速对照排查。现象可能原因检查与解决手段内核启动后看不到can0接口设备树节点没匹配/驱动未编译lsmod查驱动是否加载检查compatible字符串是否匹配查看/sys/firmware/devicetree/base下节点是否存在can0能up但发送报文报错中断配置错误/时钟未使能dmesg查看request_irq错误信息核对设备树interrupts字段与Vivado中断ID检查clocks属性是否指向正确FCLK回环测试正常但接总线不通收发器/终端电阻/波特率不匹配检查CANH/CANL是否接120Ω终端电阻用示波器量TX/RX波形确认总线两端波特率一致通信时好时坏错误帧较多物理层干扰/地电位差/采样点设置不合理使用隔离收发器优化采样点设置推荐75%检查线缆质量和走线长度高总线负载下丢帧RX FIFO深度不够/应用程序读取不及时在Vivado里加大接收FIFO深度确保应用用独立线程及时读取socket数据bus off错误错误累计过多检查收发器供电、终端电阻必要时配置bus-off恢复机制并在驱动层做自动恢复无法配置bitrate接口未down就修改参数先ip link set can0 down再执行type can bitrate配置5.3 调试工具使用心得调试CAN总线除了Linux命令行硬件上最好备一个USBCAN分析仪或者类似的CAN总线分析工具。这个投资非常值得因为当Zynq这边抓耳挠腮查问题时总线分析仪能直观告诉你报文有没有真的从Zynq发出来ID对不对数据对不对CRC有没有错。有一次我在调一个多节点总线仲裁问题总线分析仪直接显示了两个节点同时发同ID报文的冲突情况这要是光靠Zynq这端查根本无从下手。在Zynq这端dmesg是排查驱动问题的第一工具日志里如果出现can0 link up之类的信息说明基本通路没问题。candump -x能显示报文收发的时间戳分析时序非常有用。canbusload can0500000可以实时监控当前总线负载率做压力测试时用这个看接近满载还是有余量一目了然。还有一点如果发现设备树改了没生效确认你重新编译了image.ub并拷贝到SD卡Zynq启动时有些版本不会自动重读设备树这个低级错误我犯过一次。6. 应用场景扩展与后续方向6.1 多路CAN扩展与CAN FD切换一个AXI-CAN在Zynq上只能提供一路CAN通道有些设备需要同时接多路CAN总线比如车载网关要同时跟动力总线和车身总线通信。这种情况下在Vivado里添加多个AXI-CAN IP核分配不同的寄存器地址分别引出各自的中断到PS的GICLinux启动后会出现can0、can1等多个接口每条总线的波特率完全可以独立设置。唯一要注意的是多路CAN共享同一个参考时钟时如果它们的波特率要求不一样采样点设置要分别计算好。PL资源方面多路CAN只增加几千个LUT的使用量只要别同时加太多东西资源压力完全可控。CAN FD是更现代的CAN协议带宽比经典CAN高很多数据段最高可到8Mbps。Xilinx在新版驱动里对CAN FD也做了支持前提是硬件IP核要选支持CAN FD的版本。不过说实话Zynq-7000这个级别的方案搭配CAN FD除非业务确实需要大带宽否则经典CAN 2.0B在很多场景下已经够用了。这里不展开说细节方向提一嘴大家按需去查。6.2 与系统升级、传感采集等业务结合AXI-CAN在Zynq上打通之后它的价值不只是能通信而已而是给整个系统的业务能力加了一条腿。我自己在工业设备项目里就做过把CAN总线的固件升级功能跟Linux底层的在线升级流程整合到一起的方案Linux系统里跑一个升级服务进程从CAN总线上接收分包发送的固件镜像校验通过后写入Flash分区整个过程不需要工程师开箱拆设备远程就能完成固件更新。这一套流程结合起来产品运维成本能降不少。另外CAN总线经常跟传感器和执行器搭配使用Zynq的PL侧有丰富的IO资源可以用同一套AXI总线上再挂一个GPIO控制器或ADC采集IP核跟CAN数据一起在Linux应用层做融合处理。这样整个设备相当于一个多协议边缘控制器CAN负责跟底层设备通信Linux负责跑协议栈和业务逻辑再往外接个网口就能上云整体架构特别适合工业物联网边缘网关的场景。6.3 个人对这套方案的一点体会做了这么多年Zynq开发我最大的体会是Zynq这玩意儿最大的优势就是灵活但灵活的前提是你得把每一层的接口关系彻底搞清楚。AXI-CAN只是众多PL外设中的一个代表它的调试思路完全适用于GPIO、UART、SPI、以太网这些挂在AXI总线上的设备Vivado里配硬件、设备树里配软件、内核驱动做接口、应用层用通用框架。这套方法论一旦建立起来换什么外设都不慌。最后再分享一个小技巧如果板子上的CAN总线上什么都没有但你又想快速验证Linux侧的收发功能可以考虑在CANH和CANL之间直接焊一个120Ω电阻模拟单节点总线。CAN协议本身是支持单节点自发自收的只要终端电阻和收发器是好的Zynq这边就能正常工作。这个土办法在实验室里排除问题的时候特别好用接线简单问题定位快推荐大家试试。
返回列表