历史上的今天
返回首页

历史上的今天

今天是:2024年12月12日(星期四)

正在发生

2018年12月12日 | STM32F103X启动代码详细分析

2018-12-12 来源:eefocus

1.      在分析启动代码之前,先把STM32的存储结构说一下:



上面这张图来自CORTEX M3权威指南


STM32F103RTB6 有20k的SRAM,起始地址为0x20000000,128k的闪存flash,起始地址为0x08000000(处于code区域).


        从主闪存存储器启动时,主闪存存储器被映射到启动空间(0x00000000),但仍然能够在它原有的地址(0x08000000)访问它,即闪存存储器的内容可以在两个地址区域访问,0x00000000或0x0800 0000。


         通过boot0和boot1的配置可以选着三种启动方式:



当我们下载程序时,选着的是系统存储器启动,当我们一上电开始跑程序的时候,应选择闪存flash启动.


1.      再明确一下一些代码对齐的规则:


1.1   字对齐: 4字节对齐,ARM指令时32位一跳的; 半字对齐: 2字节对齐.thumb指令是16位一跳的。而CORTEX-M3  是thumb-2指令集,16位32位都有


1.2   注意align的不同:


AREA    STACK, NOINIT, READWRITE, ALIGN=3


此处的align表示接下来的堆栈段是2^3=8字节对齐的


而单纯.align或ALIGN表示字对齐(32位)


3.我想我们还要明确比较重要的一点,既然我们的程序是从flash闪存上开始执行的,在STM32中文手册上由这么一句话:,CPU从地址0x0000 0000获取堆栈顶的地址,并从启动存储器的0x00000004指示的地址开始执行代码。而0x00000004开始的地址放的是什么呢?我可以告诉你从该处开始放的是cortex-m3规定的异常向量表。而且我们还可以确定,0x0000 0004出放的必然是复位异常向量。


4.下面好好来分析启动代码,我从keil得到的文件是STM32F10X.s,跟着我的注释走吧


//栈大小


Stack_Size      EQU    0x00000200                


//定义堆栈段,8字节对齐,注意,是可读写!!而我们的闪存flash是要擦除后才能写的,这就有问题了,说明我们的堆栈段不可能是安排在Flash闪存上的,那安排在哪呢?当然是内部20k的SRAM上啦!


                AREA    STACK, NOINIT, READWRITE, ALIGN=3


//stack_Mem为堆栈的底部,SPACE表示存储Stack_size个 分配单元


Stack_Mem       SPACE  Stack_Size


//__initial_sp很显然表示的是栈顶地址


__initial_sp


//下面是在SRAM上分配堆空间,大小为0


Heap_Size       EQU    0x00000000


 


                AREA    HEAP, NOINIT, READWRITE, ALIGN=3


//__heap_base和Heap_Mem为堆起始地址


__heap_base


Heap_Mem        SPACE  Heap_Size


//__heap_limit为堆结束的地址


__heap_limit


//8字节对齐,在keil中必须要这一条


                PRESERVE8


//使用的是thumb指令集,但是cortex-m3是thumb-2版本,16位和32位的指令都有


       THUMB


//只读代码段


                AREA    RESET, DATA, READONLY


//导出__Vectors中断向量表起始地址,相当于在此声明__Vectors为一个全局变量,别的文件时可以访问到的   


                            EXPORT __Vectors


//前面说过0x0地址必须放堆栈顶地址


__Vectors       DCD    __initial_sp              ; Top ofStack


//接下来是一些异常向量表,当发生该异常时,PC将会跳到这里执行


                DCD     Reset_Handler             ; Reset Handler


                DCD     NMI_Handler               ; NMI Handler


                DCD     HardFault_Handler         ; Hard Fault Handler


                DCD     MemManage_Handler         ; MPU Fault Handler


                DCD     BusFault_Handler          ; Bus Fault Handler


                DCD     UsageFault_Handler        ; Usage Fault Handler


                DCD    0                         ;Reserved


                DCD     0                         ; Reserved


                DCD     0                         ; Reserved


                DCD     0                         ; Reserved


                DCD     SVC_Handler               ; SVCall Handler


                DCD     DebugMon_Handler          ; Debug Monitor Handler


                DCD     0                         ; Reserved


                DCD     PendSV_Handler            ; PendSV Handler


               DCD     SysTick_Handler           ; SysTick Handler


