STM32F407同时使用USART与SD卡时数据丢失问题技术问询
STM32F407 USART接收+SDIO存SD卡丢数解决方案
核心故障原因
仅执行f_mount就触发数据丢失、回传错误,本质是两个问题叠加:
- 中断优先级配置错误:SDIO相关中断抢占优先级高于USART接收中断,SD卡初始化/读写操作触发的SDIO中断会持续抢占CPU,USART接收中断无法及时响应,导致接收寄存器溢出(ORE标志置位),数据丢失甚至错乱
- 底层驱动/代码逻辑问题:旧版本STM32F4 HAL库的SDIO驱动会在卡初始化、读写操作时长时间关闭全局中断,直接阻塞所有外设中断响应;如果直接在主流程/中断里执行完整的FatFS文件操作流程,单次阻塞时长可达几十到上百毫秒,远超USART接收的容错窗口。
分步修复方案
- 第一步:重新配置中断优先级
首先将NVIC优先级分组设置为NVIC_PRIORITYGROUP_4(全部4位优先级位用于抢占优先级,无子优先级),按响应优先级从高到低配置:- USART接收中断(如果用IDLE+DMA接收,还要加对应DMA接收中断):抢占优先级设为0~2的高优先级段
- SDIO全局中断、SDIO DMA传输中断:抢占优先级设为4~6的低优先级段
保证USART接收中断可以随时打断SDIO相关的中断服务和操作,不会被SD卡流程阻塞响应。配置完成后可以在读异常时查看USART->SR寄存器的ORE位,如果该位为1说明仍存在中断响应不及时的问题。
- 第二步:拆分接收与写入逻辑,加环形缓冲区做隔离
绝对不要在USART中断服务函数中执行任何FatFS、SD卡相关操作。USART中断内仅做最精简的操作:将接收到的字节/数据块直接存入环形FIFO缓冲区,立刻退出中断。
所有SD卡相关操作(f_mount、f_open、f_write等)全部放到主循环的低优先级逻辑中执行,检测到环形缓冲区攒够1个SD卡扇区(512字节)的数据时,再批量写入SD卡,避免频繁操作拉长阻塞时间。 - 第三步:修复SDIO驱动的关中断问题
如果你使用的CubeF4固件包版本低于1.27,检查stm32f4xx_hal_sd.c驱动代码,找到其中直接调用__disable_irq()关闭全局中断的逻辑,替换为仅关闭SDIO对应中断的操作,避免SDIO操作期间全局阻塞所有中断;也可以直接升级CubeIDE内的STM32F4固件包到最新稳定版,新版本已经修复了绝大多数SDIO驱动长时间关中断的bug。
调试阶段先把SDIO时钟分频设置为24MHz以下,避免高速通信出错触发重传,额外拉长操作耗时。 - 第四步:优化FatFS操作逻辑减少阻塞
不要每次写入都执行f_mount->f_open->f_lseek->f_write->f_close的全流程:上电阶段仅执行一次f_mount,打开目标文件后长期持有文件句柄,每次写入前用f_lseek移到文件末尾即可,等设备下电、卡拔出前再执行f_close和f_mount(NULL, SDPath, 0)的卸载操作,能将单次写入的阻塞时间压缩到毫秒级。
对实时性要求高的场景,打开SDIO的DMA传输模式,SD卡读写过程中CPU无需轮询等待,可以正常响应USART中断处理接收数据,仅在DMA传输完成后触发低优先级中断做收尾即可。
原测试使用的存在性能问题的SD卡操作代码:
if(f_mount(&myFatFS, SDPath,1)==FR_OK) { //HAL_GPIO_WritePin(GPIOG,GPIO_PIN_1,GPIO_PIN_SET); char myFileName[]="TEST1.TXT"; if (f_open(&myFile,myFileName,FA_WRITE | FA_OPEN_ALWAYS)==FR_OK) { //HAL_GPIO_WritePin(GPIOG,GPIO_PIN_2,GPIO_PIN_SET); f_lseek(&myFile, f_size(&myFile)); if(f_write(&myFile,store_data_1,sizeof(store_data_1),&myBytes)==FR_OK) { //HAL_GPIO_WritePin(GPIOG,GPIO_PIN_3,GPIO_PIN_SET) } f_close(&myFile); } }
内容的提问来源于stack exchange,提问作者mahdieh asadi
相关产品推荐
相关产品推荐

