你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F0系列之使用汇编点亮LED灯

[复制链接]
STMCU小助手 发布时间:2022-8-25 21:30
一、启动流程
对于STM32F103从flash的启动流程如下:
首先设置栈:CPU会从0x08000000读取值,用来设置SP(不使用C语言可以不设置,或者在程序里设置SP)
然后跳转:CPU从0x08000004得到地址值,根据它的BIT0切换为ARM状态或Thumb状态,然后跳转
          对于cortex M3/M4,它只支持Thumb状态,所以0x08000004上的值bit0必定是1
           0x08000004上的值 = Reset_Handler + 1
接着就从Reset_Handler继续执行
二、在keil-MDK下编写程序
打开keil,新建工程,选择STM32F103ZE

20210101185822103.png

新建start.s文件,编写如下代码;



  1.                 PRESERVE8                                                        ;指示编译器8字节对齐
  2.                 THUMB                                                                ;指示编译器以后的指令为THUMB指令                                                               


  3. ; Vector Table Mapped to Address 0 at Reset
  4.                                 AREA    RESET, CODE, READONLY                ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址
  5.                                 EXPORT  __Vectors                                        ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
  6.                                        
  7. __Vectors       DCD     0                                        ;当前地址写入一个字(32bit)数据,值为0x00000000,实际是应该填入栈顶地址
  8.                 DCD     Reset_Handler                      ;当前地址写入一个字(32bit)数据,值为Reset_Handler的值,即程序入口地址

  9.                                 AREA    |.text|, CODE, READONLY                ;定义代码段,标记为.text

  10. ; Reset handler        ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
  11. Reset_Handler   PROC                                                                ;过程的开始
  12.                                 EXPORT  Reset_Handler        [WEAK]                ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。

  13.                                 ; 1、使能 GPIOB
  14.                                 LDR R0, =(0x40021000 + 0x18)
  15.                                 LDR R1, [R0]
  16.                                 ORR R1, R1, #(1<<3)
  17.                                 STR R1, [R0]
  18.                                 
  19.                                 ; 2、把GPIOB5设置为输出引脚
  20.                                 LDR R0, =(0x40010C00 + 0x00)
  21.                                 LDR R1, [R0]
  22.                                 ORR R1, R1, #(1<<20)
  23.                                 STR R1, [R0]
  24.                                 
  25.                                 ; 3、设置GPIOB5的输出寄存器
  26.                                 LDR R2, =(0x40010C00 + 0x0C)
  27.                                 
  28.                                 ;4、loop循环
  29. Loop                                
  30.                                 ; 5、设置GPIOB5输出高
  31.                                 LDR R1, [R2]
  32.                                 ORR R1, R1, #(1<<5)
  33.                                 STR R1, [R2]
  34.                                 
  35.                                 LDR R0, =1000000
  36.                                 BL delay
  37.                                 
  38.                                 ; 6、设置GPIOB5输出低
  39.                                 LDR R1, [R2]
  40.                                 BIC R1, R1, #(1<<5)
  41.                                 STR R1, [R2]
  42.                                 
  43.                                 LDR R0, =1000000
  44.                                 BL delay
  45.                                 
  46.                                 B Loop
  47.                 ENDP                                                                ;过程的结束

  48. delay
  49.                                 SUBS R0, R0, #1
  50.                                 BNE delay
  51.                                 BX LR

  52.                 ALIGN                                                                 ;填充字节使地址对齐
  53.                 END                                                                        ;整个汇编文件结束
复制代码

然后添加如下两行在编译中执行的命令:
  1. fromelf  --bin  --output=led.bin  Objects\led.axf
  2. fromelf  --text  -a -c  --output=led.dis  Objects\led.axf
复制代码

或者如下通用命令,和上面的命令是等效的
  1. fromelf --bin -o "[        DISCUZ_CODE_2        ]lt;a href="mailto:L@L.bin">L@L.bin</a>" "#L"
  2. fromelf --text -a -c --output="[        DISCUZ_CODE_2        ]lt;a href="mailto:L@L.dis">L@L.dis</a>" "#L"
复制代码

第一行生成.bin文件,第二行生成反汇编.dis文件

20210101203833562.png

