解剖USB控制器移植:从VeriSilicon到MindMotion的“外科手术式”改造

🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习

🎬擅长领域:驱动开发,嵌入式软件开发,BSP开发

❄️作者主页:一个平凡而乐于分享的小比特的个人主页

✨收录专栏:通信协议,本专栏为记录项目中用到的知识点,以及一些硬件常识总结

欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖

🧩 解剖USB控制器移植:从VeriSilicon到MindMotion的"外科手术式"改造

一句话定性:这不是简单的换芯片,而是把一台"自动挡汽车"的发动机,移植到一台"手动挡赛车"上------前者油门刹车自动匹配,后者换挡离合全靠驾驶员(代码)精准操作。


第一章:先看"手术现场"------两份代码揭示的架构DNA

提供的两份usbreg.c,恰好是一次真实的生产级移植 :从MM32L052(VeriSilicon USB IP)移植到MM32F0160(MindMotion MCF OTG IP)。通过代码差异,我们能反向工程出两个IP核在设计哲学上的根本不同。

🔬 代码解剖:一眼看出架构差异

代码特征 MM32L052(VeriSilicon IP) MM32F0160(MindMotion BDT)
中断处理 细粒度中断:EP_IN_NACKEP_OUT_ACKEP_SETUPEP_STALL 单一USB_INT_TOKENDONE统一处理
数据搬运 直接FIFO读写:USB_EP0_FIFO BDT表 + DMA:需要填充ADDRBCOWN
端点控制 写寄存器触发:USB_EP0_CTRL = 0x80 + 长度 手动Arm BDT:usb_bdt_arm() + ep0_tx_busy
收发缓冲 硬件FIFO自动管理 软件双缓冲ep0_txbufep0_rxbuf + ep_next_odd
总线复位 软件写寄存器:USB_USBRST 硬件自动产生USB_INT_RESET中断

第二章:架构差异的"灵魂"对比

🚗 VeriSilicon IP------"傻瓜式自动挡"

设计哲学 :把复杂的USB协议栈硬件化,让开发者像操作UART一样简单。
#mermaid-svg-qSCp3X40pBZ1O035{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qSCp3X40pBZ1O035 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qSCp3X40pBZ1O035 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qSCp3X40pBZ1O035 .error-icon{fill:#552222;}#mermaid-svg-qSCp3X40pBZ1O035 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qSCp3X40pBZ1O035 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qSCp3X40pBZ1O035 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qSCp3X40pBZ1O035 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qSCp3X40pBZ1O035 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qSCp3X40pBZ1O035 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qSCp3X40pBZ1O035 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qSCp3X40pBZ1O035 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qSCp3X40pBZ1O035 .marker.cross{stroke:#333333;}#mermaid-svg-qSCp3X40pBZ1O035 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qSCp3X40pBZ1O035 p{margin:0;}#mermaid-svg-qSCp3X40pBZ1O035 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qSCp3X40pBZ1O035 .cluster-label text{fill:#333;}#mermaid-svg-qSCp3X40pBZ1O035 .cluster-label span{color:#333;}#mermaid-svg-qSCp3X40pBZ1O035 .cluster-label span p{background-color:transparent;}#mermaid-svg-qSCp3X40pBZ1O035 .label text,#mermaid-svg-qSCp3X40pBZ1O035 span{fill:#333;color:#333;}#mermaid-svg-qSCp3X40pBZ1O035 .node rect,#mermaid-svg-qSCp3X40pBZ1O035 .node circle,#mermaid-svg-qSCp3X40pBZ1O035 .node ellipse,#mermaid-svg-qSCp3X40pBZ1O035 .node polygon,#mermaid-svg-qSCp3X40pBZ1O035 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qSCp3X40pBZ1O035 .rough-node .label text,#mermaid-svg-qSCp3X40pBZ1O035 .node .label text,#mermaid-svg-qSCp3X40pBZ1O035 .image-shape .label,#mermaid-svg-qSCp3X40pBZ1O035 .icon-shape .label{text-anchor:middle;}#mermaid-svg-qSCp3X40pBZ1O035 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qSCp3X40pBZ1O035 .rough-node .label,#mermaid-svg-qSCp3X40pBZ1O035 .node .label,#mermaid-svg-qSCp3X40pBZ1O035 .image-shape .label,#mermaid-svg-qSCp3X40pBZ1O035 .icon-shape .label{text-align:center;}#mermaid-svg-qSCp3X40pBZ1O035 .node.clickable{cursor:pointer;}#mermaid-svg-qSCp3X40pBZ1O035 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qSCp3X40pBZ1O035 .arrowheadPath{fill:#333333;}#mermaid-svg-qSCp3X40pBZ1O035 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qSCp3X40pBZ1O035 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qSCp3X40pBZ1O035 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qSCp3X40pBZ1O035 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qSCp3X40pBZ1O035 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qSCp3X40pBZ1O035 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qSCp3X40pBZ1O035 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qSCp3X40pBZ1O035 .cluster text{fill:#333;}#mermaid-svg-qSCp3X40pBZ1O035 .cluster span{color:#333;}#mermaid-svg-qSCp3X40pBZ1O035 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qSCp3X40pBZ1O035 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qSCp3X40pBZ1O035 rect.text{fill:none;stroke-width:0;}#mermaid-svg-qSCp3X40pBZ1O035 .icon-shape,#mermaid-svg-qSCp3X40pBZ1O035 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qSCp3X40pBZ1O035 .icon-shape p,#mermaid-svg-qSCp3X40pBZ1O035 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qSCp3X40pBZ1O035 .icon-shape .label rect,#mermaid-svg-qSCp3X40pBZ1O035 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qSCp3X40pBZ1O035 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qSCp3X40pBZ1O035 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qSCp3X40pBZ1O035 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VeriSilicon USB IP
CPU
硬件FIFO
硬件SIE引擎
PHY物理层
USB总线

