欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

Stm 32 IAP 在线 升级IAP 的 操作

发布时间:2025/3/21 56 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Stm 32 IAP 在线 升级IAP 的 操作 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

(扩展-IAP主要用于产品出厂后应用程序的更新作用,考虑到出厂时要先烧写IAP  再烧写APP应用程序要烧写2次增加工人劳动力基础上写了“STM32 IAP+APP ==>双剑合一”链接稍后发)

一、在进入主题之前我们先了解一些必要的基础知识----stm32系列芯片的种类和型号

startup_stm32f10x_cl.s 互联型的器件,STM32F105xx,STM32F107xx
startup_stm32f10x_hd.s 大容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_hd_vl.s 大容量的STM32F100xx
startup_stm32f10x_ld.s 小容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_ld_vl.s 小容量的STM32F100xx
startup_stm32f10x_md.s 中容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_md_vl.s 中容量的STM32F100xx  (我项目中用的是此款芯片 stm32f100CB)
startup_stm32f10x_xl.s FLASH在512K到1024K字节的STM32F101xx,STM32F102xx,STM32F103xx (例如:像stm32f103re 这个型号的 芯片flash是512k 的, 启动文件用startup_stm32f10x_xl.s  或者startup_stm32f10x_hd.s  都可以;
cl:互联型产品,stm32f105/107系列
vl:超值型产品,stm32f100系列
xl:超高密度产品,stm32f101/103系列
ld:低密度产品,FLASH小于64K
md:中等密度产品,FLASH=64 or 128
hd:高密度产品,FLASH大于128


二、在拿到ST公司官方的IAP 程序后 我们要思考几点:

        1.ST 官方IAP是什么针对什么芯片型号的,我们要用的又是什么芯片型号;

2.我们要用官方IAP适合我们芯片的程序升级使用,要在原有的基础上做那些改变;

(我的资源里有官方IAP源码:http://download.csdn.NET/detail/yx_l128125/6445811)

       

初略看了一下IAP源码后,现在我们可以回答一下上面的2个问题了:

1.官网刚下载的IAP针对的是stm32f103c8芯片的,所以他的启动代码文件选择的是 startup_stm32f10x_md.s,而我的芯片是stm32f100cb,所以我的启动代码文件选择的是  startup_stm32f10x_md_lv.s 




          2 .第二个问题就是今天我们要做详细分析才能回答的问题了;

          (1).知道了IAP官方源码的芯片和我们要用芯片的差异,首先我们要在源码的基础上做芯片级的改动;

A.首先改变编译器keil的芯片型号上我们要改成我们的芯片类型---STM32F100CB;

 B.在keil的options for  targer 选项C/C++/PREPROMCESSOR symbols的Define栏里定义,把有关STM32F10X_MD的宏定义改成:STM32F10X_MD_VL

也可以在STM32F10X.H里用宏定义 [plain] view plaincopy
  •   /* Uncomment the line below according to the target STM32 device used in your  
  •    application   
  •   */  
  •   
  • #if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)   
  •   /* #define STM32F10X_LD */    /*!< STM32F10X_LD: STM32 Low density devices */  
  •   /* #define STM32F10X_LD_VL */ /*!< STM32F10X_LD_VL: STM32 Low density Value Line devices */    
  •   /* #define STM32F10X_MD  */  /*!< STM32F10X_MD: STM32 Medium density devices */  
  •    #define STM32F10X_MD_VL     /*!< STM32F10X_MD_VL: STM32 Medium density Value Line devices */    
  •   /* #define STM32F10X_HD */    /*!< STM32F10X_HD: STM32 High density devices */  
  •   /* #define STM32F10X_HD_VL */ /*!< STM32F10X_HD_VL: STM32 High density value line devices */    
  •   /* #define STM32F10X_XL */    /*!< STM32F10X_XL: STM32 XL-density devices */  
  •   /* #define STM32F10X_CL */    /*!< STM32F10X_CL: STM32 Connectivity line devices */  
  • #endif  
  • 上面代码说的是如果没有定义 STM32F10X_MD_VL, 则宏定义 STM32F10X_MD_VL

    C.外部时钟问价在stm32f10x.h  依据实际修改,原文是 说如果没有宏定义外部时钟HES_VALUE的值,但是宏定义了stm32f10x_cl 则外部时钟设置为25MHZ, 否则外部时钟都设置为8MHZ;  我用的外部晶振是8MHZ的所以不必修改这部分代码;

    [plain] view plaincopy
  • #if !defined  HSE_VALUE  
  •  #ifdef STM32F10X_CL     
  •   #define HSE_VALUE    ((uint32_t)25000000) // Value of the External oscillator in Hz <pre name="code" class="plain"> #else </pre>  #define HSE_VALUE    ((uint32_t)8000000) //Value of the External oscillator in Hz  #endif /* STM32F10X_CL */#endif /* HSE_VALUE */  

  • D.做系统主频时钟的更改

    system_stm32f10x.c的系统主频率,依实际情况修改 ;我用的芯片主频时钟是24MHZ; [plain] view plaincopy
  •       
  • #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)  
  • /* #define SYSCLK_FREQ_HSE    HSE_VALUE */  
  •  #define SYSCLK_FREQ_24MHz  24000000  
  • #else  
  • /* #define SYSCLK_FREQ_HSE    HSE_VALUE */  
  •  #define SYSCLK_FREQ_24MHz  24000000   
  • /* #define SYSCLK_FREQ_36MHz  36000000 */  
  • /* #define SYSCLK_FREQ_48MHz  48000000 */  
  • /* #define SYSCLK_FREQ_56MHz  56000000 */  
  • /*#define SYSCLK_FREQ_72MHz  72000000*/   
  • #endif  
  • E.下面是关键部分操作了,在说这部分操作前我们先来说一下内存映射: 下图在stm32f100芯片手册的29页,我们只截取关键部分

    从上图我们看出几个关键部分:

    1.内部flash 是从0x0800 0000开始 到0x0801 FFFF  结束,    0x0801FFFF-0x0800 0000= 0x20000 =128k    128也就是flash的大小;

    2.SRAM的开始地址是   0x2000 0000 ;

    我们要把我们的在线升级程序IAP放到FLASH里以0x0800 0000 开始的位置,   应用程序放APP放到以0x08003000开始的位置,中断向量表也放在0x0800 3000开始的位置;如图


    所以我们需要先查看一下misc.h文件中的中断向量表的初始位置宏定义为  NVIC_VectTab_Flash  0x0800 0000

    那么要就要设置编译器keil 中的  options  for target 的target选项中的 IROM1地址 为0x0800 0000 大小为 0x20000即128K;

                                                                                                       IRAM1地址为0x2000 0000  大小为0x2000;

    (提示:这一项IROM1 地址 即为当前程序下载到flash的地址的起始位置)

    下面我们来分析一下修改后的IAP代码:

    [plain] view plaincopy
  • /*******************************************************************************  
  •   * @函数名称   main  
  •   * @函数说明   主函数  
  •   * @输入参数   无  
  •   * @输出参数   无  
  •   * @返回参数   无  
  • *******************************************************************************/  
  • int main(void)  
  • {  
  •     //Flash 解锁  
  •     FLASH_Unlock();  
  •   
  •     //配置PA15管脚  
  •     KEY_Configuration() ;  
  •     //配置串口1  
  •     IAP_Init();  
  •     //PA15是否为低电平  
  •     if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)  == 0x00)  
  •     {  
  •           
  •         //执行IAP驱动程序更新Flash程序  
  •   
  •         SerialPutString("\r\n======================================================================");  
  •         SerialPutString("\r\n=              (C) COPYRIGHT 2011 Lierda                             =");  
  •         SerialPutString("\r\n=                                                                    =");  
  •         SerialPutString("\r\n=     In-Application Programming Application  (Version 1.0.0)        =");  
  •         SerialPutString("\r\n=                                                                    =");  
  •         SerialPutString("\r\n=                                   By wuguoyan                      =");  
  •         SerialPutString("\r\n======================================================================");  
  •         SerialPutString("\r\n\r\n");  
  •         Main_Menu ();  
  •     }  
  •     //否则执行用户程序  
  •     else  
  •     {  
  •         //判断用处是否已经下载了用户程序,因为正常情况下此地址是栈地址  
  •         //若没有这一句话,即使没有下载程序也会进入而导致跑飞。  
  •         if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)  
  •         {  
  •             SerialPutString("Execute user Program\r\n\n");  
  •             //跳转至用户代码  
  •             JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);  
  •             Jump_To_Application = (pFunction) JumpAddress;  
  •   
  •             //初始化用户程序的堆栈指针  
  •             __set_MSP(*(__IO uint32_t*) ApplicationAddress);  
  •             Jump_To_Application();  
  •         }  
  •         else  
  •         {  
  •             SerialPutString("no user Program\r\n\n");  
  •         }  
  •     }  

  • 这里重点说一下几句经典且非常重要的代码:

    第一句: if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000)   //判断栈定地址值是否在0x2000 0000 - 0x 2000 2000之间

    怎么理解呢? (1),在程序里#define ApplicationAddress    0x8003000 ,*(__IO uint32_t*)ApplicationAddress)  即取0x8003000开始到0x8003003 的4个字节的值, 因为我们的应用程序APP中设置把 中断向量表 放置在0x08003000 开始的位置;而中断向量表里第一个放的就是栈顶地址的值

    也就是说,这句话即通过判断栈顶地址值是否正确(是否在0x2000 0000 - 0x 2000 2000之间) 来判断是否应用程序已经下载了,因为应用程序的启动文件刚开始就去初始化化栈空间,如果栈顶值对了,说应用程已经下载了启动文件的初始化也执行了;



    第二句:    JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);   [  common.c文件第18行定义了:  pFunction   Jump_To_Application;]
                          

    ApplicationAddress + 4  即为0x0800 3004 ,里面放的是中断向量表的第二项“复位地址”  JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); 之后此时JumpAddress

    第三句:    Jump_To_Application = (pFunction) JumpAddress;
     startup_stm32f10x_md_lv. 
    文件中别名  typedef  void (*pFunction)(void);     这个看上去有点奇怪;正常第一个整型变量   typedef  int  a;  就是给整型定义一个别名 a

     void (*pFunction)(void);   是声明一个函数指针,加上一个typedef 之后  pFunction只不过是类型 void (*)(void) 的一个别名;例如:

    [cpp] view plaincopy
  • pFunction   a1,a2,a3;  
  •   
  • void  fun(void)  
  • {  
  •     ......  
  • }  
  •   
  • a1 = fun;  
  • 所以,Jump_To_Application = (pFunction) JumpAddress;  此时Jump_To_Application指向了复位函数所在的地址;

    第四 、五句: __set_MSP(*(__IO uint32_t*) ApplicationAddress);      \\设置主函数栈指针
                   Jump_To_Application();                         \\执行复位函数

    我们看一下启动文件startup_stm32f10x_md_vl。s 中的启动代码,更容易理解


    移植后的IAP代码在我的资源(如果是stm32f100cb的芯片可以直接用):http://download.csdn.Net/detail/yx_l128125/6475219

    三、我们来简单看下启动文件中的启动代码,分析一下这更有利于我们对IAP的理解: (下面这篇文章写的非常好,有木有!)

    下文来自于:http://blog.sina.com.cn/s/blog_69bcf45201019djx.html

    解析 STM32 的启动过程

    解析STM32的启动过程

    当前的嵌入式应用程序开发过程里,并且C语言成为了绝大部分场合的最佳选择。如此一来main函数似乎成为了理所当然的起点——因为C程序往往从main函数开始执行。但一个经常会被忽略的问题是:微控制器(单片机)上电后,是如何寻找到并执行main函数的呢?很显然微控制器无法从硬件上定位main函数的入口地址,因为使用C语言作为开发语言后,变量/函数的地址便由编译器在编译时自行分配,这样一来main函数的入口地址在微控制器的内部存储空间中不再是绝对不变的。相信读者都可以回答这个问题,答案也许大同小异,但肯定都有个关键词,叫启动文件,用英文单词来描述是Bootloader

    无论性能高下,结构简繁,价格贵贱,每一种微控制器(处理器)都必须有启动文件,启动文件的作用便是负责执行微控制器从复位开始执行main函数中间这段时间(称为启动过程)所必须进行的工作。最为常见的51AVRMSP430等微控制器当然也有对应启动文件,但开发环境往往自动完整地提供了这个启动文件,不需要开发人员再行干预启动过程,只需要从main函数开始进行应用程序的设计即可。

    话题转到STM32微控制器,无论是keil
    uvision4
    还是IAR EWARM开发环境,ST公司都提供了现成的直接可用的启动文件,程序开发人员可以直接引用启动文件后直接进行C应用程序的开发。这样能大大减小开发人员从其它微控制器平台跳转至STM32平台,也降低了适应STM32微控制器的难度(对于上一代ARM的当家花旦ARM9,启动文件往往是第一道难啃却又无法逾越的坎)。

    相对于ARM上一代的主流ARM7/ARM9内核架构,新一代Cortex内核架构的启动方式有了比较大的变化。ARM7/ARM9内核的控制器在复位后,CPU会从存储空间的绝对地址0x000000取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为0x000000PC = 0x000000)同时中断向量表的位置并不是固定的。而Cortex-M3内核则正好相反,有3种情况:
    1
     通过boot引脚设置可以将中断向量表定位于SRAM区,即起始地址为0x2000000,同时复位后PC指针位于0x2000000处;
    2
     通过boot引脚设置可以将中断向量表定位于FLASH区,即起始地址为0x8000000,同时复位后PC指针位于0x8000000处;
    3
     通过boot引脚设置可以将中断向量表定位于内置Bootloader区,本文不对这种情况做论述;
    Cortex-M3内核规定,起始地址必须存放堆顶指针,而第二个地址则必须存放复位中断入口向量地址,这样在Cortex-M3内核复位后,会自动从起始地址的下一个32位空间取出复位中断入口向量,跳转执行复位中断服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。
    有了上述准备只是后,下面以STM322.02固件库提供的启动文件stm32f10x_vector.s为模板,对STM32的启动过程做一个简要而全面的解析。
    程序清单一:
    ;文件stm32f10x_vector.s,其中注释为行号
    DATA_IN_ExtSRAM EQU 0 
    1
    Stack_Size EQU 0x00000400 
    2
    AREA STACK, NOINIT, READWRITE, ALIGN = 3 
    3
    Stack_Mem SPACE Stack_Size 
    4
    __initial_sp 
    5
    Heap_Size EQU 0x00000400 
    6
    AREA HEAP, NOINIT, READWRITE, ALIGN = 3 
    7
    __heap_base 
    8
    Heap_Mem SPACE Heap_Size 
    9
    __heap_limit 
    10
    THUMB 
    11
    PRESERVE8 
    12
    IMPORT NMIException 
    13
    IMPORT HardFaultException 
    14
    IMPORT MemManageException 
    15
    IMPORT BusFaultException 
    16
    IMPORT UsageFaultException 
    17
    IMPORT SVCHandler 
    18
    IMPORT DebugMonitor 
    19
    IMPORT PendSVC 
    20
    IMPORT SysTickHandler 
    21
    IMPORT WWDG_IRQHandler 
    22
    IMPORT PVD_IRQHandler 
    23
    IMPORT TAMPER_IRQHandler 
    24
    IMPORT RTC_IRQHandler 
    25
    IMPORT FLASH_IRQHandler 
    26
    IMPORT RCC_IRQHandler 
    27
    IMPORT EXTI0_IRQHandler 
    28
    IMPORT EXTI1_IRQHandler 
    29
    IMPORT EXTI2_IRQHandler 
    30
    IMPORT EXTI3_IRQHandler 
    31
    IMPORT EXTI4_IRQHandler 
    32
    IMPORT DMA1_Channel1_IRQHandler 
    33
    IMPORT DMA1_Channel2_IRQHandler 
    34
    IMPORT DMA1_Channel3_IRQHandler 
    35
    IMPORT DMA1_Channel4_IRQHandler 
    36
    IMPORT DMA1_Channel5_IRQHandler 
    37
    IMPORT DMA1_Channel6_IRQHandler 
    38
    IMPORT DMA1_Channel7_IRQHandler 
    39
    IMPORT ADC1_2_IRQHandler 
    40
    IMPORT USB_HP_CAN_TX_IRQHandler 
    41
    IMPORT USB_LP_CAN_RX0_IRQHandler 
    42
    IMPORT CAN_RX1_IRQHandler 
    43
    IMPORT CAN_SCE_IRQHandler 
    44
    IMPORT EXTI9_5_IRQHandler 
    45
    IMPORT TIM1_BRK_IRQHandler 
    46
    IMPORT TIM1_UP_IRQHandler 
    47
    IMPORT TIM1_TRG_COM_IRQHandler 
    48
    IMPORT TIM1_CC_IRQHandler 
    49
    IMPORT TIM2_IRQHandler 
    50
    IMPORT TIM3_IRQHandler 
    51
    IMPORT TIM4_IRQHandler 
    52
    IMPORT I2C1_EV_IRQHandler 
    53
    IMPORT I2C1_ER_IRQHandler 
    54
    IMPORT I2C2_EV_IRQHandler 
    55
    IMPORT I2C2_ER_IRQHandler 
    56
    IMPORT SPI1_IRQHandler 
    57
    IMPORT SPI2_IRQHandler 
    58
    IMPORT USART1_IRQHandler 
    59
    IMPORT USART2_IRQHandler 
    60
    IMPORT USART3_IRQHandler 
    61
    IMPORT EXTI15_10_IRQHandler 
    62
    IMPORT RTCAlarm_IRQHandler 
    63
    IMPORT USBWakeUp_IRQHandler 
    64
    IMPORT TIM8_BRK_IRQHandler 
    65
    IMPORT TIM8_UP_IRQHandler 
    66
    IMPORT TIM8_TRG_COM_IRQHandler 
    67
    IMPORT TIM8_CC_IRQHandler 
    68
    IMPORT ADC3_IRQHandler 
    69
    IMPORT FSMC_IRQHandler 
    70
    IMPORT SDIO_IRQHandler 
    71
    IMPORT TIM5_IRQHandler 
    72
    IMPORT SPI3_IRQHandler 
    73
    IMPORT UART4_IRQHandler 
    74
    IMPORT UART5_IRQHandler 
    75
    IMPORT TIM6_IRQHandler 
    76
    IMPORT TIM7_IRQHandler 
    77
    IMPORT DMA2_Channel1_IRQHandler 
    78
    IMPORT DMA2_Channel2_IRQHandler 
    79
    IMPORT DMA2_Channel3_IRQHandler 
    80
    IMPORT DMA2_Channel4_5_IRQHandler 
    81
    AREA RESET, DATA, READONLY 
    82
    EXPORT __Vectors 
    83
    __Vectors 
    84
    DCD __initial_sp 
    85
    DCD Reset_Handler 
    86
    DCD NMIException 
    87
    DCD HardFaultException 
    88
    DCD MemManageException 
    89
    DCD BusFaultException 
    90
    DCD UsageFaultException 
    91
    DCD 0 
    92
    DCD 0 
    93
    DCD 0 
    94
    DCD 0 
    95
    DCD SVCHandler 
    96
    DCD DebugMonitor 
    97
    DCD 0 
    98
    DCD PendSVC 
    99
    DCD SysTickHandler 
    100
    DCD WWDG_IRQHandler 
    101
    DCD PVD_IRQHandler 
    102
    DCD TAMPER_IRQHandler 
    103
    DCD RTC_IRQHandler 
    104
    DCD FLASH_IRQHandler 
    105
    DCD RCC_IRQHandler 
    106
    DCD EXTI0_IRQHandler 
    107
    DCD EXTI1_IRQHandler 
    108
    DCD EXTI2_IRQHandler 
    109
    DCD EXTI3_IRQHandler 
    110
    DCD EXTI4_IRQHandler 
    111
    DCD DMA1_Channel1_IRQHandler 
    112
    DCD DMA1_Channel2_IRQHandler 
    113
    DCD DMA1_Channel3_IRQHandler 
    114
    DCD DMA1_Channel4_IRQHandler 
    115
    DCD DMA1_Channel5_IRQHandler 
    116
    DCD DMA1_Channel6_IRQHandler 
    117
    DCD DMA1_Channel7_IRQHandler 
    118
    DCD ADC1_2_IRQHandler 
    119
    DCD USB_HP_CAN_TX_IRQHandler 
    120
    DCD USB_LP_CAN_RX0_IRQHandler 
    121
    DCD CAN_RX1_IRQHandler 
    122
    DCD CAN_SCE_IRQHandler 
    123
    DCD EXTI9_5_IRQHandler 
    124
    DCD TIM1_BRK_IRQHandler 
    125
    DCD TIM1_UP_IRQHandler 
    126
    DCD TIM1_TRG_COM_IRQHandler 
    127
    DCD TIM1_CC_IRQHandler 
    128
    DCD TIM2_IRQHandler 
    129
    DCD TIM3_IRQHandler 
    130
    DCD TIM4_IRQHandler 
    131
    DCD I2C1_EV_IRQHandler 
    132
    DCD I2C1_ER_IRQHandler 
    133
    DCD I2C2_EV_IRQHandler 
    134
    DCD I2C2_ER_IRQHandler 
    135
    DCD SPI1_IRQHandler 
    136
    DCD SPI2_IRQHandler 
    137
    DCD USART1_IRQHandler 
    138
    DCD USART2_IRQHandler 
    139
    DCD USART3_IRQHandler 
    140
    DCD EXTI15_10_IRQHandler 
    141
    DCD RTCAlarm_IRQHandler 
    142
    DCD USBWakeUp_IRQHandler 
    143
    DCD TIM8_BRK_IRQHandler 
    144
    DCD TIM8_UP_IRQHandler 
    145
    DCD TIM8_TRG_COM_IRQHandler 
    146
    DCD TIM8_CC_IRQHandler 
    147
    DCD ADC3_IRQHandler 
    148
    DCD FSMC_IRQHandler 
    149
    DCD SDIO_IRQHandler 
    150
    DCD TIM5_IRQHandler 
    151
    DCD SPI3_IRQHandler 
    152
    DCD UART4_IRQHandler 
    153
    DCD UART5_IRQHandler 
    154
    DCD TIM6_IRQHandler 
    155
    DCD TIM7_IRQHandler 
    156
    DCD DMA2_Channel1_IRQHandler 
    157
    DCD DMA2_Channel2_IRQHandler 
    158
    DCD DMA2_Channel3_IRQHandler 
    159
    DCD DMA2_Channel4_5_IRQHandler 
    160
    AREA |.text|, CODE, READONLY 
    161
    Reset_Handler PROC 
    162
    EXPORT Reset_Handler 
    163
    IF DATA_IN_ExtSRAM == 1 
    164
    LDR R0,= 0x00000114 
    165
    LDR R1,= 0x40021014 
    166
    STR R0,[R1] 
    167
    LDR R0,= 0x000001E0 
    168
    LDR R1,= 0x40021018 
    169
    STR R0,[R1] 
    170
    LDR R0,= 0x44BB44BB 
    171
    LDR R1,= 0x40011400 
    172
    STR R0,[R1] 
    173
    LDR R0,= 0xBBBBBBBB 
    174
    LDR R1,= 0x40011404 
    175
    STR R0,[R1] 
    176
    LDR R0,= 0xB44444BB 
    177
    LDR R1,= 0x40011800 
    178
    STR R0,[R1] 
    179
    LDR R0,= 0xBBBBBBBB 
    180
    LDR R1,= 0x40011804 
    181
    STR R0,[R1] 
    182
    LDR R0,= 0x44BBBBBB 
    183
    LDR R1,= 0x40011C00 
    184
    STR R0,[R1] 
    185
    LDR R0,= 0xBBBB4444 
    186
    LDR R1,= 0x40011C04 
    187
    STR R0,[R1] 
    188
    LDR R0,= 0x44BBBBBB 
    189
    LDR R1,= 0x40012000 
    190
    STR R0,[R1] 
    191
    LDR R0,= 0x44444B44 
    192
    LDR R1,= 0x40012004 
    193
    STR R0,[R1] 
    194
    LDR R0,= 0x00001011 
    195
    LDR R1,= 0xA0000010 
    196
    STR R0,[R1] 
    197
    LDR R0,= 0x00000200 
    198
    LDR R1,= 0xA0000014 
    199
    STR R0,[R1] 
    200
    ENDIF 
    201
    IMPORT __main 
    202
    LDR R0, =__main 
    203
    BX R0 
    204
    ENDP 
    205
    ALIGN 
    206
    IF :DEF:__MICROLIB 
    207
    EXPORT __initial_sp 
    208
    EXPORT __heap_base 
    209
    EXPORT __heap_limit 
    210
    ELSE 
    211
    IMPORT __use_two_region_memory 
    212
    EXPORT __user_initial_stackheap 
    213
    __user_initial_stackheap 
    214
    LDR R0, = Heap_Mem 
    215
    LDR R1, = (Stack_Mem + Stack_Size) 
    216
    LDR R2, = (Heap_Mem + Heap_Size) 
    217
    LDR R3, = Stack_Mem 
    218
    BX LR 
    219
    ALIGN 
    220
    ENDIF 
    221
    END 
    222
    ENDIF 
    223
    END 
    224
    如程序清单一,STM32的启动代码一共224行,使用了汇编语言编写,这其中的主要原因下文将会给出交代。现在从第一行开始分析:
     1行:定义是否使用外部SRAM,为1则使用,为0则表示不使用。此语行若用C语言表达则等价于:
    #define DATA_IN_ExtSRAM 0
     2行:定义栈空间大小为0x00000400个字节,即1Kbyte。此语行亦等价于:
    #define Stack_Size 0x00000400
     3行:伪指令AREA,表示
     4行:开辟一段大小为Stack_Size的内存空间作为栈。
     5行:标号__initial_sp,表示栈空间顶地址。
     6行:定义堆空间大小为0x00000400个字节,也为1Kbyte
     7行:伪指令AREA,表示
     8行:标号__heap_base,表示堆空间起始地址。
     9行:开辟一段大小为Heap_Size的内存空间作为堆。
     10行:标号__heap_limit,表示堆空间结束地址。
     11行:告诉编译器使用THUMB指令集。
     12行:告诉编译器以8字节对齐。
     1381行:IMPORT指令,指示后续符号是在外部文件定义的(类似C语言中的全局变量声明),而下文可能会使用到这些符号。
     82行:定义只读数据段,实际上是在CODE区(假设STM32FLASH启动,则此中断向量表起始地址即为0x8000000
     83行:将标号__Vectors声明为全局标号,这样外部文件就可以使用这个标号。
     84行:标号__Vectors,表示中断向量表入口地址。
     85160行:建立中断向量表。
     161行:
     162行:复位中断服务程序,PROCENDP结构表示程序的开始和结束。
     163行:声明复位中断向量Reset_Handler为全局属性,这样外部文件就可以调用此复位中断服务。
     164行:IFENDIF为预编译结构,判断是否使用外部SRAM,在第1行中已定义为不使用
     165201行:此部分代码的作用是设置FSMC总线以支持SRAM,因不使用外部SRAM因此此部分代码不会被编译。
     202行:声明__main标号。
     203204行:跳转__main地址执行。
     207行:IFELSEENDIF结构,判断是否使用DEF:__MICROLIB(此处为不使用)。
     208210行:若使用DEF:__MICROLIB,则将__initial_sp__heap_base__heap_limit亦即栈顶地址,堆始末地址赋予全局属性,使外部程序可以使用。
     212行:定义全局标号__use_two_region_memory
     213行:声明全局标号__user_initial_stackheap,这样外程序也可调用此标号。
     214行:标号__user_initial_stackheap,表示用户堆栈初始化程序入口。
     215218行:分别保存栈顶指针和栈大小,堆始地址和堆大小至R0R1R2R3寄存器。
     224行:程序完毕。
    以上便是STM32的启动代码的完整解析,接下来对几个小地方做解释:
    1
     AREA指令:伪指令,用于定义代码段或数据段,后跟属性标号。其中比较重要的一个标号为READONLY或者READWRITE,其中READONLY表示该段为只读属性,联系到STM32的内部存储介质,可知具有只读属性的段保存于FLASH区,即0x8000000地址后。而READONLY表示该段为可读写属性,可知可读写段保存于SRAM区,即0x2000000地址后。由此可以从第37行代码知道,堆栈段位于SRAM空间。从第82行可知,中断向量表放置与FLASH区,而这也是整片启动代码中最先被放进FLASH区的数据。因此可以得到一条重要的信息:0x8000000地址存放的是栈顶地址__initial_sp0x8000004地址存放的是复位中断向量Reset_HandlerSTM32使用32位总线,因此存储空间为4字节对齐)。
    2
     DCD指令:作用是开辟一段空间,其意义等价于C语言中的地址符&。因此从第84行开始建立的中断向量表则类似于使用C语言定义了一个指针数组,其每一个成员都是一个函数指针,分别指向各个中断服务函数。
    3
     标号:前文多处使用了标号一词。标号主要用于表示一片内存空间的某个位置,等价于C语言中的地址概念。地址仅仅表示存储空间的一个位置,从C语言的角度来看,变量的地址,数组的地址或是函数的入口地址在本质上并无区别。
    4
     202行中的__main标号并不表示C程序中的main函数入口地址,因此第204行也并不是跳转至main函数开始执行C程序。__main标号表示C/C++标准实时库函数里的一个初始化子程序__main的入口地址。该程序的一个主要作用是初始化堆栈(对于程序清单一来说则是跳转__user_initial_stackheap标号进行初始化堆栈的),并初始化映像文件,最后跳转C程序中的main函数。这就解释了为何所有的C程序必须有一个main函数作为程序的起点——因为这是由C/C++标准实时库所规定的——并且不能更改,因为C/C++标准实时库并不对外界开发源代码。因此,实际上在用户可见的前提下,程序在第204行后就跳转至.c文件中的main函数,开始执行C程序了。
    至此可以总结一下STM32的启动文件和启动过程。首先对栈和堆的大小进行定义,并在代码区的起始处建立中断向量表,其第一个表项是栈顶地址,第二个表项是复位中断服务入口地址。然后在复位中断服务程序中跳转¬¬C/C++标准实时库的__main函数,完成用户堆栈等的初始化后,跳转.c文件中的main函数开始执行C程序。假设STM32被设置为从内部FLASH启动(这也是最常见的一种情况),中断向量表起始地位为0x8000000,则栈顶地址存放于0x8000000处,而复位中断服务入口地址存放于0x8000004处。当STM32遇到复位信号后,则从0x80000004处取出复位中断服务入口地址,继而执行复位中断服务程序,然后跳转__main函数,最后进入mian函数,来到C的世界。

    总结

    以上是生活随笔为你收集整理的Stm 32 IAP 在线 升级IAP 的 操作的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。