STM32远程升级基本思路

STM32远程升级基本思路


  • 开发环境:IAR for ARM 8.30.1
  • MCU:STM32F103RCT6
  • 存储介质:w25q32

1.实现思路

1.需要一个bootloader程序和APP程序
2.APP程序通过网络或者串口等方式将要升级的代码写到spiFlash中约定的位置,然后重启
3.bootloader判断spiFlash中是否有文件需要更新,有就将文件更新到stm32的内部Flash的App区域,然后跳 转到APP,否则直接跳转

2.知识储备

STM32闪存模块组织

stm32F103RCT6属于大容量型产品,ROM:256K,RAM:48K,页大小为2k,闪存分为三个块:

  • 主存储器:页大小为2K,256K也就是128页
  • 信息块:分为两个部分:
    • 系统存储器(存放启动程序代码,ST出厂固化,不可更改,用于ISP编程)
    • 用户选项字节(Option Bytes,可以用它设置读写保护,硬件看门狗使能啥的)
  • 闪存存储器接口寄存器:操作stm32内部Flash要用到这些寄存器;

在这里插入图片描述

启动配置

在这里插入图片描述
● 从主闪存存储器启动:主闪存存储器被映射到启动空间(0x0000 0000)
● 从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000)
● 从内置SRAM启动:只能在0x2000 0000开始的地址区访问SRAM

3.Bootloader和App的工程设置

Bootloader和App公用RAM,占用不同ROM空间,16K给Bootloader,240K给App

  • Bootloader:
    • Vector Table Start:0x0800 0000
    • ROM:0x0800 0000 ~ 0x0800 4000
    • RAM:0x0800 0000 ~ 0x0800 BFFF
    • CSTACK: 0x400
    • Heap: 0x0
  • App:
    • Vector Table Start:0x0800 4000
    • ROM:0x0800 4000 ~ 0x0803 FFFF
    • RAM:0x0800 0000 ~ 0x0800 BFFF
    • CSTACK: 0x400
    • Heap: 0x0
      App程序中还要注意到的地方:修改中断向量偏移VECT_TAB_OFFSET,偏移量就是bootloader程序大小
      在这里插入图片描述

4.Bootloader程序编写

话不多说,下面就是代码:

  • 头文件
#define FLASH_MAX_ADDR                      (0x0803FFFFU)  //MCU的Flash最大地址

#ifndef FLASH_PAGE_SIZE
  #define FLASH_PAGE_SIZE                   (0x800U)       //MCU的Flash的页大小,大容量的为2K,其他是1K
#endif

#define APP_BASEADDR                        (0x08004000U)  //升级程序地址


#define APP_PAGE_NUM                        ((FLASH_MAX_ADDR-APP_BASEADDR)/FLASH_PAGE_SIZE+1)

#define SPIFLASHBUF_MAX_LEN                 (0x1000U)  //spi flash最大缓冲4096字节
  • C文件
void JumpToApplication(void)
{
  typedef  void (*pFunction)(void);
  pFunction Jump_To_Application;
  u32 JumpAddress;    
  
  /* Test if user code is programmed starting from address "ApplicationAddress" */
  if (((*(__IO uint32_t*)APP_BASEADDR) & 0x2FFE0000 ) == 0x20000000)
  {
    
    DBG_LOG("----[Boot]Jump to Application!!!\r\n");
    LED_ALL_OFF();
    __disable_irq();
    
    /* Jump to user application */
    JumpAddress = *(__IO uint32_t*) (APP_BASEADDR + 4);
    Jump_To_Application = (pFunction) JumpAddress;
    /* Initialize user application's Stack Pointer */
    __set_MSP(*(__IO uint32_t*) APP_BASEADDR);
    Jump_To_Application();
  }
  else
  {
    DBG_LOG("----[Boot]Application Address is ERROR!!!\r\n");
    LED_ALL_ON();
  }    
}

union {
  u32 stm32[SPIFLASHBUF_MAX_LEN/4];
  u8  spi[SPIFLASHBUF_MAX_LEN];
}Flash;