//下面是外部中断的向量表


                ; External Interrupts


                DCD     WWDG_IRQHandler           ; Window Watchdog


                DCD     PVD_IRQHandler            ; PVD through EXTI Line detect


                DCD    TAMPER_IRQHandler         ; Tamper


                DCD     RTC_IRQHandler            ; RTC


                DCD     FLASH_IRQHandler          ; Flash


                DCD     RCC_IRQHandler            ; RCC


                DCD     EXTI0_IRQHandler          ; EXTI Line 0


                DCD     EXTI1_IRQHandler          ; EXTI Line 1


                DCD     EXTI2_IRQHandler          ; EXTI Line 2


                DCD     EXTI3_IRQHandler          ; EXTI Line 3


                DCD     EXTI4_IRQHandler          ; EXTI Line 4


                DCD     DMAChannel1_IRQHandler    ; DMA Channel 1


                DCD     DMAChannel2_IRQHandler    ; DMA Channel 2


                DCD     DMAChannel3_IRQHandler    ; DMA Channel 3


                DCD     DMAChannel4_IRQHandler    ; DMA Channel 4


                DCD     DMAChannel5_IRQHandler    ; DMA Channel 5


                DCD     DMAChannel6_IRQHandler    ; DMA Channel 6


                DCD     DMAChannel7_IRQHandler    ; DMA Channel 7


                DCD     ADC_IRQHandler            ; ADC


                DCD     USB_HP_CAN_TX_IRQHandler  ; USB High Priority or CAN TX


                DCD     USB_LP_CAN_RX0_IRQHandler ; USB Low  Priority or CAN RX0


                DCD     CAN_RX1_IRQHandler        ; CAN RX1


                DCD     CAN_SCE_IRQHandler        ; CAN SCE


                DCD     EXTI9_5_IRQHandler        ; EXTI Line 9..5


                DCD     TIM1_BRK_IRQHandler       ; TIM1 Break


                DCD     TIM1_UP_IRQHandler        ; TIM1 Update


                DCD     TIM1_TRG_COM_IRQHandler   ; TIM1 Trigger and Commutation


                DCD     TIM1_CC_IRQHandler        ; TIM1 Capture Compare


                DCD     TIM2_IRQHandler           ; TIM2


               DCD     TIM3_IRQHandler           ; TIM3


                DCD     TIM4_IRQHandler           ; TIM4


                DCD     I2C1_EV_IRQHandler        ; I2C1 Event


                DCD     I2C1_ER_IRQHandler        ; I2C1 Error


                DCD     I2C2_EV_IRQHandler        ; I2C2 Event


                DCD     I2C2_ER_IRQHandler        ; I2C2 Error


                DCD     SPI1_IRQHandler           ; SPI1


                DCD     SPI2_IRQHandler           ; SPI2


                DCD     USART1_IRQHandler         ; USART1


                DCD     USART2_IRQHandler         ; USART2


                DCD     USART3_IRQHandler         ; USART3


                DCD     EXTI15_10_IRQHandler      ; EXTI Line 15..10


                DCD     RTCAlarm_IRQHandler       ; RTC Alarm through EXTI Line


                DCD     USBWakeUp_IRQHandler      ; USB Wakeup from suspend


//声明代码段|.text|是约定的代码段名称


AREA    |.text|, CODE,READONLY


//中断异常向量的函数指针


Reset_Handler   PROC


//到处该符号,[WEAK]表示如果外部有同名符号,外部该同名符号是优先使用的


                EXPORT  Reset_Handler             [WEAK]


