MCU SD 卡上电加载流程:从寄存器访问到文件系统挂载

SD 卡上电加载流程:从寄存器访问到文件系统挂载

摘要 :上电时已经插着的卡不会触发卡检测中断。此时 CD 引脚电平稳定,没有跳变可供触发;驱动在创建 host 结束时主动读一次 CDETECT 寄存器,确认卡在位后直接向检测线程发送事件。中断 SDIO_INT_CARD_DET 处理的是使用过程中插拔产生的跳变。

本文讨论上电阶段 SD 卡驱动从无到有、最终挂载 /sd/ 的过程,不涉及读写性能。过程分四段,章节顺序与之一致:

阶段 回答的问题 涉及机制 章节
寄存器访问 软件如何操作外设寄存器 地址译码、MMIO、D 触发器锁存 2.1、2.2
驱动初始化 驱动何时被调用、建了哪些对象 自动初始化等级、rt_mmcsd_host、事件对象 2.3、2.4
卡检测 插入状态如何判定、中断如何进入 CD 引脚、去抖窗口、CDETECT、CLIC 向量跳转 3.1 至 3.6
挂载 事件如何变成可读写的 /sd/ 检测线程、识别线程、命令序列、dfs_mount 4.1 至 4.4

一、两条触发路径

1.1 触发路径对比

#mermaid-svg-dHoUQUvkn0ENStF8{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-dHoUQUvkn0ENStF8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dHoUQUvkn0ENStF8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dHoUQUvkn0ENStF8 .error-icon{fill:#552222;}#mermaid-svg-dHoUQUvkn0ENStF8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dHoUQUvkn0ENStF8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dHoUQUvkn0ENStF8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dHoUQUvkn0ENStF8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dHoUQUvkn0ENStF8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dHoUQUvkn0ENStF8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dHoUQUvkn0ENStF8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dHoUQUvkn0ENStF8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dHoUQUvkn0ENStF8 .marker.cross{stroke:#333333;}#mermaid-svg-dHoUQUvkn0ENStF8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dHoUQUvkn0ENStF8 p{margin:0;}#mermaid-svg-dHoUQUvkn0ENStF8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dHoUQUvkn0ENStF8 .cluster-label text{fill:#333;}#mermaid-svg-dHoUQUvkn0ENStF8 .cluster-label span{color:#333;}#mermaid-svg-dHoUQUvkn0ENStF8 .cluster-label span p{background-color:transparent;}#mermaid-svg-dHoUQUvkn0ENStF8 .label text,#mermaid-svg-dHoUQUvkn0ENStF8 span{fill:#333;color:#333;}#mermaid-svg-dHoUQUvkn0ENStF8 .node rect,#mermaid-svg-dHoUQUvkn0ENStF8 .node circle,#mermaid-svg-dHoUQUvkn0ENStF8 .node ellipse,#mermaid-svg-dHoUQUvkn0ENStF8 .node polygon,#mermaid-svg-dHoUQUvkn0ENStF8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dHoUQUvkn0ENStF8 .rough-node .label text,#mermaid-svg-dHoUQUvkn0ENStF8 .node .label text,#mermaid-svg-dHoUQUvkn0ENStF8 .image-shape .label,#mermaid-svg-dHoUQUvkn0ENStF8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-dHoUQUvkn0ENStF8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dHoUQUvkn0ENStF8 .rough-node .label,#mermaid-svg-dHoUQUvkn0ENStF8 .node .label,#mermaid-svg-dHoUQUvkn0ENStF8 .image-shape .label,#mermaid-svg-dHoUQUvkn0ENStF8 .icon-shape .label{text-align:center;}#mermaid-svg-dHoUQUvkn0ENStF8 .node.clickable{cursor:pointer;}#mermaid-svg-dHoUQUvkn0ENStF8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dHoUQUvkn0ENStF8 .arrowheadPath{fill:#333333;}#mermaid-svg-dHoUQUvkn0ENStF8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dHoUQUvkn0ENStF8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dHoUQUvkn0ENStF8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dHoUQUvkn0ENStF8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dHoUQUvkn0ENStF8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dHoUQUvkn0ENStF8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dHoUQUvkn0ENStF8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dHoUQUvkn0ENStF8 .cluster text{fill:#333;}#mermaid-svg-dHoUQUvkn0ENStF8 .cluster span{color:#333;}#mermaid-svg-dHoUQUvkn0ENStF8 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-dHoUQUvkn0ENStF8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dHoUQUvkn0ENStF8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-dHoUQUvkn0ENStF8 .icon-shape,#mermaid-svg-dHoUQUvkn0ENStF8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dHoUQUvkn0ENStF8 .icon-shape p,#mermaid-svg-dHoUQUvkn0ENStF8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dHoUQUvkn0ENStF8 .icon-shape .label rect,#mermaid-svg-dHoUQUvkn0ENStF8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dHoUQUvkn0ENStF8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dHoUQUvkn0ENStF8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dHoUQUvkn0ENStF8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-dHoUQUvkn0ENStF8 .hw>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .hw span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .hw tspan{fill:#103a80!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .cd>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .cd span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .cd tspan{fill:#0b3d22!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .irq>*{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .irq span{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .irq tspan{fill:#2a1a5e!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .evt>*{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .evt span{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .evt tspan{fill:#083d3d!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .ok>*{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .ok span{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-dHoUQUvkn0ENStF8 .ok tspan{fill:#6b3209!important;} 上电:电平稳定,无跳变
插拔:电平产生跳变
SD 卡插入
上电时已在位

还是使用中插拔
主动查询 CDETECT
SDIO_INT_CARD_DET 中断
rt_event_send 发卡检测事件
CLIC 向量跳转进中断服务函数
检测线程 → 识别 → 挂载 /sd/

两条路径的区别不在卡是否存在,而在电平是否变化:卡是否在位是一个状态,中断针对的是这个状态的跳变。

1.2 上电与热插拔的差异

维度 上电时已插卡 使用中热插拔
触发源 软件主动查询 硬件中断
是否走中断
触发机制 创建 host 时读一次 CDETECT CD 引脚跳变后由 CLIC 向量跳转
时序前提 发生在卡检测中断使能之前 发生在中断使能之后
后续路径 发事件 → 检测线程 → 识别 → 挂载 与左列相同

上电这次查询发生在 host 创建函数的末尾,先于卡检测中断的使能:

c 复制代码
rthw_sdio_irq_update(host, 0);

if (0x01 == rthw_sd_detect(host))                        /* 主动读一次 CDETECT */
{
    rt_event_send(&hw_sdio->event, SDIO_INT_CARD_DET);   /* 在位则直接发事件 */
}

驱动使能卡检测中断时的顺序是先清除该中断标志、再开放中断,而上面的查询发生在这两步之前。因此上电阶段不必依赖中断:CD 电平没有变化,把当前状态直接告知检测线程即可。

接下来要问的是,这次查询凭什么能读到一个寄存器,以及驱动为什么会在这一刻被执行。下一章先说明这两件事。

二、寄存器访问与驱动初始化

2.1 地址译码与内存映射输入输出

