ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于APM32F072的USB-CAN分析仪制作与固件移植实战

基于APM32F072的USB-CAN分析仪制作与固件移植实战 不知道你们手头有没有那种“积灰开发板”——不是吃灰是那种当初想玩却没找到合适项目、一直躺抽屉里的板子。前段时间我翻出一块APM32F072核心板原本计划做个小控制器后来看到GitHub上moonglow这个开源USB-CAN固件项目灵光一闪能不能把它刷进去变成一台正经的USB-CAN分析仪试下来还真的可行而且不止moonglow另一套kvaser兼容固件也能跑。今天就把整个移植过程、硬件方案和踩坑经验整理出来给想用低成本方式上手CAN总线调试的朋友一个参考。简单说这个项目就是把APM32F072这颗国产Cortex-M0芯片做成USB转CAN的硬件再通过moonglow或kvaser兼容固件让电脑上的PCAN-View、Kvaser CanKing这类软件直接识别它变成一个几十块钱的CAN报文分析工具。适合搞车载电子、工业控制、机器人调试的开发者也适合刚接触CAN总线、不想一上来就花几百上千买品牌分析仪的学生和爱好者。整个过程涉及USB协议栈、CAN控制器驱动、固件编译和硬件设计一次玩下来能学到不少东西。1. 项目定位APM32F072为什么适合做USB-CAN分析仪1.1 USB-CAN分析仪在调试中的作用CAN总线在车载、工控、医疗器械这些领域几乎是无处不在。两根差分线CAN_H和CAN_L串联起各个节点波特率从125kbps到1Mbps不等。调试的时候最常见的需求就是“看一眼总线上到底在传什么”——哪个节点发了什么ID、数据对不对、有没有错误帧。这时候USB-CAN分析仪就是刚需。品牌分析仪的功能确实强但价格也很感人。我印象中某进口品牌的单通道USB-CAN要两三千国产主流品牌也要几百块。对于学生和刚入门的人来说这个价格有点劝退。而开源的固件方案配合一颗带USB和CAN外设的MCU就能把硬件成本压到几十块钱功能上收发报文、看错误帧、录数据完全够用。1.2 APM32F072这颗芯片有什么特别的地方APM32F072是极海半导体推出的Cortex-M0 MCU最吸引人的一点是它和意法半导体的STM32F072做到了pin-to-pin兼容外围电路基本可以照搬。片上同时集成了USB 2.0 Full Speed控制器和CAN 2.0B控制器这两个外设正好是USB-CAN分析仪的核心构成。我用的型号是APM32F072CB主频48MHz64KB Flash16KB SRAM。跑一个USB CDC CAN收发的固件资源绰绰有余。网上绝大多数开源USB-CAN固件都是基于STM32F072开发的这就有个先天优势代码可以直接拿过来适配不用从零写协议栈。顺便说一句APM32F072的价格和供货在国产芯片里都算友好。自己做板子玩就算焊坏一两片也不心疼。1.3 moonglow与kvaser兼容固件选哪个更好这两个固件解决的是同一个问题让MCU被电脑上的CAN分析软件识别。但它们的协议方向不同。moonglow固件兼容的是CANtact和PCAN协议刷完之后PCAN-View可以直接识别不需要额外的驱动适配。PCAN-View是PEAK公司提供的免费软件功能简单但够用看报文、发报文都很方便。kvaser兼容固件走的是Kvaser Leaf硬件协议。刷上之后电脑会把它识别成Kvaser设备然后就能配合Kvaser CanKing、Kvaser Database Editor这些官方软件使用。Kvaser的软件生态比PCAN更丰富支持CANopen、UDS等高层协议的插件。我的建议是如果你主要是看报文、发报文用moonglow配PCAN-View就够了软件简单、稳定。如果想折腾更上层的东西比如CANopen、UDS诊断选kvaser兼容固件能用的工具更多。两套固件的移植思路其实是互通的把一套跑通了另一套就是改改配置的事。2. 硬件方案搭一个能跑固件的USB-CAN最小系统2.1 电源、晶振和复位最容易被忽略的三件事很多人画板子喜欢把精力放在USB和CAN接口上结果忽略了最小系统的“三件套”最后板子不工作还找不到原因。我这次用的是现成的APM32F072核心板三件套厂家已经帮你搞定了但如果你是打算自己画板三个点必须注意。电源方面APM32F072的工作电压是2.0V到3.6V典型3.3V。USB-CAN分析仪一般通过USB取电USB口的VBUS是5V所以板子上要有一个3.3V的LDO。我用过AMS1117-3.3便宜够用注意输入输出电容别省。另外如果CAN收发器用的是5V供电的型号还需要一颗独立的5V电源供给收发器的VCC脚3.3V和5V的电源域要分清楚。晶振方面USB要求48MHz的时钟精度所以必须用外部晶振。STM32F072的标准做法是用8MHz晶振经过PLL倍频到48MHz。APM32F072的时钟树和STM32F072一样直接照搬。晶振的两个负载电容一般是15pF到22pF具体看晶振规格书。这里不能图省事用内部RC振荡器经验是内部时钟的精度跑USB大概率会枚举失败。复位电路就简单了一个10k上拉电阻加一个100nF电容接到NRST脚就行。如果用了核心板这些都已经处理好不用操心。2.2 USB接口部分D/D-怎么接才能枚举成功USB Full Speed设备在电气上有一条硬性要求D线上要有1.5kΩ上拉电阻主机才能识别到设备插入。STM32F072这颗芯片比较特殊D上拉是内置的由USB IP内部的DPPU控制。APM32F072的USB控制器同样实现了这个功能所以硬件上不需要外加上拉电阻。但有两个细节要注意。第一D和D-线上最好各串一个22Ω的电阻位置靠近MCU引脚。这个电阻作用有两个抑制信号振铃以及在USB线出现静电时先扛一下。第二如果板子空间允许在VBUS和D/D-附近加一颗USBLC6-2这样的TVS阵列静电防护效果会好很多。我自己有块板子没加防护插拔几次后USB枚举就开始不稳定加TVS之后再没出过类似问题。另外USB座子的外壳地不要悬空常规做法是串一个1MΩ电阻接到GND再并一个10nF电容到GND这样既能泄放静电又不会形成地环路。2.3 CAN收发器选型与总线保护APM32F072内部集成了CAN协议控制器但引脚出来的是TX/RX数字信号电平只有3.3V不能直接怼到CAN总线上。中间必须加一颗CAN收发器把数字信号转换成CAN_H和CAN_L差分信号同时完成电平转换和总线驱动。选型上我建议从这两颗里挑SN65HVD2303.3V供电适合和MCU共用电源功耗低TJA10505V供电驱动能力强抗干扰更好。如果你的MCU是3.3VTJA1050的TXD/RXD引脚也是兼容3.3V逻辑的可以直接连。我用的是TJA1050因为手头存货多实测和APM32F072直连没有问题。收发器到总线之间标准做法是串两个30Ω的共模电感或者直接短接。终端电阻方面如果只是两个设备短距离点对点调试120Ω终端电阻可以省如果是接入真实总线环境必须在总线两端各接一个120Ω电阻。自制分析仪一般默认不焊终端电阻把位置留出来需要的时候再焊上灵活性更高。2.4 用开发板还是自己画PCB如果你只是想验证固件能不能跑强烈建议直接买一块APM32F072核心板再把CAN收发器模块插上去用杜邦线连。核心板已经把USB座、晶振、电源都做好了你要做的只是确认CAN_TX和CAN_RX对应哪两个引脚然后飞线到收发器模块。但我这次是希望把它做成一个能长久用的工具所以自己画了PCB。尺寸控制在银行卡大小一边是USB Type-C座一边是CAN接口端子中间是MCU和收发器。两层板就能搞定注意USB差分线尽量等长、走线短一点CAN的差分线也同理。GPIO全部引出万一以后想扩展还能用。画板建议把BOOT0引脚的跳线或拨码也做出来调试时方便切换启动模式。我第一次画的时候把这个漏了结果每次想进DFU模式都要飞线非常痛苦。3. 固件准备拉取源码、搭建编译环境、核对芯片差异3.1 源码仓库和工具链选择moonglow固件的源码在GitHub上可以找到仓库不大结构很清晰。根目录下有README说明了硬件适配、编译方法和烧录方式。kvaser兼容固件的仓库同样在GitHub上搜索关键词就能找到。工具链我推荐两条路。第一条是Linux环境下的arm-none-eabi-gcc加CMake命令行编译干净利落。第二条是STM32CubeIDE图形化界面内置了编译器和烧录工具适合不熟悉命令行的人。我自己习惯用命令行因为要反复修改配置重新编译脚本一键搞定比鼠标点来点去效率高。如果是Windows环境建议装一个WSL或者Git Bash然后在里面跑Linux工具链。需要注意的一点是仓库里的HAL库版本可能比较老新版arm-none-eabi-gcc编译的时候可能会出现警告或错误我遇到的是头文件里某个宏未定义手动加一个即可解决。3.2 从STM32F072到APM32F072需要改哪些地方按道理说APM32F072兼容STM32F072固件应该能直接跑。但实际移植的时候有几个坑我逐个说。第一芯片ID检查。部分固件在初始化时会读取STM32的Device ID用来确认芯片型号。ST的F072Device ID是0x442而APM32F072的Device ID不一定一样。我刷进去之后发现程序卡死在初始化加了串口打印才发现是ID检查不过。解决办法简单粗暴把ID检查的代码注释掉或者根据APM32F072的实际ID值改判断条件。第二HAL库的时钟配置。APM32F072可以用ST的HAL库跑但极海官方有自己适配的HAL库叫APM32F0xx HAL接口基本兼容。如果你用的是moonglow仓库里自带的ST HAL库一般没问题只要注意RCC的时钟源配置。HSE_VALUE这个宏要确认是80000008MHz因为有的板子焊的是12MHz晶振改一下这个宏就能修正所有PLL计算。第三USB描述符。这个严格说起来不是芯片差异而是不同固件默认的VID/PID不同。moonglow默认的VID/PID和PCAN官方设备可能保持一致这样PCAN-View才能识别。如果刷完电脑识别出设备但软件不认就需要看一下固件里的usb_desc.c文件确认VID/PID配置是否正确。3.3 固件关键配置项VID/PID、波特率和协议固件源码里有两个配置文件值得花时间过一遍usb_desc.c和board.h或者类似的命名。usb_desc.c里面定义USB描述符包括厂商ID、产品ID、字符串描述符等。board.h或者config.h里面定义了CAN外设的引脚以及默认波特率等参数。CAN引脚映射这块moonglow默认使用的是STM32F072的CAN0引脚PA11/CAN_RXPA12/CAN_TX。APM32F072的引脚定义和STM32F072一致所以不用改。但如果你用的是其他开发板引脚被占用就要在board.h里改成重映射。F072的CAN引脚可以重映射到PB8/PB9改起来也不麻烦。波特率方面固件默认一般是500kbps但PCAN-View连接时可以选择波特率所以不一定要在固件里改死。需要注意的是如果固件实现了自动波特率检测那就不用关心如果没有默认值和你要调试的总线波特率不一致就会一直报错。调试时建议先用默认500k跑通了再试其他速率。4. 烧录和首次上电从SWD刷入到PC识别4.1 三种烧录方式对比给APM32F072烧录固件常见的有三种方式SWD、DFU、UART ISP。SWD是最直接的方式。一个ST-Link或者J-Link接上SWDIO、SWCLK、GND、3V3四个脚直接用STM32CubeProgrammer烧录。这个方式不依赖芯片里的任何bootloader即使固件刷死了也能救回来所以我第一次刷机用SWD。DFU方式是USB Device Firmware Upgrade芯片出厂时自带USB bootloader通过BOOT0引脚进入系统存储器然后用USB连接电脑用STM32CubeProgrammer的USB模式烧录。这种方式不需要下载器但前提是板子的USB口能工作。APM32F072同样支持DFU极海官方有对应的驱动和工具。UART ISP是用USART1的bootloader通过串口烧录速度比较慢我基本不推荐除非手头既没有下载器也没有USB连接条件。4.2 SWD刷机实操过程我这次用的ST-Link V2在STM32CubeProgrammer里选择ST-LINK连接方式SWD频率设为4MHz。连接之前先确认板子供电正常ST-Link和目标板共地。连接成功后CubeProgrammer会读出芯片型号和Flash容量。如果型号显示正常说明SWD链路没问题。然后选择固件生成的hex文件点击下载。整个过程十几秒。下载完成后把目标板重新上电程序就开始运行了。这里有个小建议刷机之前先把复位引脚通过ST-Link连好。如果固件初始化有问题跑飞了至少能用复位控制让它停在正确位置。我遇到过固件里开了看门狗导致调试器连接不上的情况用复位拉低再点连接成功率会高很多。4.3 首次上电和驱动安装刷完moonglow固件把USB线插到电脑上。第一次插上Windows设备管理器里会出现一个未知设备设备描述符请求会成功但驱动还没装。moonglow固件用的描述符和PCAN官方设备一致所以直接去PEAK官网下载PCAN驱动安装完后设备管理器里会多出一个PCAN-View的接口设备。如果是kvaser兼容固件需要安装Kvaser的驱动。Kvaser官方驱动默认只认自家设备对于第三方兼容固件通常需要手动更新驱动选择“让我从计算机上的可用驱动程序列表中选取”然后指向Kvaser驱动目录强制安装。Windows 10/11 64位系统下如果驱动没有数字签名需要先禁用驱动程序强制签名再安装具体步骤是设置-系统-恢复-高级启动重启后按7禁用驱动签名。装完驱动打开Kvaser CanKing就能看到设备。如果插上USB后设备管理器连未知设备都没有那问题基本出在硬件侧USB线上拉、晶振、D/D-焊接挨个排查。5. 实际测试连接CAN总线收发报文5.1 环回测试先证明单片机自己没问题固件跑起来之后先做环回Loopback测试验证CAN控制器和固件协议栈工作正常。环回模式不需要外部总线CAN控制器的TX输出会在内部直接回送到RX输入自己发自己收。moonglow固件里如果默认没有开启环回模式可以通过CAN控制器的寄存器打开CAN-BTR寄存器里的SLKM位Silent Loopback Mode或者Normal Loopback Mode要看具体使用的是哪种模式。我测试时在程序初始化里临时把CAN外设配置成Loopback然后打开PCAN-View选择设备设置波特率500kbps点Online然后在发送窗口发一帧标准ID 0x123数据0x11 0x22 0x33马上就能在接收列表里看到自己发的那帧。看到这帧说明MCU的CAN收发、固件的USB转CAN逻辑、PC软件识别整条链路都通了。如果不能收到先别急着怀疑硬件检查固件里是否真的打开了中断和FIFO接收很多开源固件默认只处理发送接收路径需要确认一下。5.2 双节点收发用真实总线验证环回测试只能说明内部通路没问题实际使用场景还要接外部总线。我把自制的USB-CAN分析仪接到一个STM32F103的CAN节点上节点程序循环发送0x100和0x200两帧报文每帧8个字节间隔100ms。连接方式很简单分析仪的CAN_H接STM32节点的CAN_HCAN_L接CAN_L两个设备之间距离很短我没有接终端电阻。上电后PCAN-View在Online状态下马上就能收到两个ID的报文数据内容和我写在STM32里的完全一致。反过来在PCAN-View里发送一帧0x300STM32节点也能通过串口打印输出接收到的数据。这个测试验证了两件事收发器芯片的电气转换正确波特率匹配。如果你在PCAN-View里设置了错误的波特率CAN控制器会报出大量的Error Passive或Bus Off状态报文窗口里会出现红叉。这时候把波特率改对或者看看总线有没有接好就行。真实总线上调试时还要注意一点如果总线上只有两个节点而且没有一个节点在接收时回ACK发送方会一直重发帧看起来好像是总线拥堵。CAN协议要求接收节点在帧末尾回送ACK位如果总线上只有发送节点和你的分析仪分析仪作为接收方是会回ACK的所以这个场景没问题。5.3 从固件差分升级聊到后续功能扩展这个项目跑通之后我一直在想怎么让维护更方便。每次改了固件都要拿ST-Link重新烧录在桌面上操作还行但如果是装到设备里做嵌入式调试拆壳接下载器就很麻烦。于是我把目光放在了固件更新机制上正好看到一个开源项目在做固件差分升级思路很有意思。简单说差分升级就是先给固件分成两个区Bootloader区和App区。Bootloader负责USB的DFU协议App区跑USB-CAN应用。每次升级时电脑端先把旧固件和新固件的差异算出来只把差异部分通过USB发到设备Bootloader收到后用补丁方式合并到App区最后跳转执行。相比每次全量更新几十KB的固件差分升级能省下不少传输时间尤其适合USB传输不稳定或者后台更新的场景。在APM32F072上做这种事情Flash资源也够用。64KB的FlashBootloader留8KBApp区留下50多KB固件本身一般十几KB有充足的空间。唯一的代价是跳转时要重新配置时钟和中断向量表这属于嵌入式开发的常规操作网上资料很多。如果你想让这个USB-CAN工具更好玩很推荐试着加一版差分升级Bootloader进去。6. 踩坑记录常见问题与排查经验6.1 上电后USB无法枚举的排查USB设备插上电脑后如果设备管理器一点反应都没有按照我的经验优先级是这样的先查电源再查晶振最后查USB线序。电源问题最直接用万用表量一下MCU的VDD是否为3.3V如果板子用的是USB的5V经过LDO供电量LDO输出。有时候LDO的使能脚没接对输出就是0V。晶振问题稍微隐蔽一点可以量OSC_IN和OSC_OUT引脚的波形正常情况下应该看到8MHz的正弦波形幅度不大但很规整。如果没有波形十有八九是晶振虚焊或者负载电容不匹配。USB线序问题也有过Type-C座子焊反了或者D/D-两条线接翻了就会出现只有供电没有枚举。还有一个容易忽略的APM32F072的USB模块需要48MHz时钟如果固件配置的RCC时钟是错的USB模块的时钟频率可能是8MHz或者别的值USB协议对时钟精度要求很高这种情况设备管理器会出现“无法识别的USB设备”。遇到这种情况仔细检查HSE_VALUE和PLL配置。6.2 收不到CAN报文的几个原因如果USB枚举和软件识别都正常但总线上就是看不到报文按我这次调试的经验先别怀疑固件大概率是这三个原因。第一CAN_H和CAN_L接反了。我用万用表量过总线空闲时CAN_H和CAN_L都是2.5V看起来一样但实际上差值决定显性位接反之后接收端完全解不出有效电平。两个设备对接时交换CAN_H和CAN_L就能排除。第二波特率不一致。PCAN-View连接时设置的波特率必须和分析仪所在总线的波特率完全一致。CAN协议里波特率匹配是硬约束差一点就会产生位错误节点会不断重发最终进Bus Off。建议先用设备已知的正确波特率测试例如用CANscope这类工具抓一下总线隐性/显性位的宽度推算波特率。第三只有一个节点在总线上且没有终端电阻。CAN协议中帧末尾的ACK位需要接收节点应答如果总线上没有第二个节点发送节点会一直重发普通分析仪软件有时会把这种重发显示成错误帧。单节点调试时应该用另一个节点配合或者把分析仪配置成Loopback模式做自测。6.3 长时间运行稳定性问题自制的USB-CAN分析仪最怕的就是长时间挂机跑着跑着软件卡死或者设备从电脑上掉了。这里有两个典型的坑。一个是USB CDC缓冲区的管理。开源固件里USB发送缓冲区和CAN接收队列如果不设置互斥或者队列长度不够高速CAN报文灌进来时就会丢帧甚至死机。我跑的某版固件默认CAN接收FIFO只有16帧1Mbps波特率下总线繁忙时很容易溢出。解决办法是把FIFO深度改到64或128同时把USB CDC的发送缓冲加大到512字节。改完之后长时间连续收包再没出过问题。另一个是防电脑睡眠和USB休眠。Windows的USB选择性挂起策略会在一段时间无活动后给设备发送挂起命令有些固件没有处理REMOTE_WAKEUP设备就再起不来了。解决方案有两个一是Windows里关掉USB选择性挂起二是在固件里正确处理SET_FEATURE(DEVICE_REMOTE_WAKEUP)或者干脆在描述符里不声明远程唤醒能力。我就是直接在设备管理器里把“允许计算机关闭此设备以节约电源”的勾选去掉省事且有效。6.4 几个必须记住的工程经验最后整理几条纯经验性质的建议都是我亲手焊板子、刷固件、调试之后总结出来的常规文档里不会写这么细。第一APM32F072的CAN控制器和STM32F072的bxCAN基本一致但寄存器地址和中断号可能存在细微差异。如果你在移植过程中发现某个CAN中断不触发去查一下启动文件startup_apm32f0xx.s里的中断向量表确认CAN_IRQn的中断处理函数是否和固件源码里定义的一致。我的固件里用的是USBD_CAN_RX_IRQHandler这种命名得和启动文件对上才行。第二自制PCB时CAN收发器的VCC和GND之间一定要放一个100nF的陶瓷电容靠近供电脚。这个电容的作用是吸收收发器在总线驱动瞬间产生的电流尖峰不加的话在2Mbps高速率下会出现偶发的位错误。同理MCU的每个电源引脚都要有去耦电容别只用板子上的一个大电容糊弄。第三如果你在Windows上装完PCAN驱动后软件还是找不到设备检查一下USB线的质量。USB Full Speed对线材要求不算高但劣质线缆上压降大设备电压不足就无法完成枚举。我遇到过一根实际只有供电线、没有数据线的“充电线”插上之后设备管理器毫无反应换了根正规数据线立刻正常。这个排查起来最容易也最容易被忽略。最后说点个人体会。这个USB-CAN项目技术上没有太高深的东西但把硬件设计、固件移植、上位机联调都串起来了一次性补全了我对USB协议栈、CAN控制器底层和国产MCU兼容性的理解。APM32F072在这类中小规模应用上表现超出预期稳定性也在线最关键的是成本实在低焊坏或者刷死都不心疼。以后调试CAN总线我都是直接掏出自制的这个工具便宜不怕丢真弄坏了再刷一遍固件就行。如果你手头也有一块积灰的F072板子不妨按这个思路试一下说不定也能捣鼓出一个顺手的小工具。
返回列表