//__main标号起始不是我们c语言中的main函数,而是C/C++标准实时库函数里的一个初始化子程序__main的入口地址,该程序的一个主要作用是初始化堆栈(对于我们的程序来说是跳转到后面的_user_initial_stackheap标号出进行初始化堆栈),并初始化映象文件,最后跳转到C程序的main函数。我们就理解为__main最后就跳到了main吧


                IMPORT  __main


                LDR     R0, =__main


                BX      R0


                ENDP


//下面就是其他向量的函数地址了,这里只是简单的死循环,不做任何处理,然而很有意思的是,他们都EXPORT…[WEAK]了,所以,当我们要设置该异常的中断向量函数时,以我们设置的同名标号为准,这就是我们经常在keil中写的各个外部中断的handler了,然而,当没有设置这个异常的中断函数就引发了该中断,程序就会死在中断函数入口了。


; Dummy Exception Handlers (infinite loopswhich can be modified)               


 


NMI_Handler     PROC


                EXPORT  NMI_Handler               [WEAK]


                B       .


                ENDP


HardFault_Handler\


                PROC


                EXPORT  HardFault_Handler         [WEAK]


                B       .


                ENDP


MemManage_Handler\


                PROC


                EXPORT  MemManage_Handler         [WEAK]


                B       .


                ENDP


BusFault_Handler\


                PROC


                EXPORT  BusFault_Handler          [WEAK]


                B       .


                ENDP


UsageFault_Handler\


                PROC


                EXPORT  UsageFault_Handler        [WEAK]


                B       .


                ENDP


SVC_Handler     PROC


                EXPORT  SVC_Handler               [WEAK]


                B       .


                ENDP


DebugMon_Handler\


                PROC


                EXPORT  DebugMon_Handler          [WEAK]


                B       .


                ENDP


PendSV_Handler  PROC


                EXPORT  PendSV_Handler            [WEAK]


                B       .


                ENDP


SysTick_Handler PROC


                EXPORT  SysTick_Handler           [WEAK]


                B       .


                ENDP


 


Default_Handler PROC


 


                EXPORT  WWDG_IRQHandler           [WEAK]


                EXPORT  PVD_IRQHandler            [WEAK]


                EXPORT  TAMPER_IRQHandler         [WEAK]


                EXPORT  RTC_IRQHandler            [WEAK]


                EXPORT  FLASH_IRQHandler          [WEAK]


                EXPORT  RCC_IRQHandler            [WEAK]


                EXPORT  EXTI0_IRQHandler          [WEAK]


                EXPORT  EXTI1_IRQHandler          [WEAK]


                EXPORT  EXTI2_IRQHandler          [WEAK]


                EXPORT  EXTI3_IRQHandler          [WEAK]


                EXPORT  EXTI4_IRQHandler          [WEAK]


                EXPORT  DMAChannel1_IRQHandler    [WEAK]


                EXPORT  DMAChannel2_IRQHandler    [WEAK]


                EXPORT  DMAChannel3_IRQHandler    [WEAK]


                EXPORT  DMAChannel4_IRQHandler    [WEAK]


                EXPORT  DMAChannel5_IRQHandler    [WEAK]


                EXPORT  DMAChannel6_IRQHandler    [WEAK]


                EXPORT  DMAChannel7_IRQHandler    [WEAK]


                EXPORT  ADC_IRQHandler            [WEAK]


                EXPORT  USB_HP_CAN_TX_IRQHandler  [WEAK]


                EXPORT  USB_LP_CAN_RX0_IRQHandler [WEAK]


                EXPORT  CAN_RX1_IRQHandler        [WEAK]


                EXPORT  CAN_SCE_IRQHandler        [WEAK]


                EXPORT  EXTI9_5_IRQHandler        [WEAK]


                EXPORT  TIM1_BRK_IRQHandler       [WEAK]


                EXPORT  TIM1_UP_IRQHandler        [WEAK]


                EXPORT  TIM1_TRG_COM_IRQHandler   [WEAK]


                EXPORT  TIM1_CC_IRQHandler        [WEAK]


                EXPORT  TIM2_IRQHandler           [WEAK]


                EXPORT  TIM3_IRQHandler           [WEAK]


                EXPORT  TIM4_IRQHandler           [WEAK]


                EXPORT  I2C1_EV_IRQHandler        [WEAK]


                EXPORT  I2C1_ER_IRQHandler        [WEAK]


                EXPORT  I2C2_EV_IRQHandler        [WEAK]


                EXPORT  I2C2_ER_IRQHandler        [WEAK]


                EXPORT  SPI1_IRQHandler           [WEAK]


                EXPORT  SPI2_IRQHandler           [WEAK]


                EXPORT  USART1_IRQHandler         [WEAK]


                EXPORT  USART2_IRQHandler         [WEAK]


                EXPORT  USART3_IRQHandler         [WEAK]


                EXPORT  EXTI15_10_IRQHandler      [WEAK]


                EXPORT  RTCAlarm_IRQHandler       [WEAK]


                EXPORT  USBWakeUp_IRQHandler      [WEAK]


 