关键特征

  1. 中断丰富:每个USB事件都有独立中断标志(SETUP、IN_NACK、OUT_ACK、STALL),开发者不需要轮询
  2. FIFO直通 :写USB_EP0_FIFO寄存器,数据自动进入发送队列
  3. 硬件状态机:控制传输的SETUP→DATA→STATUS阶段,硬件自动管理

代码证据

c 复制代码
// L052: 简单!写FIFO就发数据
write_mreg32(USB_EP0_FIFO, data_byte);  // 直接写到硬件FIFO
write_mreg32(USB_EP0_CTRL, 0x80 | len); // 触发发送

🏎️ MindMotion BDT------"手动挡赛车"

设计哲学 :把控制权完全交给软件,硬件只做"无脑搬运工"。
#mermaid-svg-h75hMG60ETXekxSe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-h75hMG60ETXekxSe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-h75hMG60ETXekxSe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-h75hMG60ETXekxSe .error-icon{fill:#552222;}#mermaid-svg-h75hMG60ETXekxSe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-h75hMG60ETXekxSe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-h75hMG60ETXekxSe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-h75hMG60ETXekxSe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-h75hMG60ETXekxSe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-h75hMG60ETXekxSe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-h75hMG60ETXekxSe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-h75hMG60ETXekxSe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-h75hMG60ETXekxSe .marker.cross{stroke:#333333;}#mermaid-svg-h75hMG60ETXekxSe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-h75hMG60ETXekxSe p{margin:0;}#mermaid-svg-h75hMG60ETXekxSe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-h75hMG60ETXekxSe .cluster-label text{fill:#333;}#mermaid-svg-h75hMG60ETXekxSe .cluster-label span{color:#333;}#mermaid-svg-h75hMG60ETXekxSe .cluster-label span p{background-color:transparent;}#mermaid-svg-h75hMG60ETXekxSe .label text,#mermaid-svg-h75hMG60ETXekxSe span{fill:#333;color:#333;}#mermaid-svg-h75hMG60ETXekxSe .node rect,#mermaid-svg-h75hMG60ETXekxSe .node circle,#mermaid-svg-h75hMG60ETXekxSe .node ellipse,#mermaid-svg-h75hMG60ETXekxSe .node polygon,#mermaid-svg-h75hMG60ETXekxSe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-h75hMG60ETXekxSe .rough-node .label text,#mermaid-svg-h75hMG60ETXekxSe .node .label text,#mermaid-svg-h75hMG60ETXekxSe .image-shape .label,#mermaid-svg-h75hMG60ETXekxSe .icon-shape .label{text-anchor:middle;}#mermaid-svg-h75hMG60ETXekxSe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-h75hMG60ETXekxSe .rough-node .label,#mermaid-svg-h75hMG60ETXekxSe .node .label,#mermaid-svg-h75hMG60ETXekxSe .image-shape .label,#mermaid-svg-h75hMG60ETXekxSe .icon-shape .label{text-align:center;}#mermaid-svg-h75hMG60ETXekxSe .node.clickable{cursor:pointer;}#mermaid-svg-h75hMG60ETXekxSe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-h75hMG60ETXekxSe .arrowheadPath{fill:#333333;}#mermaid-svg-h75hMG60ETXekxSe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-h75hMG60ETXekxSe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-h75hMG60ETXekxSe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h75hMG60ETXekxSe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-h75hMG60ETXekxSe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h75hMG60ETXekxSe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-h75hMG60ETXekxSe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-h75hMG60ETXekxSe .cluster text{fill:#333;}#mermaid-svg-h75hMG60ETXekxSe .cluster span{color:#333;}#mermaid-svg-h75hMG60ETXekxSe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-h75hMG60ETXekxSe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-h75hMG60ETXekxSe rect.text{fill:none;stroke-width:0;}#mermaid-svg-h75hMG60ETXekxSe .icon-shape,#mermaid-svg-h75hMG60ETXekxSe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h75hMG60ETXekxSe .icon-shape p,#mermaid-svg-h75hMG60ETXekxSe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-h75hMG60ETXekxSe .icon-shape .label rect,#mermaid-svg-h75hMG60ETXekxSe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h75hMG60ETXekxSe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-h75hMG60ETXekxSe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-h75hMG60ETXekxSe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} MindMotion BDT架构
CPU
BDT描述符表

