[STM32F1]SD卡Bootloader离线升级基于STM32F103

 做过很多Bootloader升级的产品,感觉Bootloader还是很有意思的。通过芯片的一段程序,去更新剩余的程序。从而达到更新产品软件的作用。芯片自带的Bootloader是通过芯片厂家的协议,通过烧录器把程序更新到Flash里面。而我们自己为什么还要部分的空间再写一个Bootloader呢?因为我们想通过我们自己的方式,升级芯片里的软件。

    传输方式那就太多了,基本有的通信方式理论上都可以进行传输升级,包括CAN、SPI、IIC、USART等等。做过汽车上面的CAN升级、USART升级、SD卡升级、OTA升级。其中CAN和USART升级都是在线升级,SD卡可以称之为离线升级。就是不用PC端,在线下插入SD卡,就可完成升级。(CAN和USART如果有硬件升级的设备,也可以做成离线升级)。

    讲一下SD卡的升级,使用离线升级,设备端需要有SD卡槽,升级的时候,将升级的文件放入SD卡中,再插入卡槽完成升级。(SD卡使用的SPI驱动,原理上其实也可以称为SPI升级。。。)

    这里使用STM32F103RCT6的芯片制作SD卡Bootloader。

一.硬件

    我使用的原子mini开发板,芯片为STM32F103RCT6,带SPI驱动的SD卡槽。

二.软件(寄存器编码,为的是减少Bootloader的代码占用空间)

1. SD卡使用的是SPI驱动。SPI1_Init()初始化,SPI1_ReadWriteByte读写。

 

2. SD卡驱动和FATFS文件系统。读SD卡、写SD卡、初始化SD卡等等,都是写好的驱动程序,直接可以用。这里也是用到了FATFS文件系统,需要移植两个文件。这里不多说。


 

3. 芯片Flash的操作。由于升级APP程序片需要用到Flash的操作,所以Flash的擦除,写入不能少。

 

4. APP程序跳入。当Flash里面写入了更新后的程序,需要跳转到Flash的起始地址,所以有一个函数需要。

5. 应用部分:

  首先选择一个起始地址,是需要刷写程序的起始地址。只要大于Bootloader程序的总长度,并且APP程序的长度不能超过(芯片大小 - Bootloader程序大小)即可。

  然后Flash中选取一个地址作为标志位,用于判断是否需要更新程序。

  最后就是读取SD卡里的文件,把读取的写入到对应的Flash里面,完成跳转。

    Main函数,先检测0x08002FFE这个地址的标志位,如果是0x02,说明有应用APP程序,不需要进行升级,所以直接iap_load_app(FLASH_APP_ADDR)跳转到APP的起始地址,开始运行程序,BOOT程序就到这里结束。

如果不是0x02,说明是新的芯片,或者是没有进行过升级的。就开始进行BOOT程序的升级流程SD_Update()。


 

  这里是打开SD卡、挂载的一些操作。如果成功进行到下面。


 

    f_read读取SD卡中的文件&file,并赋值到buffer数组中,STMFLASH_ErasePage擦除一片FLash区域,STMFLASH_WriteHalfWord进行写入。写入完成后PageOffest += STM_PAGE_SIZE,记录写入的片数,继续读SD卡的文件(注意,这里不是一次性全部读完,每次读取STM_PAGE_SIZE的大小,再写入),擦除写入。。。直到(res || br = 0),没有可读的,break,退出while(1)循环。擦除标志位的地址STMFLASH_ErasePage(0x08002FFE),并写入0xFF02,*(vu16*)(u16)(0x08000000 + 0x2FFE)=0xFF02(下次上电后读到这个0x02的标志位说明已经有APP程序了,直接跳转到APP地址就好了)。

  最后iap_load_app(FLASH_APP_ADDR),SD卡的Bootloader流程结束,进入到APP程序中运行了。

  附上Keil工程共大家参考。
