STM32MP1x 的 USB‑OTG 工作在 Gadget(外设)模式时,硬件拥有 4KB(1024 个 32bit 字)专用 FIFO‑RAM,供 USB 端点收发数据包使用。默认设备树 FIFO 参数仅适配单 USB 功能;当搭建复合 USB 设备(多 ACM、NCM、RNDIS 等多个功能同时启用),默认 FIFO 分配不足,会出现丢包、USB 枚举失败、大数据传输卡顿、BULK 吞吐量下降等疑难现象。
LAT6041 文档讲解 DWC2 控制器 FIFO 硬件架构、内存计算公式、设备树 DTS 三个关键属性配置方法,并且给出「1 路 NCM+3 路 ACM」复合设备完整调参示例。本文梳理硬件原理、计算规则、DTS 配置、踩坑排错要点。
单位重要提示:DTS 中 FIFO 配置单位是32bit 字,不是字节;1 字 = 4 字节,计算时必须做换算。
资料获取:实战经验 | LAT6041 STM32MP1x USB OTG FIFO设置_v1.0
1. OTG 外设模式 FIFO 硬件架构
STM32MP1 OTG 硬件 FIFO 内存总大小:4096 字节,等价1024个32bit字。 其中 9 个 DMA 通道(1RX+8TX)固定占用每个通道 8 个字,合计占用 72 个字;实际可分配给 USB FIFO 的总资源 = 952 个字,所有 RX、TX FIFO 总和不能超过 952 字。
外设模式 FIFO 关键特性
- 所有 OUT 端点共享唯一 Rx‑FIFO 全部 OUT 端点共用接收缓冲区,寄存器
OTG_GRXFSIZ控制 Rx‑FIFO 大小;FIFO 填满之后,后续 USB 包会直接返回 NAK 握手,造成丢包。 - 每一个 IN 端点拥有独立 Tx‑FIFO EP0 控制端点使用
OTG_DIEPTXF0;EP1‑EP7 共 7 个 IN 端点各自拥有独立 TxFIFO 寄存器; - 区分周期性端点、非周期性端点
- 周期性:中断、同步 (Isochronous) 端点;
- 非周期性:Bulk 批量、控制传输端点。
硬件寄存器与设备树 DTS 映射
OpenST‑Linux 内核 DWC2 驱动不直接操作寄存器,通过设备树三个属性完成 FIFO 划分:
| DTS 属性 | 含义(单位:32bit 字) | 对应硬件 |
|---|---|---|
g‑rx‑fifo‑size |
全部 OUT 端点共享接收 FIFO 大小 | OTG_GRXFSIZ |
g‑np‑tx‑fifo‑size |
非周期性 TX FIFO,主要用于 EP0 控制端点 | OTG_DIEPTXF0 |
g‑tx‑fifo‑size |
数组,共 8 个值,依次分配 EP1~EP7 IN 端点周期性 FIFO | OTG_DIEPTXF1‑7 |
注意:g‑tx‑fifo‑size数组 8 个成员,每个成员最小强制 16 字,即使该端点没有被使用;内核启动时会自动遍历数组,为 Gadget 功能自动匹配大于等于端点 MaxPacket 的 FIFO 资源,不需要人为绑定端点序号。
2. FIFO 最小空间计算公式
2.1 Rx‑FIFO(共享接收缓冲区)
Rx‑FIFO 除数据包之外,还必须预留 SETUP 包、NAK 状态、每个包附带状态描述符空间。
参考最小计算公式: RxFIFO = (5*控制端点数量+8) + ((最大数据包大小/4)+1) + 2*OUT端点数量+1
- 如果存在多个等时端点,建议放大为 2 倍
(最大数据包/4+1),防止连续数据包溢出丢包。
2.2 Tx‑FIFO(IN 端点发送缓冲区)
每个 IN 端点 TxFIFO 最小:TxFIFO = MaxPacketSize / 4; 工程实践建议取 2 倍值,提升高速传输稳定性。
MaxPacketSize 为 USB 端点最大包大小,高速 Bulk 端点典型 512 字节,换算字:512 /4 = 128字;通知中断端点 64 字节换算:64/4=16字,一般工程取 32 字留裕量。
3. 实战案例:NCM + 三路 ACM 复合设备
业务需求:单 OTG 实现 1 个 NCM 网络接口 + 3 个 ACM 虚拟串口复合设备。
- NCM:1 个 OUT,2 个 IN;Bulk IN 最大包 512 字节(需要≥128 字);Notify 中断 IN 最大包 64 字节(建议 32 字)。
- 每一路 ACM:1 个 OUT,2 个 IN;Bulk IN 最大包 512 字节,需要≥128 字;Notify 通知 IN 64 字节。
- 合计:一共4 路 Bulk IN 端点,每一路都至少 128 字,其余通知中断端点使用 32 字。
DTS 配置计算
g‑np‑tx‑fifo‑size:EP0 控制端点,MaxPacket=64 字节,设置32字;g‑tx‑fifo‑size数组:4 个 128 字 + 4 个 32 字:<128 128 128 128 32 32 32 32>- 总消耗:
32 + (128*4)+(32*4)= 672字;剩余资源分配给g‑rx‑fifo‑size,设置 256 字; - 总和:
256+32+672 = 960,接近硬件上限 952,微调为 256,满足整套复合设备。
修改 dts 片段示例(stm32mp135f‑dk.dts)
&usbotg_hs {
phy‑names = "usb2‑phy";
usb‑role‑switch;
status = "okay";
g‑rx‑fifo‑size = <256>;
g‑np‑tx‑fifo‑size = <32>;
g‑tx‑fifo‑size = <128 128 128 128 32 32 32 32>;
};
该配置已经耗尽硬件绝大多数 FIFO 资源,这也是 STM32MP1 单 OTG 硬件可以支撑的最大复杂度 Gadget 复合设备配置。
4. 工程落地排查清单
- 复合 Gadget 枚举失败,dmesg 打印 dwc2 fifo 资源不足
- 检查全部 FIFO 字总和,必须≤952;
- 检查
g‑tx‑fifo‑size数组 8 个成员,每个数值不能小于 16,未使用端点也要填 16 及以上; - Bulk 高速端点 512 字节 MaxPacket,FIFO 至少配置 128 字。
- USB 可以枚举,但是大吞吐量传输随机丢包,偶发 NAK
- Rx‑FIFO 分配过小,增大
g‑rx‑fifo‑size;多等时端点场景建议按照 2 倍数据包空间分配; - 核对 IN 端点 TxFIFO,只配置理论最小值容易出现传输不稳定,建议放大到 2 倍 MaxPacket/4。
- Rx‑FIFO 分配过小,增大
- 修改 DTS 之后,参数没有生效
- 确认编译更新 dtb 设备树二进制;确认 Bootloader 加载的是新 dtb;
- 内核 dmesg 日志可以打印 dwc2 的 FIFO 分配统计,确认参数是否被内核读取。
- 单 Gadget 功能(RNDIS 或者 ACM)工作正常,叠加第二个 Gadget 立刻异常
- 默认 DTS 的 FIFO 偏向单设备,IN 端点大部分 FIFO 资源分配给第一个端点;复合设备场景需要重新均分
g‑tx‑fifo‑size数组。
- 默认 DTS 的 FIFO 偏向单设备,IN 端点大部分 FIFO 资源分配给第一个端点;复合设备场景需要重新均分
5. 小结
- STM32MP1 OTG‑Gadget 模式,FIFO 总可用资源 952 个 32bit 字,DTS 属性全部以字为单位,不是字节;OUT 端点共享 Rx‑FIFO,每个 IN 端点拥有独立 Tx‑FIFO。
- 三个 DTS 属性:
g‑rx‑fifo‑size、g‑np‑tx‑fifo‑size、g‑tx‑fifo‑size[8];数组 8 项,每项最小 16 字;内核自动为 Gadget 端点匹配 FIFO,无需硬编码绑定端点编号。 - 复合 USB 设备(NCM + 多路 ACM)需要重新做资源预算,不能沿用出厂默认 DTS 配置;文中示例为单 OTG 硬件能力上限的复合配置。
- Rx‑FIFO 除数据包之外,还需要预留 SETUP 包、状态描述符;多等时端点建议放大接收缓冲区,避免 NAK 丢包。
6. FAQ
Q:g‑tx‑fifo‑size 数组顺序是否必须和 USB 端点编号一一对应?
A:不需要。内核遍历数组,自动挑选大于等于该端点 MaxPacketSize 的 FIFO 资源分配给 IN 端点,顺序无关,只要数组内存在满足大小的数值即可。
Q:如果 g‑tx‑fifo‑size 里面某个值小于端点 MaxPacket/4 会发生什么?
A:Gadget 功能初始化失败,dmesg 会打印 FIFO 资源不足,USB 复合设备枚举失败。
Q:主机模式下,这套 FIFO 配置是否生效?
A:本文只针对 Gadget 外设 (Device) 模式;Host 主机模式 FIFO 组织架构完全不同,DTS 这几个属性不会生效。免责声明:本文全部基于 ST 官方 LAT6041 文档;实际项目以 OpenST‑Linux 内核 dwc2 绑定文档、硬件手册为准。
233