十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

STM32 SDIO接口深度解析:从协议原理到驱动调试实战

STM32 SDIO接口深度解析:从协议原理到驱动调试实战 1. 项目概述为什么需要深入理解STM32的SDIO如果你正在用STM32做项目尤其是涉及到存储卡、Wi-Fi模块比如ESP8266/ESP32的SDIO模式或者一些高速外设那你大概率绕不开SDIO这个接口。很多朋友第一次接触SDIO可能都是从SD卡读写开始的用CubeMX点点鼠标HAL库函数调一调好像也能跑起来。但一旦项目稍微复杂点比如要求高稳定性、高速度或者遇到了莫名其妙的读写失败、数据损坏你就会发现仅仅停留在“能用”的层面是远远不够的。SDIO全称Secure Digital Input/Output它不仅仅是SD卡的接口协议更是一个在嵌入式领域广泛应用的高速、可扩展的总线标准。STM32家族从F1到最新的H7系列绝大多数型号都集成了SDIO控制器。理解它意味着你能更高效地利用STM32的性能能更从容地调试外设也能在方案选型时做出更明智的决策。比如当你的产品需要高速数据存储时你是选择SPI模式操作SD卡还是SDIO模式两者的性能差异可能高达十倍。再比如你想用SDIO接口驱动一个Wi-Fi模块官方的驱动库可能只提供了基础功能当需要深度定制或优化时不了解底层协议和寄存器操作几乎寸步难行。我自己在多个工业数据采集和物联网网关项目中都深度使用了SDIO接口。从最初的F4系列驱动SD卡记录传感器数据到后来用F7系列通过SDIO连接Wi-Fi模块实现百兆级的数据透传期间踩过的坑数不胜数。这篇文章我就结合这些实战经验把STM32的SDIO从协议框架、硬件设计、驱动编写到调试排错系统地拆解一遍。目标不是复述数据手册而是让你能真正“掌握”它在项目中用得放心、用得高效。2. SDIO协议核心与STM32硬件架构解析要驾驭STM32的SDIO外设不能只盯着库函数必须对其背后的协议和硬件架构有个清晰的认知。这就像开车只知道踩油门和刹车也能开但懂点发动机和变速箱原理开起来会更顺出了问题也知道大概该查哪里。2.1 SDIO协议栈命令、响应与数据流SDIO协议是一种主从式、基于命令响应的通信协议。整个通信过程可以想象成一场严谨的对话命令Command阶段主机STM32向从设备如SD卡发送一个6字节的命令帧。这个帧包含了命令索引比如CMD0是复位命令、参数比如要读写的地址以及一个7位的CRC校验码。所有命令都是通过CMD线单向发送的。响应Response阶段从设备收到命令后必须通过CMD线回送一个响应帧。响应有多种格式R1, R2, R3, R6, R7等长度从1字节到17字节不等包含了命令执行状态、设备状态寄存器OCR、CID、CSD等或操作条件如电压范围等信息。数据Data阶段对于读写命令在响应之后会进入数据阶段。数据通过1位默认模式或4位高速模式的DAT[3:0]数据线传输同时伴随数据时钟。每个数据块Block传输结束后会有一个16位的CRC校验。STM32的SDIO控制器硬件会自动处理CRC的生成与校验。这里的关键是理解命令类型。SDIO命令分为广播命令无地址发给所有卡如CMD0和寻址命令带相对卡地址RCA发给特定卡如CMD17读单块。上电初始化过程本质上就是通过一系列广播命令和寻址命令识别卡的类型SDSCv1, SDSCv2, SDHC/SDXC、获取其操作条件、分配地址并切换到高速模式的过程。注意很多初始化失败的问题根源在于命令序列或时序不符合规范。例如在发送CMD8检查电压范围后必须正确解析R7响应否则后续的ACMD41激活初始化可能不会得到正确响应。2.2 STM32 SDIO控制器内部机制STM32的SDIO控制器是一个相当复杂的DMA状态机综合体。它帮你完成了协议中最繁琐的部分但你需要正确配置它才能发挥效能。时钟系统这是性能与稳定的基石。SDIO外设有独立的时钟域SDIOCLK通常由PLL提供。你需要通过SDIO_CLK引脚输出给卡用的时钟CK。这里有三个关键时钟SDIOCLK控制器工作时钟最高可达AHB总线频率如F407是48MHzH743可达200MHz以上。CK输出给SD卡的时钟。其频率由SDIOCLK经过一个CLKDIV分频器得到。初始化阶段必须使用低速通常400kHz识别完成后才能切换到高速最高可达SDIOCLK/2即25MHz或50MHz模式。总线时钟指AHB总线时钟用于控制器与内核、DMA之间的数据交换。 配置时钟时务必确认你的STM32型号和主频支持的目标CK频率。过高的初始时钟会导致设备无响应。数据路径与FIFO控制器内部有一个嵌入式的数据FIFO通常是32位宽深度可能为32或更多字。当使能DMA时数据会在FIFO和内存之间自动搬运如果不使能DMA你就需要查询状态寄存器或使用中断在FIFO半满/半空时及时读写数据。FIFO的深度和触发阈值配置直接影响到DMA传输的效率和总线占用率。状态与控制寄存器STM32提供了丰富的寄存器来监控和控制传输过程。最常用的有SDIO_POWER控制电源和时钟使能。SDIO_CLKCR配置时钟分频、边沿、总线宽度等。SDIO_ARG存放命令参数。SDIO_CMD写入命令索引和启动命令传输。SDIO_RESPx1-4读取命令响应。SDIO_DCTRL控制数据块大小、传输方向、使能等。SDIO_STA状态寄存器包含命令响应超时、CRC错误、数据超时、FIFO状态等数十个标志位。调试时这个寄存器是你的第一现场。SDIO_DCOUNT数据计数器用于多块传输。SDIO_FIFO数据端口寄存器通过它读写FIFO中的数据。理解这些寄存器你就能看懂HAL库甚至标准库背后的操作在库函数出现问题或需要极致优化时可以直接操作寄存器。2.3 SDIO与SPI模式对比何时该用谁这是一个经典的选型问题。简单对比如下特性SDIO模式SPI模式引脚数最少6根CMD, CLK, DAT[3:0]最少4根CS, CLK, MISO, MOSI通信协议专用SD协议有命令/响应/数据阶段通用SPI协议通过发送特定命令字节序列模拟速度高。支持1位/4位总线时钟可达50MHz理论速率25MB/s。低。通常受限于SPI时钟如F1系列最高18MHz实际速率10MB/s。硬件支持需要MCU集成SDIO控制器。几乎所有MCU都有SPI外设。软件复杂度较高需处理完整初始化序列、状态机。较低驱动简单有大量现成代码。典型应用高速SD卡读写、SDIO接口Wi-Fi/蓝牙模块。低速SD卡读写、与众多SPI外设共用总线。选型建议追求极致性能、存储大数据如视频、音频缓存、高速日志无脑选SDIO模式。引脚资源紧张项目简单速度要求不高1MB/s可以用SPI模式省下SDIO的引脚做其他用途。驱动特定SDIO外设如Wi-Fi模块必须使用SDIO模式因为这类模块的通信协议完全基于SDIO标准定义的功能和命令集。3. 从零构建SD卡驱动HAL库与寄存器操作双视角了解了原理我们动手实现一个健壮的SD卡驱动。我会同时展示HAL库和寄存器级操作让你理解上层封装和底层硬件之间的联系。3.1 硬件设计与引脚配置首先硬件连接必须正确。以STM32F407ZGT6和标准SD卡槽为例STM32引脚SD卡引脚功能备注PC8DAT0数据线04位模式时必需PC9DAT1数据线14位模式时必需PC10DAT2数据线24位模式时必需PC11DAT3数据线34位模式时也用作卡检测可选PC12CLK时钟需配置为高速输出PD2CMD命令/响应开漏输出必须接上拉电阻通常10kΩ实操心得上拉电阻是关键。CMD线和DAT线在协议中都是开漏/推挽可配置的但为了确保信号质量和高速下的上升沿速度外部上拉电阻4.7kΩ~10kΩ必不可少。很多不稳定、时好时坏的问题都是上拉电阻没接或阻值不合适导致的。DAT3线在初始化后通常会被卡内部上拉用于卡检测但外部上拉能增加可靠性。在CubeMX中配置相对简单找到SDIO外设选择4位总线宽度然后检查自动分配的引脚是否正确尤其是PD2 CMD引脚有时会被错误分配。时钟配置里注意SDIOCLK的来源确保其频率在你的预期内。3.2 初始化流程深度剖析初始化流程是一套固定的“组合拳”其核心目的是让卡进入传输状态Transfer State并协商到最高的可用速度和总线模式。以下是基于寄存器视角的详细步骤我会穿插说明HAL库HAL_SD_Init()内部在做什么。步骤1电源与时钟基础配置// 1. 使能SDIO时钟和外设GPIO时钟 RCC-AHB1ENR | RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN; RCC-APB2ENR | RCC_APB2ENR_SDIOEN; // 2. 配置GPIO为复用功能高速输出上拉硬件已上拉则软件上拉可选 // ... GPIO初始化代码 ... // 3. 软复位SDIO控制器可选但建议做 SDIO-POWER 0x00000000; SDIO-CLKCR 0x00000000; SDIO-ARG 0x00000000; SDIO-CMD 0x00000000; SDIO-DCTRL 0x00000000; SDIO-ICR 0xFFFFFFFF; // 清除所有中断标志 SDIO-MASK 0x00000000; // 4. 给卡上电设置电源状态 (PWRCTL[1:0]11) SDIO-POWER SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1; // 等待至少74个时钟周期让电源稳定简单延时即可 delay_us(10);这一步HAL库在HAL_SD_MspInit()和SD_PowerON()函数中完成。步骤2卡识别模式初始化目标是在低速400kHz下让卡进入待机状态并获取其基本信息。// 5. 设置低速时钟例如SDIOCLK48MHz目标CK400kHz则CLKDIV 48M/(2*400k)-2 ≈ 58 SDIO-CLKCR (58 0); // CLKDIV // 保持1位总线宽度上升沿采样 SDIO-CLKCR ~(SDIO_CLKCR_WIDBUS_0 | SDIO_CLKCR_WIDBUS_1); // 6. 发送CMD0 (GO_IDLE_STATE)让所有卡复位到空闲状态 SDIO-ARG 0x00000000; SDIO-CMD (0 SDIO_CMD_CMDINDEX_Pos) | SDIO_CMD_CPSMEN; // 等待命令发送完成标志CMDSENT或超时 while(!(SDIO-STA SDIO_STA_CMDSENT) (timeout MAX_TIMEOUT)); SDIO-ICR SDIO_STA_CMDSENT; // 清除标志CMD0是广播命令无响应。发送成功后所有卡进入空闲状态。步骤3验证操作条件与卡类型识别这是初始化最核心也最容易出错的部分。// 7. 发送CMD8 (SEND_IF_COND)检查电压范围2.7-3.6V和请求模式检查 SDIO-ARG 0x000001AA; // [7:0]检查模式0xAA[11:8]电压2.7-3.6V (0x1) SDIO-CMD (8 SDIO_CMD_CMDINDEX_Pos) | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0; // 等待短响应R7 // 等待响应就绪标志CMDREND或超时 if (SDIO-STA SDIO_STA_CMDREND) { uint32_t resp SDIO-RESP1; // 读取R7响应 if ((resp 0xFFF) 0x1AA) { // 卡支持CMD8是SD卡v2.0或更高版本 card_type CARD_SD_V2; } else { // 响应不匹配可能是v1.x卡或不支持该电压的卡按v1.x流程处理 card_type CARD_SD_V1; } SDIO-ICR SDIO_STA_CMDREND; } else { // 超时无响应可能是MMC卡或v1.x SD卡它们不支持CMD8 card_type CARD_SD_V1_OR_MMC; }为什么CMD8如此重要它是区分SD卡v2.0和旧版卡/MMC卡的关键。只有v2.0的SD卡才会响应CMD8并且返回你发送的参数。如果无响应你需要按v1.x或MMC流程走。步骤4发送ACMD41进行初始化ACMD41SD_SEND_OP_COND是应用特定命令发送前必须先发CMD55APP_CMD告知卡下一个是应用命令。uint32_t timeout 0; uint32_t arg 0; if (card_type CARD_SD_V2) { arg 0x40FF8000; // HCS1 (支持高容量SDHC/SDXC), XPC0, S18R0, 电压范围3.2-3.3V } else { arg 0x00FF8000; // HCS0, 电压范围 } do { // 先发CMD55 (APP_CMD)带上RCA此时为0因为卡还没地址 SDIO-ARG 0x00000000; SDIO-CMD (55 SDIO_CMD_CMDINDEX_Pos) | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0; // ... 等待响应检查R1响应中的APP_CMD位 ... // 再发ACMD41 (SD_APP_OP_COND) SDIO-ARG arg; SDIO-CMD (41 SDIO_CMD_CMDINDEX_Pos) | SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0; // ... 等待响应读取R3响应 ... uint32_t ocr SDIO-RESP1; // OCR寄存器 if (timeout MAX_INIT_TIMEOUT) { return SD_ERROR; // 初始化超时 } delay_ms(10); // 等待卡上电完成 } while (!(ocr (1UL 31))); // 检查OCR第31位卡上电完成位这是一个循环过程因为卡需要时间完成内部初始化。循环发送ACMD41直到卡的OCR寄存器第31位被置1表示卡已准备好。这里HAL库的SDIO_PowerON()函数封装了这个循环但超时时间和参数需要根据你的卡调整。步骤5获取CID、分配RCA、选择卡并切换到高速模式// 8. 所有卡都响应了ACMD41后发送CMD2 (ALL_SEND_CID)获取唯一CID // 9. 发送CMD3 (SEND_RELATIVE_ADDR)为卡分配一个相对地址RCA卡会通过R6响应返回其RCA // 10. 发送CMD7 (SELECT/DESELECT_CARD)带上RCA选择该卡进入传输状态 // 11. 发送CMD16 (SET_BLOCKLEN)设置块大小通常为512字节 // 12. 发送ACMD6 (SET_BUS_WIDTH)切换到4位总线模式如果支持 // 13. 调整SDIO-CLKCR中的CLKDIV提高时钟频率到最高允许值如24MHz或更高完成以上步骤后卡就处于就绪状态可以进行读写操作了。HAL库的HAL_SD_InitCard()函数完整实现了这一序列。3.3 单块与多块读写操作实现初始化成功后读写操作相对标准化。核心是配置好数据控制寄存器SDIO_DCTRL然后发送相应的读写命令。单块读操作CMD17流程设置SDIO_DCTRL数据块大小512、数据传输方向控制器到卡、使能数据传输。设置SDIO_DTIMER配置数据超时时间根据时钟频率计算。设置SDIO_DLEN设置数据长度块大小。发送CMD17READ_SINGLE_BLOCK参数为要读取的扇区地址对于SDHC/SDXC卡地址是扇区号对于标准容量卡地址是字节地址。等待数据就绪。如果使能了DMA则DMA会自动搬运数据如果使用查询或中断则需要轮询SDIO_STA的RXDAVL标志并从SDIO_FIFO读取数据。等待数据结束标志DATAEND清除状态。多块读操作CMD18流程与单块读类似但发送的是CMD18READ_MULTIPLE_BLOCK并且SDIO_DLEN设置为总字节数块数*块大小。传输完成后需要发送CMD12STOP_TRANSMISSION来终止多块传输。写操作CMD24/CMD25流程与读操作对称但数据传输方向相反卡到控制器发送的命令是CMD24WRITE_BLOCK或CMD25WRITE_MULTIPLE_BLOCK。重要避坑点地址对齐与DMA缓存。STM32的SDIO DMA通常要求源/目标内存地址是4字节对齐的。如果你要读写一个不是4字节对齐的缓冲区可能会导致DMA传输错误或数据错位。解决方法有两种一是确保你的读写缓冲区地址是4字节对齐的例如使用__align(4)修饰符或编译器特定属性二是在使用DMA时先对齐数据到临时缓冲区再进行传输。HAL库内部有时会处理这个问题但自己写底层驱动时必须留意。4. 性能优化与高级功能探索当基础驱动跑通后我们自然会追求更快的速度和更稳定的表现。这里有几个关键的优化方向。4.1 提升吞吐量4位模式、高时钟与DMA优化启用4位宽模式这是提升速度最直接有效的方法。在初始化完成后发送ACMD6命令并将SDIO_CLKCR寄存器的WIDBUS位设置为014位总线。理论带宽立即提升至4倍。提高SDIO时钟CK频率在卡支持的情况下通过CSD寄存器中的TRAN_SPEED字段获取逐步提高CLKDIV分频值提高CK。对于Class10以上的卡通常可以稳定运行在25MHzSDIO模式甚至50MHz高速模式需发送CMD6切换。注意提高频率可能带来信号完整性问题务必确保PCB走线良好上拉电阻合适。高效使用DMASDIO支持DMA1或DMA2的通道4。配置DMA为外设到存储器读或存储器到外设写模式数据宽度为字32位并开启FIFO。关键技巧是合理设置DMA传输的数据量。对于多块读写一次性设置好总数据长度让DMA连续传输比多次启动单块DMA效率高得多。同时利用DMA的双缓冲或循环模式可以实现“乒乓操作”在传输当前数据块时CPU可以处理上一个数据块实现流水线作业最大化吞吐量。优化CPU与SDIO的协作如果不用DMA采用中断方式处理FIFO。将FIFO阈值设置为合理值例如接收时设为FIFO半满以减少中断频率降低CPU负载。4.2 使用SDIO驱动Wi-Fi模块以ESP8266为例SDIO不仅是存储接口更是功能强大的通用外设接口。以乐鑫ESP8266的SDIO从机模式为例其通信框架基于SDIO协议但定义了自定义的功能Function和命令。硬件连接除了标准的CMD、CLK、DAT[3:0]通常还需要一根中断线INT从Wi-Fi模块接到STM32的GPIO用于模块向主机发起事件通知。初始化差异初始化流程与SD卡类似也需要发送CMD0、CMD5等命令进行枚举。但CMD5的响应OCR寄存器内容不同用于协商电压和识别SDIO设备。功能与读写SDIO协议支持多个“功能”Function每个功能有独立的寄存器和数据空间。例如Function 0是公共区域用于卡识别Function 1可能是Wi-Fi模块的数据端口。对Wi-Fi模块的读写通常通过CMD52IO_RW_DIRECT和CMD53IO_RW_EXTENDED来完成。CMD52用于读写一个字节到功能寄存器的指定地址。这是配置模块如设置工作模式、中断使能的主要方式。CMD53用于块读写是数据传输的主力。你需要指定功能号、地址模式字节/块、读写方向、块大小和数量。中断处理Wi-Fi模块通过INT线通知主机有数据到达或状态改变。STM32需要在对应的GPIO中断服务函数中读取模块的状态寄存器通过CMD52判断事件类型然后通过CMD53读取数据或进行相应处理。驱动SDIO Wi-Fi模块的复杂性远高于SD卡因为你需要实现一套完整的“SDIO主机驱动栈”包括中断处理、数据包封装/解封装、与网络协议栈如LWIP的对接等。通常模块厂商会提供基础的驱动库但深度优化和稳定性调试需要你对SDIO协议有很深的理解。4.3 低功耗设计考量在电池供电设备中SDIO的功耗不容忽视。动态时钟控制在不进行读写操作时可以通过设置SDIO_CLKCR的CLKEN位来关闭CK时钟输出显著降低功耗。在需要通信前再重新使能。电源管理对于SD卡可以通过发送CMD7将其置入断开状态Disconnect State此时DAT线输出驱动被关闭。更彻底的方法是控制卡槽的电源MOSFET物理断电。睡眠模式下的处理当STM32进入Stop等低功耗模式时SDIO时钟会停止。唤醒后必须重新初始化SDIO外设和SD卡因为卡可能已经丢失了状态。你的驱动需要具备重初始化的能力。5. 调试实战常见问题与排查指南即使按照手册一步步来调试SDIO也常会遇到各种“玄学”问题。下面是我总结的一些典型故障和排查思路。5.1 初始化失败问题排查现象可能原因排查步骤与解决方案发送CMD0后无任何反应1. 硬件连接错误CMD/CLK接反2. 电源问题电压不足、电流不够3. 时钟频率初始值太高1. 用示波器测量CMD和CLK线看是否有波形。CMD0发送时CMD线应有脉冲。2. 测量VDD引脚电压应在2.7-3.6V并确保电源能提供足够的峰值电流可达100mA以上。3. 将初始时钟分频调到最大降至100kHz以下再试。CMD8响应错误或超时1. 卡是SDv1.x或MMC卡不支持CMD82. 发送的检查模式参数0xAA或电压参数不对1. 如果CMD8超时按v1.x流程继续发ACMD41不带HCS位。2. 确认SDIO-ARG参数是否正确设置为0x1AA。ACMD41循环超时1. 卡不支持指定的电压范围2. ACMD41参数错误特别是HCS位3. 发送ACMD41前未正确发送CMD551. 检查OCR响应确认卡接受的电压范围是否匹配。2. 对于SDv2卡尝试将HCS位设为0再试。3.确保每次发ACMD41前都先对同一RCA发CMD55并检查CMD55的响应中APP_CMD位是否被置位。获取到RCA后CMD7选择卡失败1. RCA错误2. 卡未准备好还在初始化3. 总线冲突多卡情况1. 确认使用的RCA是CMD3响应中返回的值。2. 增加ACMD41循环后的延时。3. 排查硬件确保总线上只有一张卡。5.2 读写操作中的数据错误现象可能原因排查步骤与解决方案读出的数据全为0或0xFF1. 数据线连接问题DAT0未接通2. 未切换到4位模式但按4位模式读取3. 读命令的地址错误LBA与字节地址混淆1. 测量DAT0线在读写时的波形。2. 确认SDIO_CLKCR的WIDBUS位设置与实际总线宽度一致。3.对于SDHC/SDXC卡容量2GBCMD17/18/24/25的地址是扇区号LBA不是字节地址这是最常见的错误之一。数据CRC错误1. 时钟频率过高信号质量差2. 数据线或CMD线上拉电阻缺失或阻值过大3. PCB走线过长存在反射或串扰1. 降低时钟频率看是否改善。2. 在CMD和所有DAT线靠近MCU端添加4.7kΩ上拉电阻。3. 检查PCB确保SDIO走线尽量短等长远离高速噪声源。多块读写中途失败1. DMA缓冲区溢出或下溢2. 数据超时时间设置太短3. 卡性能不足跟不上主机速度1. 检查DMA配置确保传输数据量与SDIO_DLEN一致且缓冲区足够大。2. 根据时钟频率重新计算并增大SDIO_DTIMER值。3. 在块之间增加少量延时或降低时钟频率。5.3 稳定性与长时间运行问题热插拔检测很多SD卡槽带有机械开关Card Detect CD连接到STM32的一个GPIO。你需要配置该GPIO为外部中断模式在中断服务程序中进行卡的卸载和重新初始化。注意卡拔出时应先发送CMD7将卡置为断开状态再停止时钟最后进行软件资源的释放。卡插入时需要完整的重新初始化流程。中断与DMA冲突如果在SDIO中断服务函数如传输完成中断中进行了耗时操作可能会影响DMA的进行或导致其他中断丢失。确保中断服务函数尽可能短小仅设置标志位在主循环中处理复杂逻辑。电源噪声SD卡在读写瞬间电流变化较大可能引起电源纹波影响MCU或其他敏感电路。在VDD引脚附近放置一个10-100μF的钽电容或电解电容并搭配一个0.1μF的陶瓷电容进行退耦能极大提升稳定性。调试的终极武器是逻辑分析仪。抓取CMD和DAT线上的波形对照SD Physical Layer Specification的时序图可以清晰地看到命令、响应和数据的每一个bit绝大多数软件问题都会无所遁形。没有逻辑分析仪的话充分利用STM32的SDIO_STA状态寄存器在关键步骤后打印出状态值也能提供宝贵的线索。最后分享一个我个人的体会STM32的SDIO外设功能强大但细节繁多第一次做可能会觉得头大。最好的学习方法是先用CubeMX和HAL库生成一个能跑通的代码然后关掉HAL库的中断和DMA用查询方式从CMD0开始一步一步地通过读写寄存器来实现初始化。这个过程会让你对协议的理解产生质的飞跃。之后再逐步加入中断、DMA等优化。当你能够脱离库仅凭数据手册和示波器/逻辑分析仪就能调通SDIO时你对STM32和嵌入式总线的理解就真正上了一个台阶。
返回列表