论坛大神
  
- 积分
- 3223
- 金钱
- 3223
- 注册时间
- 2015-7-26
- 在线时间
- 811 小时
|
本帖最后由 it_do_just 于 2019-11-7 07:49 编辑
很久没回来发贴了,最近抽空写了个简单的汇编程序,由于我后面开发大多在linux平台下进行,所以这次写这个程序的时候也考虑了下使用gcc来完成整个编译链接的过程,当然实际开发不会这么做,毕竟代码一大了,写起Makefile来还是比较麻烦的,而且也没有IDE这个强大的调试追踪功能,所以使用gcc和汇编来完成点灯纯粹仅供学习,这个程序没有使用官方提供的启动文件,也没有那些官方的配置文件,做到了一个文件就能点灯,下面是点灯的汇编代码,可以直接使用原子提供的FlyMcu这个isp下载工具把这段代码进行编译链接后下载到战舰上测试。
首先使用 EQU 指示字来定义常数, 主要是定义寄存器地址和一些操作数
- ;RCC 寄存器地址定义
- .equ RCC_BASE, 0x40021000
- .equ RCC_CR, (RCC_BASE + 0x00)
- .equ RCC_CFGR, (RCC_BASE + 0x04)
- .equ RCC_APB2ENR, (RCC_BASE + 0x18)
- ;GPIOB 寄存器地址定义
- .equ GPIOB_BASE, 0x40010C00
- .equ GPIOB_CRL, (GPIOB_BASE + 0x00)
- .equ GPIOB_ODR, (GPIOB_BASE + 0x0C)
- ;FLASH缓冲区及访问速度配置
- .equ FLASH_ACR, 0x40022000
- ;用于操作寄存器的一些常数
- .equ Bit0, 0x00000001
- .equ Bit1, 0x00000002
- .equ Bit2, 0x00000004
- .equ Bit3, 0x00000008
- .equ Bit4, 0x00000010
- .equ Bit5, 0x00000020
- .equ Bit6, 0x00000040
- .equ Bit7, 0x00000080
- .equ Bit8, 0x00000100
- .equ Bit9, 0x00000200
- .equ Bit10, 0x00000400
- .equ Bit11, 0x00000800
- .equ Bit12, 0x00001000
- .equ Bit13, 0x00002000
- .equ Bit14, 0x00004000
- .equ Bit15, 0x00008000
- .equ Bit16, 0x00010000
- .equ Bit17, 0x00020000
- .equ Bit18, 0x00040000
- .equ Bit19, 0x00080000
- .equ Bit20, 0x00100000
- .equ Bit21, 0x00200000
- .equ Bit22, 0x00400000
- .equ Bit23, 0x00800000
- .equ Bit24, 0x01000000
- .equ Bit25, 0x02000000
- .equ Bit26, 0x04000000
- .equ Bit27, 0x08000000
- .equ Bit28, 0x10000000
- .equ Bit29, 0x20000000
- .equ Bit30, 0x40000000
- .equ Bit31, 0x80000000
- .equ STACK_TOP, 0x20000800
- .text
- .global _start
- .code 16
- .syntax unified
- _start:
- .word STACK_TOP, start
- .type start, function
-
-
- start:
- ;外部高速时钟时能 RCC->CR |= Bit16
- LDR R0, =RCC_CR
- LDR R1, [R0]
- ORR R1, #Bit16
- STR R1, [R0]
-
- ;检验外部时钟是否就绪
- RCC_CLK_NOTOK:
- LDR R1, [R0]
- ANDS R1, #Bit17
- BEQ RCC_CLK_NOTOK
- LDR R1, [R0]
- ORR R1, #Bit17
- STR R1, [R0]
-
- ;FLASH缓冲区及访问速度配置
- LDR R0, =FLASH_ACR
- MOV R1, #0X00000032
- STR R1, [R0]
-
- ;设置系统时钟倍频
- LDR R0, =RCC_CFGR
- LDR R1, [R0]
-
- ;HCLK 2分频
- ORR R1, #Bit10
-
- ;9倍频[21:18]-->0111
- ORR R1, #Bit18
- ORR R1, #Bit19
- ORR R1, #Bit20
- ;设置HSE为PLL输入时钟源
- ORR R1, #Bit16
- STR R1, [R0]
-
- ;开启倍频
- LDR R0, =RCC_CR
- LDR R1, [R0]
- ORR R1, #Bit24
- STR R1, [R0]
-
- ;等待倍频生效
- RCC_PLL_NOTOK:
- LDR R1, [R0]
- ANDS R1, #Bit25
- BEQ RCC_PLL_NOTOK
-
- ;设置PLL为当前系统时钟
- LDR R0, =RCC_CFGR
- LDR R1, [R0]
- ORR R1, #Bit1
- STR R1, [R0]
- ;验证系统时钟状态是否切换为PLL
- MOV R2, #0X02
- RCC_PLL_NOTRDY:
- LDR R1, [R0]
- LSR R1, R1, #2
- AND R1, #0X03
- CMP R1, R2
- BNE RCC_PLL_NOTRDY
-
- ;开启APB2口时钟
- LDR R0, =RCC_APB2ENR
- LDR R1, [R0]
- ORR R1, #Bit3
- STR R1, [R0]
-
- ;配置PB口功能,PB5设置为通用推挽输出
- LDR R0, =GPIOB_CRL
- LDR R1, [R0]
- LDR R2, =0XFF0FFFFF
- AND R1, R2
- MOV R2, #0X03
- ORR R1, R1, R2, LSL #20
- STR R1, [R0]
-
- ;初始化led灯的状态,默认打开
- LDR R0, =GPIOB_ODR
- LDR R1, [R0]
- ORR R1, #0
- STR R1, [R0]
- ;死循环
- deadloop:
- b deadloop
- .end
复制代码
上面代码的寄存器的配置参考了原子哥代码和网友代码的配置,这部分配置跟原来没什么差别,如果嫌看手册麻烦,也可以反汇编原子哥提供的例程代码,可以很容易得出汇编配置的代码,copy过来用也行。这份汇编代码的反汇编文件我会作为附件上传上来,总的来说就是先配置时钟再配置GPIO,也没有把中断向量表加进来,纯粹的为了点个灯,具体汇编指令的含义如下:
1 . word :指示字定义 MSP 起始值为 0x2000_0800,并且把”start”作为复位向量。
2 . text :也是一个预定义的指示字,表示从这以后是一个代码区,需要予以汇编。
3 . global :使_start 标号可以由其它目标文件使用。
4 . code 16 :指示程序代码使用 thumb 写成。
5 . syntax unified :指示使用了统一汇编语言语法。
6 . _start :是一个标号,指示出程序区的入口点
7 . start :是另一个标号,它指示复位向量。
8 . type start, function :宣告了 start 是一个函数。对于所有处于向量表中的异常向量,这种
宣告都是必要的,否则汇编器会把向量的 LSB 清零——这在 thumb 中是不允许的。
9 . end :指示程序文件的结束
其它汇编指令含义如下:EQU:指示字来定义常数
LDR : 从存储器中加载字到一个寄存器中
ORR : 按位或
STR : 把一个寄存器按字存储到存储器中
ANDS/AND : 按位与
BEQ : 数据跳转指令, 标志寄存器中Z标志位等于零时, 跳转到BEQ后标签处
BNE : 数据跳转指令,标志寄存器中Z标志位不等于零时, 跳转到BNE后标签处
MOV : 寄存器加载数据,既能用于寄存器间的传输,也能用于加载立即数
LSR : 逻辑右移
LSL:逻辑左移
b : 跳转
上面有关于 FLASH_ACR 的配置寄存器信息如下:
上面的代码写完后就可以使用 gcc 来编译啦,当前提是你已经搭建好了linux的开发环境,我使用的ubuntu18,安装相应的编译器指令如下:
sudo apt-get install gcc-arm-none-eabi
下载好编译器后,使用下面的指令进行编译链接:
编译:arm-none-eabi-as -mcpu=cortex-m3 -mthumb led.s -o led.o
链接:arm-none-eabi-ld -Ttext 0x8000000 -o led.out led.o
生成反汇编:arm-none-eabi-objdump -S led.out > led.list
生成hex文件:arm-none-eabi-objcopy -Oihex led.out led.hex
需要说明的是上面 -Ttext 0x8000000 用于指示代码段的存放地址,编译后就可以把 hex 文件通过串口下载到战舰开发板上啦,串口烧写过程原子哥的教程有说明,使用FlyMcu这个软件就可以了。
最后就是激动人心的点灯效果了:
|
|