STM32的bootloader IAP编程

发布者:彩虹微笑最新更新时间:2018-05-31 来源: eefocus关键字:STM32  bootloader  IAP编程 手机看文章 扫描二维码
随时随地手机看文章

首先谈谈stm32的ISP和IAP区别和联系。

ISP(In-System Programming)在系统可编程,指电路板上的空白器件可以编程写入最终用户代码, 而不需要从电路板上取下器件,已经编程的器件也可以用ISP方式擦除或再编程。IAP(In-Application Programming) 指MCU可以在系统中获取新代码并对自己重新编程,即可用程序来改变程序。ISP和IAP技术是未来仪器仪表的发展方向。 

  1  ISP和IAP的工作原理
  ISP的实现相对要简单一些,一般通用做法是内部的存储器可以由上位机的软件通过串口来进行改写。对于单片机来讲可以通过SPI或其它的串行接口接收上位机传来的数据并写入存储器中。所以即使我们将芯片焊接在电路板上,只要留出和上位机接口的这个串口,就可以实现芯片内部存储器的改写,而无须再取下芯片。 

  IAP的实现相对要复杂一些,在实现IAP功能时, 单片机内部一定要有两块存储区,一般一块被称为BOOT区,另外一块被称为存储区。单片机上电运行在BOOT区,如果有外部改写程序的条件满足,则对存储区的程序进行改写操作。如果外部改写程序的条件不满足,程序指针跳到存储区,开始执行放在存储区的程序,这样便实现了IAP功能。


2 ISP和IAP的优点 
  ISP技术的优势是不需要编程器就可以进行单片机的实验和开发,单片机芯片可以直接焊接到电路板上,调试结束即成成品,免去了调试时由于频繁地插入取出芯片对芯片和电路板带来的不便。 
  IAP技术是从结构上将Flash存储器映射为两个存储体,当运行一个存储体上的用户程序时,可对另一个存储体重新编程,之后将程序从一个存储体转向另一个。 
  ISP的实现一般需要很少的外部电路辅助实现, 而IAP的实现更加灵活,通常可利用单片机的串行口接到计算机的RS232口,通过专门设计的固件程序来编程内部存储器,可以通过现有的INTERNET或其它通讯方式很方便地实现远程升级和维护。 

IAP的编写流程

设计思想

        由Bootloader负责检测SD卡中是否有固件更新所需的BIN文件。如果检测到所需要的BIN文件,则开始复制文件更新固件。更新结束后跳转到指定的地址开始执行最新的程序。

 知识要点

  STM32内部FLASH的起始地址为0X08000000,Bootloader程序文件就从此地址开始写入,存放APP程序的首地址设置在紧跟Bootloader之后。当程序开始执行时,首先运行的是Bootloader程序,此时Bootloader检测SD卡中的BIN文件并将其复制到APP区域使固件得以更新,固件更新结束后还需要跳转到APP程序开始执行新的程序,完成这最后这一步要了解Cortex-M3的中断向量表:

                       

  程序启动后,将首先从“中断向量表”取出复位中断向量执行复位中断程序完成启动,当复位中断程序运行完成后才跳转到main函数。由此可见,在最后一步的设计中需要根据存放APP程序的起始地址以及中断向量表来设置栈顶地址,并获取复位中断地址跳转到复位中断程序。接下来开始分析程序设计步骤。

  Bootloader程序设计

  1.确定存放APP程序的首地址

  #define FLASH_APP_ADDR 0x08010000 //应用程序起始地址(存放在FLASH)上一句代码中是0X08010000可以看出,留给Bootloader程序的存储空间大小为64K。存放APP程序的起始地址为0X08010000。

2.Bootloader检测是否有BIN文件

  gCheckFat = f_open(&FP_Struct,"/APP/LIKLON.BIN",FA_READ);//判读gCheckFat确定上面的代码是检测是否存在liklon.bin这个文件存在,其中liklon.bin文件就是固件升级所需要的BIN文件。

  3.复制文件到指定地址

  上一步中如果gCheckFat为0则表示存在所需BIN文件,则可以执行这一步。f_read (&FP_Struct,ReadAppBuffer,512,(UINT *)&ReadNum); //读取512个字节将512个字节转换为256个16位的数据存放在ChangeBuffer数组中,准备写入FLASH。FlashWrite(FLASH_APP_ADDR + i * 512,ChangeBuffer,256); //向指定地址写入读出数据向APP程序区写入512个字节的数据。按照这样读取写入,就可以完成对APP程序区的更新。

