完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、在进入主题之前我们先了解一些必要的基础知识---- stm32系列芯片的种类和型号:
startup_stm32f10x_cl.s互联型的标志,STM32F105xx,STM32F107xx startup_stm32f10x_hd。小号大容量的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这个型号的芯片闪烁是512K的,启动文件用startup_stm32f10x_xl.s或者startup_stm32f10x_hd.s都可以) CL:互联型产品,stm32f105 / 107系列 VL:超值型产品,stm32f100系列 XL:超高密度产品, stm32f1 /103系列ld:低密度产品,FLASH小于64K md:中等密度产品,FLASH=64 or 128 hd:高密度产品,FLASH大于128 二、在获得ST公司官方的IAP程序后我们要 考虑官方官方IAP :1.ST是什么芯片型号的,我们需要的又是什么芯片型号; 2.我们需要IAP适合我们芯片的程序升级使用,要在原有的基础上做那些改变; 初略看了一下IAP源码后,现在我们可以回答一下上面的2个问题了: 1.官网刚下载的IAP是stm32f103c8芯片的,所以他的启动代码文件选择的是startup_stm32f10x_md.s,而我的芯片是stm32f100cb,所以我的启动代码文件选择的是startup_stm32f10x_md_lv.s 2 。问题就是今天我们要详细分析,不能回答的问题了; (1)。 知道了IAP官方源码的芯片和我们需要多少我们,首先我们要在源码的基础上做芯片级的改动; A.首先改变编译器的芯片型号上要改成我们的芯片类型---STM32F100CB; B.在keil的选项选项C/C++/PREPROMCESSOR符号的定义栏里定义,把有关STM32F10X_MD的宏定义改成:STM32F10X_MD_VL 也可以在STM32F10X.H里用宏定义 /* 根据您使用的目标 STM32 设备取消注释以下行 应用 */ #if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_HD_Defined!XF)&& !defined (STM32F10X_HD_VL) /* #define STM32F10X_LD */ /*!《 STM32F10X_LD: STM32 低密度设备 */ /* #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 /* 根据应用中使用的目标 STM32 设备取消注释以下行 */#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F) && !defined (STM32F) && !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL) /* #define STM32F10X_LD */ /*!《 STM32F10X_LD: STM32 低密度设备*/ /* #define STM32F10X_LD_F10X STM32F10X_LD */ STM32F10X_LD_F10X STM32F10X_L10X_F10X低密度价值线器件 */ /* #define STM32F10X_MD */ /*!《 STM32F10X_MD: STM32 中密度器件 */ #define STM32F10X_MD_VL /*!《 STM32F10X_MD_VL: STM32 中密度价值线器件 */ /* #define STM_32F /*!《 STM32F10X_HD:STM32 高密度器件 */ /* #define STM32F10X_HD_VL */ /*!《 STM32F10X_HD_VL: STM32 高密度价值线器件 */ /* #define STM32F10X_XL */ /*!《 STM32F10X_XL: STM32 /* #密度器件 */定义 STM32F10X_CL */ /*!《 STM32F10X_CL: STM32 连接线设备 */#endif 上面代码说如果没有定义 STM32F10X_MD_VL,则宏定义 STM32F10X_MD_VL C.外部逻辑问在 stm32f10x.h 讨论实际修改,译文是说如果没有宏外部定义 HES_VALUE 的值,但是宏定义了 stm32f10x_cl 则为25MHZ,其他外部电话都设置为8MHZ; 我用的外部晶振是8MHZ的所以不用修改这部分代码; #if !defined HSE_VALUE #ifdef STM32F10X_CL #define HSE_VALUE ((uint32_t)25000000) // 以Hz为单位的外部振荡器值 《pre nam》 #else 《/pre》 #define HSE_VALUE ((uint32_t)8000000) //以Hz为单位的外部振荡器值#endif /* STM32F10X_CL */#endif /* HSE_VALUE */ #if !defined HSE_VALUE #ifdef STM32F10X_CL #define HSE_VALUE ((uint32_t)25000000) // 外部振荡器的赫兹值 #else #define HSE_VALUE ((uint32_t)8000000) //外部振荡器的Hz值#endif /* STM32F10X_CL */#endif /* HSE_VALUE */ D.做系统主频率的更改system_stm32f10x.c的系统频率主,依实际情况修改;我用的芯片主频时钟是24MHZ; #if 定义 (STM32F10X_LD_VL) || (定义STM32F10X_MD_VL) || (定义 STM32F10X_HD_VL) /* #define SYSCLK_FREQ_HSE HSE_VALUE */ #define SYSCLK_FREQ_24MHz 24000000 #别的 /* #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 */ /*#定义SYSCLK_FREQ_72MHz 72000000*/ #万一 #if 定义 (STM32F10X_LD_VL) || (定义STM32F10X_MD_VL) || (定义STM32F10X_HD_VL)/ *#定义SYSCLK_FREQ_HSE HSE_VALUE * /#定义SYSCLK_FREQ_24MHz 24000000#否则/ *#定义SYSCLK_FREQ_HSE HSE_VALUE * /#定义SYSCLK_FREQ_24MHz 24000000 / *#定义SYSCLK_FREQ_36MHz 36000000 * // *的#define SYSCLK_FREQ_48MHz 48000000 * // *#定义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. 00是2xSRAM 的地址0000 ; 我们要我们的在线升级程序我开始启动表打开FLASH里以0x0800 0000 0000 0x080000000000000000000000000000000000000000000000000000000000 开始的位置; 所以我们需要先查看一下misc.h 文件中宏中断表的最终位置定义为NVIC_VectTab_Flash 0x0800 0000 那么要设置地址编译器keil 中的目标选项中的目标选项中的IROM1 为0x0800 0000 大小为0x20000即128K; IRAM1地址为0x2000 0000 大小为0x2000; (提示:这本书IROM1地址即为当前下载到flash的地址的程序位置) 下面我们来分析一下修改后的IAP代码: /***************************************************** ********************************** * @函数名称main * @函数说明 主函数 * @输入参数无 * @输出参数无 * @返回参数无 ****************************************************** ********************************/ int main(void) { //闪光弹 FLASH_Unlock(); //配置PA15管脚 KEY_Configuration() ; //配置串口1 IAP_Init(); //PA15是否为低电平 if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15) == 0x00) { //执行IAP驱动程序更新Flash程序 SerialPutString(“rn====================================================================rn= (C) COPYRIGHT 2011 Lierda rn= rn= In-Application Programming Application (Version 1.0.0) rn= rn= By wuguoyan rn====================================================================rnrn”); Main_Menu (); } //否则执行用户程序 else { //判断用处是否已经下载了用户程序,因为正常情况下此地址是栈地址 //若没有这一句话,即使没有下载程序也会进入而导致跑飞。 if (((*(__IO uint32_t*)ApplicationAddress) & 0x2FFE0000 ) == 0x20000000) { SerialPutString(“Execute user Programrnn”); //跳转至用户代码 JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); Jump_To_Application = (pFunction) JumpAddress; //初始化用户程序的堆栈指针 __set_MSP(*(__IO uint32_t*) ApplicationAddress); Jump_To_Application(); } else { SerialPutString(“no user Programrnn”); } } /***************************************************** ****************************** * @函数名称 main * @函数说明 主函数 * @输入参数无 * @输出参数无* @返回参数无******************************************** ************************************/int(void){ //闪光主体FLASH_Unlock(); //配置PA15管脚KEY_Configuration(); //配置串口1 IAP_Init(); //PA15是否为低数据 if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15) == 0x00) { //执行IAP驱动程序更新程序程序SerialPutString(“rn============== ================================================== ========); SerialPutString(”rn= (C) COPYRIGHT 2011 Lierda =“); SerialPutString(”rn= = =); SerialPutString(“ Jump_To_Application = (pFunction) JumpAddress; //初始化用户程序的数据轨迹 __set_MSP(*(__IOuint32_t) ApplicationAddress); Jump_To_Application(); } else { SerialPutString(”无用户程序rnn“); } } 这里重点说一下几句经典且非常重要的代码: 第一句: 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 ); 之后此时跳转地址 第三句: Jump_To_Application = (pFunction) JumpAddress; 启动_stm32f10x_md_lv。文件中别名 typedef void (*pFunction)(void); 这个有点相似;正常第一个整型类型定义 int a; 就是给整型定义一个别名 a void (*pFunction)(void); 是声明一个函数方法,加上一个类型之后 pFunction 确实是类型 void (*)(void) 的一个别名;例如: pFunction a1,a2,a3; 无效的乐趣(无效) { 。..。.. } a1 = 有趣; pFunction a1,a2,a3;void fun(void){ 。..。..}a1 = fun; 所以,Jump_To_Application = (pFunction) JumpAddress 句;此时Jump_To_Application 思维了复位函数所属的 第四、五项: __set_MSP(*(__IO uint32_t*) 应用地址); \设置主函数栈 路径Jump_To_Application(); \执行复位函数 我们看一下启动文件startup_stm32f10x_md_vl。s中的启动代码 三,我们来简单看下启动文件中的启动代码,分析一下这更有利于我们对IAP的理解,解析STM32的启动过程解析STM32的启动过程 当前的嵌入式应用程序,并且 C 语言成为开发过程开始了执行场合的最佳选择。 所以那个主要函数似乎成为了理所当然的开始——因为 C 程序往往从主要函数。但一个经常会被忽悠的问题是:作为微控制器(控制器)上电后,是如何寻找并执行主函数的呢?语言后,变量/函数的地址由编译器在编译时本身决定的,这种主要函数的地址入口在微控制器的内部存储空间中不再是绝对不变的问题。 ,回答可能大同小异,但肯定有一个关键词,叫“文件”,用英文单词来启动描述是“Bootloader”。一种性能高下,结构简繁,价格贵贱,每微控制器(处理器) )都必须有启动文件,启动文件的作用就是执行微控制器从“复位”到“开始执行主函数”中间这段时间(即启动函数)必须进行的工作。大多数过程中常见的51, AVR或MSP430等微控制器当然也有相应启动,但开发环境会自动完整地提供了这个启动文件,不需要开发人员再行启动过程,只需要从主函数开始进行应用程序的设计纯化。 现在转到STM32微控制器, 无论是keil uvision4还是IAR EWARM开发环境,ST公司都提供了现成的直接可以启动文件,程序开发人员可以直接引用启动文件后直接进行C应用程序的开发。虚拟平台开发人员从其他微控制器跳转到STM32,也降低了适应STM322微控制器的难度(对于上一代ARM的当家花ARM,启动文件往往是第一道难缠却又无法超越)的坎)。 相对于ARM上一代的主流ARM7/ARM9内核,下一代Cortex内核的启动方式有了大的变化。ARM7/ARM9内核的控制器在复位后,CPU会从存储空间的地址0x000000取出一条指令执行复位中断服务程序的方式启动,即固定了复位后的动画地址为0x000000(PC = 0x000000)种情况: 1、通过引导定位设置可以将解定位定位到SRAM区,即定位定位为0x2000000,同时复位后PC定位0x2000000处; 2、通过引导定位可以将解定位于FLASH,即风景地址为0x8000000,同时0x80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000之间; 3、通过引导区设置可以将中断定位定位于内置Bootloader, 而不是这种情况做接口;而Cortex-M3内核规定,吸引地址必须举行集会顶活动,而第二个地址则必须召开中断中断入口,使其在Cortex-M3捕捉后,会自动从捕捉地址的下一个32位空间取出中断入口跳转执行复位服务程序。对比ARM7/ARM9内核,Cortex-M3内核则是固定了破坏表的位置而出现的地址是可变化的。 上述准备只是之后,下面以STM32的2.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 大拇指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 导入 DMA1_Channel6_IRQHandler ;38 导入 DMA1_Channel7_IRQHandler ;39 导入 ADC1_2_IRQHandler ;40 导入 USB_HP_CAN_TX_IRQHandler ;41 导入 USB_LP_CAN_RX0_IRQHandler ;42 导入 4_3IRQHandler ;42导入 4_3IRQHandler ; 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 导入 SPI1_IRQHandler ;57 导入 SPI2_IRQHandler ;58 导入 USART1_IRQHandler ;59 导入 USART2_IRQHandler ;60 导入 USART3_IRQHandler ;61 导入 EXTI15_10_IRQHandler ;62 IMQIRPORT RTCAlar 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, EXPORT ; 82V 端口; __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_5_IRQHandler ;127 DCD TIM1_C1_8IRQHandler ;125 DCD TIM1_C1_DIRQ1_C1_2IRQHandler ;2 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_BRK_IRQHandler ;147 DCD SD3_BRK_IRQHandler ;147 DCD ADC3_89D DCIO ; DSMC14_IRQ1D FSMC1Q1D ; 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,只读; 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,0,=110Rx10 ] Rx108 ; 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,= __主; 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字节字节外部。 第13—81行:导入指令,说明符号是在文件定义的(类似C语言中的变量声明),而可能会使用到这些。 第82符号:定义只读数据段,实际上是在CODE区(虚拟STM32从FLASH启动,则此中断表地址即为0x8000000) 第83行:将标号__Vectors声明为这个标号,这样外部文件就可以使用标号。 第84行:标号__Vectors,表示中断向量表入口。 第85—160行:建立中断向量表地址。 第161行: 第162行:复位中断服务程序,PROC…ENDP结构表示的开始和结束。 第163行:声明复位中断动画Reset_Handler为属性,这样外部文件就调用此复位中断。服务。 第 164 行:IF…ENDIF 为预编译结构,判断是否使用外部 SRAM,在第 1 行中已定义为“不使用”。 第 165—201 行:此部分代码的作用是设置 FSMC 总线以支持SRAM,因不使用外部SRAM,因此部分代码不会被编译。 第202行:声明__main标号。 第203—204行:跳转__main地址执行。 第207行:IF…ELSE …ENDIF结构,判断是否使用DEF:__MICROLIB(此处为不使用)。 第208—210行:若使用DEF:__MICROLIB,则将__initial_sp,__heap_base,__heap_limit亦即栈顶地址,堆始末地址属性,使外部程序可以使用。 第212行:定义网络标号__use_two_region_memory。 第213行:声明网络标号__user_initial_stackheap,这样外程序也可调用此标号。 第214行:标号__user_initial_stackheap,表示用户初始化程序入口。 第215—218行:分别保存栈顶路径和大小栈,堆始地址和堆大小至R0,R,R,R2,R31。 第224行:程序完成。 以上是STM32的启动代码的完整解析,下游对几个小地方做的解释: 1、 AREA 语句:伪指令,用于定义代码段或数据段,后跟属性标号。其中比较重要的一个标号为“READONLY”或“READWRITE”,其中“READONLY” ”该段为只读属性,表示到STM32的内部信息,具有可读属性的段保存于FLASH区,即0x8000000地址后该段。而“READONLY”表示段为“可读写”属性,知道“可读写”保存于SRAM区,即0x2000000后。这一次可以从第3段、7行代码知道,第3段位于SRAM地址空间。从82行,中断表定位与FLASH区,而这整片启动代码中最先被初始化的片段得到了FLASH区的数据。因此可以得到一条一条的信息:0x8000000地址也是栈顶地址__initial_sp,0x8000004地址行动是重新启动重新启动Reset_Handler(STM3232位总线) ,因此存储空间为4字节对齐)。 2,DCD指令:作用是开辟一段空间,其意义等价于ç语言中的地址符“&”因此从第84行开始建立的中断向量表则类似3、 于使用C语言定义了一个线程组,每一个成员都有一个函数路径,各自独立的服务函数。 3、号:前文多空间标号处了“标号”。本地标号主要用于表示内存某个语言的位置,等价于C中的“地址”概念。表达了自己的空间的一个位置,从C语言的地址的角度来看,变量的地址,数组的地址的地址功能的入口在本质上并无区别。 4、第202行中的__main标号不显示C程序中的main函数入口地址,因此第204行也不是跳转至main函数开始执行C程序。__main标号C/C++标准实时库函数显示该的一个初始化程序__main的入口地址。该主要的一个作用是初始化程序(对于程序简洁一言则是跳转__user_ial_stackheap标号进行初始化火箭的),并初始化映像文件,最终跳转C程序中的main函数。这是因为解释了为什么所有的C程序必须有一个main函数作为程序的起点——由C/C++标准实时库规定——并且不能更改,因为C/C++标准实时库不对小程序源开发代码。因此,实际上在用户可见的程序下,程序在第204行后就跳转到.c文件中的主函数,开始执行C程序了。 到可以总结一下STM32的启动程序文件和启动过程。首先对栈和堆的大小进行定义,并在代码区的可爱处创建中断表,其第一个表项是栈顶地址,第二个表项是恢复中断服务入口地址。然后在复位中断服务程序中跳转¬¬C/C++标准实时库的__main函数,完成用户函数开始等的初始化后,跳转c文件中的执行C程序。假想32被设置为从内部FLASH启动(这也是最常见的一种情况),中断表恢复状态为08000000,则栈顶地址召开于0x8000000处,而复位服务入口地址在0x8000004处。当STM32遇到复位信号后,则从0x80000004处继取出恢复中断服务地址,而执行复位中断入口服务,然后跳转__main函数,最终进入函数,来到C的世界。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1801 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1096 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
735 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1684 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
745浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
579浏览 3评论
601浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
565浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 13:28 , Processed in 1.027802 second(s), Total 75, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号