WWDG_IRQHandler


PVD_IRQHandler


TAMPER_IRQHandler


RTC_IRQHandler


FLASH_IRQHandler


RCC_IRQHandler


EXTI0_IRQHandler


EXTI1_IRQHandler


EXTI2_IRQHandler


EXTI3_IRQHandler


EXTI4_IRQHandler


DMAChannel1_IRQHandler


DMAChannel2_IRQHandler


DMAChannel3_IRQHandler


DMAChannel4_IRQHandler


DMAChannel5_IRQHandler


DMAChannel6_IRQHandler


DMAChannel7_IRQHandler


ADC_IRQHandler


USB_HP_CAN_TX_IRQHandler


USB_LP_CAN_RX0_IRQHandler


CAN_RX1_IRQHandler


CAN_SCE_IRQHandler


EXTI9_5_IRQHandler


TIM1_BRK_IRQHandler


TIM1_UP_IRQHandler


TIM1_TRG_COM_IRQHandler


TIM1_CC_IRQHandler


TIM2_IRQHandler


TIM3_IRQHandler


TIM4_IRQHandler


I2C1_EV_IRQHandler


I2C1_ER_IRQHandler


I2C2_EV_IRQHandler


I2C2_ER_IRQHandler


SPI1_IRQHandler


SPI2_IRQHandler


USART1_IRQHandler


USART2_IRQHandler


USART3_IRQHandler


EXTI15_10_IRQHandler


RTCAlarm_IRQHandler


USBWakeUp_IRQHandler


 


                B       .


 


                ENDP


// 字对齐(32位)


ALIGN


; User Initial Stack & Heap


//这里我们没有定义__MICROLIB,走下面分支


                IF      :DEF:__MICROLIB


                //导出栈顶,堆头和堆尾地址


                EXPORT  __initial_sp


                EXPORT  __heap_base


                EXPORT  __heap_limit


               


                ELSE


               


               


IMPORT __use_two_region_memory


//一个小函数,我们前面提到在__main中会调用他来初始化堆栈


                EXPORT  __user_initial_stackheap


__user_initial_stackheap


                                     //传入这些关于堆栈的地址,作为参数


                LDR     R0, = Heap_Mem


                LDR     R1, =(Stack_Mem + Stack_Size)


                LDR     R2, = (Heap_Mem +  Heap_Size)


                LDR     R3, = Stack_Mem


                                     //调回__mian中调用__user_initial_stackheap的地方去


                BX      LR


 


               ALIGN


 


                ENDIF


//汇编结束


END

推荐阅读

史海拾趣

Geyer Electronic E K公司的发展小趣事

Geyer Electronic E.K.公司的发展故事

故事一:创立与初步发展

