实战手记:基于STM32F407的SD卡Bootloader开发
stm32f407 SD卡升级 bootloader程序 基于sdio和fatfs系统的stm32 bootloader程序 使用fatfs系统读取bin文件。 功能简介: 本程序使用fatfs系统读取bin文件。 开机后会自动检测sd卡,检测到sd卡后,再读取固定名称的bin文件,之后会对bin文件进行首包校验,判断该升级包的起始地址是否正确,正确的话,就循环读取bin文件并写入到flash中。 完成升级。 详细流程请看流程图
最近在项目里折腾了个基于SD卡的IAP升级方案,用到了STM32F407的SDIO接口和FatFs文件系统。整个过程踩了不少坑,记录些关键点给需要的小伙伴参考。
stm32f407 SD卡升级 bootloader程序 基于sdio和fatfs系统的stm32 bootloader程序 使用fatfs系统读取bin文件。 功能简介: 本程序使用fatfs系统读取bin文件。 开机后会自动检测sd卡,检测到sd卡后,再读取固定名称的bin文件,之后会对bin文件进行首包校验,判断该升级包的起始地址是否正确,正确的话,就循环读取bin文件并写入到flash中。 完成升级。 详细流程请看流程图
先来点干货,整个流程的核心代码结构长这样:
// SDIO初始化(关键参数设置) if(FATFS_LinkDriver(&SD_Driver, SDPath) != 0) return; f_mount(&fs, "", 1); // 文件操作 FRESULT res = f_open(&fil, "firmware.bin", FA_READ); f_read(&fil, buffer, sizeof(buffer), &br); // 首包校验 if(*(uint32_t*)buffer != APP_ADDRESS) { // 弹窗警告 show_error("起始地址错误!"); return; } // Flash写入 HAL_FLASH_Unlock(); FLASH_Erase_Sector(FLASH_SECTOR_6, VOLTAGE_RANGE_3); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, APP_ADDRESS, data); HAL_FLASH_Lock();硬件层那些事儿
SDIO的时钟配置直接关系到读写稳定性。实测发现当SD卡工作在4bit模式时,SDIOCLK设置为48MHz比较稳。遇到过几次文件系统挂载失败,后来发现是DMA传输时没做好内存对齐:
// 内存池必须4字节对齐! __align(4) uint8_t buffer[512];FatFs的暗坑
文件系统初始化时,特别注意f_mount返回值。有个隐蔽bug:当SD卡突然拔出时,直接重新初始化会导致死锁。后来改成超时重试机制:
for(int retry=0; retry<3; retry++){ if(f_mount(&fs, "", 1) == FR_OK) break; HAL_Delay(100); }首包校验的玄机
升级文件头四个字节必须是应用程序的起始地址。但直接读取可能会遇到大小端问题。后来改用联合体处理:
typedef union { uint32_t address; uint8_t bytes[4]; } header_check; if(header_check.address != 0x08008000) // 应用程序起始地址Flash操作的实战技巧
- 擦除前必须解锁,操作完记得上锁
- 建议按扇区擦除而不是整片擦除
- 写入时开启电源监控,防止电压不稳导致写入失败
// 带异常处理的擦除操作 if(FLASH_WaitForLastOperation(1000) != HAL_OK){ // 擦除超时处理 flash_error_handler(); }性能优化点
- 使用双缓冲机制:一边写入Flash,一边读取下一块数据
- 提前计算文件CRC32,和预先存储的校验值对比
- 升级完成后自动复位,避免手动重启
// 双缓冲示例 while(!f_eof(&fil)){ f_read(&fil, buf[active_buf], BLOCK_SIZE, &br); // 等待前一个块写入完成 while(flash_busy); memcpy(flash_buffer, buf[active_buf], BLOCK_SIZE); active_buf ^= 1; // 切换缓冲区 }避坑指南:测试阶段务必连接调试器,在Flash写入函数里设置断点。遇到过最诡异的问题是SD卡文件系统正常,但升级后程序跑飞,最后发现是中断向量表偏移量没设置。解决方案是在跳转应用前加这么一句:
SCB->VTOR = APP_ADDRESS & 0x1FFFFF80;整个方案实测升级1MB的固件文件约6秒完成,稳定性通过了连续100次拔插测试。关键还是处理好异常状态,毕竟实际使用中什么奇葩情况都可能出现——比如升级到一半用户突然拔卡,这时候需要在Flash里保存升级状态,下次启动时继续完成。
