STM32启动代码学习

2020-03-24来源: elecfans关键字:STM32  启动代码  汇编指令

第一部分:汇编指令学习

1.伪指令

1).EQU


EQU伪指令:用来为一个数字常量、或一个和内核寄存器相关的数值或一个和程序计数器相关的数值定义的一个符号名称。类似于C语言中的#define 。


格式: name     EQU   expr{ , type} 

格式:  名称     EQU  表达式(,类型)

例如: 

Stack_Size  EQU   0X00000400  //定义1k字节的栈空间

Heap_Size   EQU   0x00000200  //定义512字节的堆空间


2).AREA


AREA伪指令:用于定义一个代码段或数据段。其中,段名若以数字开头,则该段名需用“|”括起来,如:|1_test| 。


格式: AREA 段名 属性1 ,属性2 ,……  

属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:    

     — CODE 属性:用于定义代码段,默认为READONLY 。    

     — DATA 属性:用于定义数据段,默认为READWRITE 。    

     — READONLY 属性:指定本段为只读,代码段默认为READONLY 。    

     — READWRITE 属性:指定本段为可读可写,数据段的默认属性为READWRITE 。

— ALIGN 属性:使用方式为ALIGN表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。    

    — COMMON 属性:该属性定义一个通用的段,不包含任何的用户代码和数据。各源文件中同名的COMMON段共享同一段存储单元。 


例如1:

AREA HEAP, NOINIT, READWRITE, ALIGN=3

其中:

HEAP: 定义一个堆段,名字 HEAP

NOINIT: 只分配空间不初始化零

READWRITE:可以读写

ALIGN=3 : 8字节对齐

例如2:

AREA STACK, NOINIT, READWRITE, ALIGN=3

定义一个栈段,名字是STACK,不初始化为0,可以读写,8字节对齐

例如3:

AREA RESET, DATA, READONLY

定义一个数据段,名字是RESET,只可读;这里面的DATA属性表示RESET是一个数据段

例如4:

AREA |.text|, CODE, READONLY

定义一个代码段,名字是 |.text|,只可读;这里面的CODE属性表示|.text|是一个代码段


3). SPACE


SPACE伪指令:用于分配一片连续的存储单元并初始化为0,其中表达式为要分配的字节数



格式:标号 SPACE 表达式


例如1:

Stack_Mem SPACE Stack_Size

分配连续Stack_Size 字节的存储单元,存储单元的名字是Stack_Mem,这里是在内存中连续分配1k字节的栈空间

例如2:

Heap_Mem SPACE Heap_Size

分配连续Heap_Size 字节的存储单元,存储单元的名字是Heap_Mem,这里是在内存中连续分配512字节的堆空间


4). DCD(或DCDU)


DCD伪指令:用于分配一片连续的字存储单元,并用伪指令中指定的表达式初始化。其中,表达式可以为程序标号或数字表达式。 DCD 也可用 “ & ” 代替。用 DCD 分配的字存储单元是字对齐的,而用 DCDU 分配的字存储单元并不严格字对齐。


格式:标号   DCD (或 DCDU )  表达式


**例如1:**下面是摘自STM32f4启动代码的例子

其中:_Vectors是一个标号,该处的物理地址值即为 _Vetors 标号所表示的值,该地址中存储__initial_sp所表示的地址值。使用DCD定义了一个内存数组,数组首地址放置的是栈指针地址,然后是复位中断服务入口地址。这个表的作用的作用定义一个存放地址的数组表。


例如2:

SwiFunction

DCD TASK_SW

DCD ENTER_CRITICAL

DCD EXIT_CRITICAL

DCD ISRBegin

DCD ChangeToSYSMode

DCD ChangeToUSRMode


5). ENTRY


ENTRY伪指令用于指定汇编程序的入口点。


6).PROC/ENDP


过程就是子程序。一个程序可以被其他程序所调用(CALL),过程的最后一投指令一般反汇指令(RET),需要注意PROC和ENDP必须成对出现。


格式:

<过程名>  PROC   [类型]

          ...

          ...


  ENDP


例如1:复位中断服务函数

Reset_Handler PROC

EXPORT Reset_Handler [WEAK]

IMPORT SystemInit

IMPORT __main


             LDR     R0, =SystemInit

             BLX     R0

             LDR     R0, =__main

             BX      R0

             ENDP


例如2:硬件中断服务函数


HardFault_Handler PROC

EXPORT HardFault_Handler [WEAK]

B .