Geyer Electronic E.K.公司由Rudolf Geyer于1964年创立,最初是一家位于慕尼黑莱姆区的电子产品零售店。在那个年代,电子产品行业正处于快速发展阶段,Geyer凭借其敏锐的市场洞察力和对技术的热情,逐渐在市场中站稳了脚跟。起初,店铺销售各类电子产品,从简单的收音机到复杂的电子设备,一应俱全。随着时间的推移,Geyer Electronic凭借其优质的服务和丰富的产品线,逐渐赢得了当地消费者的信任和支持。

故事二:转型与专业化

1992年,Geyer Electronic经历了一次重要的转折点。在Jürgen Reichmann的领导下,公司被收购并进行了战略调整,正式转型为一家专门从事频率产品和特殊电池的公司。这一转型标志着Geyer Electronic开始专注于某一特定领域,并致力于在该领域成为行业的领导者。公司投入大量资源进行技术研发和产品创新,不断推出符合市场需求的高质量频率产品和特殊电池,逐渐在行业内树立了良好的口碑。

故事三:全球化布局

随着业务的不断扩展,Geyer Electronic开始将目光投向全球市场。公司不仅在欧洲建立了稳固的市场地位,还逐渐将业务拓展到亚洲和美国等其他地区。为了实现全球化战略,Geyer Electronic加强了与全球合作伙伴的合作与交流,共同推动频率产品和特殊电池技术的创新与发展。同时,公司还建立了完善的全球销售网络,确保产品能够在短时间内送达全球各地的客户手中。

故事四:认证与品质保证

为了进一步提升产品质量和客户满意度,Geyer Electronic积极寻求国际认证。公司通过了DIN ISO 9001:2015等国际质量管理体系认证,这标志着Geyer Electronic在质量管理方面已经达到了国际先进水平。通过严格的质量控制和持续的技术创新,Geyer Electronic不断推出高品质的频率产品和特殊电池,赢得了全球客户的广泛认可和信赖。

故事五:搬迁与未来发展

为了满足未来发展的需要,Geyer Electronic于2022年搬到了位于Planegg的新公司所在地。这次搬迁不仅为公司提供了更加宽敞和现代化的办公和生产环境,还为公司未来的发展奠定了坚实的基础。在新的起点上,Geyer Electronic将继续秉承“质量第一、客户至上”的经营理念,不断推动技术创新和产品升级,为全球客户提供更加优质、高效的服务和解决方案。同时,公司还将积极探索新的市场领域和发展机遇,努力成为全球电子行业中的佼佼者。

Ericsson公司的发展小趣事

Ericsson公司在早期就非常注重市场拓展和全球布局。通过与各国电信运营商建立合作关系,Ericsson成功将其产品和服务推广到了全球各地。特别是在中国市场,Ericsson早在19世纪90年代就与中国签订了供货合同,成为中国通信网络建设的重要参与者。如今,Ericsson已经在中国扎根130余年,成为了唯一一家从1G到5G全程参与中国通信网络建设的企业。

Anixter Inc公司的发展小趣事

Ericsson公司在早期就非常注重市场拓展和全球布局。通过与各国电信运营商建立合作关系,Ericsson成功将其产品和服务推广到了全球各地。特别是在中国市场,Ericsson早在19世纪90年代就与中国签订了供货合同,成为中国通信网络建设的重要参与者。如今,Ericsson已经在中国扎根130余年,成为了唯一一家从1G到5G全程参与中国通信网络建设的企业。

CoolerMaster公司的发展小趣事

林仁政跳出已有的框架,不断思考机箱的设计。他敏锐地觉察到人们对于免工具安装的主板散热片的偏好,并深知散热效果不仅仅取决于散热片和风扇,更需要考虑空气的流动情况。结合日本高水准的立体设计灵感,林仁政带领工程师挑战困难,成功设计出了一台铝制机箱。这一机箱不仅具有高度的创新性,更因其纯手工制作的特性而显得弥足珍贵,对Cooler Master的发展具有重要意义。

