STM32 SD卡 booloader IAP 跳转 APP

本文详细介绍了如何使用STM32F405RGT芯片和STM32cube库函数实现从SD卡更新应用程序的Bootloader。通过修改flash地址、生成bin文件并将其复制到SD卡,再通过Bootloader程序进行APP程序的更新,包括文件系统的挂载、程序的擦除、下载和校验等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32 bootloader的意义以及其原理大家可自行去网上搜索,我这里就不多说了,其方式有多种,无非是从外设获取更新数据,然后再下载到相应的地址,程序进行跳转。有串口更新的方式,也可以无线进行更新的方式,多种多样,只需保证更新数据传输的过程当中的稳定性即可,这里采用的是从SD卡获取APP程序编译的bin文件进行更新,我这里使用的是STM32F405RGT芯片,用的STM32cube的库函数。
由于有两段程序,一个是bootloader程序,下载之后不会进行擦除,还有就是APP程序,即我们需要进行更新的程序,那么第一步,就先生成APP程序的bin文件,这里使用的是keil5编译软件。
一.APP程序

  1. 修改flash地址
    打开“option for target-Target,”如下图图中红色区域的地方,原本的地址为0x8000000、0x100000,0x8000000为主存储器的起始地址,0x100000为该芯片当中主存储器的大小,我修改为0x8070000、0x60000,起始地址与大小可根据自己程序的实际大小进行调整。
    在这里插入图片描述

flash主存储器构成
在这里插入图片描述

2.生成bin文件
这里不进行赘述,详情请参考一下链接
https://www.cnblogs.com/alanfeng/p/5659253.html
https://blog.youkuaiyun.com/zhzht19861011/article/details/5927924
生成bin文件之后,复制到SD卡中。

二. bootloader

1.修改ROM地址,同APP程序操作一样修改相关地址,起始地址为0x800000,大小为0x70000,后续接着为APP的起始地址。芯片得电后,在BOOT1、 BOOT2接地的情况下,即从主存储器启动,是从地址0x8000000启动程序的,故需将bootloader程序放在首地址,是不需要进行擦除的。
在这里插入图片描述

2.sSD卡bootloader流程
该程序总的流程如下:
1.挂在文件系统
2.是否存在升级文件BIN
3.解锁flash
4.擦除APP地址程序
5.读取文件数据
6.下载文件到APP ROM地址
7.校验APP地址数据
8.锁定flash
9.指定栈指针地址,一般指向APP初始地址,跳转复位向量APPaddr+4

3.相关程序

3.1 读取更新文件“Prj.bin”,查询是否存在
在这里插入图片描述
3.2解锁flash,进行APP地址程序擦除
在这里插入图片描述
3.3读取更新文件数据,这里采用的是循环读取,每次读取512字节并下载进APP地址,直至将所有数据读取完成。若采用指针进行动态内存分配,将所有数据一次性读取完成下载也可,不过该方式编程数据类型容易出错,容易导致flsh寄存器SR 当中 PGS、PGP 两位硬件置1错误,导致程序不能进行正确的下载。
在这里插入图片描述
3.4 地址数据校验
在这里插入图片描述
3.5 指定栈指针,跳转复位向量。注意:若数据下载过程出错,程序会一直循环跳转至当前程序的入口,会跑飞。
在这里插入图片描述

至此SD boot更新APP完成。有问题欢迎讨论。

<think>我们正在讨论STM32IAP(在应用编程)升级,特别是通过SD进行升级。根据引用内容,IAP通常需要一个Bootloader程序来更新应用程序(APP)。用户希望找到使用SD进行IAP升级的示例代码和实现方法。实现思路:1.设计Bootloader程序:存储在STM32Flash的起始地址,负责检查SD中是否有新的固件,如果有,则将固件复制到Flash的APP区域,然后跳转APP执行。2.设计APP程序:存储在Flash中Bootloader之后的位置,需要配置中断向量表偏移(因为APP的起始地址不是0x08000000)。3.通过SD存储新的固件(通常是.bin文件),Bootloader能够读取SD中的文件。关键步骤:a.Bootloader程序:-初始化硬件(时钟、SD、UART等)-挂载SD文件系统(通常使用FATFS)-检查特定文件(如update.bin)是否存在-如果存在,则读取该文件,并将内容写入到APP的起始地址(如0x08010000)-校验固件(可选:CRC校验)-跳转APP(设置栈指针和程序计数器)b.APP程序:-修改中断向量表偏移(在system_stm32f10x.c中修改VECT_TAB_OFFSET,或者在启动时调用NVIC_SetVectorTable)-编译时设置程序起始地址(例如在Keil中设置IROM1的Start为0x08010000)c.生成固件文件:-在APP工程中,编译后生成.bin文件(通过fromelf命令或IDE配置)-将.bin文件复制到SD中,并命名为Bootloader识别的文件名(如update.bin)示例代码(Bootloader部分关键代码):由于代码较长,这里只给出关键步骤的伪代码和部分实际代码。注意:以下代码为简化示例,实际应用需要根据具体硬件和需求调整。1.Bootloader的main函数:```cintmain(void){//初始化系统时钟、SD、串口等SystemInit();SD_Init();//初始化SDUSART_Init(115200);//初始化串口用于调试信息//挂载文件系统if(f_mount(&fs,"",0)!=FR_OK){printf("MountSDCardFailed!\n");while(1);}//检查升级文件if(f_open(&file,"update.bin",FA_READ)==FR_OK){//获取文件大小f_size=f_size(&file);//检查文件大小是否合适(不超过APP区域的最大空间)if(f_size<=APP_MAX_SIZE){//擦除APP区域(从APP_START_ADDR开始,擦除足够的页)FLASH_Erase(APP_START_ADDR,f_size);//读取文件并写入Flashuint32_tbytes_read;uint32_taddr=APP_START_ADDR;uint8_tbuffer[512];while(!f_eof(&file)){f_read(&file,buffer,sizeof(buffer),&bytes_read);//将buffer写入Flash地址addrFLASH_Program(addr,buffer,bytes_read);addr+=bytes_read;}//关闭文件f_close(&file);//可选:校验固件(例如计算CRC并和文件中的CRC比较,或者使用其他方法)//...//删除文件(避免下次启动再次升级)f_unlink("update.bin");}else{printf("Firmwaretoobig!\n");}}//跳转APPJumpToApp();}voidJumpToApp(void){typedefvoid(*pFunction)(void);pFunctionJump_To_Application;uint32_tJumpAddress;//检查APP起始地址是否有有效栈指针(即APP的栈顶地址)if((*(volatileuint32_t*)APP_START_ADDR&0x2FFE0000)==0x20000000){//设置跳转地址(APP起始地址+4的位置是复位中断向量的地址)JumpAddress=*(volatileuint32_t*)(APP_START_ADDR+4);Jump_To_Application=(pFunction)JumpAddress;//设置主堆栈指针__set_MSP(*(volatileuint32_t*)APP_START_ADDR);//跳转Jump_To_Application();}else{printf("NovalidAPP!\n");}}```2.APP程序配置:-在APP工程中,修改链接脚本(.ld文件或分散加载文件)将程序起始地址设为APP_START_ADDR(如0x08010000)。-在APP的main函数开始处,设置中断向量表偏移(如果使用HAL库,可以在SystemInit函数中修改,或者调用以下函数):```c//在APP的main函数开始处调用voidSystemInit(void)//或者在SystemInit中添加,或者单独调用一个函数{//...其他初始化SCB->VTOR=FLASH_BASE|VECT_TAB_OFFSET;//设置偏移量,例如0x10000}```3.生成APP的bin文件:-在Keil中,通过设置Output选项中的“CreateHEXFile”,然后使用fromelf工具生成bin文件:fromelf--bin--output=app.bin!L-或者使用J-Flash等工具将hex文件转换为bin文件。4.将生成的app.bin文件复制到SD中,并重命名为update.bin。5.将Bootloader程序烧录到0x08000000,将APP烧录到0x08010000(或者通过Bootloader更新APP)。注意事项:-在Bootloader中,需要确保对Flash的擦除和写入操作不会影响Bootloader自身(注意擦除的页不要覆盖Bootloader)。-在跳转前,需要关闭所有外设中断,并清除中断标志。-为了安全,可以添加固件校验(如CRC校验)。参考示例工程:引用中提到的GitHub示例工程(https://github.com/zengzhaorong/stm32_IAP-demo)是一个很好的参考,虽然它可能不是专门针对SD的,但IAP的核心部分(跳转、Flash编程)是通用的。我们可以在此基础上增加SD读取的功能。另外,也可以参考ST官方提供的IAP例程(如AN2557),其中包含了通过串口进行IAP的示例,我们可以将其修改为通过SD进行。相关问题:1.如何保证IAP升级过程中断电不会导致设备变砖?2.除了SD,还有哪些常用的IAP升级方式?3.在IAP升级中,BootloaderAPP之间如何传递参数(例如升级状态)?</think>### STM32 SD IAP升级实现详解 #### 一、基本原理 IAP(In-Application Programming)允许STM32通过自身程序更新Flash内容。SDIAP升级流程如下: 1. **Bootloader程序**:存储在Flash起始地址(0x08000000),负责检测SD中的新固件 2. **APP程序**:存储在Flash偏移地址(如0x08010000) 3. **升级过程**: - Bootloader检测SD中的.bin文件 - 擦除APP区域Flash - 将SD数据写入APP区域 - 跳转APP执行[^1][^2] #### 二、关键实现步骤 ##### 1. Bootloader程序设计(核心代码) ```c // main.c in Bootloader project #define APP_ADDR 0x08010000 // APP起始地址 int main(void) { // 初始化外设 SD_Init(); // 初始化SD USART_Init(); // 调试串口 FLASH_Unlock(); // 解锁Flash if(SD_Detect()) { // 检测SD插入 FIL file; if(f_open(&file, "firmware.bin", FA_READ) == FR_OK) { uint32_t file_size = f_size(&file); // 擦除APP区域Flash FLASH_EraseSector(FLASH_SECTOR_5, VOLTAGE_RANGE_3); // 从SD读取数据写入Flash uint8_t buffer[512]; uint32_t addr = APP_ADDR; while(!f_eof(&file)) { UINT bytes_read; f_read(&file, buffer, sizeof(buffer), &bytes_read); FLASH_Program(addr, buffer, bytes_read); addr += bytes_read; } f_close(&file); } } // 跳转APP void (*app_entry)(void) = (void (*)(void))(*(uint32_t*)(APP_ADDR + 4)); __set_MSP(*(uint32_t*)APP_ADDR); // 设置主堆栈指针 app_entry(); // 执行APP } ``` ##### 2. APP程序设计要点 1. **修改中断向量表偏移**: ```c // system_stm32f10x.c #define VECT_TAB_OFFSET 0x10000 // 匹配APP起始地址 ``` 2. **设置链接脚本**(Keil示例): ```text ; STM32F103x8.ld MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 128K // 偏移64KB } ``` ##### 3. SD文件系统集成 使用FATFS库(需包含以下组件): - `diskio.c`:底层SDIO/SPI驱动 - `ff.c`:FAT文件系统核心 - `ffconf.h`:配置文件系统参数 #### 三、完整实现流程 1. **编译Bootloader**:烧录到0x08000000 2. **编译APP**: - 设置程序起始地址(如0x08010000) - 生成.bin文件(Keil: `fromelf --bin -o app.bin !L`) 3. **准备SD**: - 格式化为FAT32 - 复制app.bin并重命名为`firmware.bin` 4. **升级操作**: - 插入SD后复位 - Bootloader自动检测并更新固件 #### 四、参考实现资源 1. **GitHub示例工程**: [STM32 IAP with SD Card Demo](https://github.com/zengzhaorong/stm32_IAP-demo) [^1] - 包含BootloaderAPP完整工程 - 支持STM32F1/F4系列 - SDIO和SPI两种驱动方式 2. **关键优化点**: - **固件校验**:添加CRC校验防止写入错误 - **双APP备份**:引用[2]提到的APP1/APP2交替升级 - **安全跳转**:检查栈指针合法性再跳转 ```c if((*(uint32_t*)APP_ADDR & 0x2FFE0000) == 0x20000000) { // 合法栈地址才跳转 } ``` #### 五、常见问题解决 1. **跳转失败**: - 检查APP的向量表偏移设置 - 确保Bootloader关闭所有中断再跳转 2. **SD读取失败**: - 确认FATFS正确初始化 - 检查SD电压匹配(3.3V) 3. **Flash写入错误**: - 确保擦除扇区大小正确(不同STM32系列不同) - 验证写保护已解除
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值