void Boot_Initializes(void)
{

  u16 i,j;
  
  u32 update_file_mark;
  
  u32 writeFlashData;
 
  HAL_StatusTypeDef status;
  
  FLASH_EraseInitTypeDef f;
  
	f.TypeErase = FLASH_TYPEERASE_PAGES;
	f.PageAddress = APP_BASEADDR;
	f.NbPages = APP_PAGE_NUM;

  //1.判断spi flash DFU区是否有文件需要升级
  SFlash_Read(SECTOR_ADDR(SECTOR_DFU_START),(u8 *)&update_file_mark,4);
  
  if(update_file_mark == 0xFFFFFFFF){
    DBG_LOG("[Boot] No Firmware Need to Update."); 
    LED_ON(ERR);
    JumpToApplication();
    return;
  }
  //有文件需要升级
  DBG_LOG("[Boot] New Firmware Exist! Update Beginning..."); 
  
  //2.Flash解锁
  status = HAL_FLASH_Unlock();
  
  if(status != HAL_OK){
    DBG_LOG("[Boot] FLASH Unlock Failed."); 
    LED_ON(ERR);
    return;
  }
  DBG_LOG("[Boot] FLASH Unlock Ok."); 
  
  DBG_LOG("[Boot] Ready to Erase Flash ..."); 
  //3.擦除Flash
  status = HAL_FLASHEx_Erase(&f,&writeFlashData);
  
  if(status != HAL_OK){
    DBG_LOG("[Boot] Flash Erase Failed."); 
    LED_ON(ERR);
    return;
  }
  DBG_LOG("[Boot] Flash Erase OK."); 
  
  
  //4.从SPIFlash中读出数据然后copy到内部Flash中
  for(i = 0;i < (APP_PAGE_NUM / 2);i++){
    
    SFlash_Read(SECTOR_ADDR(SECTOR_DFU_START) + SPIFLASHBUF_MAX_LEN*i, Flash.spi, SPIFLASHBUF_MAX_LEN);
    
    DBG_LOG("[Boot] Write Flash Progress:%d%%",(i*100/(APP_PAGE_NUM / 2)) ); 
    
    LED_TOGGLE(WIFI);
    
    for(j = 0;j < (SPIFLASHBUF_MAX_LEN/4);j++){
      //注意基地址是在变化的
      HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, APP_BASEADDR+SPIFLASHBUF_MAX_LEN*i+4*j, Flash.stm32[j]);
    }    
  }
  
  DBG_LOG("[Boot] Write Flash Progress:100%%");
  DBG_LOG("[Boot] Program Complete!!!");
  
  //5.Flash上锁
  HAL_FLASH_Lock();  
  
  //6.跳转到用户程序区
  JumpToApplication();
  
}


  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
针对STM32远程升级固件的方案,可以分为以下几个步骤: 1. 准备升级固件:首先需要准备一份新的固件文件,可以使用Keil或者IAR等开发工具进行编译生成。同时,需要为每个设备分配一个唯一的设备ID,以便在升级时进行识别。 2. 搭建远程升级服务器:在服务器上搭建一个Web服务器,将升级固件文件上传至服务器上,并在服务器端编写相应的升级程序,以便设备在连接服务器时能够自动下载并升级固件。此外,需要注意的是,服务器上需要记录每个设备的设备ID和当前固件版本等信息。 3. 设备连接服务器:设备上需要预先写好连接服务器的程序,以便能够通过网络连接到服务器。在连接服务器时,设备需要发送设备ID和当前固件版本等信息,以便服务器进行识别并判断是否需要进行升级。 4. 服务器进行升级:如果服务器判断需要进行升级,就会将最新的固件文件发送给设备,并通知设备进行升级操作。设备在接收到升级指令后,需要将自身的固件进行备份,然后将新的固件文件进行解析和写入。 5. 升级完成:设备在升级完成后需要重新启动,并将新的固件版本信息发送给服务器进行记录。同时,如果升级失败,设备需要自动恢复之前备份的固件。 需要注意的是,在进行远程升级时需要考虑到网络的不稳定性和设备自身的安全性问题,以便能够保证升级的可靠性和安全性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值