Coil-Q Corporation公司的发展小趣事

随着全球市场的开放和融合,Coil-Q意识到国际化是公司发展的必然趋势。于是,公司开始积极布局海外市场,先后在多个国家和地区设立了分公司或办事处。通过深入了解当地市场需求和文化习惯,Coil-Q成功打开了多个新的市场,实现了业务的快速增长。

Herga公司的发展小趣事

近年来,Herga公司紧跟智能制造的发展趋势,大力推动生产线的自动化和智能化升级。公司引入了先进的机器人、自动化设备和智能管理系统,实现了从原材料采购、生产加工到成品检验的全流程自动化控制。这一举措不仅大大提高了生产效率和质量稳定性,还降低了人力成本和运营风险。Herga公司的智能制造实践为电子行业树立了典范,也为公司的持续发展注入了新的动力。

问答坊 | AI 解惑

PID算法

本帖最后由 paulhyde 于 2014-9-15 03:27 编辑 PID算法,愿大伙在今年全国赛取得好成绩  …

查看全部问答>

有关PROTEL原理图的一些问题

在画原理图的时候,怎么查找具有相同文本的标号(暂且叫标号吧)。 比如说:在一个原理图中,MCU芯片上有一个TXD,又另一部分也有TXD(表示这两端是相连的),我怎么找出来这两个TXD? 用快捷方式,或着菜单栏?…

查看全部问答>

U盘过滤驱动win2000下的安装问题

最近在做一个U盘,移动硬盘等移动存储设备的过滤驱动。功能大致如下:1)当插入经过处理的加密U盘时,会提示输入密码,在密码验证正确之前不可以用;2)当插入的是一个未经处理过的普通U盘时会禁止使用,双击打开时会提示未格式化无法打开,该U盘在 ...…

查看全部问答>

如何在wince系统中实现sd卡的热插拔

在wince系统启动之前sd卡可以认得到,但是拔掉之后,系统好像还是认为sd卡仍然存在,但是却读不到数据的。再把sd卡插进去,再也无法读写sd卡了,请教各位大侠,感激不尽。 使用的wince 4.2版本的平台,cpu是三星2440a芯片,bsp包是smdk2440…

查看全部问答>

找一起学习的同学

我的QQ是1286997688.我是电子信息工程专业的本科生。同时也十分热爱英语。希望能有也在学习电子的同学加我,一起学习一起进步。…

查看全部问答>

寻LED显示屏供应商(不知贴在这边合适不合适)

有朋友最近想做LED广告屏,让帮忙找找有没有合适的供应商。 有意向的可以留下联系方式和公司产品介绍相关链接,谢谢~…

查看全部问答>

电话电压

最近在做一个和电话有关的东东 我测量电话电压是50V 可是在网上查的却是待机时12V或者20V 谁知道这是为什么吗?…

查看全部问答>

ARM9260EJ-S MMU初始化问题

我在初始化ARM9260EJ-S CPU(AT91SAM9260EJ-S)时遇到了一个问题,SDRAM 8M,按Section初始化,影射成8个块,每块1M,SDRAM的物理地址为0x20000000,未启动MMU时,SDRAM上的所有读写都正常,启动MMU之后,0x20500000开始的1M SDRAM读写就发现异常,MMU初 ...…

查看全部问答>

EQ 6 1 10混合动力电动汽车再生

EQ 6 1 10混合动力电动汽车再生制动控制策略研究…

查看全部问答>

【挖电源】3个厂家的LED灯T8管驱动电源

这是为LED灯T8管供电的隔离驱动电源,那个最长的驱动电源,装在灯管后,售价是在200元以上的,只是这些驱动电源在装进灯管时,都是用热缩套管套着得,这在欧美是不允许的,但是国内可以! [ 本帖最后由 dongguanze 于 2011-7-31 09:23 编辑 ]…

查看全部问答>