---------------------
作者:小叶三千
链接:https://bbs.21ic.com/icview-3147318-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的基于STM32F103的CAN Bootloader升级程序代码,仅供参考: ``` // 定义 CAN Bootloader 升级命令 #define CAN_CMD_BOOTLOADER_START 0x01 #define CAN_CMD_BOOTLOADER_DATA 0x02 #define CAN_CMD_BOOTLOADER_END 0x03 // 定义 CAN Bootloader 升级状态 #define CAN_BOOTLOADER_STATE_IDLE 0 #define CAN_BOOTLOADER_STATE_READY 1 #define CAN_BOOTLOADER_STATE_TRANSFER 2 #define CAN_BOOTLOADER_STATE_COMPLETE 3 // 定义 CAN Bootloader 升级数据包大小 #define CAN_BOOTLOADER_DATA_SIZE 8 // 定义 CAN Bootloader 升级数据结构 typedef struct { uint8_t cmd; uint32_t address; uint32_t length; uint8_t data[CAN_BOOTLOADER_DATA_SIZE]; } can_bootloader_packet_t; // 定义 CAN Bootloader 升级状态变量 volatile uint8_t can_bootloader_state = CAN_BOOTLOADER_STATE_IDLE; // 定义 CAN Bootloader 升级数据缓冲区 volatile can_bootloader_packet_t can_bootloader_packet; // 处理 CAN Bootloader 升级命令 void can_bootloader_handle_command(uint8_t cmd, uint32_t address, uint32_t length) { switch(cmd) { case CAN_CMD_BOOTLOADER_START: // 处理 Bootloader 启动命令 // 初始化升级状态变量和数据缓冲区 can_bootloader_state = CAN_BOOTLOADER_STATE_READY; can_bootloader_packet.address = address; can_bootloader_packet.length = length; break; case CAN_CMD_BOOTLOADER_DATA: // 处理 Bootloader 数据传输命令 if(can_bootloader_state == CAN_BOOTLOADER_STATE_TRANSFER) { // 将数据写入指定地址 uint8_t* address_ptr = (uint8_t*) address; for(int i = 0; i < CAN_BOOTLOADER_DATA_SIZE && length > 0; i++, address_ptr++, length--) { *address_ptr = can_bootloader_packet.data[i]; } // 如果数据传输完成,则修改升级状态 if(length == 0) { can_bootloader_state = CAN_BOOTLOADER_STATE_COMPLETE; } } break; case CAN_CMD_BOOTLOADER_END: // 处理 Bootloader 结束命令 // 重置升级状态变量和数据缓冲区 can_bootloader_state = CAN_BOOTLOADER_STATE_IDLE; memset(&can_bootloader_packet, 0, sizeof(can_bootloader_packet_t)); break; default: // 未知命令 break; } } // 处理 CAN Bootloader 升级数据 void can_bootloader_handle_data(uint8_t* data, uint8_t length) { if(can_bootloader_state == CAN_BOOTLOADER_STATE_READY) { // 处理 Bootloader 启动命令 memcpy(can_bootloader_packet.data, data, length); can_bootloader_state = CAN_BOOTLOADER_STATE_TRANSFER; } else if(can_bootloader_state == CAN_BOOTLOADER_STATE_TRANSFER) { // 处理 Bootloader 数据传输命令 if(length <= CAN_BOOTLOADER_DATA_SIZE) { memcpy(can_bootloader_packet.data, data, length); } } } // 处理接收到的 CAN 消息 void can_receive_handler(can_message_t* msg) { if(msg->id == CAN_BOOTLOADER_ID) { // 处理 CAN Bootloader 升级命令 can_bootloader_handle_command(msg->data[0], *(uint32_t*)(msg->data + 1), *(uint32_t*)(msg->data + 5)); } else if(msg->id == CAN_BOOTLOADER_DATA_ID) { // 处理 CAN Bootloader 升级数据 can_bootloader_handle_data(msg->data, msg->length); } } int main() { // 初始化 CAN 总线和中断 can_init(); can_set_receive_handler(can_receive_handler); while(1) { // 主循环 } } ``` 注意:该代码仅供参考,具体实现可能会因为硬件和软件环境等因素而有所不同。此外,正确的CAN Bootloader升级操作需要谨慎处理,避免出现意外情况导致设备无法正常工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值