
我板子呢这大概是我过去一年最常对终端喊的一句话。不是真的丢了板子——它就在桌上电源灯亮着Windows设备管理器里也认得好好的但WSL里的lsusb干干净净一条USB设备都看不见。这篇文章是这个系列的第7篇前几篇我们把工具链、工程结构、C代码都捋顺了这篇专门解决最后一步怎么在WSL里直接烧录STM32开发板。会涉及全流程的USB设备重定向配置、OpenOCD的烧录命令、ST-Link之外的两种备选方案以及一份板子失联排查手册。适合每天在WSL里写嵌入式代码、却总在烧录环节被逼回Windows图形界面的人。1. 与其切回Windows不如把USB通路打通1.1 我的开发环境长什么样先交代一下我工作的基本盘。代码编辑在VS Code里编译全部在WSL里完成CMake加GNU嵌入式工具链工程目录也放在WSL的文件系统里。写完代码直接在终端跑make产出firmware.elf然后呢然后就卡住了。Windows下那些烧录软件我当然能用但每次板子这一侧要打开另一个图形工具、换个窗口、拖文件进去、点烧录、等进度条整个过程跟WSL的终端工作流完全割裂。后来我给自己定的目标很明确开一个终端编译、烧录、看串口日志最好都在同一个WSL会话里完成。这样不仅省事还能把整个流程脚本化后面做自动化校验、批量烧录也方便。为了这个目标WSL里的USB访问就成了必须翻过去的第一座山。1.2 WSL2的USB盲区到底是怎么回事很多人第一次踩坑的时候不知道原因。WSL1和WSL2的架构完全不同WSL1是系统调用翻译层对设备访问的处理跟Windows共享得比较多WSL2实际上跑在一个轻量虚拟机里有独立的内核宿主机Windows能看到的USB设备虚拟机内部默认一个都看不到。这就是我板子呢这句话最根本的技术来源。既然WSL2是虚拟机那解决思路也很明确——把USB设备从宿主机转发进虚拟机。目前最成熟的方案就是usbipd-win它利用usbip协议把Windows上的USB设备共享给WSL2。听起来复杂用起来其实比想象中简单真正的坑都藏在配置细节里下面一节我会把每一步掰开讲。2. 让WSL看见板子的完整配置2.1 Windows端安装usbipd-win并暴露设备先确认你的WSL是WSL2wsl -l -v看一下发行版版本如果是VERSION 1就先用wsl --set-version 发行版名称 2转一下。WSL1在这套方案下表现不太稳定不建议折腾。然后在Windows端安装usbipd-win。最省事的方式是winget install usbipd装完后用管理员权限打开PowerShell先看看系统识别了哪些USB设备usbipd list输出里会列出所有当前连接的USB设备找到你的ST-Link注意记下BUSID比如3-2这样的格式。接下来用bind命令把设备暴露出来usbipd bind --busid 3-2这里我要特别强调bind这一步很容易被忽略但跳过它直接attach系统会报device is not shared之类的错误。bind的作用是把设备与usbipd服务绑定让它可以被共享这不是一次性的临时操作。设备重新插拔之后这个绑定关系有可能会失效需要重新bind这也是我后面排查时的高频检查点。2.2 WSL端装上usbip让内核认领设备设备在Windows侧准备好之后把设备attach进WSLusbipd attach --wsl --busid 3-2这条命令执行的时候Windows端会把USB设备推送给指定的WSL发行版。但这里有一个前置条件很容易踩坑WSL里必须装好了用户态的usbip命令否则attach可能会静默失败或者报一堆看不懂的内核错误。提前把工具装上sudo apt install linux-tools-generic usbutils装好之后再执行attach然后回到WSL里确认一下lsusb如果看到类似ID 0483:3748这样的条目说明ST-Link已经成功进入WSL板子看见了。这一步是整个烧录流程的地基后面OpenOCD能不能碰到芯片全靠这里通不通。2.3 权限与udev规则最容易被忽略的一步设备进来了但它现在默认属于root。你直接运行OpenOCD大概率会碰到权限错误。两条路可以走第一条每次都sudo openocd简单但很烦而且sudo环境下PATH和配置容易出幺蛾子第二条写udev规则让普通用户也能访问设备节点。在WSL里创建/etc/udev/rules.d/99-stlink.rules内容类似这样SUBSYSTEMusb, ATTR{idVendor}0483, ATTR{idProduct}3748, MODE666然后重新加载规则sudo udevadm control --reload-rules sudo udevadm trigger这里有个WSL特有的细节旧的WSL默认不跑systemd而udev规则依附于systemd的基础设施。新版WSL可以在/etc/wsl.conf里加systemdtrue来启用然后wsl --shutdown重启WSL生效。如果你不想动systemd最简单的临时办法就是sudo chmod 666 /dev/bus/usb/...先顶一下但以我的个人经验该上systemd就上不光是udev后面很多开发相关守护进程的工作流都会方便很多。3. 用OpenOCD完成一次真正的烧录3.1 为什么选OpenOCD而不是图形化工具USB通路打通之后烧录工具我最推荐OpenOCD。原因很简单它能在纯命令行环境下工作跟你WSL的编译-烧录-看日志全终端流程无缝衔接它同时支持JTAG和SWD两种调试协议ST-Link、J-Link、CMSIS-DAP这些常见调试器都认脚本化也非常顺手一条命令就能完成擦除、烧录、校验、复位整套动作。当然芯片原厂也有自己的图形化工具和CLI工具在WSL里跑CLI版本也可以很多用惯图形界面的同事更倾向那边。不过OpenOCD胜在开源、灵活、可定制而且跟我后面要说的排查思路配合得最好——日志清晰、报错直接、配置透明。3.2 烧录配置与命令拆解OpenOCD的启动参数其实由三部分组成调试器接口配置、目标芯片配置、要执行的动作。最典型的烧录命令长这样openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c program build/firmware.elf verify reset exit拆开看每一段-f interface/stlink.cfg告诉OpenOCD用的调试器是ST-Link-f target/stm32f4x.cfg声明目标芯片型号我这边用的是某系列芯片对应配置文件是stm32f4x.cfg你换成自己芯片对应的文件即可-c program ... verify reset exitprogram代表烧录verify是烧录完成后校验reset是复位重启exit是完成后退出OpenOCD进程。第一次跑这个命令如果看到** Programming Started **和** Verify Started **两行输出基本就成了。烧录完成后开发板会自动复位开始跑你的固件。整个过程十几秒比图形化工具省事太多。3.3 从编译产物到开发板跑起来一个最小示例我习惯在Makefile里加一个烧录目标把OpenOCD封装进去这样以后只需要敲一行make flash对应的Makefile片段大概是这样flash: firmware.elf openocd -f interface/stlink.cfg -f target/stm32f4x.cfg \ -c program $ verify reset exit如果烧录时经常带一堆额外参数更好的做法是单独维护一个board.cfg把通用配置固化进去。比如source [find interface/stlink.cfg] source [find target/stm32f4x.cfg] transport select swd adapter speed 4000然后把烧录命令简化为openocd -f board.cfg -c program build/firmware.elf verify reset exit把配置固化成文件最大的好处是换电脑、换环境都能一键复现不用每次回忆那一长串参数。我强烈建议把board.cfg纳入版本管理跟着工程代码一起走。4. 没有ST-Link串口ISP与DFU就是备胎方案4.1 串口ISP烧录USB转TTL方案的完整命令不是所有时候手边都有ST-Link。比如出差只带了一块板子和一个USB转TTL模块这种时候就得靠芯片内置的Bootloader。STM32出厂时ROM里有一段引导程序只要把BOOT0引脚拉高再复位芯片就会进入系统Bootloader模式这时候用串口就能刷固件。先把USB转TTL模块通过usbipd attach进WSL然后确认串口设备节点ls /dev/ttyUSB0如果你用的是ST-Link自带的虚拟串口设备节点一般是/dev/ttyACM0注意区分。权限不够就加udev规则或者用sudo chmod 666 /dev/ttyUSB0临时处理。然后安装串口烧录工具sudo apt install stm32flash烧录命令stm32flash -w build/firmware.bin -v -g 0x0 /dev/ttyUSB0这里说一下参数含义-w指定要写入的固件文件-v烧录后校验-g 0x0表示烧完从地址0启动程序。不加-g的话烧完不会自动运行适合你还需要继续操作的时候。千万记得接线顺序TX接RXRX接TXGND共地别接反了接反屏幕上只会出现一堆乱码或者干脆没反应。4.2 DFU烧录内置Bootloader的另一种玩法除了串口ISP很多STM32芯片还支持USB DFU方式烧录。这种方式连USB转TTL都不用直接一根USB线连接芯片的USB引脚和电脑同样以BOOT0拉高进入系统Bootloader然后上位机通过DFU协议把固件推送到芯片内部Flash。WSL里的操作是这样的先安装工具sudo apt install dfu-util然后把设备attach进WSL确认lsusb出现了新的设备ID执行dfu-util -a 0 -s 0x08000000:leave -D build/firmware.bin-a 0选择DFU的alternate接口-s 0x08000000:leave表示从内部Flash起始地址写入写完自动跳转运行。如果卡在Waiting for DFU device这一步大概率是BOOT0没拉高或者设备没有重新枚举拔插一下USB线基本能解决。4.3 三种烧录方式怎么选这三种方式各有各的适用场景我在实际项目里的选择逻辑列个表方便你对照烧录方式硬件要求适合场景主要痛点OpenOCD ST-LinkST-Link调试器日常开发、断点调试、频繁迭代需要USB重定向和udev权限配置串口ISPUSB转TTL模块没有调试器、只刷固件接线容易反、依赖BOOT0状态USB DFU芯片自带USB引脚批量现场升级、无额外硬件BOOT0设置麻烦、连接时序敏感我的建议是平时开发主用OpenOCD加ST-Link顺手还能调试外出应急就串口ISP模块体积小、随处都有DFU适合产品量产时走工厂测试流程不太适合日常改代码。三种都掌握基本上任何场合都不怕板子刷不进去。5. 板子失联排查手册从lsusb没反应到连接超时5.1 WSL里彻底看不到设备这是最高频出现的问题。遇到这种情况我一般按这个顺序快速过一遍Windows端跑usbipd list看设备在不在列表里不在就是线缆、驱动或者板子本身的问题在的话看bind状态是不是还生效不生效就重新bindWSL里确认usbip命令是否可用不可用就安装linux-tools-generic重新执行usbipd attach --wsl --busid观察报错内容。这个过程大多数情况下能在三分钟内定位问题。印象最深的一次是bind之后Windows重启过、WSL也重启过但忘了重新attach折腾了十分钟才发现只是少敲了一条命令。所以排查的第一步永远是把状态全部列出来看一眼别凭记忆推断。5.2 看得到设备但OpenOCD权限报错症状是lsusb完全正常但OpenOCD一跑就报permission denied或者unable to open。这种基本是权限问题优先检查udev规则有没有生效。注意WSL里的规则坑如果没启用systemdudev规则可能压根没有被解析。先去/etc/wsl.conf确认systemdtrue然后wsl --shutdown重启。重启完再ls -l /dev/bus/usb/...看看设备节点权限不再是root专属的660就说明规则生效了。如果急着烧录临时sudo chmod 666也能验证是不是这个原因。5.3 连接超时与烧录后无反应另一种常见情况是OpenOCD能识别ST-Link但报target not responding。这时候问题往往不在WSL而在硬件连接。SWD接口的四根线——SWDIO、SWCLK、GND、3.3V——是不是都接好了信号线是否接触不良目标板是不是独立供电这些硬件问题没法靠软件解决只能一根一根线排查。还有可能是芯片进入了低功耗模式或者被锁死需要先用擦除命令清掉Flash再试。烧录成功但板子不跑八成是BOOT0引脚的问题。如果BOOT0还悬在高位芯片每次复位都进Bootloader你的用户程序自然不执行。把BOOT0拉低再复位一次程序就正常跑了。这些坑我全踩过扔在这里供参考真的能省很多时间。6. 让日常烧录更舒服的几个习惯6.1 用脚本固化attach流程每次手动敲usbipd bind和usbipd attach确实有点烦尤其是早上开机、插上板子、打开终端准备干活的时候。我在Windows端写了一个PowerShell脚本管理员权限执行usbipd bind --busid 3-2 usbipd attach --wsl --busid 3-2WSL这边也加一条alias随时确认设备在线alias checkstlinklsusb | grep 0483一条命令确认状态省得每次都要敲lsusb再人眼找一长串输出。6.2 烧录日志与错误信息的正确阅读姿势OpenOCD的日志默认打到stdout很多信息看着像噪音但排查问题的时候是真的有用。建议真出问题时用调试级别跑一次openocd -d -f board.cfg -c program build/firmware.elf verify reset exit 21 | tee flash.log-d会输出调试信息tee把日志留到文件里比终端滚动输出好查得多。串口侧同样建议用screen或minicom打开设备节点看printf输出比如screen /dev/ttyUSB0 115200烧录之后程序有没有跑起来串口日志是最直接的证据。6.3 现在一直在用的工作流最后说说目前的日常PowerShell里一个脚本把ST-Link和USB转串口模块都attach进WSLWSL里依次执行make和make flash然后同一个终端直接打开串口看日志。改代码、编译、烧录、看输出全程不需要离开WSL更不用去碰Windows图形工具。这套工作流我用了几个月稳定性很满意。如果你还在纠结板子呢照着上面的步骤把USB通路打通把烧录命令封装好你也会跟我一样再也回不去在Windows里来回切窗口的日子了。