ARM 汇编入门实践
ARM 入门实践 —— ARM 汇编
搭建 keil 开发环境
添加芯片 pack 包
keil 安装后打开界面如下:
点击 Pack Installer,打开界面如下:
我们使用的是 STM32F103C8T6,选择 STM32F103C8 :
由于网站在国外,所以下载较慢,请耐心等待
下载好的 pack 包如下:
可以在这里找到我们所需要的芯片的 pack 包,和一些需要的 CMIS文件等,点击对应的链接会跳转到官网进行下载。下载好按如下步骤进行添加:
选择自己需要的 pack 文件,添加好之后显示如下:
到此,pack 包添加完成
创建项目
点击 project 创建新项目:
注意:项目创建的路径中不能有中文和空格,路径中如遇到中文将无法解析,而空格可能由于系统和软件版本的不同解析为
或%20
如下界面需要选择我们使用的芯片型号:
接下来,选择我们需要的运行环境(可以不选,到后面手动添加,但是比较麻烦,这里直接选择添加环境):
选择好环境之后,点击 OK ,到此项目创建完毕,项目文件如下:
STM32 程序
汇编程序
右键点击 Source Group1,然后点击如图所示:
汇编程序源文件的后缀是 .s ,所以添加 Asm File(.s) 文件,命名后保存(也可以直接在本地创建好 .s 文件之后进行添加):
汇编代码格式如下:
AREA MAIN, CODE, READONLY
; AREA 用来定义段,MAIN 是段名,CODE 表示是一个代码段,READONLY 表示段是只读
; 系统的默认入口为 RESEAT ,需要修改名字
代码正文
END ;结束标致
代码内容如下:
AREA MYDATA, DATA
AREA MYCODE, CODE
ENTRY
EXPORT __main
__main
MOV R0, #10
MOV R1, #11
MOV R2, #12
MOV R3, #13
;LDR R0, =func01
BL func01
;LDR R1, =func02
BL func02
BL func03
LDR LR, =func01
LDR PC, =func03
B .
func01
MOV R5, #05
BX LR
func02
MOV R6, #06
BX LR
func03
MOV R7, #07
MOV R8, #08
BX LR
写好代码后,我们需要进行仿真调试:
仿真调试
首先我们需要设置仿真模式,过程如下:
在设置窗口点击 Debug ,然后修改设置如下:
勾选 Use Simulator ,表示软件使用仿真环境测试
由于我们使用的是 USB 到 JTAG 转换盒,所以这里的调试器选择 J-LINK/J-TRACE Cortext
J-LINK、JTAG、ULINK、STLINK 区别可以参考下面这篇博客:JLINK、JTAG、ULINK和STLINK的区别介绍
勾选 Run to main() 表示跳过汇编代码,直接跳转到 main 函数开始仿真
设置 Dialog DLL 项目为 DARMSTM.DLL 和 Parameter 项目为 -pSTM32F103C8 的软硬仿真(这里选择符合自己使用的硬件和芯片的型号即可)
设置好如下图:
然后点击编译,查看是否有报错和警告,出现报错和警告需要及时处理并解决:
注意:每次修改源代码之后,需要进行 Rebuild
编译并确保没有报错和警告之后,点击进行调试:
点击运行后点击停止,即可得到输出数据:
运行结果如下,得到汇编对应的正确结果:
warning 解决办法
如果出现以下 warning :
.\Objects\ARM_assembly.sct(8): warning: L6314W: No section matches pattern *(InRoot$$Sections).
# 编译后会显示两个 warning ,但都是这一条
只需要打开对应的 sct 文件,将 *(InRoot$$Sections)
注释掉即可
HEX 文件
生成 Hex 文件
在 Option 中选择 Output 界面,然后将 Create HEX File 勾选上:
生成的 HEX 文件会保存在 Object 文件夹中:
HEX 文件内容如下:
:020000040800F2
:1000000000060020ED000008F5000008F7000008D9
:10001000F9000008FB000008FD00000800000000D7
:10002000000000000000000000000000FF000008C9
:10003000010100080000000003010008050100089C
:100040000701000807010008070100080701000870
:100050000701000807010008070100080701000860
:100060000701000807010008070100080701000850
:100070000701000807010008070100080701000840
:100080000701000807010008070100080701000830
:100090000701000807010008070100080701000820
:1000A0000701000807010008070100080701000810
:1000B0000701000807010008070100080701000800
:1000C00007010008070100080701000807010008F0
:1000D00007010008070100080701000807010008E0
:1000E00007010008070100080701000809488047C8
:1000F00009480047FEE7FEE7FEE7FEE7FEE7FEE70A
:10010000FEE7FEE7FEE7FEE704480549054A064B21
:10011000704700006102000835010008000000205F
:1001200000060020000200200002002070477047F7
:10013000704700004FF00A004FF00B014FF00C0227
:100140004FF00D0300F009F800F00AF800F00BF88A
:10015000DFF81CE0DFF81CF0FEE74FF00505704704
:100160004FF0060670474FF007074FF0080870473A
:100170005B0100086701000810B500F001F810BD30
:100180000CB50020019000903348006840F48030A6
:100190003149086000BF3048006800F4003000902A
:1001A0000198401C0190009818B90198B0F5A06F13
:1001B000F1D12948006800F4003010B1012000900E
:1001C00001E0002000900098012843D123480068F6
:1001D00040F01000214908600846006820F0070040
:1001E00008600846006840F0020008601A4840684D
:1001F000194948600846406848600846406840F42D
:10020000806048600846406820F47C1048600846DA
:10021000406840F4E81048600846006840F080708C
:10022000086000BF0C48006800F000700028F9D09A
:100230000948406820F003000749486008464068C4
:1002400040F00200486000BF0348406800F00C0026
:100250000828F9D10CBD0000001002400020024027
:1002600010B51348006840F00100114908600846C5
:100270004068104908400E494860084600680E4929
:1002800008400B4908600846006820F48020086098
:100290000846406820F4FE0048604FF41F00886064
:1002A000FFF76AFF4FF000600449086010BD0000CE
:1002B000001002400000FFF8FFFFF6FE08ED00E02E
:0400000508000135B9
:00000001FF
HEX 文件分析
扩展线性地址记录
扩展线性地址记录(hex 文件的第一排十六进制)也叫作 32 位地址记录或 HEX386 记录
这些记录包含数据地址的高 16 位
扩展线性地址记录总是有两个数据字节,外观如下(这里我通过标记方便对应原始数据):
:020000040800F2
内容 | 描述 |
---|---|
02 | 这个记录当中数据字节的数量 |
0000 | 地址域,对于扩展线性地址记录,这个域总是 0000 |
04 | 记录类型 04 (扩展线性地址记录) |
0800 | 是地址的高 16 位 |
F2 | 是这个记录的校验和,计算方法:01h + NOT(02h + 00h + 00h + 04h + 08h + 00h) |
当一个扩展线性地址记录被读取,存储于数据域的扩展线性地址被保存,它被应用于从 Intel HEX 文件读取来的随后的记录
线性地址保持有效,直到它被另外一个扩展地址记录所改变
通过把记录当中的地址域与被移位的来自扩展线性地址记录的地址数据相加获得数据记录的绝对存储器地址
数据部分
Intel HEX 由任意数量的十六进制记录组成。每个记录包含 5 个域,它们按一定格式排列::llaaaatt[dd...]cc
每一组字母对应一个不同的域,每一个字母对应一个十六进制编码的数字
每一个域由至少两个十六进制编码数字组成,它们构成一个字节,就像以下描述的那样:
:llaaaatt[dd…]cc
内容 | 描述 |
---|---|
: | 每个Intel HEX记录都由冒号开头 |
aaaa | 地址域,它代表记录当中数据的起始地址 |
tt | 代表HEX记录类型的域,它可能是以下数据当中的一个:00(数据记录)、01(文件结束记录)、02(扩展段地址记录)、04(扩展线性地址记录) |
dd | 数据域,它代表一个字节的数据。一个记录可以有许多数据字节.记录当中数据字节的数量必须和数据长度域(ll)中指定的数字相符 |
cc | 校验和域,它表示这个记录的校验和(校验和的计算是通过将记录当中所有十六进制编码数字对的值相加,以256为模进行以下补足) |
文件尾
在文件的最后一排,是一个文件的结束标志:
:00000001FF
内容 | 描述 |
---|---|
00 | 记录的长度为 0 |
0000 | LOAD OFFSET 为 0000 |
01 | TYPE = 01 |
FF | 校验和为 FF |