STM32F4启动代码分析

您所在的位置:网站首页 stm32f4代码 STM32F4启动代码分析

STM32F4启动代码分析

#STM32F4启动代码分析| 来源: 网络整理| 查看: 265

STM32F4启动代码分析 用到的汇编指令介绍;EQU其他指令介绍如下可以利用keil直接查看汇编指令 代码解读配置栈(Stack)的大小和相关信息配置堆(Heap)的大小和相关信息对齐方式与兼容指令集中断向量表定义复位处理程序 代码执行分析

用到的汇编指令介绍 ;

  在汇编中,分号(;)用于表示注释。当汇编器遇到分号时,它会将分号后的内容视为注释,不会对其进行编译或解析。

EQU

  'EQU’是一个汇编语言的伪指令,用于为符号常量分配一个特定的值。它不是真正的指令,而是由汇编器处理的一个指令,用于在编译时进行符号替换。   'EQU’指令的作用是将符号与一个特定的值进行绑定。当汇编器遇到使用该符号的地方,会将符号替换为预定义的值。这样可以方便地在程序中使用符号常量,提高代码的可读性和可维护性。   例如,假设有以下代码片段:

Stack_Size EQU 0x00000400

在这个例子中,‘EQU’指令将’Stack_Size’定义为‘0x00000400’,每当程序中使用’Stack_Size’时,汇编器会将其替换为’0x00000400’,以便在程序中使用固定的值。这样可以避免在代码中多次使用硬编码的值,使代码更易于理解和修改。

其他指令介绍如下

在这里插入图片描述

可以利用keil直接查看汇编指令

请添加图片描述

代码解读 配置栈(Stack)的大小和相关信息 Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp

  这段代码的作用是定义一个名为’STACK’的区域,用于存储栈的数据。通过MAP文件可知(在目标工程栏–>>双击工程名,就会在kail文件显示框出现map文件),STACK的地址为 0x20002150, Stack_Mem大小为1024字节,__initial_sp的地址为0x20002550(0x20002150+0x400) 在这里插入图片描述 在这里插入图片描述

Stack_Size EQU 0x00000400

  在该代码中,‘Stack_Size’用于指定栈的大小,即为栈分配的内存空间的字节数。在嵌入式系统中,栈用于存储函数调用期间的局部变量、函数参数以及其他与函数执行相关的信息。通过设置’Stack_Size’的值,可以根据应用程序的需求来调整栈的大小。   该代码将栈的大小设置为1024字节。

AREA STACK, NOINIT, READWRITE, ALIGN=3

  在汇编语言中,’AREA‘是用于定义代码或数据的存储区域(Area)的伪指令之一。’AREA’指令用于在程序中创建一个新的存储区域,并指定该区域的属性和特征。   以下是’AREA’指令中的参数解释:

‘STACK’:存储区域的名称。在这种情况下,名称为”STACK“。’NOINIT‘:存储区域中的数据不需要进行初始化。这意味着该区域中的数据在被访问之前不会被自动清零或设置为默认值。’READWRITE‘:存储区域可以被读取和写入。这表示该区域中的数据可以被读取和修改。’ALIGN=3’:存储区域的对齐方式,为2的ALIGN次方。在这个例子中,对齐值为3,表示存储区域的起始地址需要按照2^3=8字节的边界对齐。   这个‘AREA’指令的作用是定义一个名为’STACK’的存储区域,该区域不需要进行初始化,可以被读取和写入,并且其起始地址需要按照8字节的边界对齐。通常,这种存储区域被用作栈空间,用于存储函数调用的局部变量和其他相关数据。 Stack_Mem SPACE Stack_Size

  在汇编语言中,‘SPACE’是一个伪指令,用于分配一段指定大小的连续内存空间(给STACK分配)。   ’Stack_Mem‘是一个符号,用来表示一个内存区域的起始地址和标签。’Stack_Size‘是一个常数或符号,表示要分配的内存空间的大小。   这行代码的目的是给STACK分配一块大小为’Stack_Size’ 字节的内存空间,并将其起始地址赋值给 ’Stack_Mem’符号,以便在后续的程序中使用这个内存空间。一般情况下,这种内存空间被用作栈,用于存储函数调用的局部变量、返回地址和其他相关数据。