内存中的任务清单
DMA引擎
系统内存缓冲区
SIE引擎
PHY物理层
USB总线

关键特征

  1. 单一中断 :所有传输完成统一触发USB_INT_TOKENDONE,软件必须读取BDT判断是哪个端点、什么方向
  2. BDT驱动 :每次传输前,必须填充BDT表的ADDR(缓冲区地址)、BC(字节数)、OWN(所有权标志)
  3. 双缓冲乒乓 :软件必须管理even/odd两个缓冲区的切换,类似"双倍缓冲手写笔迹"

代码证据

c 复制代码
// F0160: 复杂!手动填充BDT,手动管理双缓冲
odd = ep_next_odd[0][USB_Direction_IN];  // 选奇偶缓冲
usb_bdt_arm(&usb_bd_tbl.Table[0][USB_Direction_IN][odd],
            ep_data_n[0][USB_Direction_IN],  // DATA0/DATA1
            usb_ep0_txbuf,                   // 缓冲区地址
            val & 0x7f);                     // 长度
ep_next_odd[0][USB_Direction_IN] ^= 1;     // 切换奇偶
ep0_tx_busy = 1;                           // 软件锁

第三章:核心机制深度拆解

🔄 中断处理机制对比

事件 VeriSilicon(L052) MindMotion(F0160)
SETUP包到达 独立EP_SETUP中断 TOKDONE中断中读取token类型判断
IN数据发送 EP_IN_NACK中断 TOKDONE中通过dir==IN判断
OUT数据接收 EP_OUT_ACK中断 TOKDONE中通过dir==OUT判断
传输完成 EP_FINISH中断 同上TOKDONE
STALL握手 EP_STALL独立中断 USB_INT_STALL独立中断

