ARTICLE DETAIL

资讯详情

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

深入解读 embassy-usb-synopsys-otg:Synopsys USB OTG 内核的异步驱动核心

深入解读 embassy-usb-synopsys-otg:Synopsys USB OTG 内核的异步驱动核心 嵌入式物联网异步编程【免费下载链接】embassyModern embedded framework, using Rust and async.项目地址https://gitcode.com/gh_mirrors/em/embassy点击查看免费下载本指南面向使用 Rust 与 async 进行嵌入式开发的工程师系统讲解 Embassy 框架中embassy-usb-synopsys-otgcrate 的定位、架构与实现原理。该 crate 是embassy-usb-drivertrait 在 Synopsys DesignWare USB OTG又称 DWC2内核上的参考实现它剥离了芯片特定的时钟与引脚初始化只保留跨芯片通用的驱动核心被embassy-stm32STM32 系列与esp-halESP32 系列等 HAL 直接复用。读完本文你将掌握该驱动核心的目录结构、设备/主机两种模式的关键 API、Config配置项的语义与适用场景以及如何在自己的 HAL 中完成集成。一、crate 定位embassy-usb-driver 的 Synopsys OTG 实现embassy-usb-synopsys-otg的职责非常单一且明确为 Synopsys USB OTG 设备IP 核在 STM32 上通常被称作 OTG_FS / OTG_HS在 ESP32 上则由 DWC2 演化而来实现embassy-usb-driver定义的那套异步 USB 驱动接口。从它的 Cargo.toml 可以看到其依赖关系这是理解它不做什么的关键embassy-usb-driver 0.2.2非可选依赖Bus、ControlPipe、EndpointIn、EndpointOut等 trait 全部来自这里embassy-sync 0.8.0提供AtomicWaker、CriticalSectionRawMutex等无栈并发原语用于中断上下文与任务之间的事件传递embassy-time 0.5.1可选仅在启用embassy-time/hostfeature 时启用用于握手超时与远端唤醒延时portable-atomic在没有原生原子指令的平台上如 Xtensa 架构提供原子操作defmt/log均可选两套互斥的日志后端。依赖面如此之窄意味着它只关心USB 协议 寄存器操作这一层。时钟树配置、GPIO 复用、VBUS 电源管理这些与具体芯片强相关的工作全部留给上层 HAL 完成。README 对此有明确说明It contains the core of the driver that is common across all chips using the Synopsys OTG IP, but it doesnt contain chip-specific initialization such as clock setup and GPIO muxing.它包含所有使用 Synopsys OTG IP 的芯片共通的驱动核心但不包含时钟配置、GPIO 复用等芯片特定初始化。正因为这种分层设计绝大多数使用者不应该直接依赖本 crate而应通过集成它的 HAL 使用例如embassy-stm32提供的usb::Driver与usb::Otg。二、架构分层驱动核心与 HAL 的边界在哪里README 明确列出了两个已经集成该驱动的 HALembassy-stm32面向 ST 的 STM32 芯片esp-hal面向乐鑫的 ESP32 芯片。如果你要为自己的设备集成这个 crate就需要补上设备特定初始化这一层。README 给出的集成路径是参考上述两个 crate 的集成方式为你的芯片补齐初始化代码。在仓库源码中可以清晰地看到这条边界是如何被embassy-stm32补全的。HAL 侧需要做三件事构造OtgInstance把寄存器指针regs、共享状态T::state()、FIFO 深度、PHY 类型、TX FIFO 数量以及 TRDT 计算函数一起打包交给OtgDriver::new注册中断处理把embassy_usb_synopsys_otg::on_interrupt接到芯片的 USB 中断向量上InterruptHandlerT中on_interrupt_impl(r, T::state())提供Instancetrait让芯片模块给出regs()与state()同时负责时钟、引脚的初始化。从源码结构看embassy-stm32的这一层同时也承担了DpPin/DmPin内部 FS PHY 的 D/D- 引脚或 ULPI 接口的接线工作——例如在new_hs构造路径中会要求传入两个引脚。这正是 README 所说的device-specific initialization。三、源码构成四个模块各司其职crate 的src/目录只有四个文件职责划分非常清晰文件职责lib.rs驱动主体设备模式Device的全部实现包括Driver、Bus、ControlPipe、Endpoint、Config、PhyType、State/StateStorage、OtgInstance以及核心中断处理on_interrupthost.rs主机模式Host实现通过hostfeature 启用OtgHost、HostStateStorage、OtgHostInstance、Channel等otg_v1.rsDWC2 内核的寄存器与位域定义PAC约 5000 行是整个驱动触碰硬件的地基fmt.rs日志格式化辅助如Bytes包装为defmt/log提供可读的二进制输出otg_v1.rs的注释值得留意DWC2 内核以公开文档稀少而闻名well known for being poorly documented publicly驱动作者通过Otg结构体上的方法如gintsts()、grxstsp()、fifo()、diepctl()等提供了类型化的寄存器访问这是整个驱动与硬件交互的唯一通道。四、设备模式核心 API 详解设备模式是本 crate 的默认能力不启用任何 feature 即可使用。下面按使用与实现的顺序拆解核心类型。4.1 Config三个配置项的真实语义Config是驱动构造时传入的配置结构仅三个字段但每一个都对应着 USB 协议或芯片勘误表中的真实问题字段类型默认值语义与适用场景vbus_detectionboolfalse是否启用 VBUS 检测。USB 规范要求设备监测 USB 线缆的插拔若设备由总线供电bus-powered即从 VBUS 取电拔线后设备本来就断电可以始终假定线缆已插入因此可不检测若设备自供电self-powered拔线后仍保持供电则必须置true否则设备在拔线后仍会以为处于连接状态。置true时硬件上需要把 VBUS 分压后接入检测引脚vbus_valid_overrideboolfalseVBUS 检测的软件覆盖。当vbus_detection关闭时允许把分压后的 VBUS 接到任意数字输入引脚由软件控制vbvaloven/vbvalovalVBUS 有效覆盖、avaloen/avalovalA 外设会话有效覆盖、bvaloen/bvalovalB 外设会话有效覆盖这几组寄存器位xcvrdlyboolfalse收发器延时。某些 ULPI PHY如 Microchip USB334x 系列要求在 ULPI 寄存器写入发起 HS Chirp与随后的发送命令之间插入延时否则 HS Chirp 不会执行、设备会退化为 Full-Speed 枚举。STM32H7 等芯片的 USB 链路 IP 支持加入该延时以兼容这些 PHYDefault实现给出了三个字段的默认值全部为false也就是说驱动默认假定总线供电、不做 VBUS 检测、不需要收发器延时。Config在运行时如何生效从 Bus::poll 可以看到它的关键作用点若vbus_detection与vbus_valid_override都为false驱动在首次初始化后直接上报一次Event::PowerDetected跳过对 VBUS 中断的等待若任一为true则依赖srqint会话请求/上电检测与otgint中的sedet会话结束中断分别产生PowerDetected与PowerRemoved事件PowerRemoved会触发disable_all_endpoints()把 USBAEP 位清零、唤醒所有等待中的端点 future 使其上报Disabled。4.2 PhyType四种 PHY 形态PhyType枚举了驱动支持的四种 PHY 组合InternalFullSpeed内部 Full-Speed PHY大多数带高速外设的芯片上可用InternalHighSpeed内部 High-Speed PHY少数 STM32 芯片可用ExternalFullSpeed外部 ULPI Full-Speed PHY或高速 PHY 运行在 FS 模式ExternalHighSpeed外部 ULPI High-Speed PHY。它提供两个辅助方法internal()是否为内部 PHY与high_speed()是否为高速 PHY并内部映射到寄存器中的Dspd设备速度位域。PHY 类型直接决定 configure_as_device 中GUSBCFG寄存器的写法内部 FS PHY 走physel路径内部 HS PHY 走 UTMI 路径并依据GHWCFG4硬件配置位宽外部 PHY 则走 ULPI 单数据率路径。4.3 State 与 StateStorage中断与任务共享的内存由于驱动同时被中断处理函数ISR和异步任务访问状态管理是嵌入式驱动设计的核心问题。本 crate 的解法是编译期定长的StateStorage 类型擦除的State借用StateStorageconst EP_COUNT: usize, M以常量泛型声明端点数量EP0 用户端点内部持有ControlPipeSetupStateSETUP 包缓存、[EpState; EP_COUNT]每个端点的 waker、缓冲区指针、分配信息、AtomicWaker总线事件唤醒器和互斥锁M。它可以在const fn new中构造因此能够以static形式分配State::as_state()返回Stated, M——一个只包含引用与类型参数的轻量视图可以在OtgInstance、Driver、Bus以及on_interrupt之间自由复制传递Copy。EpState内部有个值得注意的设计点in_enabled/out_enabled是DIEPCTL/DOEPCTL.USBAEP 的 RAM 镜像。源码注释说明在部分芯片如 nRF54LM20A上无 VBUS 供电时读取该寄存器位会让整个芯片挂死因此端点 future 检查 RAM 镜像而非直接读寄存器。这是一个跨芯片通用核心必须回避硬件坑的典型例子。4.4 Driver 与 OtgInstance构造驱动的两个参数Driver::new接受三个参数ep_out_buffer: d mut [u8]——内部临时缓冲区用于暂存收到的 OUT 包必须能容纳所有 OUT 端点的最大包长之和否则端点分配会失败对应EndpointAllocErrorinstance: OtgInstanced, M——硬件相关的打包描述config: Config。OtgInstance是 HAL 集成层与驱动核心的握手结构字段包括regs: Otg外设寄存器入口state: State共享状态来自StateStorage::as_statefifo_depth_words: u16专用 FIFO 总深度按 32 位字计phy_type: PhyTypePHY 类型extra_rx_fifo_words: u16某些实现额外需要的 RX FIFO 字长tx_fifo_count: u8TX FIFO 数量可以小于端点数量无空闲 TX FIFO 时 IN 端点分配失败calculate_trdt_fn: fn(speed: Dspd) - u8根据内核时钟速度计算 TRDT收发器往返延时值的回调这是少数因芯片而异的函数指针。4.5 端点分配FIFO 记账与失败场景alloc_endpoint是端点分配的核心逻辑可以从中学到 DWC2 资源管理的全部约束OUT 端点从ep_out_buffer中划出一段与max_packet_size等长的缓冲越界则EndpointAllocErrorFIFO 字长OUT 端点按(max_packet_size 3) / 4取整IN 端点取max(该值, 16)——因为 DWC2 的INEPTXFD要求TX FIFO 最小为 16 个字容量检查fifo_size_words 已分配 FIFO 字长 fifo_depth_words时报错槽位选择可以显式指定ep_addr要求索引合法、EP0 仅限 Control 类型、未被占用也可以让驱动自动找空槽EP0 被保留给控制管道TX FIFO 分配EP0 使用 TX FIFO 0其余 IN 端点从 1 号开始找空闲 FIFO见alloc_tx_fifo。Driver::start会先自动分配 EP0 的 IN/OUT 两个控制端点并断言索引为 0随后返回Bus与ControlPipe。4.6 on_interruptISR 的核心工作流on_interrupt是设备模式中断处理的唯一入口HAL 只需把它挂到中断向量上。它处理四类事件全局事件wkupint唤醒、usbsusp挂起、usbrst总线复位、enumdne枚举完成、otgintOTG 中断、srqint会话请求——统一遮蔽 IN/OUT 端点与 RX FIFO 中断后唤醒Bus::pollRX FIFO 非空共享 RX FIFO所有 OUT 端点共用按grxstsp中的pktstsd分派SETUP_DATA_RX8 字节 SETUP 包从 FIFO 读出写入setup_data原子缓存、OUT_DATA_RX将数据拷入端点 OUT 缓冲、写入长度、唤醒 waker、OUT_DATA_DONE等状态IN 端点中断清中断、处理 TXFETX FIFO 空、唤醒对应 IN wakerOUT 端点中断处理 STUPSETUP 就绪、唤醒 OUT waker不完整等时 IN 传输iisoixfr帧结束发现等时 IN 端点仍持有未发送的包时翻转包极性even/odd frame并在下一帧重发——这是等时传输在 slave 模式下的标准补救手法。4.7 控制管道与端点数据传输ControlPipesetup()从setup_data原子缓存重组 8 字节 SETUP 包并清 NAKdata_in在发送最后一包后等待主机状态阶段accept_set_address在写入DCFG.DAD后必须再走一次accept()——源码注释明确这是 Synopsys 驱动的要求Endpoint::read与writeread通过out_size原子变量与 ISR 同步缓冲区独占权配合EP_OUT_BUFFER_EMPTY哨兵值等时端点会依据当前帧号设置奇偶位并在重新使能时注意新版 DWC2 内核如 nRF54LM20A每次传输后自动清 EPENAwrite在 FIFO 空间不足时使能 TXFE 中断等待且把写 FIFO放入互斥锁内以规避勘误向 FIFO 的写入序列若被其他 OTG_FS 寄存器访问打断会损坏数据EP0 的 MPSIZep0_mpsizlib.rs#L1992把 EP0 最大包长映射为特殊编码8→0b11、16→0b10、32→0b01、64→0b00其他值直接 panic——这是 DWC2 寄存器层面的硬约束。4.8 远端唤醒remote_wakeuplib.rs#L1577仅在启用embassy-timefeature 时可用先解除挂起期间的 PHY 时钟门控PCGCCTL.STPPCLKHS 内核还需清GATEHCLK再置DCTL.RWUSIG发起 K 态恢复信号并保持 10msUSB 2.0 规范要求 1–15ms最后撤销。未启用embassy-time时直接返回Unsupported。五、主机模式host feature 下的 OtgHost自 0.4.0 起crate 通过hostfeature 引入完整的 USB Host 模式支持实现在 host.rs 中。embassy-stm32的usb-hostfeature 即透传启用它。5.1 主机侧的结构对应关系主机模式的构件与设备模式一一对应设备模式主机模式说明StateStorageEP_COUNTHostStateStorageCH_COUNT以常量泛型声明通道数channel每个通道有自己的AtomicWaker、事件标志、RX 缓冲区指针与分配标记State::as_stateHostStateStorage::as_host_state返回可复制的HostStated, M视图OtgInstanceOtgHostInstance打包regs、state、FIFO 深度与 PHY 类型on_interrupton_host_interrupt主机中断入口主机 ISR 的处理重点是端口事件连接/断开/过流通过port_event位掩码与port_waker上报、RX FIFO 非空按通道号读取 IN 数据、以及通道中断把 XFRC/STALL/NAK/NYET/TXERR/BBERR 等事件位按位或进通道result原子邮箱。源码中还处理了一个 slave 模式专属的坑每个 IN 数据包到达后 DWC2 会把该通道从调度器中摘除即使HCCHAR.CHENA仍为 1 且HCTSIZ.PKTCNT 0因此 ISR 需要重新写回 CHENA1 以排队下一个 IN 令牌否则多包传输会在第一包后停止。5.2 主机初始化与总线复位OtgHost在首次wait_for_device_event时完成两阶段初始化configure_as_host按CID寄存器匹配 DWC2 内核版本v1 如 0x1100/0x1200、v2/v3 如 0x2000/0x2300/0x3000、v5 如 0x5000/0x6100分别配置GCCFG的 PHY 上下电与 VBUS 传感位然后强制fhmod进入主机模式轮询cmod位等待切换生效最长 50msinit_host配置HCFG的 PHY 时钟HS PHY 用 30/60MHzFS PHY 用 48MHz按RX FIFO 一半、非周期 TX FIFO 四分之一、周期 TX FIFO 四分之一的比例切分总 FIFO冲掉所有 FIFO给端口上电HPRT.PPWR最后使能端口、通道、断开、RX FIFO 与 SOF 中断。bus_reset实现标准的复位时序先停掉残留活动的硬件通道、清中断、冲 FIFO然后置PRST保持 50msUSB 规范要求 ≥10ms解除复位后再等待 20ms。5.3 通道Pipe与传输原语Channel是UsbPipe的具体实现通过OtgHostAllocator::alloc_pipe以原子 CAS 抢占空闲通道槽位获得。它的传输原语对 USB 语义的处理很讲究do_out_transfer/do_in_transfer对 NAK/NYET 无限重试——注释明确NAK 是合法的 再试一次 响应没有时间上限需要超时由调用方负责HS 设备返回 NYET 后会在下一轮重新置dopingPING 令牌do_control_in/do_control_out实现完整的控制传输三阶段SETUP → DATA → STATUS数据阶段按最大包长切分并交替 DATA0/DATA1STATUS 阶段固定用 DATA1 的零长包且无数据阶段时按请求方向bmRequestType的 bit7决定 STATUS 方向事件分类classify_events按优先级处理断开 STALL 数据翻转错误 串扰 坏响应 完成 NYET NAK 通道停止Drop实现自动请求硬件停止通道、屏蔽该通道中断并释放槽位。此外驱动通过request_in/request_out内部维护 data toggle并根据实际传输的包数div_ceil翻转在高速根端口后接低速/全速设备时若未提供 split 传输支持则明确返回错误而不是发出设备无法响应的令牌。六、功能特性一览crate 的 features 定义如下Feature依赖效果用途default空无额外能力defmtdep:defmtembassy-usb-driver/defmt使用 defmt 格式日志与log二选一logdep:log使用logcrate 日志hostembassy-time启用 USB 主机模式支持host.rs仅在此时编译embassy-timedep:embassy-time启用设备模式下的远端唤醒remote wakeup支持其中host与embassy-time两个 feature 的注释分别写明Enables USB host mode support 与 Enables remote wakeup support in device mode。crate 的 CI 构建矩阵Cargo.toml#L12-L27覆盖了thumbv7m-none-eabiCortex-M与xtensa-esp32s2-none-elfESP32-S2两类目标并逐一验证defmt/log、embassy-time、host的组合这从侧面说明了它对 STM32 与 ESP32 两大平台的双重支持。七、如何集成到自己的 HALREADME 的结尾给出了明确指引如果你想把这个 crate 集成进自己设备的 HAL需要补上设备特定的初始化参考embassy-stm32与esp-hal的做法。结合源码一个最小集成需要完成定义Instancetrait提供regs()Otg寄存器指针与state()StateStorage的as_state()在中断处理中调用embassy_usb_synopsys_otg::on_interrupt(r, state)设备模式或on_host_interrupt主机模式构造OtgInstance填好fifo_depth_words查参考手册的 OTG_FS/OTG_HS FIFO RAM 大小、phy_type、tx_fifo_count、extra_rx_fifo_words与calculate_trdt_fn调用OtgDriver::new(ep_out_buffer, instance, config)得到驱动交给embassy-usb协议栈使用。至于更上层embassy-usb栈、类驱动、embassy-executor任务调度如何使用这个驱动可以参考 docs/pages/examples.adoc 中列出的 USB 示例。八、小结embassy-usb-synopsys-otg是 Embassy 生态中跨芯片驱动核心分层思想的范本它把 Synopsys OTG/DWC2 内核那套晦涩难懂的寄存器与 FIFO 管理封装成符合embassy-usb-drivertrait 的异步接口同时把所有芯片相关性时钟、引脚、PHY 上电顺序、TRDT 计算通过OtgInstance和 HAL 层剥离出去。理解它的Config语义、StateStorage共享状态设计、FIFO 分配规则与设备/主机两套中断工作流不仅有助于在 STM32、ESP32 上正确使用 USB 功能也能为编写其他外设驱动提供良好的参考模式。赞分享嵌入式物联网异步编程【免费下载链接】embassyModern embedded framework, using Rust and async.项目地址https://gitcode.com/gh_mirrors/em/embassy点击查看免费下载相关推荐embassy-usb-driver 深度解析embassy 的 USB 驱动抽象层设计与 0.2.x 关键变更全解读embassy usb driver 深度解析embassy 的 USB 驱动抽象层设计与 0.2.x 关键变更全解读 embassy usb driver嵌入式物联网异步编程embassy-usb-host 演进全解读从 CHANGELOG 看异步 USB Host 协议栈的枚举、类驱动与可靠性设计embassy usb host 演进全解读从 CHANGELOG 看异步 USB Host 协议栈的枚举、类驱动与可靠性设计 本文以 embassy usb嵌入式物联网异步编程embassy-usb-driver为 Rust 异步 USB 设备栈编写硬件驱动所需的全部 Trait 指南embassy usb driver为 Rust 异步 USB 设备栈编写硬件驱动所需的全部 Trait 指南 导读 embassy usb driver 是嵌入式物联网异步编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表