__initial_sp

  ‘__initial_sp’是一个符号,用于表示初始栈指针的值。   在嵌入式系统中,栈是用来管理程序执行过程中的函数调用、局部变量和其他相关数据的一种数据结构。栈指针是一个寄存器或内存地址,它指向当前栈顶的位置。在程序执行过程中,栈指针会根据函数调用和返回的操作动态地进行移动,但初始栈指针的值是在系统启动时预先确定的。当函数被调用时,栈指针会向下移动,为局部变量和其他数据结构分配空间。当函数返回时,栈指针会向上移动,释放之前分配的空间。

配置堆(Heap)的大小和相关信息

  堆是计算机内存中一种用于动态分配内存的数据结构。它用于存储程序运行时需要动态分配的内存对象,例如在运行时创建的对象、数据结构、数组等。堆内存的分配和释放是在程序运行时动态进行的,与静态内存(如全局变量和静态变量)或栈内存(用于函数调用和局部变量)不同。   堆内存的特点包括:

动态分配:堆内存的大小可以根据需要在运行时进行动态分配和释放,而不是在编译时确定。灵活性:堆内存可以用于存储各种大小和类型的对象,可以根据实际需求进行动态调整。持久性:堆内存中的对象可以在函数调用之间保持存在,不会随着函数的退出而销毁。相对较慢的访问速度:与栈内存相比,堆内存的访问速度较慢,因为需要通过指针进行间接访问。 例如使用malloc()等相关函数在堆上分配内存,然后使用free()函数释放已分配的内存。 Heap_Size EQU 0x00000000 ;我们不使用MDK自带的malloc和free函数,所以设置这里为0. AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit

  这段代码的作用是定义一个名为’HEAP’的区域,用于存储堆的数据。通过MAP文件可知,堆的大小为0 在这里插入图片描述

Heap_Size EQU 0x00000000 ;我们不使用MDK自带的malloc和free函数,所以设置这里为0.

  利用EQU伪指令设置Heap_Size的大小为0,即堆(Heap)的大小被设置为0字节,没有为堆分配任何内存空间。

AREA HEAP, NOINIT, READWRITE, ALIGN=3

  利用AREA指令定义一个名为’HEAP’的存储区域,该区域不需要初始化,可以被读取和写入,并且其起始地址需要按照8字节的边界对齐。

__heap_base

该标识符用于表示堆的起始地址

Heap_Mem SPACE Heap_Size

  利用SPACE指令在堆中为变量‘Heap_Mem’分配了‘Heap_Size’大小的连续内存空间。这样,‘Heap_Mem’可以被用作堆中动态分配的对象、数据结构或数组的起始地址,可以通过‘Heap_Mem’来访问这块分配的内存空间。

__heap_limit

  ’__heap_limit‘是一个汇编语言中的符号,用于表示堆的结束地址。   在该代码中,’__heap_limit‘被用于表示堆的边界,即堆的结束地址,它通常在堆的配置中使用,用于确定堆的大小以及堆的起始地址和结束位置。   '__heap_limit’可以用来判断堆中分配的内存是否超出了预先设定的堆大小。从而进行错误检查和处理。

对齐方式与兼容指令集 PRESERVE8

  'PRESERVE8’是一个指令或指示符,用于在汇编语言中指定对齐要求。指定当前文件的栈按照8字节对齐

THUMB

  THUMB指定后面所使用的指令集为THUMB

中断向量表定义 ; Vector Table Mapped to Address 0 at Reset

  存储在地址0处的向量表(vector Table),用于处理器复位时的初始化。(地址0并不是真正的地址0,假设STM32从flash启动,则此中断向量表起始地址为0x8000000) 在这里插入图片描述

AREA RESET, DATA, READONLY

  定义了名为’RESET’的代码段,其中存储的数据是只读的。

EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size

EXPORT伪指令,用于在程序中声明全局的变量,该变量可以在其他文件中引用。EXPORT可用GLOBAL代替。变量在程序中区分大小写。