流程图对比
#mermaid-svg-Vst1Psum4wQYuClY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Vst1Psum4wQYuClY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Vst1Psum4wQYuClY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Vst1Psum4wQYuClY .error-icon{fill:#552222;}#mermaid-svg-Vst1Psum4wQYuClY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Vst1Psum4wQYuClY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Vst1Psum4wQYuClY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Vst1Psum4wQYuClY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Vst1Psum4wQYuClY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Vst1Psum4wQYuClY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Vst1Psum4wQYuClY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Vst1Psum4wQYuClY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Vst1Psum4wQYuClY .marker.cross{stroke:#333333;}#mermaid-svg-Vst1Psum4wQYuClY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Vst1Psum4wQYuClY p{margin:0;}#mermaid-svg-Vst1Psum4wQYuClY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Vst1Psum4wQYuClY .cluster-label text{fill:#333;}#mermaid-svg-Vst1Psum4wQYuClY .cluster-label span{color:#333;}#mermaid-svg-Vst1Psum4wQYuClY .cluster-label span p{background-color:transparent;}#mermaid-svg-Vst1Psum4wQYuClY .label text,#mermaid-svg-Vst1Psum4wQYuClY span{fill:#333;color:#333;}#mermaid-svg-Vst1Psum4wQYuClY .node rect,#mermaid-svg-Vst1Psum4wQYuClY .node circle,#mermaid-svg-Vst1Psum4wQYuClY .node ellipse,#mermaid-svg-Vst1Psum4wQYuClY .node polygon,#mermaid-svg-Vst1Psum4wQYuClY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Vst1Psum4wQYuClY .rough-node .label text,#mermaid-svg-Vst1Psum4wQYuClY .node .label text,#mermaid-svg-Vst1Psum4wQYuClY .image-shape .label,#mermaid-svg-Vst1Psum4wQYuClY .icon-shape .label{text-anchor:middle;}#mermaid-svg-Vst1Psum4wQYuClY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Vst1Psum4wQYuClY .rough-node .label,#mermaid-svg-Vst1Psum4wQYuClY .node .label,#mermaid-svg-Vst1Psum4wQYuClY .image-shape .label,#mermaid-svg-Vst1Psum4wQYuClY .icon-shape .label{text-align:center;}#mermaid-svg-Vst1Psum4wQYuClY .node.clickable{cursor:pointer;}#mermaid-svg-Vst1Psum4wQYuClY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Vst1Psum4wQYuClY .arrowheadPath{fill:#333333;}#mermaid-svg-Vst1Psum4wQYuClY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Vst1Psum4wQYuClY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Vst1Psum4wQYuClY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Vst1Psum4wQYuClY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Vst1Psum4wQYuClY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Vst1Psum4wQYuClY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Vst1Psum4wQYuClY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Vst1Psum4wQYuClY .cluster text{fill:#333;}#mermaid-svg-Vst1Psum4wQYuClY .cluster span{color:#333;}#mermaid-svg-Vst1Psum4wQYuClY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Vst1Psum4wQYuClY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Vst1Psum4wQYuClY rect.text{fill:none;stroke-width:0;}#mermaid-svg-Vst1Psum4wQYuClY .icon-shape,#mermaid-svg-Vst1Psum4wQYuClY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Vst1Psum4wQYuClY .icon-shape p,#mermaid-svg-Vst1Psum4wQYuClY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Vst1Psum4wQYuClY .icon-shape .label rect,#mermaid-svg-Vst1Psum4wQYuClY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Vst1Psum4wQYuClY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Vst1Psum4wQYuClY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Vst1Psum4wQYuClY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} MindMotion:单一TOKDONE
USB中断
判断中断类型
TOKDONE → 统一处理
读取BDT获取端点/方向/token
根据token分发到SETUP/IN/OUT
VeriSilicon:多路并行中断
USB中断
判断中断类型
EP_SETUP → SETUP处理
EP_IN_NACK → IN处理
EP_OUT_ACK → OUT处理
EP_STALL → STALL处理


📦 数据传输路径对比

VeriSilicon:寄存器直通模式

c 复制代码
// 发送数据:简单寄存器操作
void usb_send_ep0(uint8 *data, uint8 len) {
    for (i=0; i<len; i++) {
        write_mreg32(USB_EP0_FIFO, data[i]);  // 逐个写入FIFO
    }
    write_mreg32(USB_EP0_CTRL, 0x80 | len);   // 启动发送
}

MindMotion:BDT+DMA模式

c 复制代码
// 发送数据:复杂的BDT配置流程
void usb_send_ep0(uint8 *data, uint8 len) {
    // 1. 先拷贝到软件缓冲区
    memcpy(usb_ep0_txbuf, data, len);
    
    // 2. 选哪个BDT槽位(even/odd乒乓)
    uint8 odd = ep_next_odd[0][USB_Direction_IN];
    
    // 3. 填充BDT描述符
    usb_bdt_arm(&usb_bd_tbl.Table[0][USB_Direction_IN][odd],
                ep_data_n[0][USB_Direction_IN],
                usb_ep0_txbuf,
                len);
    
    // 4. 切换下一个槽位
    ep_next_odd[0][USB_Direction_IN] ^= 1;
    
    // 5. 软件锁(防重入)
    ep0_tx_busy = 1;
}

🧠 控制传输状态机差异