CPU 执行读写指令时,只负责把目标地址放到地址总线上,并用控制信号声明本次是读还是写。CPU 不区分地址背后是内存、CLIC 还是 SDIO 寄存器,区分工作由总线上的地址译码器完成:它比较地址高位,判断本次访问落在哪台设备的地址区间,只对该设备发出有效的片选信号。
#mermaid-svg-KaMei2Ch8gNtvLBc{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-KaMei2Ch8gNtvLBc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KaMei2Ch8gNtvLBc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KaMei2Ch8gNtvLBc .error-icon{fill:#552222;}#mermaid-svg-KaMei2Ch8gNtvLBc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KaMei2Ch8gNtvLBc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KaMei2Ch8gNtvLBc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KaMei2Ch8gNtvLBc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KaMei2Ch8gNtvLBc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KaMei2Ch8gNtvLBc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KaMei2Ch8gNtvLBc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KaMei2Ch8gNtvLBc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KaMei2Ch8gNtvLBc .marker.cross{stroke:#333333;}#mermaid-svg-KaMei2Ch8gNtvLBc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KaMei2Ch8gNtvLBc p{margin:0;}#mermaid-svg-KaMei2Ch8gNtvLBc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KaMei2Ch8gNtvLBc .cluster-label text{fill:#333;}#mermaid-svg-KaMei2Ch8gNtvLBc .cluster-label span{color:#333;}#mermaid-svg-KaMei2Ch8gNtvLBc .cluster-label span p{background-color:transparent;}#mermaid-svg-KaMei2Ch8gNtvLBc .label text,#mermaid-svg-KaMei2Ch8gNtvLBc span{fill:#333;color:#333;}#mermaid-svg-KaMei2Ch8gNtvLBc .node rect,#mermaid-svg-KaMei2Ch8gNtvLBc .node circle,#mermaid-svg-KaMei2Ch8gNtvLBc .node ellipse,#mermaid-svg-KaMei2Ch8gNtvLBc .node polygon,#mermaid-svg-KaMei2Ch8gNtvLBc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KaMei2Ch8gNtvLBc .rough-node .label text,#mermaid-svg-KaMei2Ch8gNtvLBc .node .label text,#mermaid-svg-KaMei2Ch8gNtvLBc .image-shape .label,#mermaid-svg-KaMei2Ch8gNtvLBc .icon-shape .label{text-anchor:middle;}#mermaid-svg-KaMei2Ch8gNtvLBc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KaMei2Ch8gNtvLBc .rough-node .label,#mermaid-svg-KaMei2Ch8gNtvLBc .node .label,#mermaid-svg-KaMei2Ch8gNtvLBc .image-shape .label,#mermaid-svg-KaMei2Ch8gNtvLBc .icon-shape .label{text-align:center;}#mermaid-svg-KaMei2Ch8gNtvLBc .node.clickable{cursor:pointer;}#mermaid-svg-KaMei2Ch8gNtvLBc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KaMei2Ch8gNtvLBc .arrowheadPath{fill:#333333;}#mermaid-svg-KaMei2Ch8gNtvLBc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KaMei2Ch8gNtvLBc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KaMei2Ch8gNtvLBc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KaMei2Ch8gNtvLBc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KaMei2Ch8gNtvLBc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KaMei2Ch8gNtvLBc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KaMei2Ch8gNtvLBc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KaMei2Ch8gNtvLBc .cluster text{fill:#333;}#mermaid-svg-KaMei2Ch8gNtvLBc .cluster span{color:#333;}#mermaid-svg-KaMei2Ch8gNtvLBc 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-KaMei2Ch8gNtvLBc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KaMei2Ch8gNtvLBc rect.text{fill:none;stroke-width:0;}#mermaid-svg-KaMei2Ch8gNtvLBc .icon-shape,#mermaid-svg-KaMei2Ch8gNtvLBc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KaMei2Ch8gNtvLBc .icon-shape p,#mermaid-svg-KaMei2Ch8gNtvLBc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KaMei2Ch8gNtvLBc .icon-shape .label rect,#mermaid-svg-KaMei2Ch8gNtvLBc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KaMei2Ch8gNtvLBc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KaMei2Ch8gNtvLBc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KaMei2Ch8gNtvLBc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-KaMei2Ch8gNtvLBc .cpu>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .cpu span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .cpu tspan{fill:#103a80!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .bus>*{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .bus span{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .bus tspan{fill:#5a4a06!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .dec>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .dec span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .dec tspan{fill:#0b3d22!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .dev>*{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .dev span{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .dev tspan{fill:#2a1a5e!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .idle>*{fill:#e9edf2!important;stroke:#8794a5!important;color:#3a4450!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .idle span{fill:#e9edf2!important;stroke:#8794a5!important;color:#3a4450!important;}#mermaid-svg-KaMei2Ch8gNtvLBc .idle tspan{fill:#3a4450!important;} 地址总线 + 控制信号
片选有效
片选有效
片选有效
片选无效:输出高阻
CPU 执行 load / store
总线:地址 / 数据 / 控制
地址译码器

比较地址高位
SDIO 控制器寄存器
UART 寄存器
CLIC 中断控制器寄存器
被选中者驱动数据总线
不参与本次响应

这就是内存映射输入输出(MMIO,Memory-Mapped I/O):外设寄存器以内存地址的形式暴露,软件用普通读写指令即可操作。代码里表现为一个基地址加一个结构体指针,此后 XXX->REG = value 等价于向该寄存器写入。

c 复制代码
#define SDIO0_BASE  0x????0000UL     /* 具体值由芯片地址映射决定 */
#define SDIO0_REG   ((SDIO_Type *)SDIO0_BASE)

2.2 写寄存器的硬件过程

寄存器由多个 D 触发器(Flip-Flop)构成,每个触发器保存 1 bit:时钟有效沿到来时,把输入端的数据写入并保持;时钟不来则维持原值。由此,写寄存器的含义是触发目标触发器的时钟,把数据总线上的值锁存进存储单元并保持。
#mermaid-svg-sKmZJuJe0sRRlnyh{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-sKmZJuJe0sRRlnyh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sKmZJuJe0sRRlnyh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sKmZJuJe0sRRlnyh .error-icon{fill:#552222;}#mermaid-svg-sKmZJuJe0sRRlnyh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sKmZJuJe0sRRlnyh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sKmZJuJe0sRRlnyh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sKmZJuJe0sRRlnyh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sKmZJuJe0sRRlnyh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sKmZJuJe0sRRlnyh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sKmZJuJe0sRRlnyh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sKmZJuJe0sRRlnyh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sKmZJuJe0sRRlnyh .marker.cross{stroke:#333333;}#mermaid-svg-sKmZJuJe0sRRlnyh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sKmZJuJe0sRRlnyh p{margin:0;}#mermaid-svg-sKmZJuJe0sRRlnyh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sKmZJuJe0sRRlnyh .cluster-label text{fill:#333;}#mermaid-svg-sKmZJuJe0sRRlnyh .cluster-label span{color:#333;}#mermaid-svg-sKmZJuJe0sRRlnyh .cluster-label span p{background-color:transparent;}#mermaid-svg-sKmZJuJe0sRRlnyh .label text,#mermaid-svg-sKmZJuJe0sRRlnyh span{fill:#333;color:#333;}#mermaid-svg-sKmZJuJe0sRRlnyh .node rect,#mermaid-svg-sKmZJuJe0sRRlnyh .node circle,#mermaid-svg-sKmZJuJe0sRRlnyh .node ellipse,#mermaid-svg-sKmZJuJe0sRRlnyh .node polygon,#mermaid-svg-sKmZJuJe0sRRlnyh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sKmZJuJe0sRRlnyh .rough-node .label text,#mermaid-svg-sKmZJuJe0sRRlnyh .node .label text,#mermaid-svg-sKmZJuJe0sRRlnyh .image-shape .label,#mermaid-svg-sKmZJuJe0sRRlnyh .icon-shape .label{text-anchor:middle;}#mermaid-svg-sKmZJuJe0sRRlnyh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sKmZJuJe0sRRlnyh .rough-node .label,#mermaid-svg-sKmZJuJe0sRRlnyh .node .label,#mermaid-svg-sKmZJuJe0sRRlnyh .image-shape .label,#mermaid-svg-sKmZJuJe0sRRlnyh .icon-shape .label{text-align:center;}#mermaid-svg-sKmZJuJe0sRRlnyh .node.clickable{cursor:pointer;}#mermaid-svg-sKmZJuJe0sRRlnyh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sKmZJuJe0sRRlnyh .arrowheadPath{fill:#333333;}#mermaid-svg-sKmZJuJe0sRRlnyh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sKmZJuJe0sRRlnyh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sKmZJuJe0sRRlnyh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sKmZJuJe0sRRlnyh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sKmZJuJe0sRRlnyh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sKmZJuJe0sRRlnyh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sKmZJuJe0sRRlnyh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sKmZJuJe0sRRlnyh .cluster text{fill:#333;}#mermaid-svg-sKmZJuJe0sRRlnyh .cluster span{color:#333;}#mermaid-svg-sKmZJuJe0sRRlnyh 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-sKmZJuJe0sRRlnyh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sKmZJuJe0sRRlnyh rect.text{fill:none;stroke-width:0;}#mermaid-svg-sKmZJuJe0sRRlnyh .icon-shape,#mermaid-svg-sKmZJuJe0sRRlnyh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sKmZJuJe0sRRlnyh .icon-shape p,#mermaid-svg-sKmZJuJe0sRRlnyh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sKmZJuJe0sRRlnyh .icon-shape .label rect,#mermaid-svg-sKmZJuJe0sRRlnyh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sKmZJuJe0sRRlnyh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sKmZJuJe0sRRlnyh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sKmZJuJe0sRRlnyh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-sKmZJuJe0sRRlnyh .cpu>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .cpu span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .cpu tspan{fill:#103a80!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .dec>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .dec span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .dec tspan{fill:#0b3d22!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .ff>*{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .ff span{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .ff tspan{fill:#2a1a5e!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .out>*{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .out span{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-sKmZJuJe0sRRlnyh .out tspan{fill:#6b3209!important;} 直到下一次改写
① 指令给出

地址 + 数据 + 写使能
② 译码器置片选有效
③ 片选 ∧ 写使能