4.跳转到新程序运行

  更新完程序后就需要跳转到新程序开始运行,具体实现看下面代码:

  1. typedef void (*iapfun)(void); //定义一个函数类型的参数  

  2. iapfun jump2app;  

  3. __asm void MSR_MSP(u32 addr) //设置堆栈指针  

  4. {  

  5.       MSR MSP, r0  

  6.       BX r14  

  7. }  

  8. //跳转到应用程序段  

  9. //appxaddr:用户代码起始地址.  

  10. void iap_load_app(u32 appxaddr)  

  11. {  

  12.       if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000) //检查栈顶地址是否合法.  

  13.       {  

  14.             jump2app = (iapfun)*(vu32*)(appxaddr+4);//用户代码区第二个字为程序开始地址(复位地址),此处查看中断向量表可知  

  15.             MSR_MSP(*(vu32*)appxaddr);//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)  

  16.             jump2app(); //跳转到APP,执行复位中断程序  

  17.       }  

  18. }  

 APP程序设计注意

  1.编译软件需要做出设置:

 

  在Bootloader程序中已经指定了APP程序存储的起始地址为0x08010000,所以在APP程序设计时需要将编译软件这里做出设置,修改起始地址和大小。

  2.修改system_stm32f10x.c文件

 

  同样是针对于APP的起始地址改变而修改这里的偏移量,如上图所示。

  文中只是简单的介绍了关于Bootloader程序的设计,作为抛砖引玉,大家可以继续深入,添加数据校验和程序加密等。

///////////////////////////////////////////////////////////////////////////////////跳转函数具体说明