USB控制传输有三个必经阶段:SETUP → DATA(可选)→ STATUS。两个IP对状态机的管理方式截然不同:

阶段 VeriSilicon(硬件管理) MindMotion(软件管理)
SETUP 硬件收到SETUP后触发EP_SETUP中断,同时自动切换到下一个状态 软件在TOKDONE中检测到SETUP token后,手动配置下一个BDT接收/发送
DATA 硬件根据wLength自动决定IN/OUT事务 软件根据SETUP包内容,手动填充BDT启动IN或OUT
STATUS 硬件自动发送/接收ZLP,完成后触发EP_FINISH 软件在DATA阶段完成后,手动 调用usb_ep0_tx_zlp()发送状态包

代码证据 :移植代码中最微妙的地方------SETUP处理完后,需要手动兜底发送状态ZLP:

c 复制代码
// F0160移植代码中的关键修补:无数据阶段的ZLP兜底
if ((wLength == 0) &&
    !USB_BufDesp_IsBusy(&usb_bd_tbl.Table[0][USB_Direction_IN][0]) &&
    !USB_BufDesp_IsBusy(&usb_bd_tbl.Table[0][USB_Direction_IN][1]))
{
    usb_ep0_tx_zlp();  // 手动发送零长度状态包!
    usb_running_ctrl_state = USB_IDLE;
}

这段代码在VeriSilicon版本中根本不需要,因为硬件自动完成了!


第四章:移植工作量全景对比

#mermaid-svg-sauGlcT3S7gYRZM1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sauGlcT3S7gYRZM1 .error-icon{fill:#552222;}#mermaid-svg-sauGlcT3S7gYRZM1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sauGlcT3S7gYRZM1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sauGlcT3S7gYRZM1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sauGlcT3S7gYRZM1 .marker.cross{stroke:#333333;}#mermaid-svg-sauGlcT3S7gYRZM1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sauGlcT3S7gYRZM1 p{margin:0;}#mermaid-svg-sauGlcT3S7gYRZM1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} USB IP移植工作量分布 中断重映射 BDT管理 控制传输适配 双缓冲管理 调试 20 18 16 14 12 10 8 6 4 2 0 工作量(人天)

移植任务 工作量 难点说明
中断重映射 ⭐⭐ 把细粒度中断合并到TOKDONE,需要重写中断分发逻辑
BDT管理 ⭐⭐⭐⭐⭐ 需要实现usb_bdt_arm()、奇偶切换、OWN位管理
控制传输适配 ⭐⭐⭐⭐⭐ SETUP→DATA→STATUS状态机完全由软件维护,必须吃透USB协议
双缓冲管理 ⭐⭐⭐⭐ 软件维护ep_next_oddep_tx_busy等状态标志
调试 ⭐⭐⭐⭐⭐ BDT调试只能看内存+逻辑分析仪,问题定位极其困难

第五章:为什么MindMotion要做这种"反人性"设计?

🎯 三个核心原因:

  1. 降低硬件成本:硬件FIFO和复杂状态机占用大量硅面积,BDT方式用软件逻辑代替硬件逻辑,芯片更小、更便宜
  2. 极致灵活性:开发者可以"绕开"标准USB协议,实现自定义行为(比如模拟复合设备、非标准端点行为)
  3. DMA效率:BDT+DMA方式在大批量数据时效率更高,CPU不需要参与每个字节的搬运(VeriSilicon的FIFO模式在高速下CPU负担重)

📊 适用场景对比雷达图

#mermaid-svg-8iZ30Gk0WicpngJA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8iZ30Gk0WicpngJA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8iZ30Gk0WicpngJA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8iZ30Gk0WicpngJA .error-icon{fill:#552222;}#mermaid-svg-8iZ30Gk0WicpngJA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8iZ30Gk0WicpngJA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8iZ30Gk0WicpngJA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8iZ30Gk0WicpngJA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8iZ30Gk0WicpngJA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8iZ30Gk0WicpngJA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8iZ30Gk0WicpngJA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8iZ30Gk0WicpngJA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8iZ30Gk0WicpngJA .marker.cross{stroke:#333333;}#mermaid-svg-8iZ30Gk0WicpngJA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8iZ30Gk0WicpngJA p{margin:0;}#mermaid-svg-8iZ30Gk0WicpngJA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 高级玩家专区 通用领域 消费电子 快速原型 NXP LPC STM32F1 MindMotion VeriSilicon 开发成本低 --> 开发成本高 灵活性低 --> 灵活性高 "两种USB IP适用场景"