产生时钟沿,D 触发器锁存
④ 锁存值保持

持续控制该功能

写入的 0/1 会持续保持,直到下次改写,因此写寄存器是状态设定,不是一次性数据传递。这也解释了为什么软件写一次中断使能位之后,该中断会一直可用。

2.3 自动初始化等级

RT-Thread 的驱动不靠上电后手工调用,而由自动初始化机制完成:内核按等级顺序执行各级 INIT_*_EXPORT 宏注册的函数。等级值写在链接段的名字里,数字越小越早。
#mermaid-svg-V0OEHfJAlRBLksaM{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-V0OEHfJAlRBLksaM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-V0OEHfJAlRBLksaM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-V0OEHfJAlRBLksaM .error-icon{fill:#552222;}#mermaid-svg-V0OEHfJAlRBLksaM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-V0OEHfJAlRBLksaM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-V0OEHfJAlRBLksaM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-V0OEHfJAlRBLksaM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-V0OEHfJAlRBLksaM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-V0OEHfJAlRBLksaM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-V0OEHfJAlRBLksaM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-V0OEHfJAlRBLksaM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-V0OEHfJAlRBLksaM .marker.cross{stroke:#333333;}#mermaid-svg-V0OEHfJAlRBLksaM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-V0OEHfJAlRBLksaM p{margin:0;}#mermaid-svg-V0OEHfJAlRBLksaM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-V0OEHfJAlRBLksaM .cluster-label text{fill:#333;}#mermaid-svg-V0OEHfJAlRBLksaM .cluster-label span{color:#333;}#mermaid-svg-V0OEHfJAlRBLksaM .cluster-label span p{background-color:transparent;}#mermaid-svg-V0OEHfJAlRBLksaM .label text,#mermaid-svg-V0OEHfJAlRBLksaM span{fill:#333;color:#333;}#mermaid-svg-V0OEHfJAlRBLksaM .node rect,#mermaid-svg-V0OEHfJAlRBLksaM .node circle,#mermaid-svg-V0OEHfJAlRBLksaM .node ellipse,#mermaid-svg-V0OEHfJAlRBLksaM .node polygon,#mermaid-svg-V0OEHfJAlRBLksaM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-V0OEHfJAlRBLksaM .rough-node .label text,#mermaid-svg-V0OEHfJAlRBLksaM .node .label text,#mermaid-svg-V0OEHfJAlRBLksaM .image-shape .label,#mermaid-svg-V0OEHfJAlRBLksaM .icon-shape .label{text-anchor:middle;}#mermaid-svg-V0OEHfJAlRBLksaM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-V0OEHfJAlRBLksaM .rough-node .label,#mermaid-svg-V0OEHfJAlRBLksaM .node .label,#mermaid-svg-V0OEHfJAlRBLksaM .image-shape .label,#mermaid-svg-V0OEHfJAlRBLksaM .icon-shape .label{text-align:center;}#mermaid-svg-V0OEHfJAlRBLksaM .node.clickable{cursor:pointer;}#mermaid-svg-V0OEHfJAlRBLksaM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-V0OEHfJAlRBLksaM .arrowheadPath{fill:#333333;}#mermaid-svg-V0OEHfJAlRBLksaM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-V0OEHfJAlRBLksaM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-V0OEHfJAlRBLksaM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V0OEHfJAlRBLksaM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-V0OEHfJAlRBLksaM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V0OEHfJAlRBLksaM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-V0OEHfJAlRBLksaM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-V0OEHfJAlRBLksaM .cluster text{fill:#333;}#mermaid-svg-V0OEHfJAlRBLksaM .cluster span{color:#333;}#mermaid-svg-V0OEHfJAlRBLksaM 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-V0OEHfJAlRBLksaM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-V0OEHfJAlRBLksaM rect.text{fill:none;stroke-width:0;}#mermaid-svg-V0OEHfJAlRBLksaM .icon-shape,#mermaid-svg-V0OEHfJAlRBLksaM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-V0OEHfJAlRBLksaM .icon-shape p,#mermaid-svg-V0OEHfJAlRBLksaM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-V0OEHfJAlRBLksaM .icon-shape .label rect,#mermaid-svg-V0OEHfJAlRBLksaM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-V0OEHfJAlRBLksaM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-V0OEHfJAlRBLksaM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-V0OEHfJAlRBLksaM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-V0OEHfJAlRBLksaM .lv>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-V0OEHfJAlRBLksaM .lv span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-V0OEHfJAlRBLksaM .lv tspan{fill:#103a80!important;}#mermaid-svg-V0OEHfJAlRBLksaM .core>*{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-V0OEHfJAlRBLksaM .core span{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-V0OEHfJAlRBLksaM .core tspan{fill:#5a4a06!important;}#mermaid-svg-V0OEHfJAlRBLksaM .app>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-V0OEHfJAlRBLksaM .app span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-V0OEHfJAlRBLksaM .app tspan{fill:#0b3d22!important;}#mermaid-svg-V0OEHfJAlRBLksaM .th>*{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-V0OEHfJAlRBLksaM .th span{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-V0OEHfJAlRBLksaM .th tspan{fill:#083d3d!important;} 上电复位
1 INIT_BOARD_EXPORT

板级 GPIO、时钟、SD 供电
2 INIT_PREV_EXPORT

mmcsd core:邮箱 + 识别线程
4 INIT_COMPONENT_EXPORT

组件与内核服务
5 INIT_ENV_EXPORT

文件系统等环境
6 INIT_APP_EXPORT

rt_hw_sdio_init
创建 host / 事件对象 / 检测线程

其中有两条先后关系容易被弄反。一是识别线程比 SD 驱动更早创建:rt_mmcsd_core_init()INIT_PREV_EXPORT 注册,它建好邮箱 mmcsd_detect_mbmmcsd_hotpluge_mb 和识别线程 mmcsd_detect;SD 驱动以 INIT_APP_EXPORT 注册,执行更晚。顺序写反,驱动发出的邮箱消息就没有接收者。二是卡供电与卡检测引脚在板级初始化中配置,驱动只使用这些配置。

2.4 host、事件对象与检测线程

host 指 rt_mmcsd_host 结构体,描述一个 SDIO 控制器及其所接卡片。rt_hw_sdio_init 为每个控制器调用 sdio_host_create,该阶段只建立数据结构与回调,不访问卡片:
#mermaid-svg-7BlvyTgGx1vFLKd7{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-7BlvyTgGx1vFLKd7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7BlvyTgGx1vFLKd7 .error-icon{fill:#552222;}#mermaid-svg-7BlvyTgGx1vFLKd7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7BlvyTgGx1vFLKd7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .marker.cross{stroke:#333333;}#mermaid-svg-7BlvyTgGx1vFLKd7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7BlvyTgGx1vFLKd7 p{margin:0;}#mermaid-svg-7BlvyTgGx1vFLKd7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .cluster-label text{fill:#333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .cluster-label span{color:#333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .cluster-label span p{background-color:transparent;}#mermaid-svg-7BlvyTgGx1vFLKd7 .label text,#mermaid-svg-7BlvyTgGx1vFLKd7 span{fill:#333;color:#333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .node rect,#mermaid-svg-7BlvyTgGx1vFLKd7 .node circle,#mermaid-svg-7BlvyTgGx1vFLKd7 .node ellipse,#mermaid-svg-7BlvyTgGx1vFLKd7 .node polygon,#mermaid-svg-7BlvyTgGx1vFLKd7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7BlvyTgGx1vFLKd7 .rough-node .label text,#mermaid-svg-7BlvyTgGx1vFLKd7 .node .label text,#mermaid-svg-7BlvyTgGx1vFLKd7 .image-shape .label,#mermaid-svg-7BlvyTgGx1vFLKd7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-7BlvyTgGx1vFLKd7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7BlvyTgGx1vFLKd7 .rough-node .label,#mermaid-svg-7BlvyTgGx1vFLKd7 .node .label,#mermaid-svg-7BlvyTgGx1vFLKd7 .image-shape .label,#mermaid-svg-7BlvyTgGx1vFLKd7 .icon-shape .label{text-align:center;}#mermaid-svg-7BlvyTgGx1vFLKd7 .node.clickable{cursor:pointer;}#mermaid-svg-7BlvyTgGx1vFLKd7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .arrowheadPath{fill:#333333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7BlvyTgGx1vFLKd7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7BlvyTgGx1vFLKd7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7BlvyTgGx1vFLKd7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7BlvyTgGx1vFLKd7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7BlvyTgGx1vFLKd7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7BlvyTgGx1vFLKd7 .cluster text{fill:#333;}#mermaid-svg-7BlvyTgGx1vFLKd7 .cluster span{color:#333;}#mermaid-svg-7BlvyTgGx1vFLKd7 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-7BlvyTgGx1vFLKd7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7BlvyTgGx1vFLKd7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-7BlvyTgGx1vFLKd7 .icon-shape,#mermaid-svg-7BlvyTgGx1vFLKd7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7BlvyTgGx1vFLKd7 .icon-shape p,#mermaid-svg-7BlvyTgGx1vFLKd7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7BlvyTgGx1vFLKd7 .icon-shape .label rect,#mermaid-svg-7BlvyTgGx1vFLKd7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7BlvyTgGx1vFLKd7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7BlvyTgGx1vFLKd7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7BlvyTgGx1vFLKd7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-7BlvyTgGx1vFLKd7 .core>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .core span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .core tspan{fill:#103a80!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .hw>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .hw span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .hw tspan{fill:#0b3d22!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .ipc>*{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .ipc span{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .ipc tspan{fill:#083d3d!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .hal>*{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .hal span{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-7BlvyTgGx1vFLKd7 .hal tspan{fill:#6b3209!important;} ops 回调表
private_data ↔ host