‘EXPORT __Vectors’:导出变量‘__Vectors’‘EXPORT __Vectors_End’:导出变量‘__Vectors_End’,表示向量表的结束位置。’EXPORT __Vectors_Size‘:导出变量’__Vectors_Size‘,表示向量表的大小。 __Vectors DCD __initial_sp ; Top of Stack 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 detection DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line DCD FLASH_IRQHandler ; FLASH DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line0 DCD EXTI1_IRQHandler ; EXTI Line1 DCD EXTI2_IRQHandler ; EXTI Line2 DCD EXTI3_IRQHandler ; EXTI Line3 DCD EXTI4_IRQHandler ; EXTI Line4 DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0 DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1 DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2 DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3 DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4 DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5 DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6 DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s DCD CAN1_TX_IRQHandler ; CAN1 TX DCD CAN1_RX0_IRQHandler ; CAN1 RX0 DCD CAN1_RX1_IRQHandler ; CAN1 RX1 DCD CAN1_SCE_IRQHandler ; CAN1 SCE DCD EXTI9_5_IRQHandler ; External Line[9:5]s DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9 DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10 DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11 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 ; External Line[15:10]s DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12 DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13 DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14 DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7 DCD FSMC_IRQHandler ; FSMC DCD SDIO_IRQHandler ; SDIO DCD TIM5_IRQHandler ; TIM5 DCD SPI3_IRQHandler ; SPI3 DCD UART4_IRQHandler ; UART4 DCD UART5_IRQHandler ; UART5 DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors DCD TIM7_IRQHandler ; TIM7 DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0 DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1 DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2 DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3 DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4 DCD ETH_IRQHandler ; Ethernet DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line DCD CAN2_TX_IRQHandler ; CAN2 TX DCD CAN2_RX0_IRQHandler ; CAN2 RX0 DCD CAN2_RX1_IRQHandler ; CAN2 RX1 DCD CAN2_SCE_IRQHandler ; CAN2 SCE DCD OTG_FS_IRQHandler ; USB OTG FS DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5 DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6 DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7 DCD USART6_IRQHandler ; USART6 DCD I2C3_EV_IRQHandler ; I2C3 event DCD I2C3_ER_IRQHandler ; I2C3 error DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI DCD OTG_HS_IRQHandler ; USB OTG HS DCD DCMI_IRQHandler ; DCMI DCD CRYP_IRQHandler ; CRYP crypto DCD HASH_RNG_IRQHandler ; Hash and Rng DCD FPU_IRQHandler ; FPU __Vectors_End

  这段代码定义了一个向量表,它包含了处理器中断和异常的处理程序的地址。逐行解释如下:

__Vectors DCD __initial_sp ; Top of Stack

  ’DCD‘是一个伪指令,用于分配一片连续的字存储单元并用指定的数据初始化。   这行代码的作用是将栈的起始地址存储在向量表的特定位置,以便处理器在启动时可以正确的设置栈的初始值,栈是用于存储函数调用、局部变量和其他临时数据的一块内存区域。通过将栈的起始地址存储在向量表中,处理器在启动时可以使用正确的栈地址,确保程序的正常运行。   向量表的第一个表项是栈顶地址,该处物理地址值即为__Vectors 变量所表示的值,该地址中存储’__initial_sp‘所表示的地址值,大小为一个字(32bit)。

DCD Reset_Handler ; Reset Handler 。。。。。。。 DCD FPU_IRQHandler ; FPU

  这些代码将复位处理函数Reset_Handler 等的地址存于中断向量表中,每个中断都有一个对应的处理程序。

DCD 0 ; Reserved

  这种行代码将保留的位置填充为零。

__Vectors_End

  这行代码定义了向量表的结束。   总的来说,向量表这段代码定义了一个包含处理器中断和异常处理程序地址的向量表。在处理器发生中断或异常时,它会根据向量表中的条目跳转到相应的处理程序。

__Vectors_Size EQU __Vectors_End - __Vectors

  ’__Vectors_Size‘是一个符号常量,用于表示向量表的大小。其值是通过’ __Vectors_End - __Vectors‘得到,即向量表的结束位置减去向量表的起始位置。 在这里插入图片描述 __Vectors_Size为0x188,是因为有98个元素,一个DCD分配一个或多个字的内存,这里分配的一个字即4个字节。

AREA |.text|, CODE, READONLY

  这行代码是将下面的代码片段分配到名为‘.text’的区域,并指定该区域的属性为‘CODE’和‘READONLY’。 在这里插入图片描述

; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] ;IMPORT SystemInit ;寄存器代码,不需要在这里调用SystemInit函数,故屏蔽掉,库函数版本代码,可以留下 ;不过需要在外部实现SystemInit函数,否则会报错. IMPORT __main LDR R0, =0xE000ED88 ; 使能浮点运算 CP10,CP11 LDR R1,[R0] ORR R1,R1,#(0xF


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3