1、函数原型:

  1. void Jump_Address(void)  

  2.   

  3. {  

  4.   

  5. if (((*(volatile u32*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)  

  6.   

  7. {  

  8.   

  9.  test = (*(volatile u32*)ApplicationAddress);  

  10.   

  11.   JumpAddress = *(volatile u32*) (ApplicationAddress + 4);  

  12.   

  13.  Jump_To_Application = (pFunction) JumpAddress;  

  14.   

  15.   __set_MSP(*(volatile u32*) ApplicationAddress);  

  16.   

  17.                 Jump_To_Application();  

  18.   

  19. }  

  20.   

  21. }  


2、if (((*(volatile u32*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)分析:

ApplicationAddress存放的是用户程序Flash的首地址,(*(volatile u32*)ApplicationAddress)的意思是取用户程序首地址里面的数据,这个数据就是用户代码的堆栈地址,堆栈地址指向RAM,而RAM的起始地址是0x20000000,因此上面的判断语句执行:判断用户代码的堆栈地址是否落在:0x20000000~0x2001ffff区间中,这个区间的大小为128K,笔者查阅STM32各型号的RAM大小,目前RAM最大的容量可以做到192K+4K,时钟频率为168MHZ。一般情况下,我们使用的芯片较多的落在<128K RAM的区间,因此上面的判断语句是没有太大问题的。

 

3、经过2的分析,test保存的就是堆栈地址(并且是应用程序堆栈的栈顶地址),查看STM32的向量表,可以知道:栈顶地址 + 4 存放的是复位地址,因此JumpAddress存放的是复位地址。

 

4、调用__set_MSP函数后,将把用户代码的栈顶地址设为栈顶指针

 

5、Jump_To_Application();的意思就是设置PC指针为复位地址。

 

CORTEX-M3上电后后检测BOOT引脚的电平来决定PC的位置。例:BOOT设置为FLASH启动,启动后CPU会先取两个地址:一个是栈顶地址,另一个是复位地址。因此才有了第4、第5点的写法。


关键字:STM32  bootloader  IAP编程 引用地址:STM32的bootloader IAP编程

上一篇:STM32生成bin文件
下一篇:基于STM32在IAR中调用printf()函数

推荐阅读最新更新时间:2024-03-16 16:03

STM32内部Flash读写操作接口
源文件 /* ********************************************************************************************************* * 函 数 名: GetSector * 功能说明: 根据地址计算扇区首地址 * 形 参: 无 * 返 回 值: 扇区首地址 ********************************************************************************************************* */ uint32_t GetSector(uint32
[单片机]
STM32 外部中断配置
1配置中断 1、 分配中断向量表: /* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 2、 设置中断优先级: NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断优先级 3、 初始化外部中断: /*允许EXTI4中断 */ NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel; //中断通道 NVIC_InitS
[单片机]
STM32学习笔记一一RTC实时时钟
1. 简述 STM32 的实时时钟(RTC)是一个独立的定时器。 STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC 模块和时钟配置系统 (RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域 (BKP) 的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)写保护。 RTC 由两个主要部分组成(参见上图), 第一部分(APB1 接口)用来和 APB1 总线相连。此单元还包含一组 16 位寄存器
[单片机]
<font color='red'>STM32</font>学习笔记一一RTC实时时钟
STM32时钟,外部16M设置
一般的时钟设置是外部8M的时钟,但是当设置为外部16M的时候,需要配置如下: (1)stm32f103xx的芯片,在stm32f10x.h库中修改大概119行的HSE_VALUE 为16000000(自带的是8000000),然后在system_stm32f10x.c中设置,大概在1054行,位于SetSysClockTo72(void)函数中,添加2分频(RCC_CFGR_PLLXTPRE_HSE_Div2|),然后在1056处添加同样的句子(RCC_CFGR_PLLXTPRE_HSE_Div2|),编译就可以了。 (2)stm32f40xx的芯片,在stm32f4xx.h库中修改大概122行的修改为16M如下 #if !def
[单片机]
STM32的DAC输出驱动电压
目的 项目中的模块对输出电压的改变来控制功率、所以考虑用stm32内部的DAC来输出电压作为驱动。 源代码 #include dac.h void Dac1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; DAC_InitTypeDef DAC_InitType; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPI
[单片机]
STM32开发笔记76: 初始化RTC后死机的原因
单片机型号:STM32L053R8T6 项目开发中只要初始化RTC,则系统死机。其初始化步骤可参考日志:STM32开发笔记44:RTC驱动程序的移植。按照日志STM32开发笔记75: 使用STM32CubeMX点亮一个LED使用STM32CubeMX直接生成程序则运行正常。 分析原因在于,少移植了2个函数:HAL_RTC_MspInit和HAL_RTC_MspDeInit。这两个函数的实现非常简单,可以靠STM32CubeMX直接生成。 void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc) { __HAL_RCC_RTC_ENABLE(); HAL_NVIC_SetPrio
[单片机]
STM32 输入捕获 测量频率 PWM占空比
看了网上关于STM32输入捕获的资料,有几篇介绍的很不错,但是内容上还有一点问题,稍加修改,大家可以参考一下。 重要概念理解(对于理解输入捕获功能很重要,特别看了数据手册CCR1CCR2CCR3CCR3云里雾里) PWM输入捕获模式是输入捕获模式的特例,自己理解如下 1. 每个定时器有四个输入捕获通道IC1、IC2、IC3、IC4。且IC1 IC2一组,IC3 IC4一组。并且可是设置管脚和寄存器的对应关系。 2. 同一个TIx输入映射了两个ICx信号。 3. 这两个ICx信号分别在相反的极性边沿有效。 4. 两个边沿信号中的一个被选为触发信号,并且从模式控制器被设置成复位模式。 5. 当触发信号来临时,被设置成触发输入信号的捕获
[单片机]
STM32的定时器和ADC
开启两个定时器给FPGA使用 要求是 一、定时器可以在任何时刻关闭,就算计数不满也要停 二、定时器在再次开启时可以从0计数 三、定时器可以在启动过程中停止,然后更改定时周期再开始从0计数 主要的几个函数 //tim_num=0对应 定时器2,tim_num=1对应 定时器3;tim_us:定时器uS数 void stm32_timer_start(uint16_t tim_num,uint16_t tim_us) { /* --------------------------------------------------------------- PCLK1=36MHz TIM CLK = 72 MHz, Prescaler
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved