SDHI中断处理与SD_INFO2寄存器:嵌入式存储错误处理实战

发布时间:2026/6/28 23:39:41
SDHI中断处理与SD_INFO2寄存器:嵌入式存储错误处理实战 1. SDHI中断处理与SD_INFO2寄存器从手册到实战的深度解析在嵌入式存储系统开发中与SD卡、eMMC等设备的稳定通信是项目成败的关键。很多开发者初期会依赖简单的轮询或基础的DMA传输但在面对复杂的现场环境、劣质卡或极端温度时通信链路中一个微小的CRC错误或一次意外的响应超时都可能导致整个文件系统挂起甚至数据损坏。这时一个设计精良的中断与错误处理机制就如同给系统装上了“火眼金睛”和“快速反应部队”能第一时间发现问题、定位根源并尝试恢复。瑞萨RA8T2微控制器中的SD/MMC主机接口SDHI模块其SD_INFO2寄存器正是这套机制的核心传感器。今天我们就抛开手册的冰冷描述结合我多年在工控和消费电子领域调试SDHI的经验深入聊聊这个寄存器的每一个比特位在实战中意味着什么以及如何围绕它构建一个真正健壮的存储驱动。SD_INFO2寄存器全称SD Card Interrupt Flag Register 2是一个32位状态寄存器但它真正起作用的精华部分集中在低16位。它的核心价值在于“状态捕获”而非“控制”。当SDHI硬件在执行命令或传输数据的过程中检测到任何异常都会自动将SD_INFO2中对应的标志位置1。作为驱动开发者我们的任务就是及时读取这些标志判断错误类型并执行相应的清理和恢复操作。理解它是告别“玄学”调试比如SD卡偶尔读写失败却找不到原因的第一步。接下来我们将从设计思路、寄存器详解、驱动实现到排错技巧完整走一遍实战流程。2. SD_INFO2寄存器核心功能位逐位精讲手册的位域描述是准确的但过于简略。我们需要结合物理层协议和实际编程场景理解每个标志位在何种“真实世界”的异常下会被触发以及其背后的硬件行为。2.1 错误检测标志位Bit 0-6, 15这部分是错误处理的“主战场”涵盖了从命令发出到数据收尾的全链路可能故障。CMDE (Bit 0): 命令错误标志手册描述检测到命令错误时置位。实战解读这通常意味着主机MCU发送的命令索引Command Index与从设备SD卡响应的命令索引不匹配。在SD物理层协议中响应包如R1, R6, R7会回显接收到的命令索引。不匹配可能源于CMD线受到严重干扰导致命令帧在传输过程中位错误卡解析出了另一个合法命令概率极低但存在。时序问题在高速模式如SDR104下如果SDCLK的建立/保持时间不满足要求可能在卡端采样出错。更常见的情况在命令序列执行中CBSY1软件错误地写入了新的命令到SD_CMD寄存器这会直接触发ILA非法访问错误但某些复杂的序列错误也可能导致CMDE。处理要点一旦CMDE置位当前命令序列会立即停止。你必须先处理这个错误通常需要软件复位SDHI模块或进行重新初始化才能发起新的命令。在CMD52SDIO自动发出的场景下手册提到了特殊的错误处理流程这提醒我们在编写SDIO驱动时需要额外注意。CRCE (Bit 1): CRC错误标志手册描述检测到CRC错误时置位。实战解读CRC是保证数据完整性的关键。此标志位在三种情况下置位响应CRC错误卡返回的响应包CRC校验失败。读取数据CRC错误从卡读取的数据块CRC校验失败。CRC状态令牌错误在写操作后卡会返回一个CRC状态令牌010b此令牌错误也会触发CRCE。处理要点CRC错误是物理层链路质量的晴雨表。高频的CRC错误往往意味着PCB布线问题CMD/DATA线长度不匹配阻抗不连续过孔太多。电源噪声SD卡供电纹波过大。信号完整性差未端接或端接电阻值不匹配。 处理方式通常是重试当前操作如重新发送读/写命令。SD协议本身支持单块读写失败后的重试。你需要实现重试逻辑并在重试超过一定次数后上报硬件错误。ENDE (Bit 2): 结束位错误标志手册描述检测到结束位错误时置位。实战解读SD协议中响应、数据块、CRC状态令牌都以一个“结束位”End Bit逻辑‘1’终止。ENDE置位意味着硬件在期望的位置没有检测到这个‘1’。可能原因卡突然被拔出或彻底无响应。严重的时钟不同步导致硬件采样窗口完全偏离数据位。在命令序列中对某个命令的响应长度不符合预期例如期望得到48位R1响应但只收到一部分。处理要点ENDE是一个比较严重的错误通常伴随通信完全中断。处理流程往往需要更激进比如对SDHI控制器进行软复位并尝试重新初始化卡。在热插拔检测CD/DAT3未启用的系统中ENDE可能是检测卡移除的间接信号之一。DTO (Bit 3): 数据超时标志手册描述检测到数据超时时置位。实战解读这是最常遇到的错误之一。超时计数器Ncycle由SD_OPTION.TOP[3:0]配置。DTO在多种超时场景下置位例如写操作后卡迟迟不返回CRC状态令牌SDnDAT0保持为低表示忙。读命令发出后卡迟迟不开始发送数据。在多块读传输中上一个数据块接收完成后下一个数据块迟迟不来。处理要点超时不一定是致命错误可能是卡内部正在进行擦除、写缓存等操作。关键在于合理设置TOP[3:0]。设置太短在低速卡或高负载卡上容易误报设置太长系统在卡真正死锁时响应迟钝。我的经验是对于标准SD卡初始化和识别阶段可以用较长的超时例如0xF最大值正常数据传输时根据卡性能通过CMD9读取CSD获取TAAC设置一个合理的值。处理DTO通常也是触发重试。ILW/ILR (Bit 4/5): SD_BUF0非法写/读访问标志手册描述检测到对SD_BUF0寄存器的非法访问时置位。实战解读这是防止软件BUG导致数据损坏的重要硬件保护机制。非法写场景包括在非数据传输状态下写缓冲区、缓冲区已满时继续写、在CRC错误或忙状态超时时写。非法读场景包括缓冲区为空时读、读取的数据存在CRC或END错误。处理要点在DMA传输中通常由DMA控制器自动管理BWE/BRE不易触发。但在CPU轮询搬运数据时必须严格遵循状态机先检查BWE1可写或BRE1可读再进行搬运操作搬运完成后及时清除BWE/BRE。驱动中应加入断言Assert一旦检测到ILW/ILR立即进入错误处理因为这极可能是驱动状态机出现了逻辑错误。RSPTO (Bit 6): 响应超时标志手册描述命令发出后超过640个SDCLK周期未收到响应时置位。实战解读与DTO类似但专门针对命令的响应阶段。640个时钟周期是SD协议规定的固定值不可配置。这意味着即使你的SDCLK很低如400kHz响应超时时间也会很长640/400k1.6ms。RSPTO通常意味着卡未正确初始化或处于非预期状态如处于IDLE状态却收到了非CMD0的命令。CMD线断路或对地短路。卡彻底损坏。处理要点在卡初始化序列CMD0,CMD8,ACMD41中对CMD8和ACMD41的响应超时处理是正常的用于判断卡版本和电压。但在正常数据传输中发生RSPTO通常需要执行完整的卡复位流程CMD0-CMD8-ACMD41...。ILA (Bit 15): 非法访问错误标志手册描述检测到非法访问错误时置位。实战解读这是对软件编程顺序的强约束。主要触发条件在命令序列进行中CBSY1时向SD_CMD寄存器写入新命令。设置了SD_CMD[11]1带数据传输且SD_CMD[7:0]0x0CCMD12停止传输时。CMD12本身不应被标记为带数据转移。处理要点在发送任何命令前必须检查CBSY和SD_CLK_CTRLEN标志。一个稳健的命令发送函数应该如下SDHI_StatusTypeDef SDHI_SendCommand(SDHI_HandleTypeDef *hsdhi, uint32_t Argument, uint16_t CmdIndex, uint32_t Flags) { // 1. 等待上一个命令序列完成 if (PollFlag(hsdhi-Instance-INFO2, SD_INFO2_CBSY_Msk, 0, TIMEOUT) ! SDHI_OK) { return SDHI_ERROR_TIMEOUT; } // 2. 等待时钟控制寄存器可写总线空闲 if (PollFlag(hsdhi-Instance-INFO2, SD_INFO2_SD_CLK_CTRLEN_Msk, 1, TIMEOUT) ! SDHI_OK) { return SDHI_ERROR_BUSY; } // 3. 配置命令参数和索引 hsdhi-Instance-ARG Argument; uint32_t tmp_cmd (CmdIndex SD_CMD_CMDIDX_Msk) | Flags; // 4. 写入命令寄存器启动传输 hsdhi-Instance-CMD tmp_cmd; return SDHI_OK; }严格遵守这个顺序可以完全避免ILA错误。2.2 状态与控制标志位Bit 7-14这部分标志位反映了SDHI控制器和总线的实时状态是驱动进行流控制的依据。SDD0MON (Bit 7): SDnDAT0引脚状态标志实战价值这是一个只读状态位直接反映DAT0线的电平。它的核心用途有两个轮询卡忙状态在发送诸如CMD32-35擦除或CMD38擦除等使卡进入繁忙状态的命令后卡会拉低DAT0线。此时DTO超时可能已触发但通过轮询SDD0MON从0变为1可以精确知道卡何时真正完成内部操作。辅助调试用逻辑分析仪或示波器抓波形时可以与此寄存器值对比验证硬件采样是否正确。BRE/BWE (Bit 8/9): SD_BUF0读/写使能标志手册补充这两个标志由硬件在特定条件下自动置位但必须由软件在操作完成后手动清除。这是很多新手容易忽略的关键点。CPU模式下的操作铁律读操作当BRE1时表示缓冲区有有效数据。软件应先清除BRE然后再从SD_BUF0读取SD_SIZE.LEN[9:0]指定长度的数据。如果先读数据再清BRE可能在多块传输中引发同步问题。写操作当BWE1时表示缓冲区可接受数据。软件应先清除BWE然后向SD_BUF0写入SD_SIZE指定长度的数据。与DMA的协同当使用DMA时需要将SD_INFO2_MASK中的BWEM和BREM置1屏蔽中断并设置SD_DMAEN.DMAEN1。DMA控制器会在传输完成时自动管理BWE/BRE无需软件干预。SD_CLK_CTRLEN (Bit 13): SD_CLK_CTRL写使能标志核心作用这是一个安全锁。当CBSY1命令序列进行中或命令序列刚结束的8个SDCLK周期内此位为0此时对SD_CLK_CTRL.CLKEN和CLKSEL的写操作被硬件忽略。这防止了在总线活动时突然改变或关闭时钟导致数据损坏。编程实践任何试图改变SDCLK频率如切换高速模式或启停时钟的操作前必须轮询此位为1。CBSY (Bit 14): 命令序列状态标志最关键的流控标志此位为1表示一个命令序列可能包含命令、响应、数据正在进行中。为0表示序列完成或空闲。重要时序向SD_CMD写入命令后硬件会立即将CBSY置1同时将SD_CLK_CTRLEN清0。命令序列完全结束后CBSY清0再经过8个SDCLK周期SD_CLK_CTRLEN置1。在CBSY1期间绝不要操作SD_CMD、SD_SIZE、SD_OPTION等关键寄存器。3. 构建以SD_INFO2为核心的健壮驱动框架理解了每个比特位我们需要将其融入一个完整的驱动状态机。这里我分享一个经过多个项目验证的中断驱动框架。3.1 初始化与配置初始化不仅仅是设置时钟和GPIO更重要的是配置错误处理的行为。void SDHI_Init(SDHI_HandleTypeDef *hsdhi) { // 1. 使能外设时钟配置GPIO复用功能略 // 2. 软件复位SDHI模块 (SOFT_RST.SDRST 1) hsdhi-Instance-SOFT_RST | SD_SOFT_RST_SDRST_Msk; while(hsdhi-Instance-SOFT_RST SD_SOFT_RST_SDRST_Msk); // 等待复位完成 // 3. 配置SD_OPTION超时、总线宽度 // 设置数据超时计数器TOP例如0xA约8.4ms 25MHz SDCLK MODIFY_REG(hsdhi-Instance-OPTION, SD_OPTION_TOP_Msk, 0xAUL SD_OPTION_TOP_Pos); // 设置总线宽度为4-bit假设已通过ACMD6切换 MODIFY_REG(hsdhi-Instance-OPTION, (SD_OPTION_WIDTH_Msk | SD_OPTION_WIDTH8_Msk), 0UL); // 4. 配置SD_INFO2_MASK决定哪些错误/事件能触发中断 uint32_t info2_mask 0; // 使能关键错误中断命令错、CRC错、结束位错、数据超时、响应超时、非法访问 info2_mask ~(SD_INFO2_MASK_CMDEM_Msk | SD_INFO2_MASK_CRCEM_Msk | SD_INFO2_MASK_ENDEM_Msk | SD_INFO2_MASK_DTOM_Msk | SD_INFO2_MASK_RSPTOM_Msk | SD_INFO2_MASK_ILAM_Msk); // 如果使用CPU轮询数据使能BRE/BWE中断。如果使用DMA则屏蔽它们。 #ifndef USE_SDHI_DMA info2_mask ~(SD_INFO2_MASK_BREM_Msk | SD_INFO2_MASK_BWEM_Msk); #else info2_mask | (SD_INFO2_MASK_BREM_Msk | SD_INFO2_MASK_BWEM_Msk); hsdhi-Instance-DMAEN | SD_DMAEN_DMAEN_Msk; // 使能DMA #endif // 保持ILR/ILW中断被屏蔽它们更多用于调试通常由状态机保证不触发 info2_mask | (SD_INFO2_MASK_ILRM_Msk | SD_INFO2_MASK_ILWM_Msk); hsdhi-Instance-INFO2_MASK info2_mask; // 5. 配置SD_CLK_CTRL初始低速时钟如400kHz用于识别 // 先确保可以写入 while(!(hsdhi-Instance-INFO2 SD_INFO2_SD_CLK_CTRLEN_Msk)); hsdhi-Instance-CLK_CTRL (0x01UL SD_CLK_CTRL_CLKSEL_Pos) | SD_CLK_CTRL_CLKEN_Msk; // PCLKB/4 // 6. 使能SDHI全局中断到NVIC NVIC_SetPriority(SDHI_IRQn, 5); NVIC_EnableIRQ(SDHI_IRQn); }3.2 中断服务程序ISR的设计逻辑中断服务程序是错误处理的“前线指挥部”必须高效、清晰。void SDHI_IRQHandler(void) { SDHI_HandleTypeDef *hsdhi g_sdhi_handle; // 全局句柄 uint32_t info2 hsdhi-Instance-INFO2; // 1. 处理错误标志高优先级 if (info2 SD_INFO2_CMDE_Msk) { hsdhi-ErrorCode | SDHI_ERROR_CMD_INDEX; hsdhi-Instance-INFO2 ~SD_INFO2_CMDE_Msk; // 写0清标志 // 触发错误恢复任务如软复位 OS_FlagSet(g_sdhi_error_flag, FLAG_CMD_ERROR); } if (info2 (SD_INFO2_CRCE_Msk | SD_INFO2_ENDE_Msk)) { hsdhi-ErrorCode | SDHI_ERROR_DATA_CRC; hsdhi-Instance-INFO2 ~(SD_INFO2_CRCE_Msk | SD_INFO2_ENDE_Msk); // 数据链路错误可能需重试 OS_FlagSet(g_sdhi_error_flag, FLAG_DATA_ERROR); } if (info2 SD_INFO2_DTO_Msk) { hsdhi-ErrorCode | SDHI_ERROR_DATA_TIMEOUT; hsdhi-Instance-INFO2 ~SD_INFO2_DTO_Msk; // 超时可能是卡忙触发重试或等待 OS_FlagSet(g_sdhi_event_flag, FLAG_DATA_TIMEOUT); } if (info2 SD_INFO2_RSPTO_Msk) { hsdhi-ErrorCode | SDHI_ERROR_RESP_TIMEOUT; hsdhi-Instance-INFO2 ~SD_INFO2_RSPTO_Msk; // 响应超时通常更严重可能需要重新初始化卡 OS_FlagSet(g_sdhi_error_flag, FLAG_RESP_TIMEOUT); } if (info2 SD_INFO2_ILA_Msk) { hsdhi-ErrorCode | SDHI_ERROR_ILLEGAL_ACCESS; hsdhi-Instance-INFO2 ~SD_INFO2_ILA_Msk; // 非法访问驱动逻辑BUG需要记录并复位 LOG_ERROR(SDHI ILA Error! Driver State Machine Corrupted.); OS_FlagSet(g_sdhi_error_flag, FLAG_FATAL_ERROR); } // 2. 处理数据传输事件如果使用CPU模式 #ifndef USE_SDHI_DMA if (info2 SD_INFO2_BRE_Msk) { // 数据已准备好可读取 hsdhi-RxState SDHI_RX_READY; hsdhi-Instance-INFO2 ~SD_INFO2_BRE_Msk; // 先清标志 // 在更高优先级任务或DMA回调中实际搬运数据 OS_SemaphoreGive(g_sdhi_rx_sem); } if (info2 SD_INFO2_BWE_Msk) { // 缓冲区已空可写入新数据 hsdhi-TxState SDHI_TX_READY; hsdhi-Instance-INFO2 ~SD_INFO2_BWE_Msk; // 先清标志 OS_SemaphoreGive(g_sdhi_tx_sem); } #endif // 3. 处理命令完成通过SD_INFO1寄存器但通常在同一个ISR uint32_t info1 hsdhi-Instance-INFO1; if (info1 SD_INFO1_RSPEND_Msk) { hsdhi-Instance-INFO1 ~SD_INFO1_RSPEND_Msk; // 命令响应已接收可以解析响应内容了 hsdhi-CommandResponse hsdhi-Instance-RESP[0]; // 读取响应寄存器 OS_FlagSet(g_sdhi_event_flag, FLAG_CMD_COMPLETE); } if (info1 SD_INFO1_ACEND_Msk) { hsdhi-Instance-INFO1 ~SD_INFO1_ACEND_Msk; // 整个访问命令数据结束 OS_FlagSet(g_sdhi_event_flag, FLAG_TRANSFER_COMPLETE); } }3.3 错误恢复状态机错误处理不是简单地重试而应是一个有状态、有次数限制的恢复过程。typedef enum { SDHI_STATE_IDLE, SDHI_STATE_READY, SDHI_STATE_TRANSFER, SDHI_STATE_ERROR, SDHI_STATE_RECOVERY } SDHI_StateTypeDef; SDHI_StatusTypeDef SDHI_ErrorRecovery(SDHI_HandleTypeDef *hsdhi) { static uint8_t retry_count 0; SDHI_StatusTypeDef status; switch(hsdhi-RecoveryState) { case RECOVERY_RESET_CONTROLLER: // 1. 尝试最轻量级的恢复软件复位SDHI模块 hsdhi-Instance-SOFT_RST | SD_SOFT_RST_SDRST_Msk; delay_us(100); // 重新初始化SDHI寄存器时钟、选项等但保持卡上电 SDHI_ReinitController(hsdhi); retry_count; if (retry_count 3) { hsdhi-RecoveryState RECOVERY_RETRY_OPERATION; return SDHI_BUSY; } else { // 复位控制器多次无效进入下一级 retry_count 0; hsdhi-RecoveryState RECOVERY_RESET_CARD; } break; case RECOVERY_RESET_CARD: // 2. 发送CMD0GO_IDLE_STATE对卡进行软件复位 status SDHI_SendCommand(hsdhi, 0, CMD0_INDEX, 0); if (status SDHI_OK) { // CMD0成功重新走初始化流程CMD8, ACMD41等 hsdhi-RecoveryState RECOVERY_REINIT_CARD; } else { // CMD0都失败可能是物理连接问题 hsdhi-RecoveryState RECOVERY_FATAL; } break; case RECOVERY_REINIT_CARD: // 3. 完整的卡初始化序列 status SDHI_InitCard(hsdhi); // 包含电压检查、OCR读取、CID读取等 if (status SDHI_OK) { hsdhi-State SDHI_STATE_READY; hsdhi-RecoveryState RECOVERY_IDLE; retry_count 0; return SDHI_OK; } else { retry_count; if (retry_count 2) { hsdhi-RecoveryState RECOVERY_RESET_CARD; } else { hsdhi-RecoveryState RECOVERY_FATAL; } } break; case RECOVERY_FATAL: // 4. 终极手段记录错误日志通知应用层可能需要进行硬件复位或卡移除检测 hsdhi-State SDHI_STATE_ERROR; LOG_CRITICAL(SDHI Fatal Error, Card Unrecoverable.); // 可选触发看门狗复位或进入安全模式 return SDHI_ERROR; break; default: break; } return SDHI_BUSY; }4. 实战排错指南与性能优化技巧手册不会告诉你的那些“坑”和技巧都在这里。4.1 常见问题排查速查表现象可能触发的标志位根本原因分析排查步骤与解决方案SD卡初始化失败RSPTO(CMD8/ACMD41无响应)1. 电源不稳或电压不符2. 时钟频率过高初始化应≤400kHz3. CMD线断路1. 测量VDD引脚电压2.7-3.6V检查电源电流能力2. 确认SD_CLK_CTRL.CLKSEL在初始化阶段设置为低速3. 用示波器检查CMD线上是否有波形幅值是否正常~3.3V偶尔读写数据错误CRCE,DTO1. 信号完整性差过冲、振铃2. 电源噪声大3. 时序裕量不足高速模式1. 检查PCB布线等长、参考平面、远离噪声源2. 在SD卡VDD和GND引脚就近放置10uF0.1uF电容3. 降低SDCLK频率测试。用示波器测量建立/保持时间是否满足卡规格书要求大数据量连续写失败DTO,ILW1. 卡内部写缓存满或FLASH编程慢2. 软件未及时提供数据导致BWE超时3. DMA配置错误缓冲区欠载1. 在写命令后增加等待SDD0MON变高的逻辑或使用CMD13查询卡状态2. 优化软件数据供给速率或使用双缓冲机制3. 检查DMA传输完成中断是否正常触发缓冲区大小是否匹配SD_SIZE多块传输中途卡死ENDE,ILA1. 在CBSY1时误操作了寄存器2. 发送CMD12STOP的时机或参数错误1. 检查所有SDHI寄存器操作是否都在CBSY0且SD_CLK_CTRLEN1时进行2. 确认在多块读/写结束时是否正确地发送了CMD12。对于SDIO的CMD53注意C52PUB和IOABT位的设置高负载下系统不稳定多种错误随机出现1. 中断服务程序执行时间过长导致错过其他中断或数据2. 任务堆栈溢出破坏SDHI句柄数据1. ISR中只做标志位清除和事件触发将复杂处理如数据搬运、错误恢复放到低优先级任务中2. 增加堆栈溢出检测确保hsdhi结构体所在内存不被意外修改4.2 性能与稳定性优化技巧中断与DMA的权衡对于SDHC Class 4的卡CPU中断模式足以应付且实现简单。对于Class 10/UHS-I卡强烈推荐使用DMA。将BWEM和BREM屏蔽让DMA自动处理数据搬运可以解放CPU并减少因中断延迟导致缓冲区溢出/欠载的风险。记得配置DMA为外设到存储器/存储器到外设模式数据宽度为32位与SD_BUF0对齐并启用DMA传输完成中断。超时时间的动态调整 不要死板地使用一个超时值。可以在驱动中实现一个简单的自适应策略// 根据卡类型和操作模式调整超时 void SDHI_AdjustTimeout(SDHI_HandleTypeDef *hsdhi, SDHI_OperationTypeDef OpType) { uint32_t timeout_cycles; switch(OpType) { case SDHI_OP_INIT: timeout_cycles SDHI_TIMEOUT_LONG; // 例如 0xF (最长) break; case SDHI_OP_READ_BLOCK: case SDHI_OP_WRITE_BLOCK: // 根据卡性能从CSD中读取的TAAC、TRAN_SPEED计算 timeout_cycles CalculateTimeoutFromCSD(hsdhi-CardType); break; case SDHI_OP_ERASE: timeout_cycles SDHI_TIMEOUT_VERY_LONG; // 擦除很慢 break; default: timeout_cycles SDHI_TIMEOUT_DEFAULT; } MODIFY_REG(hsdhi-Instance-OPTION, SD_OPTION_TOP_Msk, timeout_cycles SD_OPTION_TOP_Pos); }利用SD_ERR_STS1和SD_ERR_STS2进行深度诊断 当SD_INFO2报告一个概括性错误如CRCE时可以进一步读取SD_ERR_STS1来明确是响应CRC错RSPCRCE0/1还是数据CRC错RDCRCE甚至是CRC状态令牌错CRCTKE。这能帮你更精确地定位问题是发生在命令阶段还是数据阶段。SD_ERR_STS2则能区分是响应超时RSPTO0/1还是数据忙超时BSYTO0/1。SD_CLK_CTRL.CLKCTRLEN的妙用 将此位置1可以启用SDCLK的自动控制功能。在命令序列期间时钟自动运行序列结束后时钟自动停止。这不仅能降低功耗还能减少总线上的噪声对于信号完整性边缘的系统是一个很有用的功能。预防非法访问ILA/ILW/ILR的编程纪律将对SDHI寄存器的所有访问封装成函数并在函数入口处加入assert_param(IS_SDHI_NOT_BUSY(hsdhi))。在状态机切换时明确每个状态允许的操作。例如在“等待数据”状态只允许检查BRE/BWE和读SD_BUF0绝不允许写SD_CMD。最后调试SDHI这类高速外设一个逻辑分析仪至少100MHz采样率是必不可少的。抓取CMD和DAT线的波形对照SD物理层规范手册查看命令、响应、数据块的时序和内容再结合SD_INFO2等寄存器的值任何问题都无所遁形。记住寄存器状态是结果波形才是原因。把这两者结合起来你就能从被动的“救火队员”变成主动的“系统医生”。