ENDP


7).END


END伪指令:用于指示汇编语言程序段结束,因此一个源程序中仅有一个END,且一般放在程序最后。若END放在程序中间,则END后面的语句将不再被汇编。


8).LDR、STR


 LDR指令:将存储器地址所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中

 STR指令:将寄存器内容存入内存空间中

格式:

LDR{条件} 目的寄存器 <存储器地址>

STR{条件}  源寄存器, <存储器地址>


例如1:


LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0

LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0

LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0

LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,然后R1=R1+8

LDR R0,[R1],#8 ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入

LDR R0,=DATA ;将立即数DATA 加载到寄存器R0

STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8

STR R1, [R0] ;将R1寄存器的值,传送到地址值为R0的(存储器)内存中


例如2:

LDR R0, = Heap_Mem

LDR R1, =(Stack_Mem + Stack_Size)

LDR R2, = (Heap_Mem + Heap_Size)

LDR R3, = Stack_Mem


2. 汇编指令

1). IMPORT


 表示这是一个外部变量的标号,不是在本程序定义的,表明要调用的函数为外部文件定义


2).EXPORT


 表示本程序里面用到的变量提供给其他模块调用的。


3).PRESERVE8


PRESERVE8指令指定当前文件需保持堆栈八字节对齐方式。其通过设置PRES8编译属性通知连接器。


格式:      

PRESERVE8     {bool}

PRESERVE8                          ;保持代码堆栈八字节对齐。

PRESERVE8 {FALSE}           ;不保持代码堆栈八字节对齐。


4).Thumb


Thumb是ARM体系结构中一种16位的指令集。Thumb指令集可以看作是ARM指令压缩形式的子集,它是为减小代码量而提出,具有16bit的代码密度。Thumb指令体系并不完整,只支持通用功能,必要时仍需要使用ARM指令,如进入异常时。其指令的格式与使用方式与ARM指令集类似,而且使用并不频繁,Thumb指令集作一般了解。


5).跳转指令B,BL,BX,BLX


B Label ;跳转到Label处对应的地址

BL Label ;跳转到Label对应的地址,并且把跳转前的下条指令地址保存到LR

BX reg ;跳转到由寄存器reg给出的地址

BLX reg ;跳转到由寄存器reg给出的地址,并根据REG的LSB切换处理器;状态还要把转移前的下条指令地址保存到LR.

其中BX 和BLX 都会启动中断返回序列。即从SP中依次将值返回至xPSR, PC, LR, R12以及R3-R0—-其中从堆栈SP中返回PC值实现了程序跳转。 对于B和BL 则是多用于函数跳转,其中BL保存了下条指令地址到LR.


6).IF——ELSE——ENDIF


格式:

IF 判断式

执行1

ELSE

执行2

ENDIF


7).weak

一般来说,这个关键字使用在IMPORT和EXPORT这两个声明段,weak 声明其他的同名标号优先于该标号被引用。


IMPORT     StackTop [WEAK]


 AREA |.text|, CODE, READONLY 

;Vector list

ARM_Vectors

   DCD     StackTop


IMORT: 如果我们有一个名为ARM_Vectors的量表,向量表的第一个数值指向一个StackTop函数的地址。因为我们可能定义了该函数,也可能没有,为了代码的简便,我们可以使用WEAK关键字。

当我们定义了StackTop函数后,那么ARM_Vectors里第一个向量值就是StackTop函数的地址。如果没有定义StackTop,那么编译器不会报错,而这时候第一个向量值就直接赋予0。


EXPORT: EXPORT的函数带有WEAK标志的话,并且别的源代码没有定义同名函数,那么连接时就是该函数;否则,就是另外的一个同名函数(类似类的继承)


第二部分:STM32启动流程学习

1.基础知识储备

每一款芯片的启动文件都值得去研究,因为它是程序跑的最初一段代码。通过了解启动文件,我们可以体会到处理器的架构、指令集、中断向 量安排等内容,是非常值得研究的。

STM32作为一款高端Cortex-M3系列单片机,有必要了解它的启动文件。打好基础,为以后优化程序,写出高质量的代码最准备。


相对于ARM上一代的主流ARM7/ARM9内核架构,新一代Cortex内核架构的启动方式有了比较大的变化。ARM7/ARM9内核的控制器在复位后,CPU会从存储空间的绝对地址0x000000取出第一条指令执行复位中断服务程序的方式启动,即固定了复位后的起始地址为0x000000(PC = 0x000000)同时中断向量表的位置并不是固定的。而Cortex-M3内核则正好相反,有3种情况:

在这里插入图片描述

1、通过boot引脚设置可以将中断向量表定位于SRAM区,即起始地址为0x2000000,同时复位后PC指针位于0x2000000处;

2、通过boot引脚设置可以将中断向量表定位于FLASH区,即起始地址为0x8000000,同时复位后PC指针位于0x8000000处;

3、通过boot引脚设置可以将中断向量表定位于内置

[1] [2] [3] [4] [5]
关键字:STM32  启动代码  汇编指令 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic492482.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:KEIL 5 在debug调试时停留在Reset_Handler
下一篇:STM32的启动过程分析

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm8l低功耗系列
最近干刚做了一个stm8的项目用的是L低功耗系列,其中遇到一个问题。外设寄存器的值怎么都写入不进去。用IAR仿真产看寄存器的值,不论写进去多少,都是初始值。后来把所有寄存器都写了一遍,发现有的能写进去,有的写不进去。比如GPIO的寄存器就能写进去。百思不得姐,偶然查看clock的库函数发现个函数是设置外设时钟的。这个系列,亦或者整个低功耗系列的每个外设是不是都需要在时钟寄存器中单独设置时钟。(以前所使用的芯片都是在外设寄存器中使能或者是禁使能)
发表于 2020-03-09
STM8L+BC26双低功耗,微安
现在在做一个项目需要用到STM8L和BC26。长时间断链后连接下服务器,并且发送一下当前状态,需要用到STM8L和BC26的低功耗。STM8L低功耗,这里用HALT模式,RTC规定时间唤醒。第一步需要关闭所有外设,把所有管脚为设置为输出,并且输出低,管脚根据具体环境设置,需要输出高电平的则输出高电平。在关闭外设的是后是需要先_DeInit,然后在关闭外设始终,有点需要特别主要,要把在进入halt模式的时候需要把所有的中断的标志位清空,否则使用RTC唤醒则会不起作用。第二步就设置低功耗的一些配置。第三步配置完成后进入低功耗。项目中需要用到外部高速始终和BC26通信,所以在进入和退出halt模式的时候需要重新初始化active模式下的
发表于 2020-03-09
stm8l151低功耗程序架构,调试心得
最近帮医院做了一款体温记录仪,整个硬件方案资源是:stm8L151 + NTC*2 + EEPROM + 锂电池充电保护电路 + 18mAh纽扣电池;软件逻辑是,每隔一分钟,采样两路温度并保存在EEP里;通过USB转TTL,上位机能够读取,展示温度曲线,最大最小平均值等简单的运算;整个方案很简单,但也走了不少弯路......单片机程序框架之伪代码:void main(void){    CLK_Config();    GPIO_Config();    ADC_Config();    USART_Config();   
发表于 2020-03-09
STM8s外部时钟晶振失效时钟安全系统CSS启动演示
使用的最小系统晶振是8m的。这里说下配置过程:时钟自动切换,开启切换中断在中断里面清除中断标志,使能CSS并开启CSS中断CSS中断发生,清除CSS中断标志,将HSI二分频,即16M/2=8M,与外部晶振相同,这样不会影响串口波特率窗口输出配置信息:用手触碰PA1、PA2引脚使外部晶振失效串口输出CSS中断
发表于 2020-03-09
STM8s外部时钟晶振失效时钟安全系统CSS启动演示
STM8S103之时钟设置
最大时钟(指的是system clock):外部晶振24MHz,内部高速RC16MHz三个时钟源:外部晶振、内部高速RC(上电默认) +内部低速RC几个时钟:master clock(即sytem clock),fcpu,外设时钟、AWU时钟调用库函数中CLK_ClockSwitchConfig,参考库函数clk_clockselection,但是分频还得进一步设置上电默认:内部高速RC,HSIDIV=/8,CPUDIV=/1,外部时钟全使能,查看相关寄存器的Reset value
发表于 2020-03-09
STM8S103之时钟设置
stm8 16M晶振下精确软件延时
void inerDelay_us(unsigned char n) {for(;n>0;n--) { asm("nop"); //在STM8里面,16M晶振,_nop_() 延时了 333nsasm("nop"); asm("nop"); asm("nop"); }}//---- 毫秒级延时程序----------------------- void Delayms(unsigned int time) { unsigned int i; 
发表于 2020-03-08
何立民专栏 单片机及嵌入式宝典

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

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved