ARTICLE DETAIL

资讯详情

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

给APM32F072 USB-CAN卡刷入moonglow/kvaser开源固件完全指南

给APM32F072 USB-CAN卡刷入moonglow/kvaser开源固件完全指南 1. 先说结论为什么一个国产芯片的USB-CAN卡值得你这么折腾我玩USB-CAN分析仪已经好几年了从最初买的几十块钱的“裸板”到后来几千块的商用设备手里前前后后过了不下十块卡。但这个标题里涉及的东西——给一片APM32F072主控的USB-CAN卡刷入moonglow/kvaser开源固件——是我这几年折腾下来觉得最值回票价的玩法没有之一。先给还不清楚的朋友捋一下这几样东西到底是个啥。USB-CAN是USB转CAN总线的协议转换设备电脑通过USB口连上它就能直接收发CAN总线上的报文调试车载ECU、工业设备、机器人控制器都离不开它。APM32F072是极海半导体推出的一款Cortex-M0内核MCU和意法半导体的STM32F072管脚兼容、外设兼容度很高很多国产USB-CAN分析仪用的就是这颗芯片或者它的近亲STM32F072。而moonglow是Github上一个开源固件项目能让廉价的USB-CAN硬件跑起接近商用分析仪的固件功能kvaser则是瑞典一家老牌CAN总线工具厂商它的软件生态和驱动在行业内认可度很高moonglow项目的一个重要目标就是让低成本的国产硬件兼容kvaser的通信协议从而用上kvaser的Windows软件和SDK。说人话就是你有一块一百多块钱买来的USB-CAN小板内部芯片是APM32F072通过刷入一个开源固件可以让它被电脑识别成几千块钱的商用设备并且能跑商用的上位机软件。这事儿要是放几年前想都不敢想但现在开源社区把这条路彻底铺平了。这篇文章适合谁看第一类是手里正好有这类USB-CAN板子、想挖掘更多功能的人第二类是做嵌入式开发、需要多个CAN通道但又暂时不想买昂贵设备的人第三类是纯粹想研究固件移植、了解MCU内部Bootloader机制的人。全文会从硬件原理讲到刷机实操再到坑点排查手把手带你把这套流程走通。2. 硬件底子拆解APM32F072怎么就成了USB-CAN的“完美胚子”2.1 认识这块板子的核心主控、收发器、电源一个都别少要做USB-CAN分析仪主控芯片必须同时具备两个能力一是要有CAN控制器外设二是要有USB设备控制器。这两样缺一不可否则就得外挂芯片成本和复杂度都会上去。APM32F072这颗芯片恰好就是这个定位Cortex-M0内核主频48MHz内置了USB 2.0 Full-Speed设备控制器和一路CAN 2.0B控制器。和STM32F072相比虽然寄存器有些细微差异但引脚定义和整体架构几乎一致这意味着市面上大量为STM32F072写的USB-CAN开源方案理论上都可以通过适配移植到APM32上。除了主控板上还有一个CAN收发器芯片最常见的是TJA1050或者TJA1051它的作用是把MCU内部CAN控制器输出的差分信号转换成总线上的物理电平。有些便宜板子用的是国产兼容料比如SIT1050功能上没区别但需要注意供电电压是5V还是3.3V这会影响你在接线时的判断。电源部分同样不能小看。USB-CAN板子一般有两种供电方式一种是直接从USB的5V取电板上用一颗LDO降到3.3V给MCU供电另一种是板上有隔离电源模块CAN侧用单独的隔离电压常见的是B0505S这种小功率的DC-DC隔离模块。有隔离的板子抗干扰能力好很多在车上调试时不容易被共模干扰打挂价格自然也就贵一些。我之前拆过一块板子走线非常精简主控、晶振、收发器、LDO、接口全部加起来十几个元件。这种极简设计的板子反而很适合刷机研究因为变数少、问题容易排查。如果你拿到手的板子结构更复杂还带TVS管、共模电感、防静电芯片这些保护器件那就更好了刷机过程中不太容易因为静电或者接线失误把板子弄坏。2.2 Bootloader的秘密为什么“能刷机”本身就是一种设计很多朋友第一次听说可以给USB-CAN刷固件时第一反应是这玩意儿不是出厂就写死程序了吗怎么还能刷这里面的关键在于很多USB-CAN板子在出厂时就预置了一段Bootloader程序。Bootloader本身不干CAN的活儿它的作用是在上电时检查特定条件决定是进入固件升级模式还是直接跳转到用户应用程序。常见的进入Bootloader的方式有几种按住板上的按键再插USB上电短接BOOT0跳线后上电通过上位机软件发送特定命令重启进Bootloader检测到USB总线有特定请求时自动进入moonglow固件的刷入往往就要用到这种出厂Bootloader。因为Bootloader占据的是MCU的System Memory或Flash的起始区域它通过USB DFU协议或者自定义的CAN命令来接收新固件然后写入到应用区。这就意味着你不需要买ST-Link或者J-Link调试器一根USB线就能完成刷机门槛大幅降低。但也要提前打个预防针不是所有USB-CAN板子都有USB DFU引导功能。有些特别廉价的板子出厂只烧录了应用固件没有预置Bootloader或者Bootloader的通讯协议和moonglow项目预期的不一样。这种情况下你就得祭出SWD调试接口用调试器直接连芯片烧录了。所以在你下单买板子之前最好先查清楚手里的板子具体是什么型号、有没有公开的刷机教程别盲目照搬别人的步骤。2.3 兼容性分析Kvaser、PCAN等商用设备到底有什么“过人之处”聊到刷固件就绕不开一个问题凭什么一个开源固件就能让廉价硬件变身商用设备商用设备和廉价设备之间差距到底在哪里先看硬件层。商用CAN分析仪的核心器件选择其实并不神秘很多用的也是Cortex-M0/M3级别的MCU加CAN收发器单看物料成本并不高。但这几年用下来我发现商用设备的真正优势在软件生态和驱动稳定性上——比如kvaser的驱动支持非常完善Windows、Linux、macOS全平台覆盖还有CANopen、J1939、UDS等协议栈的SDK可以直接调用。这些软件层面的积累才是几千块差价的来源。moonglow这个开源项目思路很有意思它通过模拟kvaser的USB通讯协议让计算机端原本为kvaser硬件写的驱动和软件以为插上来的就是一块真正的kvaser设备。等于说开源固件在USB这一层“伪装”成了商用设备而上位机软件完全不需要改动。这有点类似打印机领域的“兼容墨盒”思路——硬件不同没关系接口协议对齐了就能无缝使用。这个方案能成立的前提是kvaser的USB协议格式被逆向分析得足够透彻。开源社区花了大量精力抓取、分析、复现了kvaser设备的USB描述符、端点配置、命令格式和应答机制。这里面很多细节非常微妙比如USB端点缓冲区大小、一次传输能携带多少条CAN报文、错误帧如何上报、时间戳是32位还是64位……任何一处对不上上位机可能就会报错或者干脆识别不了设备。当你了解这一层逻辑后就会明白刷固件其实是“站在巨人肩膀上”的活把别人逆向好的通信协议直接拿来用硬件本身只需要关心CAN收发性能就够了。3. 刷机前的准备工作工具、备份、环境一个都不能漏3.1 从零搭建刷机工作台你需要准备这些动手之前先把工具备齐不然刷到一半缺这缺那会非常难受。我建议按下面的清单准备每一件都有它的用途别嫌麻烦USB-CAN硬件板卡一块确认主控是APM32F072或STM32F072一根质量靠谱的Micro USB或Type-C数据线注意必须是带数据功能的不是纯充电线一台Windows电脑推荐Win10或Win11驱动兼容性最好ST-Link V2或者J-Link调试器备用万一块上没预置Bootloader就要靠它救砖万用表一块排查供电异常、判断板卡是否上电镊子、杜邦线若干短接跳线、飞线时用这里面最容易忽略的是数据线。我吃过好几次亏手边随便抓一根线插上去电脑一点反应都没有。后来用万用表一量发现那根线只有电源针脚数据针脚压根没接。所以建议大家固定一根专门用来刷机的数据线不要换来换去。软件环境方面基本就是三件套USB驱动工具如Zadig用于替换USB驱动、固件烧录工具STM32CubeProgrammer或者自制刷机脚本、以及moonglow源码编译工具链。3.2 固件备份这是刷机前最重要的一步没有之一很多人拿到板子第一件事就是直接刷入新固件结果刷完发现功能不对或者完全变砖想还原又找不到原厂固件只能干瞪眼。我一开始也是这样后来学乖了刷机前一定会先备份原始固件。备份方法取决于你的板子类型。如果板子上有SWD调试接口直接用ST-Link配合STM32CubeProgrammer选“Read Out”功能把整个Flash内容读出来存成bin文件。如果板子只能通过USB连接那备份的难度会高一些需要先确认板子的出厂Bootloader是否支持固件导出——大部分只支持写入不支持导出这时候你只能碰运气看网上有没有人分享同型号的原始固件。备份数据出来后妥善保存到网盘或者本地文件夹里标注好对应的板卡型号和版本。这个习惯救过我两次一次是刷了一个测试版固件导致USB枚举失败另一次是改配置时把CAN通道弄乱了都是靠恢复备份固件才让板子重新工作。所以无论你多急着想刷入新固件请一定先花五分钟做备份。3.3 认识你的板卡怎么确认具体型号和控制器版本市面上USB-CAN板卡型号五花八门但底层芯片就那么几种。刷机之前最好先把板卡彻底看清楚主要确认三点。第一看主控丝印。如果板子上芯片丝印清晰可以直观看到APM32F072或者STM32F072的字样。APM32F072的标志很好认通常是“APM32F072RBT6”或者“APM32F072CBT6”封装不同但flash大小一样都是128KB。第二看板卡有没有按键、跳线、测试点。很多可刷机的板卡都会预留一个BOOT按键方便用户进Bootloader如果你手头板子上有这个按键刷机就会非常方便。第三看PCB板上的版本丝印或厂商Logo有些厂商会把硬件版本号印在板上这个信息在查资料时非常有用。如果这些信息都不明确还有一个办法把USB插上电脑打开设备管理器看设备枚举出来的PID和VID。不同厂商的PID/VID不一样moonglow项目里通常会列出它支持的所有PID/VID列表你可以对照这个列表判断自己的板卡是否在支持范围内。3.4 为什么有人刷完没有反应先检查驱动和USB枚举状态当你把准备工作都做完了满怀信心地把USB插上电脑却发现设备管理器里什么都没有出现这时候别慌八成是驱动问题。Windows系统默认不会认识这种非标准的USB设备尤其是刷机之前设备还处于Bootloader模式下系统可能只会提示“未知USB设备”或者“设备描述符请求失败”。这时候需要用到Zadig工具把该设备的驱动手动替换为WinUSB或者libusb驱动。moonglow刷机脚本通常会依赖WinUSB来和硬件通信所以这个步骤躲不掉。Zadig用起来不难打开后选择目标设备在驱动列表里选WinUSB点击“Replace Driver”就行。但有一个坑是界面里可能同时列出多个设备你一定要确认选中的是USB-CAN那个设备别手滑把别的设备驱动给换了。如果在设备管理器里完全看不到设备那就把USB线拔了重插同时短按一下板上的复位键让设备重新枚举。还不行就换一个USB口尽量用电脑后置面板的USB口前置USB口供电不稳定偶尔会出现枚举失败。4. 编译固件并刷入手把手带你跑通整个流程4.1 获取源码从GitHub拉取moonglow项目moonglow的源码托管在GitHub上项目本身是基于libopencm3这个开源库开发的支持多种主控平台其中就包括F072系列。在拉取代码之前先确认你的电脑上已经安装了git、make、arm-none-eabi-gcc交叉编译工具链这些都是编译环境的基本要求。打开终端执行git clone https://github.com/linux-can/moonglow.git cd moonglow git submodule update --init --recursive第二行拉取子模块尤其重要因为libopencm3是作为子模块引用的如果漏了这步编译时会报找不到头文件的错误。整个项目拉下来后目录结构大致是src/固件主代码libopencm3/底层驱动库scripts/刷机脚本firmware/预编译固件或配置模板4.2 选择正确的目标板和配置文件moonglow项目支持多种硬件型号编译前需要通过Makefile参数指定目标板。常见的配置有make BOARDapm32f072cbt6或者如果你用的是STM32F072make BOARDstm32f072cbt6这里有个很容易踩的坑很多开源工程默认的BOARD是STM32F072如果你用APM32F072需要先确认Makefile里是否定义了对应的board target。有些版本的moonglow并未单独区分APM32F072直接用STM32F072的配置也能编译通过因为两者的外设寄存器地址基本一致但个别时钟配置参数可能不同。如果编出来的固件刷进去后USB无法正常工作大概率就是时钟树配置不一致导致的需要手动调整PLL参数。我自己的做法是编译前先看一眼Makefile里BOARD相关的宏定义确认时钟源是HSI还是HSE再对照APM32F072数据手册里推荐的48MHz时钟配置方案进行调整。4.3 编译从源码到可以烧录的bin文件编译过程本身不复杂无非是make命令。但环境问题可能会折磨人尤其是arm-none-eabi-gcc的版本太老或者太新都可能导致编译报错。我建议的编译流程是cd moonglow make BOARDapm32f072cbt6 clean make BOARDapm32f072cbt6编译顺利的话最终会在build/目录下生成三个文件一个.bin、一个.hex、一个.elf。其中.bin是最常用的烧录文件体积一般在几十KB左右。如果编译报错最常见的几类错误和解决办法是找不到libopencm3头文件说明子模块没拉全重新执行git submodule update --init --recursive编译器版本太老导致-fno-diagnostics-show-caret等参数不识别升级gcc-arm-none-eabi到最新稳定版报错说某个寄存器的宏定义不存在可能是这个版本的moonglow对F072支持不完整切换到master分支或者issue区推荐的稳定tag版本编译通过后不建议着急烧录先用文本编辑器查看一下生成的.bin文件大小如果大于90KB就要小心了APM32F072虽然有128KB flash但Bootloader或者出厂固件会占用掉一部分空间应用固件太大可能会覆盖Bootloader区导致刷完直接变砖。4.4 刷机实操进入Bootloader并写入新固件刷机方式有两种我分别讲一下大家根据自己手里的硬件灵活选择。方式一USB DFU刷机。这个方式需要有出厂Bootloader支持。操作流程是先拔掉USB线按住板上的按键如果有的话保持按住状态把USB插上电脑看到电脑提示新设备接入后松开按键。此时设备应该被枚举成一个DFU设备设备管理器里会出现“STM32 BOOTLOADER”或者类似的名称。接下来用STM32CubeProgrammer烧录STM32_Programmer_CLI.exe -c portUSB1 -w build/moonglow.bin 0x08000000 -v这里的0x08000000是应用固件的起始地址。如果顺利几秒钟之内就会提示烧录成功。刷完后拔掉USB重新插上设备会自动运行新的固件。方式二SWD调试器刷机。如果你手里的板子没有Bootloader或者Bootloader无法正常进入那就只能用ST-Link这类调试器直接刷了。连接方法很简单ST-Link的SWDIO、SWCLK、GND分别对应板子上的SWD测试点VCC可以不用接因为板子可以通过USB供电。连接后用STM32CubeProgrammer选ST-Link接口读取芯片ID然后再执行写入操作STM32_Programmer_CLI.exe -c portSWD modeunder-reset -w build/moonglow.bin 0x08000000 -vSWD刷机的可靠性比USB DFU更高因为不依赖出厂Bootloader是否存在也不受USB枚举状态影响。如果你手边有调试器我推荐优先用这种方式。4.5 修改配置参数的进阶技巧如何定义设备名、序列号、CAN速率刷完基本固件后的默认配置其实已经能用了但如果你想让它更像一个“自己的”设备moonglow支持通过源码中的配置项定制设备信息。在src/目录下有一个类似config.h的头文件里面定义了设备名称字符串、PID、VID、序列号格式等参数。比如#define USB_DEVICE_NAME My CAN Analyzer #define USB_VID 0x0c72 #define USB_PID 0x1301修改后重新编译烧录设备管理器里显示的就是你自定义的名字。这个功能对于设备量比较大的工作室或者实验环境非常有用免得每次都纠结插的到底是哪块板子。CAN速率的支持范围也挺宽常见的是125kbps、250kbps、500kbps、1Mbps这些都是上位机软件里动态配置的固件本身不需要针对每个速率单独编译。如果要修改默认定时器参数可以在src/can.c里调整波特率相关的分频系数但一般不建议动除非你是在做非标的低速总线调试。5. 刷完之后怎么确认成功不只看灯亮不亮5.1 USB枚举验证这一步能揭示绝大多数问题刷完固件之后第一步验证就是重新插上USB在电脑的设备管理器里看能否正确枚举。moonglow固件模拟的是kvaser设备所以正常枚举后设备管理器里应该出现一个“CANbus”或者“Kvaser”字样的设备并且不会带黄色感叹号。刚插上时Windows可能会尝试自动安装驱动如果你的系统里之前装过kvaser官方驱动这里经常能直接成功因为设备识别到的VID和PID和真正的kvaser设备一致。如果设备管理器里显示的还是“未知USB设备”那就要回溯排查了。最常见的原因是USB驱动没对用Zadig重新安装WinUSB驱动后重启再试其次是固件刷入的起始地址不对导致MCU跳转时压根没跑新固件再有就是APM32芯片的某些USB上拉电阻配置和STM32不完全一致这时候就需要改代码里的USB上拉控制引脚定义。设备管理器看到正常设备后接下来要确认的就是上位机软件能否正常打开。5.2 用kvaser官方软件验证功能打开CanKing的那一刻装好kvaser官方驱动后建议先用它的免费测试软件CanKing连接设备。打开CanKing如果固件模拟的kvaser设备被正常识别软件会显示一个CAN通道你可以在设置里选择不同的波特率。然后做一个最基本的回环测试把USB-CAN板子上的CANH接到另一个设备的CANHCANL接CANL再在CanKing里周期性发送一帧数据看对端能不能收到。没有对端设备的话可以把板子自身变成回环模式looback模式但这只能验证CAN控制器本身的工作状态测不了收发器。这里有个细节很多人会忽略CAN总线两端必须各有一个120Ω的终端电阻否则信号反射会导致通信不稳定。好多调试现场都是这个原因报错的人还以为固件有问题。拿万用表量一下CANH和CANL之间的阻值正常情况下应该在60Ω左右因为两侧各有一个120Ω电阻并联了。如果量出来是120Ω说明有一端的终端电阻没接。5.3 多通道板卡的特别注意事项通道顺序和映射关系有些USB-CAN板卡有双通道硬件上其实是主控芯片的两路CAN外设分别接了两路收发器。刷完固件后两个通道在软件里显示的编号和物理接口的对应关系需要确认清楚——很多时候通道0对应的是板子上标注为“CAN1”的那个接口但也有反过来的情况。我建议拿到新固件之后先做一次通道映射测试在通道0上发一个特定ID的报文看另一台设备从哪个物理接口收到数据记录下来后面用的时候就不会出现一直往错误通道上发数据的情况。5.4 指示灯状态与日志输出固件运行状态最直观的表征刷完固件的板子如果原厂固件和moonglow固件对LED灯的定义不一样你也别见怪。moonglow固件一般会在初始化完成后让LED闪几下然后进入空闲状态时保持常亮收发数据时LED闪烁频率会明显变化。如果板子上压根没有LED那也没关系通过上位机软件的收发包统计也能判断固件是否正常运行。CanKing这类软件会实时显示TX/RX计数器只要计数在跳动固件就是活着的。想进一步确认固件内部状态可以在编译时打开调试串口输出moonglow支持把日志信息从USART打印出来接一个USB转TTL小板就能看到详细日志包括USB枚举过程、CAN控制器初始化参数等。不过这个功能默认是关闭的需要在config.h里开启DEBUG_PRINT相关宏。6. 踩坑记录这些坑我几乎都替你踩过了6.1 刷完USB无响应设备管理器的“未知设备”问题这个是最常见的问题没有之一。现象是刷机过程报成功但重新插USB后系统只提示“Unknown Device”设备管理器里显示设备描述符请求失败。排查顺序是这样的先换一个USB口排除供电和接触问题然后用Zadig强行给这个未知设备装WinUSB驱动看能否恢复枚举都不行的话用万用表测量板子上3.3V电压是否正常如果电压偏低可能是板上LDO过载或者短路。最后再低概率怀疑固件本身刷坏了重新用SWD方式烧录一次烧录前先执行全片擦除。我自己的经验是这个问题的根源九成是驱动不是硬件也不是固件。Windows的USB驱动缓存机制偶尔会搞出一些莫名其妙的状态彻底卸载设备管理器里相关的“未知设备”条目后重新扫描硬件改动往往能解决。6.2 编译报错找不到libopencm3头文件这个问题在第一次拉取源码时就可能遇到。原因很明确子模块没有正确拉取。解决办法很简单rm -rf libopencm3 git submodule update --init --recursive如果你在拉取子模块时遇到网络问题导致拉取不完整也可以直接去libopencm3的GitHub仓库手动下载对应版本的源码放到目录里并重命名成libopencm3效果一样。6.3 APM32和STM32的时钟配置差异导致的USB不工作这是让我折腾最久的一个问题。APM32F072和STM32F072虽然管脚兼容、寄存器大体一致但在USB时钟配置上有细微差异。moonglow工程默认使用的是STM32的48MHz时钟生成配置直接刷到APM32上有可能出现USB设备枚举时好时坏的情况。现象很典型刷完后第一次插USB正常识别拔掉再插就识别不出来了反复插拔偶尔又正常。这种和插拔次数相关的诡异问题基本就是时钟不稳定导致的。解决方法是去APM32官方SDK里找到它的USB时钟初始化代码对比moonglow里的实现把PLL分频和倍频参数调整成APM32对应的数值。具体来说APM32F072的USB设备需要48MHz的USB时钟这个48MHz是通过PLL从HSE或者HSI倍频得到的检查PLL的倍频系数N与分频系数M是否产生了偏差即可发现问题所在。6.4 原厂驱动和新驱动冲突设备被识别成原厂型号如果你之前装过这款USB-CAN板的原厂驱动再刷moonglow固件后Windows可能会把新设备识别成原厂型号而不是期望的kvaser设备。这是因为Windows驱动库里缓存了旧设备的PID/VID对应关系。解决办法是去设备管理器里把该设备卸载同时勾选“删除此设备的驱动程序软件”然后拔掉USB重新插让系统重新识别并搜索匹配驱动。如果还不行就要去C:\Windows\System32\drivers里手动清理残留的旧驱动文件这一步需要管理员权限操作时小心别删到系统文件了。6.5 固件烧录后运行不稳定、报文丢帧严重刷机成功后如果出现报文丢帧、间歇性卡顿等现象先别怀疑固件问题。优先级最高的是CAN收发器的终端电阻和接线质量其次看USB线缆是否过长或者线材质量太差USB线材对高速通信的稳定性影响非常大。一般建议USB线不超过1米且尽量使用带磁环的线。排除掉物理因素后再考虑固件本身的中断优先级和缓冲区配置问题。moonglow工程默认参数在大多数场景下是够用的但如果你在高负载下长时间跑可以尝试调整src/目录下FIFO缓冲区的大小把发送缓冲区和接收缓冲区都改成深度更大的环形队列。刷完之后的一点心里话折腾USB-CAN刷机这个项目给我带来的最大收获其实不是省了那几千块设备钱而是把USB设备枚举、CAN控制器初始化、Bootloader机制、开源协议栈这些之前零散的知识串成了一条线。以前用CAN分析仪就像用黑盒出了问题只能找厂商现在固件是开源的上位机是开放的总线出了问题我能从链路层一步步往前查这种掌控感是花钱买不来的。如果你想在这个项目基础上继续延伸后面还可以做几件事一是把moonglow固件移植到APM32F303这种性能更强的芯片上获得更快的报文处理能力二是基于libopencm3自己写一个支持CANopen协议的固件让USB-CAN板变成一个小型的协议转换节点三是把固件刷入过程彻底脚本化做到一键备份、一键刷机、一键还原方便团队内部大规模部署设备。每一块USB-CAN板子背后其实都藏着一套完整的嵌入式系统设计思路刷机只是打开了这扇门。后面的路怎么走就看你自己的需求了。
返回列表