实战手记:基于STM32F407的SD卡Bootloader开发
stm32f407 SD卡升级bootloader程序基于sdio和fatfs系统的stm32 bootloader程序使用fatfs系统读取bin文件。功能简介:本程序使用fatfs系统读取bin文件。开机后会自动检测sd卡,检测到sd卡后,再读取固定名称的bin文件,之后会对bin文件进行首包校验,判断该升级包的起始地址是否正确,正确的话,就循环读取bin文件并写入到flash中。完成升级。详
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里保存升级状态,下次启动时继续完成。

更多推荐
所有评论(0)