第六章:实战经验------移植代码中最容易踩的坑

💣 坑1:DATA0/DATA1同步

VeriSilicon硬件自动管理toggle,MindMotion需要软件维护ep_data_n

移植代码中的修补

c 复制代码
// SETUP之后必须强制重置DATA toggle为DATA1
if (token == USB_TokenPid_SETUP) {
    ep_data_n[0][USB_Direction_OUT] = 1;
    ep_data_n[0][USB_Direction_IN] = 1;   // 注释:修复了原版遗漏!
}

💣 坑2:SET_ADDRESS的延迟生效

USB协议规定:设备在收到SET_ADDRESS请求后,必须在STATUS阶段的ZLP发送完成后才切换地址。

MindMotion需要手动处理

c 复制代码
if ((size == 0) && (usb_pending_addr != 0)) {
    USB_SetDeviceAddr(USB, usb_pending_addr);  // 在IN完成后才设置地址
    usb_pending_addr = 0;
}

💣 坑3:双缓冲残留数据

BDT的even/odd双缓冲机制在连续快速传输时,容易把旧数据误发出去。

移植代码的防御

c 复制代码
// 每次IN完成后,立即清除另一个空闲BDT的OWN位
usb_bd_tbl.Table[0][USB_Direction_IN][ep_next_odd[0][USB_Direction_IN]].OWN = 0;

💣 坑4:总线复位后的状态恢复

VeriSilicon的硬件复位会自动重置所有状态,MindMotion的BDT在复位后需要软件重新初始化。

移植代码的处理

c 复制代码
static void usb_bus_reset_process(void) {
    // 清空所有BDT
    for (i=0; i<...; i++) {
        usb_bd_tbl.Index[i].HEAD = 0;
    }
    // 重置软件状态
    ep0_tx_busy = 0;
    usb_state = USB_STATE_DEFAULT;
    // 重新使能端点
    USB_EnableEndPoint(USB, 0, USB_EndPointMode_Control, true);
    // 预提交EP0 OUT接收
    usb_ep0_out_receive();
}

第七章:终极总结------两张架构的"择偶指南"

如果你... 选VeriSilicon 选MindMotion BDT
应用工程师,只想快速实现USB功能 ✅ 最佳选择 ❌ 需要吃透协议
需要复合设备(键盘+鼠标+存储一体) ⚠️ 受限于硬件状态机 ✅ 灵活配置每个端点
芯片面积和成本敏感 ❌ 硬件开销大 ✅ 逻辑少,面积小
希望中断处理简单 ✅ 丰富的独立中断 ❌ 单一TOKDONE,需软件分发
需要高速批量传输(U盘、摄像头) ⚠️ FIFO模式CPU负担重 ✅ DMA模式更高效
团队有USB协议专家 ⚠️ 专家技能浪费 ✅ 专家能发挥极致灵活

一句话总结 :VeriSilicon的IP把复杂性留给自己(硬件),把简单留给开发者;MindMotion的BDT把复杂性留给开发者(软件),把灵活性和低成本留给芯片。二者没有绝对优劣,只有适用场景的区别。

相关推荐
ZenasLDR2 天前
LDR6600实现AR眼镜边充电边投屏功能
接口·芯片·usb
橘色的喵16 天前
一根数据源,两条出图路:UVC(USB)与 CSI-2(MIPI)对比解读
usb·isp·mipi·uvc·csi-2
ZenasLDR16 天前
Type-C边充边听音频转接器
接口·芯片·usb
kdxiaojie17 天前
Linux USB驱动阅读笔记(1)
linux·笔记·学习·usb
深念Y19 天前
JMS583 USB-NVMe 桥接芯片 LED 控制探索
嵌入式硬件·嵌入式·led·usb·电子·维修·硬盘盒
agathakuan19 天前
CDC-NCM 的三個 MAC:一條 USB 網路連線上到底有幾個 L2 端點
5g·usb·802.11
斐夷所非23 天前
USB | 接口标识与协议标准
usb
唐诺1 个月前
Android USB ADB 调试方案完全解析
android·adb·usb
你的强来了9981 个月前
好用的USB设备信息查看工具USBList(四)——驱动文件操作
注册表·驱动·usb·inf·驱动版本·硬件id