libusb_stm32 轻量 USB 设备栈:Flipper Zero 固件中的架构、硬件支持与构建实践
【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware
本文基于 Flipper Zero 固件仓库中 lib/libusb_stm32/readme.md 展开,系统讲解这套“轻量级 STM32 USB 设备协议栈”的设计思想、API 架构、支持的 MCU 硬件范围与 USB 类规范,并结合仓库内 Makefile、核心头文件与 Flipper 自身的 USB HAL 实现,给出可直接复制运行的构建命令与参数说明,帮助读者理解固件 USB 通信(CDC 串口、HID、U2F 等)的底层支撑。
一、定位与设计特点
libusb_stm32 是一个面向 STM32 微控制器的轻量级 USB设备端(Device)协议栈,被 Flipper Zero 固件作为 USB 底层通信栈引入(源码位于 lib/libusb_stm32 目录)。原 README 将其特点概括为四点:
- 轻量且快速(Lightweight and fast):纯 C(含少量汇编 ISR),无运行时依赖,适合资源受限的 MCU;
- 事件驱动的处理流程(Event-driven process workflow):USB 事务通过统一事件回调分发,而不是阻塞式状态机;
- USB 硬件驱动与 USB 核心完全分离(Completely separated USB hardware driver and usb core):更换 MCU 只需替换硬件驱动层,核心逻辑与 USB 类实现无需改动;
- 易用(Easy to use):以少量初始化函数和回调注册函数暴露完整 API。
这种“硬件驱动 / 核心分离”的分层可以从核心头文件 lib/libusb_stm32/inc/usbd_core.h 中直接验证:核心层通过函数指针表struct usbd_driver调用硬件层,两者之间只有回调接口,没有头文件级耦合。
二、核心架构:usbd_core 的 API 与状态机
2.1 硬件能力抽象与事件模型
核心层定义了一组 USB 设备事件(usbd_evt_*),硬件驱动的中断/轮询最终都归并到这些事件,再由usbd_poll()统一分发给用户注册的回调:
| 事件宏 | 含义 |
|---|---|
usbd_evt_reset | USB 总线复位 |
usbd_evt_sof | Start of Frame(每帧开始) |
usbd_evt_susp/usbd_evt_wkup | 挂起 / 唤醒 |
usbd_evt_eptx/usbd_evt_eprx | 某端点数据包发出 / 收到 |
usbd_evt_epsetup | 收到 SETUP 包(控制事务) |
usbd_evt_error | 数据错误 |
同时定义了 USB 设备状态机(usbd_state_disabled → disconnected → default → addressed → configured)、控制端点事务阶段(usbd_ctl_idle / rxdata / txdata / ztxdata / lastdata / statusin / statusout)以及响应枚举usbd_respond(usbd_fail触发 STALL、usbd_ack接受、usbd_nak表示忙碌)。BC 1.2 充电端口检测能力则通过usbd_lane_*(dsc/sdp/cdp/dcp)状态暴露。
2.2 硬件驱动接口表(usbd_driver)
struct usbd_driver是一张函数指针表,是硬件层必须实现的完整契约:
struct usbd_driver { usbd_hw_getinfo getinfo; // 获取硬件状态与能力位(USBD_HW_CAPS) usbd_hw_enable enable; // 使能/禁用 USB 硬件 usbd_hw_connect connect; // 连接/断开到主机(返回 lane 状态) usbd_hw_setaddr setaddr; // 设置 USB 地址 usbd_hw_ep_config ep_config; // 配置端点(ep / eptype / epsize) usbd_hw_ep_deconfig ep_deconfig; // 去配置端点 usbd_hw_ep_read ep_read; // 从 OUT/控制端点读数据 usbd_hw_ep_write ep_write; // 向 IN/控制端点写数据 usbd_hw_ep_setstall ep_setstall; // STALL/解除 STALL usbd_hw_ep_isstalled ep_isstalled; // 查询 STALL 状态 usbd_hw_poll poll; // 轮询硬件事件并派发回调 usbd_hw_get_frameno frame_no; // 获取当前帧号 usbd_hw_get_serialno get_serialno_desc; // 由硬件 ID 生成序列号字符串描述符 };硬件能力通过USBD_HW_CAPS位域描述:USBD_HW_ADDRFST(STATUS_OUT 前设置地址)、USBD_HW_BC(BC1.2 充电检测)、USND_HW_HS(支持高速)、USBD_HW_ENABLED,以及USBD_HW_ENUMSPEED枚举速度(NC/LS/FS/HS)。
2.3 设备结构体与初始化
用户侧的核心对象是struct _usbd_device,内含驱动指针、控制/完成/配置/描述符四类回调、按事件类型索引的events[]与按端点索引的endpoint[8]回调数组,以及事务状态usbd_status(控制缓冲区、端点 0 包大小、当前配置号、设备/控制状态)。
初始化是一个内联函数,只需一个控制请求缓冲(要求 32 位对齐):
usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf));之后通过usbd_reg_control / usbd_reg_config / usbd_reg_descr / usbd_reg_event注册回调,并在主循环或中断中调用usbd_poll()驱动事件。端点操作则通过usbd_ep_config / usbd_ep_deconfig / usbd_ep_read / usbd_ep_write / usbd_ep_setstall等封装函数完成,端点方向通过USB_EPDIR_*宏表达。
三、编译期控制宏(驱动行为裁剪)
原 README 的make module说明中特别提示:DEFINES 需参考 “USB Device HW driver and core API” 一节的编译期控制宏。这些宏在 usbd_core.h 中声明,直接决定硬件驱动的编译形态:
| 宏 | 作用 |
|---|---|
USBD_PINS_REMAP | 为引脚数少的封装重映射 USB 引脚 |
USBD_SOF_DISABLED | 禁用 SOF 事件处理(省中断开销) |
USBD_VBUS_DETECT | L4/F4 驱动启用 VBUS 检测 |
USBD_DP_PORT/USBD_DP_PIN | F103/F303 外部 DP 上拉引脚所在端口/引脚 |
USBD_SOF_OUT | F4 OTGFS 的 SOF 输出引脚 |
USBD_PRIMARY_OTGHS | F4 系列将 OTGHS 设为主接口 |
USBD_USE_EXT_ULPI | OTGHS 使用外部 ULPI 接口 |
USB_PMA_SIZE | PMA 内存大小(字节),USB 与 CAN 共享 PMA 时须调整以免数据损坏 |
这些宏通过 Makefile 的DEFINES变量以-D形式注入编译,例如DEFINES='STM32F4 STM32F429xx USBD_SOF_DISABLED'。
四、支持的硬件与驱动映射
原 README 给出了完整的 MCU 系列 → 驱动 → 源文件映射表,本文完整保留并补充脚注:
| MCU 系列 | 特性 | 驱动 | 文件 |
|---|---|---|---|
| STM32L0x2 / L0x3 / F070 / F0x2 / F0x8 | 双缓冲[2]、8[1] 个端点、BC1.2 | usbd_devfs | usbd_stm32l052_devfs.c |
| 同上(汇编版) | 同上 | usbd_devfs_asm | usbd_stm32l052_devfs_asm.S |
| STM32L4x2 / L4x3 / G4 系列 | 双缓冲[2]、8[1] 个端点、BC1.2 | usbd_devfs | usbd_stm32l433_devfs.c |
| 同上(汇编版) | 同上 | usbd_devfs_asm | usbd_stm32l052_devfs_asm.S* |
| STM32L1xx | 双缓冲[2]、8[1] 个端点 | usbd_devfs | usbd_stm32l100_devfs.c |
| 同上(汇编版) | 同上 | usbd_devfs_asm | usbd_stm32l100_devfs_asm.S |
| STM32F102 / F103 / F302 / F303 / F373 | 双缓冲[2]、外部 DP 上拉、8[1] 个端点 | usbd_devfs | usbd_stm32f103_devfs.c |
| 同上(汇编版) | 同上 | usbd_devfs_asm | usbd_stm32f103_devfs_asm.S |
| STM32WB55 | 双缓冲[2]、外部 DP 上拉、8[1] 个端点 | usbd_devfs | usbd_stm32wb55_devfs.c |
| STM32L4x5 / L4x6 | 双缓冲、6 个端点、BC1.2、VBUS 检测 | usbd_otgfs | usbd_stm32l476_otgfs.c |
| STM32F401 / F411 | 双缓冲、4 个端点、VBUS 检测、SOF 输出 | usbd_otgfs | usbd_stm32f429_otgfs.c |
| STM32F4x5 / F4x7 / F4x9 | 双缓冲、4 个端点(FS);6 个端点(HS);VBUS 检测、SOF 输出 | usbd_otgfs/usbd_otghs | usbd_stm32f429_otgfs.c/usbd_stm32f429_otghs.c |
| STM32F105 / F107 | 双缓冲、4 个端点、VBUS 检测、SOF 输出 | usbd_otgfs | usbd_stm32f105_otgfs.c |
| STM32F4x6 / F7 | 双缓冲、6 个端点(FS);9 个端点(HS);VBUS 检测、SOF 输出 | usbd_otgfs/usbd_otghs | usbd_stm32f446_otgfs.c/usbd_stm32f446_otghs.c |
| STM32H743 | 双缓冲、6 个端点、VBUS 检测、SOF 输出 | usbd_otgfs | usbd_stm32h743_otgfs.c |
脚注(与原 README 一致):
- 单个物理端点可以实现:一个双向/单缓冲逻辑端点(CONTROL);或一个单向/双缓冲逻辑端点(BULK 或 ISOCHRONOUS);或两个单向/单缓冲逻辑端点(BULK 或 INTERRUPT)。
- 当前 BULK IN 端点虽可使用两个缓冲区,但并非“真正”的双缓冲。
- 已实测芯片:STM32L052K8、STM32L100RC、STM32L476RG、STM32F072C8、STM32F103C8/CB、STM32F303CC/RE、STM32F429ZI、STM32F105RBT6、STM32F107VCT6、STM32L433CCT6、STM32F070CBT6、STM32G431RB、STM32F411CEUx、STM32F405RG、STM32F446RE、STM32F373CC、STM32L053R8、GD32F103C8T6、STM32F745VE、STM32F401CE、STM32H743。
各驱动目标对应的开发板详情见 lib/libusb_stm32/hardware.md(如 bluepill、NUCLEO-L476RG、NUCLEO-F429ZI、Boring Tech STM32H743 等)。
说明:原 README 表中 STM32L4x2/L4x3/G4 的汇编版驱动文件写作
usbd_stm32l052_devfs_asm.S;从仓库源码结构看,lib/libusb_stm32/src 目录下 L433 系列实际提供的是usbd_stm32l433_devfs.c(无独立 L433 汇编 ISR 文件),使用时建议以src/目录实际文件为准。
五、已实现的 USB 类规范
README 声明该栈内置了四类设备类(class)的定义与协议处理,全部依据 USB-IF 官方规范:
- USB HID—— Device Class Definition for Human Interface Devices (HID) Version 1.11;
- USB DFU—— USB Device Firmware Upgrade Specification Revision 1.1;
- USB CDC—— Class Definitions for Communication Devices 1.2;
- USB TMC—— USB Device Test and Measurement Class Specification Revision 1.0。
在仓库中,这些类以协议头文件形式位于 lib/libusb_stm32/inc:usb_hid.h、usb_dfu.h、usb_cdc.h(以及usb_cdca/cdce/cdci/cdcp/cdcw.h等 CDC 子协议细分头)、usb_tmc.h、usb_ccid.h、usb_std.h(标准请求/描述符定义),此外还有一整套 HID Usage Tables 头文件(hid_usage_keyboard.h、hid_usage_led.h、hid_usage_button.h等 13 个),可直接用于构造 HID 报告描述符。
Flipper 固件正是基于这些类头实现了furi_hal_usb_cdc.c(虚拟串口)、furi_hal_usb_hid.c(HID 键盘/鼠标)、furi_hal_usb_u2f.c(U2F 安全密钥)等 USB 接口。
六、依赖与获取
原 README 声明的运行/构建依赖:
- CMSIS V4 或 CMSIS V5(ARM 核心头文件与内核兼容层);
- stm32.h:STM32 通用设备头文件。
两者都可以通过 Makefile 内置的cmsis目标一键下载,目标目录由环境变量CMSIS指定:
make cmsis # 克隆 CMSIS_5 到 $(CMSIS) # 并克隆 dmitrystu/stm32h 到 $(CMSIS)/Device对应 Makefile 规则(见 lib/libusb_stm32/Makefile):
cmsis: $(CMSISDEV)/ST $(CMSISDEV)/ST: $(CMSIS) @git clone --recurse-submodules --depth 1 https://github.com/dmitrystu/stm32h.git $@ $(CMSIS): @git clone --depth 1 https://github.com/ARM-software/CMSIS_5.git $@七、Makefile 构建实战
7.1 构建静态库模块
将栈编译为独立静态库,供自己的固件工程链接:
make module MODULE=path/module.a DEFINES="mcu specified defines" CFLAGS="cpu specified compiler flags"Makefile 中module目标先执行clean,再按$(MODULE)名称打包src/*.c、src/*.S的全部目标文件;DEFINES会自动加-D前缀、INCLUDES会展开为-I路径。
7.2 构建并烧录 demo
demo 是 lib/libusb_stm32/demo/cdc_loop.c——一个 CDC 回环程序(收到什么发回什么),是验证 USB 连通性的最小示例:
make bluepill program # STM32F103 bluepill:构建 + st-flash 烧录 make stm32l052x8 # 仅构建 STM32L052x8 目标,产出 cdc_loop.hex/.bin make help # 查看全部目标与变量说明make help列出的全部 demo 目标包括:bluepill / stm32f103x6 / 32l100c-disco / stm32l100xc / 32l476rg-nucleo / stm32l476rg / stm32l052x8 / 32f429zi-nucleo / stm32f429xi / stm32f401xc / stm32f401xe,另有cmsis(下载依赖)与doc(Doxygen 文档)目标。
7.3 烧录方式
Makefile 提供三种烧录路径,均依赖先构建出cdc_loop.hex/cdc_loop.bin:
| 目标 | 工具 | 命令形态 |
|---|---|---|
program | st-flash(ST-Link) | $(FLASH) --reset --format ihex write $(DOUT).hex |
program_dfu | dfu-util | $(DFU_UTIL) -d 0483:DF11 -a 0 -D $(DOUT).bin -s 0x08000000 |
program_stcube | STM32CubeProgrammer CLI | $(STPROG_CLI) -c port=SWD reset=HWrst -d $(DOUT).hex -hardRst |
7.4 Makefile 默认变量一览
原 README 的默认值表如下,与 Makefile 实际定义相互印证(README 中MCU/CFLAGS/DEFINES列为 demo 工程默认值;当前 Makefile 中CFLAGS ?= -mcpu=cortex-m3、DEFINES ?= STM32F1 STM32F103x6,即以 F103 为默认 demo 目标):
| 变量 | 默认值 | 含义 |
|---|---|---|
CMSIS | ./CMSIS | CMSIS 根目录路径 |
CMSISDEV | $(CMSIS)/Device | CMSIS 设备目录路径 |
CMSISCORE | $(CMSIS)/CMSIS/Include $(CMSIS)/CMSIS/Core/Include | CMSIS 核心头文件路径 |
MCU | stm32l100xc | demo 工程的 MCU 选择 |
CFLAGS | -mcpu=cortex-m3 -mfloat-abi=soft | MCU 相关编译选项 |
DEFINES | STM32L1 STM32L100xC | MCU 相关宏定义 |
STPROG_CLI | ~/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI | ST Cube Programmer CLI 路径 |
OPTFLAGS | -Os | 代码优化级别 |
此外 Makefile 还定义了FLASH ?= st-flash、TOOLSET ?= arm-none-eabi-(工具链前缀)、MODULE ?= libusb.a(模块输出名)、LDSCRIPT/STARTUP(由每个 demo 目标分别指定各自的链接脚本与启动文件,如demo/stm32wb55xg.ld+startup_stm32wb55xx_cm4.s)。每个 demo 目标的完整参数组合都显式写在 Makefile 中,例如:
stm32wb55xg: clean @$(MAKE) demo STARTUP='$(CMSISDEV)/ST/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.s' \ LDSCRIPT='demo/stm32wb55xg.ld' \ DEFINES='STM32WB STM32WB55xx USBD_SOF_DISABLED' \ CFLAGS='-mcpu=cortex-m4'这段配置对 Flipper 用户尤其有参考价值——它演示了为具体 MCU 选择启动文件、链接脚本、系列宏与裁剪宏的标准做法。
八、Flipper Zero 固件中的实际应用
Flipper Zero(f7 目标)使用的正是本文第四表中的STM32WB55驱动 lib/libusb_stm32/src/usbd_stm32wb55_devfs.c(usbd_devfs系,外部 DP 上拉、8 个端点)。固件侧封装见 targets/f7/furi_hal/furi_hal_usb.c,关键调用链为:
// 1) 时钟/GPIO/VDDUSB 准备后,用 usbd_devfs 驱动的 usbd_hw 初始化设备 usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf)); // 2) 使能硬件,注册描述符回调与挂起/唤醒事件回调 usbd_enable(&udev, true); usbd_reg_descr(&udev, usb_descriptor_get); usbd_reg_event(&udev, usbd_evt_susp, susp_evt); usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); // 3) 开启 USB_LP/USB_HP 双中断,启动 UsbDriver 服务线程轮询事件 NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USB_HP_IRQn);其中控制端点包大小由 targets/f7/furi_hal/furi_hal_usb_i.h 中的#define USB_EP0_SIZE 8指定,并在 CDC/HID/U2F 三个接口的设备描述符bMaxPacketSize0中复用——这正是 README 强调的“核心与硬件驱动分离、端点 0 大小可配置”设计的实际体现。设备状态结构UsbSrv、控制缓冲ubuf与usbd_device udev通过PLACE_IN_SECTION("MB_MEM2")放入指定内存段,配合消息队列 + 服务线程实现线程安全的 USB 接口切换(furi_hal_usb_set_config在 CDC/HID/U2F 等接口之间切换)。
构建层面,该库的源码被纳入 lib/SConscript 的源文件清单("libusb_stm32"一项),由 SCons 统一编译进固件,而非走 README 描述的独立 Makefile 流程——独立 Makefile 保留用于库的独立开发、demo 验证与第三方项目集成。
九、小结与延伸阅读
- 本文主体内容全部来自 lib/libusb_stm32/readme.md,配套资料包括:Makefile(构建规则)、hardware.md(目标板清单)、inc/usbd_core.h(核心 API 与编译期宏)、demo/cdc_loop.c(CDC 回环示例);
- 在 Flipper 固件中追踪 USB 底层:从 targets/f7/furi_hal/furi_hal_usb.c 出发,可看到
usbd_init→ 事件回调 → CDC/HID/U2F 接口的完整链路; - 该栈遵循 Apache License 2.0(见 lib/libusb_stm32/LICENSE),类规范依据均为 USB-IF 官方文档(HID 1.11、DFU 1.1、CDC 1.2、TMC 1.0),可作为在任意 STM32 设备上实现标准 USB 设备类的完整参考实现。
【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考