然后点击构建,可以看到,已经生成了led.bin文件和反汇编led.dis文件

20210101204003119.png

打开led.dis和led.bin文件,可以看到,因为stm32f103的cotex-m3内核使用的是Thumb指令集,所以其指令长度既有16位又有32位;按stm32在flash模式下的启动顺序,先在0x0800000地址下获取栈地址,在0x08000000地址下获取程序入口地址+1的值,其中最后一位1表示thumb指令。

20210101213108321.png

将其烧写到开发板,可以看到其LED灯闪烁

1.gif

三、使用gcc编译程序

编写在gcc下使用的start.s汇编代码


  1.   .syntax unified                   /* 指明当前汇编文件的指令是ARM和THUMB通用格式 */
  2.   .cpu cortex-m3                    /* 指明cpu核为cortex-m3 */
  3.   .fpu softvfp                      /* 软浮点 */
  4.   .thumb                            /* thumb指令 */

  5. .global  _reset                     /* .global表示_start是一个全局符号 */

  6. .word 0x00000000                    /* 当前地址写入一个字(32bit)数据,值为0x00000000,实际上应为栈顶地址 */
  7. .word _reset+1                      /* 当前地址写入一个字(32bit)数据, 值为_reset标号代表的地址+1,即程序入口地址*/

  8. _reset:                             /* 标签_start,汇编程序的默认入口是_start */
  9.     /* 1、使能 GPIOB */
  10.     LDR R0, = (0x40021000 + 0x18)   /* 将APB2外设时钟使能寄存器的地址值写入R0 */
  11.     LDR R1, [R0]                    /* 读取该寄存器的值 */      
  12.     ORR.W R1, R1, #(1<<20)             /* 修改读出的值 */
  13.     STR R1, [R0]                    /* 写入修改后的值到该寄存器 */

  14.     /* 2、把GPIOB5设置为输出引脚 */
  15.     LDR R0, = (0x40010c00 + 0x00)
  16.     LDR R1, [R0]
  17.     ORR.W R1, R1, #(1<<20)
  18.     STR R1, [R0]

  19.     /* 3、设置GPIOB5的输出寄存器 */
  20.     LDR R2, = (0x40010c00 + 0x0c)

  21.     /* 4、loop循环 */
  22. loop:
  23.     /* 5、设置GPIOB5输出高 */
  24.     LDR R1, [R2]
  25.     ORR.W R1, R1, #(1<<5)
  26.     STR R1, [R2]

  27.     LDR R0, =1000000
  28.     BL delay

  29.     /* 6、设置GPIOB5输出低 */
  30.     LDR R1, [R2]
  31.     BIC.W R1, R1, #(1<<5)
  32.     STR R1, [R2]

  33.     LDR R0, =1000000
  34.     BL delay

  35.     b loop

  36. delay:
  37.     SUBS R0,R0,#1
  38.     BNE delay
  39.     BX LR
复制代码

以及Makefile文件如下


  1. led.bin:start.S
  2.         arm-none-eabi-gcc -c start.s -o led.o
  3.         arm-none-eabi-ld led.o -Ttext 0X80000000 -o led.elf
  4.         arm-none-eabi-objcopy led.elf -O ihex led.hex
  5.         arm-none-eabi-objcopy led.elf -O binary -S led.bin
  6.         arm-none-eabi-objdump -D -m cortex-m3 led.elf > led.dis

  7. clean:
  8.         rm -rf *.o led.elf led.hex led.bin led.dis
复制代码

然后执行make命令,如下所示,编译成功,

20210102013954949.png

将其烧写到开发板,可以看到其LED灯闪烁

2021010201402213.gif

四、比较MDK和GCC编译差别
分别比较两个.dis文件,如下所示,按stm32在flash模式下的启动顺序,先在0x0800000地址下获取栈地址,在0x08000000地址下获取程序入口地址+1的值,其中最后一位1表示thumb指令。
另外发现其中有一个位置不同,但在汇编文件中使用的指令是相同的,这是因为gcc编译器会强制将SUBS有两个相同寄存器指令转换为单个寄存器操作。

20210102015028523.png

————————————————
转载:Willliam_william


收藏 评论0 发布时间:2022-8-25 21:30

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版