互相持有
rt_event_init

event 事件对象
检测线程

rthw_mmcsd_detect
rt_mutex_init

mutex
hw_sdio
rt_mmcsd_host

名字形如 sdio0
发命令 / 配总线

读卡检测 / 开关中断
sdio_dev → hsdio

SDIO_HandleTypeDef
SDIO 控制器寄存器

CDETECT / DEBNCE / INT

对应的关键行:

c 复制代码
host->ops      = &ops;        /* 回调表:request / iocfg / detect / irq_update */
host->freq_min = 400000;      /* SD 协议规定的启动时钟 400 kHz */
host->valid_ocr= VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34;

hw_sdio->detect_thread =
    rt_thread_create(name, rthw_mmcsd_detect, host,
                     RT_MMCSD_DETECT_STACK_SIZE, 25, 10);
rt_thread_startup(hw_sdio->detect_thread);
rt_event_init(&hw_sdio->event, name, RT_IPC_FLAG_PRIO);

检测线程优先级为 25,创建后立即启动,随后阻塞在事件上等待卡检测,上电阶段不占用 CPU 时间。

到这里 host、事件对象与检测线程都已就绪,但还没有代码去读卡座的开关。下一章说明插入状态如何被判定,以及它如何变成一次中断。

三、卡检测与中断

3.1 CD 引脚配置与信号路由

SD 卡座内有一个随插卡动作通断的机械行程开关,它引出一根卡检测线(CD,Card Detect)。板级把该引脚的功能选择(pad 复用)切到 GPIO,并将方向设为输入:

c 复制代码
/* 板级初始化中的 GPIO 配置部分 */
Hal_PadMux_Set(HAL_PAD_MUX_FUNC_GPIO, HAL_PAD_MUX_CTRL_EN, HAL_GPIO_64);
Hal_Gpio_DirSet(HAL_GPIO_64, HAL_GPIO_DIR_INPUT);

驱动再把该 GPIO 号写入 GPIO_SEL2SD0_CDN_SEL 字段,把它路由为 SDIO 控制器的卡检测输入:

c 复制代码
HAL_GPIO_SD0_CDN_SEL(SDIO0_CDN_PIN);   /* 本板配置为 64 号 GPIO */

卡检测因此不是控制器自带的一根引线,而是普通 GPIO 经开关矩阵接到控制器的 CD 输入端。配置完成后软件不再读 GPIO 电平,而是读控制器内部的 CDETECT 寄存器,所以定位问题时看 CDETECT 即可,读 GPIO 输入值容易误判。

3.2 插入状态与去抖

开关与上拉电阻共同决定引脚电平,三种插入状态的结果如下:
#mermaid-svg-Cn8xUml2whpn1iKh{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-Cn8xUml2whpn1iKh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Cn8xUml2whpn1iKh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Cn8xUml2whpn1iKh .error-icon{fill:#552222;}#mermaid-svg-Cn8xUml2whpn1iKh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Cn8xUml2whpn1iKh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Cn8xUml2whpn1iKh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Cn8xUml2whpn1iKh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Cn8xUml2whpn1iKh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Cn8xUml2whpn1iKh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Cn8xUml2whpn1iKh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Cn8xUml2whpn1iKh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Cn8xUml2whpn1iKh .marker.cross{stroke:#333333;}#mermaid-svg-Cn8xUml2whpn1iKh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Cn8xUml2whpn1iKh p{margin:0;}#mermaid-svg-Cn8xUml2whpn1iKh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Cn8xUml2whpn1iKh .cluster-label text{fill:#333;}#mermaid-svg-Cn8xUml2whpn1iKh .cluster-label span{color:#333;}#mermaid-svg-Cn8xUml2whpn1iKh .cluster-label span p{background-color:transparent;}#mermaid-svg-Cn8xUml2whpn1iKh .label text,#mermaid-svg-Cn8xUml2whpn1iKh span{fill:#333;color:#333;}#mermaid-svg-Cn8xUml2whpn1iKh .node rect,#mermaid-svg-Cn8xUml2whpn1iKh .node circle,#mermaid-svg-Cn8xUml2whpn1iKh .node ellipse,#mermaid-svg-Cn8xUml2whpn1iKh .node polygon,#mermaid-svg-Cn8xUml2whpn1iKh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Cn8xUml2whpn1iKh .rough-node .label text,#mermaid-svg-Cn8xUml2whpn1iKh .node .label text,#mermaid-svg-Cn8xUml2whpn1iKh .image-shape .label,#mermaid-svg-Cn8xUml2whpn1iKh .icon-shape .label{text-anchor:middle;}#mermaid-svg-Cn8xUml2whpn1iKh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Cn8xUml2whpn1iKh .rough-node .label,#mermaid-svg-Cn8xUml2whpn1iKh .node .label,#mermaid-svg-Cn8xUml2whpn1iKh .image-shape .label,#mermaid-svg-Cn8xUml2whpn1iKh .icon-shape .label{text-align:center;}#mermaid-svg-Cn8xUml2whpn1iKh .node.clickable{cursor:pointer;}#mermaid-svg-Cn8xUml2whpn1iKh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Cn8xUml2whpn1iKh .arrowheadPath{fill:#333333;}#mermaid-svg-Cn8xUml2whpn1iKh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Cn8xUml2whpn1iKh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Cn8xUml2whpn1iKh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Cn8xUml2whpn1iKh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Cn8xUml2whpn1iKh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Cn8xUml2whpn1iKh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Cn8xUml2whpn1iKh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Cn8xUml2whpn1iKh .cluster text{fill:#333;}#mermaid-svg-Cn8xUml2whpn1iKh .cluster span{color:#333;}#mermaid-svg-Cn8xUml2whpn1iKh 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-Cn8xUml2whpn1iKh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Cn8xUml2whpn1iKh rect.text{fill:none;stroke-width:0;}#mermaid-svg-Cn8xUml2whpn1iKh .icon-shape,#mermaid-svg-Cn8xUml2whpn1iKh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Cn8xUml2whpn1iKh .icon-shape p,#mermaid-svg-Cn8xUml2whpn1iKh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Cn8xUml2whpn1iKh .icon-shape .label rect,#mermaid-svg-Cn8xUml2whpn1iKh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Cn8xUml2whpn1iKh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Cn8xUml2whpn1iKh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Cn8xUml2whpn1iKh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-Cn8xUml2whpn1iKh .st>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-Cn8xUml2whpn1iKh .st span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-Cn8xUml2whpn1iKh .st tspan{fill:#0b3d22!important;}#mermaid-svg-Cn8xUml2whpn1iKh .warn>*{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-Cn8xUml2whpn1iKh .warn span{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-Cn8xUml2whpn1iKh .warn tspan{fill:#5a4a06!important;}#mermaid-svg-Cn8xUml2whpn1iKh .dec>*{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-Cn8xUml2whpn1iKh .dec span{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-Cn8xUml2whpn1iKh .dec tspan{fill:#2a1a5e!important;}#mermaid-svg-Cn8xUml2whpn1iKh .out>*{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-Cn8xUml2whpn1iKh .out span{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-Cn8xUml2whpn1iKh .out tspan{fill:#6b3209!important;} 稳定计数反复清零

判决不通过
未插卡

开关断开,上拉 → 引脚 = 高
去抖窗口 20 ms

电平需连续稳定
完全插入

开关压合到地 → 引脚 = 低
半插入

触点抖动,电平高低反复
CDETECT 寄存器

bit0 = 0 表示卡在位
检测线程与中断服务函数的判据

去抖由控制器内的计数窗口完成,不是软件延时:

c 复制代码
/* 典型去抖时间 5~25 ms,此处配置为 20 ms */
HAL_SDIO_DEBNCE_SET(&sdio_dev[sdioIndex].hsdio, (Hal_Sys_AhbClkGet() / 50u));

AhbClk / 50 等于 AhbClk × 0.02 s,即以 AHB 时钟计数的 20 ms。只有 CD 引脚电平连续稳定 20 ms,控制器才更新 CDETECT 位。半插入时触点持续抖动,稳定计数不断被清零,判决无法通过,抖动在控制器内部被过滤掉,驱动层不需要再写去抖代码。

3.3 卡在位判定

驱动层的判定收敛在两级调用里:

c 复制代码
/* rthw_sd_detect():驱动侧 */
if ((Hal_Sdio_CardIsPresent(&hsdio)) || (host->flags & MMCSD_SUP_NONREMOVABLE))
{
    ret = 0x01;      /* 卡在位 */
}

/* Hal_Sdio_CardIsPresent():HAL 侧 */
if (0 == (Hal_RegRead(SDIO_REG(hsdio->Index, CDETECT), REG_MASK_ALL, 0u)))
{
    isPresent = TRUE;    /* CDETECT bit0 = 0,卡在位 */
}

CDETECT.bit0 == 0 判为在位。板级自查输出的对照是 CDETECT bit0=0 -> card present;未插卡的控制器则不注册块设备。

3.4 CLIC 向量中断

中断发生时执行的那段代码称为中断服务函数(ISR,Interrupt Service Routine)。本节说明它是如何被调用的。

该 SoC 的 CPU 是 RISC-V 内核,自带 CLIC(Core-Local Interrupt Controller,内核本地中断控制器)。外设中断请求汇入 CLIC,仲裁后进入 CPU。CLIC 初始化时把所有中断源设为向量中断模式:

c 复制代码
for (i = 0; i < MAX_IRQn; i++)
{
    CLIC->CLICINT[i].IP = 0;       /* 清除挂起位 */
    CLIC->CLICINT[i].ATTR |= 1;    /* SHV = 1,向量跳转 */
}

SHV(Selectable Hardware Vector)位的作用是:中断被判定有效后,CLIC 依据中断源编号直接向 CPU 提供处理函数地址,CPU 据此跳转,不经过软件查表。
SDIO0_IRQHandler CPU 硬件 CLIC 中断控制器 SDIO 控制器 SDIO0_IRQHandler CPU 硬件 CLIC 中断控制器 SDIO 控制器 #mermaid-svg-NNIkKe5hBkxxQd2q{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-NNIkKe5hBkxxQd2q .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NNIkKe5hBkxxQd2q .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NNIkKe5hBkxxQd2q .error-icon{fill:#552222;}#mermaid-svg-NNIkKe5hBkxxQd2q .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NNIkKe5hBkxxQd2q .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NNIkKe5hBkxxQd2q .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NNIkKe5hBkxxQd2q .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NNIkKe5hBkxxQd2q .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NNIkKe5hBkxxQd2q .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NNIkKe5hBkxxQd2q .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NNIkKe5hBkxxQd2q .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NNIkKe5hBkxxQd2q .marker.cross{stroke:#333333;}#mermaid-svg-NNIkKe5hBkxxQd2q svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NNIkKe5hBkxxQd2q p{margin:0;}#mermaid-svg-NNIkKe5hBkxxQd2q .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-NNIkKe5hBkxxQd2q text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-NNIkKe5hBkxxQd2q .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-NNIkKe5hBkxxQd2q .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-NNIkKe5hBkxxQd2q .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-NNIkKe5hBkxxQd2q .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-NNIkKe5hBkxxQd2q #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-NNIkKe5hBkxxQd2q .sequenceNumber{fill:white;}#mermaid-svg-NNIkKe5hBkxxQd2q #sequencenumber{fill:#333;}#mermaid-svg-NNIkKe5hBkxxQd2q #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-NNIkKe5hBkxxQd2q .messageText{fill:#333;stroke:none;}#mermaid-svg-NNIkKe5hBkxxQd2q .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-NNIkKe5hBkxxQd2q .labelText,#mermaid-svg-NNIkKe5hBkxxQd2q .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-NNIkKe5hBkxxQd2q .loopText,#mermaid-svg-NNIkKe5hBkxxQd2q .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-NNIkKe5hBkxxQd2q .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-NNIkKe5hBkxxQd2q .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-NNIkKe5hBkxxQd2q .noteText,#mermaid-svg-NNIkKe5hBkxxQd2q .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-NNIkKe5hBkxxQd2q .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-NNIkKe5hBkxxQd2q .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-NNIkKe5hBkxxQd2q .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-NNIkKe5hBkxxQd2q .actorPopupMenu{position:absolute;}#mermaid-svg-NNIkKe5hBkxxQd2q .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-NNIkKe5hBkxxQd2q .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-NNIkKe5hBkxxQd2q .actor-man circle,#mermaid-svg-NNIkKe5hBkxxQd2q line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-NNIkKe5hBkxxQd2q :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 校验 IE,按优先级仲裁,SHV 向量模式 读状态 / 清标志 / rt_event_send 驱动中断请求线,置 IP 位提供处理函数地址硬件向量跳转,自动保存现场mret 返回,恢复现场

SDIO0_IRQHandler 通过 ATTRIBUTE_ISR 声明,由编译器生成机器模式中断的现场保存、恢复与 mret 返回:

c 复制代码
ATTRIBUTE_ISR void SDIO0_IRQHandler(void)
{
    rt_interrupt_enter();
    if (RT_NULL != host[HAL_SDIO_INDEX_0])
    {
        rthw_sdio_irq_process(host[HAL_SDIO_INDEX_0]);
    }
    rt_interrupt_leave();
}

该函数不由软件调用,而是由 CLIC 硬件跳转进入;函数体内的 rt_interrupt_enterrt_interrupt_leave 只用于通知内核当前处于中断上下文。

3.5 电平触发与边沿触发

外设向 CLIC 发出中断请求,物理上不是发送数据,而是驱动一根专用请求线的电平。两种触发方式的差异解释了两条路径的分工:

触发方式 有效条件 撤销方式 上电时已插卡的行为
电平触发 请求线保持有效电平 软件清除标志后才撤销 标志已在中断使能前清除,且电平无变化,无待处理请求
边沿触发 请求线出现电平跳变 自动 无跳变,不产生请求

SD 卡检测属于电平触发型:标志由软件主动清除(__HAL_SDIO_CLEAR_INT),清除前请求线持续有效。驱动使能该中断时的顺序是先清除标志、再开放中断,所以上电时已插着的卡不会留下一个待处理请求,这也是上电必须由驱动主动查询一次的原因。中断信号本身只表示有事件发生,不携带事件内容;具体是哪类事件,例如卡插入、数据传输完成或超时,由 CPU 进入中断服务函数后读中断状态寄存器逐位判断得出。

3.6 中断向量表与处理函数

该 SoC 的中断源覆盖内核定时器与十余类外设,数量上百,但并非每个中断源都有专属处理函数:
#mermaid-svg-fZYHRTN4Cn9t3tVe{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-fZYHRTN4Cn9t3tVe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fZYHRTN4Cn9t3tVe .error-icon{fill:#552222;}#mermaid-svg-fZYHRTN4Cn9t3tVe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fZYHRTN4Cn9t3tVe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .marker.cross{stroke:#333333;}#mermaid-svg-fZYHRTN4Cn9t3tVe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fZYHRTN4Cn9t3tVe p{margin:0;}#mermaid-svg-fZYHRTN4Cn9t3tVe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .cluster-label text{fill:#333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .cluster-label span{color:#333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .cluster-label span p{background-color:transparent;}#mermaid-svg-fZYHRTN4Cn9t3tVe .label text,#mermaid-svg-fZYHRTN4Cn9t3tVe span{fill:#333;color:#333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .node rect,#mermaid-svg-fZYHRTN4Cn9t3tVe .node circle,#mermaid-svg-fZYHRTN4Cn9t3tVe .node ellipse,#mermaid-svg-fZYHRTN4Cn9t3tVe .node polygon,#mermaid-svg-fZYHRTN4Cn9t3tVe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fZYHRTN4Cn9t3tVe .rough-node .label text,#mermaid-svg-fZYHRTN4Cn9t3tVe .node .label text,#mermaid-svg-fZYHRTN4Cn9t3tVe .image-shape .label,#mermaid-svg-fZYHRTN4Cn9t3tVe .icon-shape .label{text-anchor:middle;}#mermaid-svg-fZYHRTN4Cn9t3tVe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fZYHRTN4Cn9t3tVe .rough-node .label,#mermaid-svg-fZYHRTN4Cn9t3tVe .node .label,#mermaid-svg-fZYHRTN4Cn9t3tVe .image-shape .label,#mermaid-svg-fZYHRTN4Cn9t3tVe .icon-shape .label{text-align:center;}#mermaid-svg-fZYHRTN4Cn9t3tVe .node.clickable{cursor:pointer;}#mermaid-svg-fZYHRTN4Cn9t3tVe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .arrowheadPath{fill:#333333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fZYHRTN4Cn9t3tVe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fZYHRTN4Cn9t3tVe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fZYHRTN4Cn9t3tVe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fZYHRTN4Cn9t3tVe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fZYHRTN4Cn9t3tVe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fZYHRTN4Cn9t3tVe .cluster text{fill:#333;}#mermaid-svg-fZYHRTN4Cn9t3tVe .cluster span{color:#333;}#mermaid-svg-fZYHRTN4Cn9t3tVe 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-fZYHRTN4Cn9t3tVe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fZYHRTN4Cn9t3tVe rect.text{fill:none;stroke-width:0;}#mermaid-svg-fZYHRTN4Cn9t3tVe .icon-shape,#mermaid-svg-fZYHRTN4Cn9t3tVe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fZYHRTN4Cn9t3tVe .icon-shape p,#mermaid-svg-fZYHRTN4Cn9t3tVe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fZYHRTN4Cn9t3tVe .icon-shape .label rect,#mermaid-svg-fZYHRTN4Cn9t3tVe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fZYHRTN4Cn9t3tVe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fZYHRTN4Cn9t3tVe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fZYHRTN4Cn9t3tVe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-fZYHRTN4Cn9t3tVe .irq>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .irq span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .irq tspan{fill:#103a80!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .weak>*{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .weak span{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .weak tspan{fill:#5a4a06!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .strong>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .strong span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-fZYHRTN4Cn9t3tVe .strong tspan{fill:#0b3d22!important;} 驱动实现了强符号
每 16 根引脚共用一个源
无强符号覆盖
中断源编号

SDIO0 / UART0 / GPIO 组 ...
启动代码为每源预置

.weak 默认项
SDIO0_IRQHandler
GPIO 分组处理函数

进入后再细分引脚
Default_Handler

默认处理或进入异常流程

启动代码为每个中断源预置 .weak 默认项,驱动以强符号覆盖其中一部分。有专属函数的只有驱动实现过的那些;GPIO 采用分组中断,每 16 根引脚共用一个中断源,进入处理后还需读引脚状态做细分。

中断服务函数内部只做三件事:读中断状态寄存器、清除标志、发送事件。卡片识别与文件系统挂载都不在这里,它们由线程负责,下一章说明这一分工。

四、挂载流程

4.1 三条线程的分工

加载由三条线程配合完成,它们之间只传信号,不传数据:
识别线程 mmcsd_detect 检测线程 rthw_mmcsd_detect 启动线程 INIT_APP 识别线程 mmcsd_detect 检测线程 rthw_mmcsd_detect 启动线程 INIT_APP #mermaid-svg-B1b1hZX5fQLIqtiH{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-B1b1hZX5fQLIqtiH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-B1b1hZX5fQLIqtiH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-B1b1hZX5fQLIqtiH .error-icon{fill:#552222;}#mermaid-svg-B1b1hZX5fQLIqtiH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-B1b1hZX5fQLIqtiH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-B1b1hZX5fQLIqtiH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-B1b1hZX5fQLIqtiH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-B1b1hZX5fQLIqtiH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-B1b1hZX5fQLIqtiH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-B1b1hZX5fQLIqtiH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-B1b1hZX5fQLIqtiH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-B1b1hZX5fQLIqtiH .marker.cross{stroke:#333333;}#mermaid-svg-B1b1hZX5fQLIqtiH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-B1b1hZX5fQLIqtiH p{margin:0;}#mermaid-svg-B1b1hZX5fQLIqtiH .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-B1b1hZX5fQLIqtiH text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-B1b1hZX5fQLIqtiH .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-B1b1hZX5fQLIqtiH .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-B1b1hZX5fQLIqtiH .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-B1b1hZX5fQLIqtiH .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-B1b1hZX5fQLIqtiH #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-B1b1hZX5fQLIqtiH .sequenceNumber{fill:white;}#mermaid-svg-B1b1hZX5fQLIqtiH #sequencenumber{fill:#333;}#mermaid-svg-B1b1hZX5fQLIqtiH #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-B1b1hZX5fQLIqtiH .messageText{fill:#333;stroke:none;}#mermaid-svg-B1b1hZX5fQLIqtiH .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-B1b1hZX5fQLIqtiH .labelText,#mermaid-svg-B1b1hZX5fQLIqtiH .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-B1b1hZX5fQLIqtiH .loopText,#mermaid-svg-B1b1hZX5fQLIqtiH .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-B1b1hZX5fQLIqtiH .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-B1b1hZX5fQLIqtiH .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-B1b1hZX5fQLIqtiH .noteText,#mermaid-svg-B1b1hZX5fQLIqtiH .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-B1b1hZX5fQLIqtiH .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-B1b1hZX5fQLIqtiH .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-B1b1hZX5fQLIqtiH .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-B1b1hZX5fQLIqtiH .actorPopupMenu{position:absolute;}#mermaid-svg-B1b1hZX5fQLIqtiH .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-B1b1hZX5fQLIqtiH .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-B1b1hZX5fQLIqtiH .actor-man circle,#mermaid-svg-B1b1hZX5fQLIqtiH line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-B1b1hZX5fQLIqtiH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 事件唤醒,开始加载 上电、CMD0、逐个尝试卡类型、建立卡信息 dfs_mount 挂载 /sd/ rt_event_send(SDIO_INT_CARD_DET)mmcsd_change 投递邮箱 mmcsd_detect_mb结果邮箱 mmcsd_hotpluge_mb

检测线程的主体是等待事件、确认结果、执行挂载的循环:

c 复制代码
while (1)
{
    rt_event_recv(&hw_sdio->event, SDIO_INT_CARD_DET,
                  RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                  RT_WAITING_FOREVER, RT_NULL);

    mmcsd_change(host);                  /* 通知识别线程 */
    ret = mmcsd_wait_cd_changed(300);    /* 等识别结果,最多 300 tick */

    if ((MMCSD_HOST_PLUGED == ret) && (0x01 == rthw_sd_detect(host)))
    {
        /* 查找块设备并挂载到 /sd/ */
        dfs_mount(name, "/sd/", "elm", 0, 0);
        mmcsd_mount_over();
    }
    else if ((MMCSD_HOST_UNPLUGED == ret) && (0x00 == rthw_sd_detect(host)))
    {
        Hal_Sdio_DeInit(&hw_sdio->sdio_dev->hsdio);   /* 拔卡后反初始化 */
    }
}

mmcsd_change 不识别卡片,它只向 mmcsd_detect_mb 投一条消息。识别是否成功的判据是 mmcsd_wait_cd_changed 的返回值,它按 host->card 是否为空返回已插入或已拔出,不再读一次 CD 引脚。

4.2 卡类型识别与命令序列

卡的类型无法凭外观判断,识别线程按 SDIO、SD、MMC 的顺序逐个尝试:每个分支先发 CMD0 复位,再发对应的探测命令,先应答成功者即按该类型处理。SD 卡分支的关键命令是 ACMD41,其响应携带卡支持的工作电压范围(OCR,Operating Conditions Register,工作条件寄存器)。确认类型后再读取卡标识与参数(CID 卡标识、CSD 卡参数、SCR 配置、RCA 相对地址),据此注册块设备。
#mermaid-svg-y25h6VEpQuV6nHLl{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-y25h6VEpQuV6nHLl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-y25h6VEpQuV6nHLl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-y25h6VEpQuV6nHLl .error-icon{fill:#552222;}#mermaid-svg-y25h6VEpQuV6nHLl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-y25h6VEpQuV6nHLl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-y25h6VEpQuV6nHLl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-y25h6VEpQuV6nHLl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-y25h6VEpQuV6nHLl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-y25h6VEpQuV6nHLl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-y25h6VEpQuV6nHLl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-y25h6VEpQuV6nHLl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-y25h6VEpQuV6nHLl .marker.cross{stroke:#333333;}#mermaid-svg-y25h6VEpQuV6nHLl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-y25h6VEpQuV6nHLl p{margin:0;}#mermaid-svg-y25h6VEpQuV6nHLl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-y25h6VEpQuV6nHLl .cluster-label text{fill:#333;}#mermaid-svg-y25h6VEpQuV6nHLl .cluster-label span{color:#333;}#mermaid-svg-y25h6VEpQuV6nHLl .cluster-label span p{background-color:transparent;}#mermaid-svg-y25h6VEpQuV6nHLl .label text,#mermaid-svg-y25h6VEpQuV6nHLl span{fill:#333;color:#333;}#mermaid-svg-y25h6VEpQuV6nHLl .node rect,#mermaid-svg-y25h6VEpQuV6nHLl .node circle,#mermaid-svg-y25h6VEpQuV6nHLl .node ellipse,#mermaid-svg-y25h6VEpQuV6nHLl .node polygon,#mermaid-svg-y25h6VEpQuV6nHLl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-y25h6VEpQuV6nHLl .rough-node .label text,#mermaid-svg-y25h6VEpQuV6nHLl .node .label text,#mermaid-svg-y25h6VEpQuV6nHLl .image-shape .label,#mermaid-svg-y25h6VEpQuV6nHLl .icon-shape .label{text-anchor:middle;}#mermaid-svg-y25h6VEpQuV6nHLl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-y25h6VEpQuV6nHLl .rough-node .label,#mermaid-svg-y25h6VEpQuV6nHLl .node .label,#mermaid-svg-y25h6VEpQuV6nHLl .image-shape .label,#mermaid-svg-y25h6VEpQuV6nHLl .icon-shape .label{text-align:center;}#mermaid-svg-y25h6VEpQuV6nHLl .node.clickable{cursor:pointer;}#mermaid-svg-y25h6VEpQuV6nHLl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-y25h6VEpQuV6nHLl .arrowheadPath{fill:#333333;}#mermaid-svg-y25h6VEpQuV6nHLl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-y25h6VEpQuV6nHLl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-y25h6VEpQuV6nHLl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y25h6VEpQuV6nHLl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-y25h6VEpQuV6nHLl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y25h6VEpQuV6nHLl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-y25h6VEpQuV6nHLl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-y25h6VEpQuV6nHLl .cluster text{fill:#333;}#mermaid-svg-y25h6VEpQuV6nHLl .cluster span{color:#333;}#mermaid-svg-y25h6VEpQuV6nHLl 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-y25h6VEpQuV6nHLl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-y25h6VEpQuV6nHLl rect.text{fill:none;stroke-width:0;}#mermaid-svg-y25h6VEpQuV6nHLl .icon-shape,#mermaid-svg-y25h6VEpQuV6nHLl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y25h6VEpQuV6nHLl .icon-shape p,#mermaid-svg-y25h6VEpQuV6nHLl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-y25h6VEpQuV6nHLl .icon-shape .label rect,#mermaid-svg-y25h6VEpQuV6nHLl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y25h6VEpQuV6nHLl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-y25h6VEpQuV6nHLl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-y25h6VEpQuV6nHLl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-y25h6VEpQuV6nHLl .seq>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-y25h6VEpQuV6nHLl .seq span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-y25h6VEpQuV6nHLl .seq tspan{fill:#103a80!important;}#mermaid-svg-y25h6VEpQuV6nHLl .try>*{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-y25h6VEpQuV6nHLl .try span{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-y25h6VEpQuV6nHLl .try tspan{fill:#5a4a06!important;}#mermaid-svg-y25h6VEpQuV6nHLl .ok>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-y25h6VEpQuV6nHLl .ok span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-y25h6VEpQuV6nHLl .ok tspan{fill:#0b3d22!important;}#mermaid-svg-y25h6VEpQuV6nHLl .reg>*{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-y25h6VEpQuV6nHLl .reg span{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-y25h6VEpQuV6nHLl .reg tspan{fill:#6b3209!important;} 类型逐个尝试
OCR 应答成功
mmcsd_power_up

上电 + 稳定延时
CMD0 复位

试 SDIO:CMD5
CMD0 复位

试 SD:CMD55 + ACMD41
CMD0 复位

试 MMC:CMD1
init_sd:CMD0 → CMD8

判 SD 2.0 → ACMD41 确认 OCR
CMD2 / CMD10 读 CID
CMD3 取 RCA

转推挽模式
CMD9 读 CSD

换算容量与速率
CMD7 选中卡

ACMD51 读 SCR
ACMD6 设 4 位总线

CMD6 切换高速
rt_mmcsd_blk_probe

注册块设备

init_sd 走完这套命令后调用 rt_mmcsd_blk_probe,按卡上是否存在分区表走 MBR 或 GPT 分支注册块设备:整卡设备名取自 host 名,有分区时另注册形如 sdio00sdio01 的分区设备。检测线程挂载时先找分区设备名,找不到再回退到整卡设备名。

4.3 挂载与实测记录

块设备就绪后,检测线程执行 dfs_mount(name, "/sd/", "elm", 0, 0),把块设备以 elm(Elm-Chan FatFs)文件系统挂到 /sd/,此后上层可读写 /sd/ 下的文件。

板级启动日志与自查输出可作为上述各环节的对照:

复制代码
[I/sd]: SD card capacity 30535680 KB.
found part[0], begin: 4194304, size: 29.120GB
[I/sdio]: card pluged!
[I/sdio]: sdmmc mount to /sd/ !
本文结论 实测对照
卡在位判据是 CDETECT.bit0 == 0 自查输出 CDETECT bit0=0 -> card present
无卡控制器不注册块设备 未插卡控制器在设备列表中 not found
上电路径以主动查询完成挂载 启动日志出现 sdmmc mount to /sd/ !,容量 29.1 GiB
插拔跳变由中断路径处理 热插拔 5 轮均正常完成,其中一轮插回后约 800 ms 检出、100 ms 内挂载成功

4.4 中断与线程的职责划分

#mermaid-svg-zGtIc3simlUsVChz{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-zGtIc3simlUsVChz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zGtIc3simlUsVChz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zGtIc3simlUsVChz .error-icon{fill:#552222;}#mermaid-svg-zGtIc3simlUsVChz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zGtIc3simlUsVChz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zGtIc3simlUsVChz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zGtIc3simlUsVChz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zGtIc3simlUsVChz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zGtIc3simlUsVChz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zGtIc3simlUsVChz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zGtIc3simlUsVChz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zGtIc3simlUsVChz .marker.cross{stroke:#333333;}#mermaid-svg-zGtIc3simlUsVChz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zGtIc3simlUsVChz p{margin:0;}#mermaid-svg-zGtIc3simlUsVChz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zGtIc3simlUsVChz .cluster-label text{fill:#333;}#mermaid-svg-zGtIc3simlUsVChz .cluster-label span{color:#333;}#mermaid-svg-zGtIc3simlUsVChz .cluster-label span p{background-color:transparent;}#mermaid-svg-zGtIc3simlUsVChz .label text,#mermaid-svg-zGtIc3simlUsVChz span{fill:#333;color:#333;}#mermaid-svg-zGtIc3simlUsVChz .node rect,#mermaid-svg-zGtIc3simlUsVChz .node circle,#mermaid-svg-zGtIc3simlUsVChz .node ellipse,#mermaid-svg-zGtIc3simlUsVChz .node polygon,#mermaid-svg-zGtIc3simlUsVChz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zGtIc3simlUsVChz .rough-node .label text,#mermaid-svg-zGtIc3simlUsVChz .node .label text,#mermaid-svg-zGtIc3simlUsVChz .image-shape .label,#mermaid-svg-zGtIc3simlUsVChz .icon-shape .label{text-anchor:middle;}#mermaid-svg-zGtIc3simlUsVChz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zGtIc3simlUsVChz .rough-node .label,#mermaid-svg-zGtIc3simlUsVChz .node .label,#mermaid-svg-zGtIc3simlUsVChz .image-shape .label,#mermaid-svg-zGtIc3simlUsVChz .icon-shape .label{text-align:center;}#mermaid-svg-zGtIc3simlUsVChz .node.clickable{cursor:pointer;}#mermaid-svg-zGtIc3simlUsVChz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zGtIc3simlUsVChz .arrowheadPath{fill:#333333;}#mermaid-svg-zGtIc3simlUsVChz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zGtIc3simlUsVChz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zGtIc3simlUsVChz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zGtIc3simlUsVChz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zGtIc3simlUsVChz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zGtIc3simlUsVChz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zGtIc3simlUsVChz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zGtIc3simlUsVChz .cluster text{fill:#333;}#mermaid-svg-zGtIc3simlUsVChz .cluster span{color:#333;}#mermaid-svg-zGtIc3simlUsVChz 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-zGtIc3simlUsVChz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zGtIc3simlUsVChz rect.text{fill:none;stroke-width:0;}#mermaid-svg-zGtIc3simlUsVChz .icon-shape,#mermaid-svg-zGtIc3simlUsVChz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zGtIc3simlUsVChz .icon-shape p,#mermaid-svg-zGtIc3simlUsVChz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zGtIc3simlUsVChz .icon-shape .label rect,#mermaid-svg-zGtIc3simlUsVChz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zGtIc3simlUsVChz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zGtIc3simlUsVChz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zGtIc3simlUsVChz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-zGtIc3simlUsVChz .isr>*{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-zGtIc3simlUsVChz .isr span{fill:#fdf3cf!important;stroke:#d4aa2c!important;color:#5a4a06!important;}#mermaid-svg-zGtIc3simlUsVChz .isr tspan{fill:#5a4a06!important;}#mermaid-svg-zGtIc3simlUsVChz .th>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-zGtIc3simlUsVChz .th span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-zGtIc3simlUsVChz .th tspan{fill:#0b3d22!important;} 线程上下文:所有耗时工作
中断上下文:只做三件事
事件标志
读中断状态寄存器
清标志
rt_event_send
检测线程:等事件、发邮箱、挂载
识别线程:上电、逐条命令、建立卡信息

中断上下文只做读状态、清标志、发事件三件事,识别与挂载这类耗时数十毫秒的工作全部在线程上下文完成。这样既保证中断响应及时,也不会让命令序列长时间占用 CPU。一次从插卡到可读写,先后经过下列阶段:
#mermaid-svg-jIuPM3UaoatrRdAj{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-jIuPM3UaoatrRdAj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jIuPM3UaoatrRdAj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jIuPM3UaoatrRdAj .error-icon{fill:#552222;}#mermaid-svg-jIuPM3UaoatrRdAj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jIuPM3UaoatrRdAj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jIuPM3UaoatrRdAj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jIuPM3UaoatrRdAj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jIuPM3UaoatrRdAj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jIuPM3UaoatrRdAj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jIuPM3UaoatrRdAj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jIuPM3UaoatrRdAj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jIuPM3UaoatrRdAj .marker.cross{stroke:#333333;}#mermaid-svg-jIuPM3UaoatrRdAj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jIuPM3UaoatrRdAj p{margin:0;}#mermaid-svg-jIuPM3UaoatrRdAj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jIuPM3UaoatrRdAj .cluster-label text{fill:#333;}#mermaid-svg-jIuPM3UaoatrRdAj .cluster-label span{color:#333;}#mermaid-svg-jIuPM3UaoatrRdAj .cluster-label span p{background-color:transparent;}#mermaid-svg-jIuPM3UaoatrRdAj .label text,#mermaid-svg-jIuPM3UaoatrRdAj span{fill:#333;color:#333;}#mermaid-svg-jIuPM3UaoatrRdAj .node rect,#mermaid-svg-jIuPM3UaoatrRdAj .node circle,#mermaid-svg-jIuPM3UaoatrRdAj .node ellipse,#mermaid-svg-jIuPM3UaoatrRdAj .node polygon,#mermaid-svg-jIuPM3UaoatrRdAj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jIuPM3UaoatrRdAj .rough-node .label text,#mermaid-svg-jIuPM3UaoatrRdAj .node .label text,#mermaid-svg-jIuPM3UaoatrRdAj .image-shape .label,#mermaid-svg-jIuPM3UaoatrRdAj .icon-shape .label{text-anchor:middle;}#mermaid-svg-jIuPM3UaoatrRdAj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jIuPM3UaoatrRdAj .rough-node .label,#mermaid-svg-jIuPM3UaoatrRdAj .node .label,#mermaid-svg-jIuPM3UaoatrRdAj .image-shape .label,#mermaid-svg-jIuPM3UaoatrRdAj .icon-shape .label{text-align:center;}#mermaid-svg-jIuPM3UaoatrRdAj .node.clickable{cursor:pointer;}#mermaid-svg-jIuPM3UaoatrRdAj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jIuPM3UaoatrRdAj .arrowheadPath{fill:#333333;}#mermaid-svg-jIuPM3UaoatrRdAj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jIuPM3UaoatrRdAj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jIuPM3UaoatrRdAj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jIuPM3UaoatrRdAj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jIuPM3UaoatrRdAj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jIuPM3UaoatrRdAj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jIuPM3UaoatrRdAj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jIuPM3UaoatrRdAj .cluster text{fill:#333;}#mermaid-svg-jIuPM3UaoatrRdAj .cluster span{color:#333;}#mermaid-svg-jIuPM3UaoatrRdAj 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-jIuPM3UaoatrRdAj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jIuPM3UaoatrRdAj rect.text{fill:none;stroke-width:0;}#mermaid-svg-jIuPM3UaoatrRdAj .icon-shape,#mermaid-svg-jIuPM3UaoatrRdAj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jIuPM3UaoatrRdAj .icon-shape p,#mermaid-svg-jIuPM3UaoatrRdAj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jIuPM3UaoatrRdAj .icon-shape .label rect,#mermaid-svg-jIuPM3UaoatrRdAj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jIuPM3UaoatrRdAj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jIuPM3UaoatrRdAj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jIuPM3UaoatrRdAj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-jIuPM3UaoatrRdAj .app>*{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-jIuPM3UaoatrRdAj .app span{fill:#dbe7fd!important;stroke:#3a6fd8!important;color:#103a80!important;}#mermaid-svg-jIuPM3UaoatrRdAj .app tspan{fill:#103a80!important;}#mermaid-svg-jIuPM3UaoatrRdAj .fs>*{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-jIuPM3UaoatrRdAj .fs span{fill:#d8f5e0!important;stroke:#2c9e5f!important;color:#0b3d22!important;}#mermaid-svg-jIuPM3UaoatrRdAj .fs tspan{fill:#0b3d22!important;}#mermaid-svg-jIuPM3UaoatrRdAj .core>*{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-jIuPM3UaoatrRdAj .core span{fill:#d2f4f4!important;stroke:#1c9e9e!important;color:#083d3d!important;}#mermaid-svg-jIuPM3UaoatrRdAj .core tspan{fill:#083d3d!important;}#mermaid-svg-jIuPM3UaoatrRdAj .drv>*{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-jIuPM3UaoatrRdAj .drv span{fill:#e9dffb!important;stroke:#7a5cc9!important;color:#2a1a5e!important;}#mermaid-svg-jIuPM3UaoatrRdAj .drv tspan{fill:#2a1a5e!important;}#mermaid-svg-jIuPM3UaoatrRdAj .hw>*{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-jIuPM3UaoatrRdAj .hw span{fill:#fde8d6!important;stroke:#e07e2f!important;color:#6b3209!important;}#mermaid-svg-jIuPM3UaoatrRdAj .hw tspan{fill:#6b3209!important;} 在位:主动发事件
不在位:等待插拔
上电复位
INIT_BOARD:供电 + 卡检测脚

INIT_PREV:邮箱 + 识别线程
INIT_APP:host + 事件 + 检测线程
CD 引脚在位
检测线程被唤醒
CD 跳变 → 中断 → 服务函数发事件
识别线程:上电、CMD0、逐个尝试、建立卡信息
dfs_mount 挂载 /sd/

上电插卡与使用中插拔在这里汇合:触发方式不同,识别与挂载的步骤相同。

相关推荐
贾伟康8 小时前
【HarmonyOS 7新能力|050】Core File Kit mmap工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·文件系统·mmap
ysu_031418 小时前
TinyML 模型部署:从 Edge Impulse 到 STM32F103
驱动开发·stm32·嵌入式硬件·mcu·硬件架构·硬件工程·dsp开发
youyou-06062 天前
Classic AUTOSAR 中 CAN 协议栈整体架构
mcu·面试·汽车
橘色的喵2 天前
从文件系统到 SD 卡:数据写入的四层路径
dma·文件系统·sd·rtos·数据拷贝
意法半导体STM323 天前
【官方原创】LAT1709STM32C5硬件CRC值的计算话题
stm32·单片机·嵌入式硬件·mcu·crc·微控制器·stm32c5
国科安芯4 天前
低轨卫星姿轨控系统中高可靠嵌入式控制单元的设计与验证
单片机·mcu·低轨卫星·星间链路·卫星姿轨控
国科安芯4 天前
卫星电源管理系统中宽温域低功耗MCU的选型与适应性分析
嵌入式硬件·mcu·抗干扰·抗辐射·宽温
youcans_5 天前
【嵌入式软件AI编程】09. 使用VS Code调试STM32程序
stm32·mcu·ai编程·嵌入式软件·claude code
国科安芯5 天前
寄存器级 Flash 擦除与六轮迭代踩坑实录
嵌入式硬件·mcu·架构·flash·抗辐射·eflash