🔥作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生,研究方向无线联邦学习
🎬擅长领域:驱动开发,嵌入式软件开发,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_NACK、EP_OUT_ACK、EP_SETUP、EP_STALL |
单一USB_INT_TOKENDONE统一处理 |
| 数据搬运 | 直接FIFO读写:USB_EP0_FIFO |
BDT表 + DMA:需要填充ADDR、BC、OWN |
| 端点控制 | 写寄存器触发:USB_EP0_CTRL = 0x80 + 长度 |
手动Arm BDT:usb_bdt_arm() + ep0_tx_busy |
| 收发缓冲 | 硬件FIFO自动管理 | 软件双缓冲 :ep0_txbuf、ep0_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总线
关键特征:
- 中断丰富:每个USB事件都有独立中断标志(SETUP、IN_NACK、OUT_ACK、STALL),开发者不需要轮询
- FIFO直通 :写
USB_EP0_FIFO寄存器,数据自动进入发送队列 - 硬件状态机:控制传输的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总线
关键特征:
- 单一中断 :所有传输完成统一触发
USB_INT_TOKENDONE,软件必须读取BDT判断是哪个端点、什么方向 - BDT驱动 :每次传输前,必须填充BDT表的
ADDR(缓冲区地址)、BC(字节数)、OWN(所有权标志) - 双缓冲乒乓 :软件必须管理
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_odd、ep_tx_busy等状态标志 |
| 调试 | ⭐⭐⭐⭐⭐ | BDT调试只能看内存+逻辑分析仪,问题定位极其困难 |
第五章:为什么MindMotion要做这种"反人性"设计?
🎯 三个核心原因:
- 降低硬件成本:硬件FIFO和复杂状态机占用大量硅面积,BDT方式用软件逻辑代替硬件逻辑,芯片更小、更便宜
- 极致灵活性:开发者可以"绕开"标准USB协议,实现自定义行为(比如模拟复合设备、非标准端点行为)
- 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把复杂性留给开发者(软件),把灵活性和低成本留给芯片。二者没有绝对优劣,只有适用场景的区别。