赞
踩
我之前一直在用KEIL以外的很多IDE进行程序开发,比如STM32CUBEIDE、SEGGER EMBEDDED STUDIO和RT-STUDIO。这些IDE一般都是使用的GNU汇编。正如我其他的文章里说的那样。然而最近我看了一本CM4的书,我又想起当时用KEIL做事情的时候的故事。于是干脆重新打开KEIL,找找感觉。
我从不否认,KEIL是非常优秀的IDE。只是之前有一阵子欧洲搞制裁,没得用了。既然现在又有的用了,拿起来感觉还是很香的。
KEIL下面使用的汇编是ARM汇编,所有的伪指令要按照ARM汇编的格式来做。具体的内容可以参考下面的文档
1、ARM Developer Suite Assembler Guide
2、ARM Compiler toolchain Using the Assembler Version 4.1
3、创建工程文件的时候系统给的startup_xxxxx.s
名称 | 描述 |
---|---|
开发板 | 正点原子的探索者F4 (STM32f407ZG) |
调试器 | J-link plus compact |
IDE | KEIL 5.38 |
CM3/4都是使用Thumb指令的。而有关的指令集除了上面介绍的两个文章中会出现,ST的官方手册中也会有。所以关于指令就不再赘述。但是伪指令就推荐在上面的第一个文件中看。比较全面。我这里只列举引导词,具体的语法参考手册。
引导词 | 用法 |
---|---|
ALIGN | 字节对齐 |
AREA | 设置区域,类似于GNU汇编中的.section。但是好像因为KEIL的链接器和其他的IDE的链接器是不一样的,所以这条语句用起来也会有不一样的地方 |
DCD、DCW、DCB | 铺数据的指令,和GNU汇编中的.word .short .byte是一样的。注意那个DCB同时也可以铺字符串。 |
SPACE | 和GNU汇编中的.space一样的用法 |
PROC 、ENDP; FUNCTION、ENDFUNC | 开始、结束一个函数 |
END | 本汇编源文件结束 |
EQU | 设置符号值 |
EXTERN、IMPORT | 引入外部符号。两者有微小区别,参考手册 |
EXPORT | 将本符号引出到外部。相当于GNU汇编的.global |
开局简单,Project >> new project >> STM32F407ZG
接下来设置RTE。这里很简单,只要把CMSIS/CORE和Device/Startup勾上就行了。
这里有个提示,说是要用C99以上的C标准。这个去魔法棒>>C/C++(AC6)调一下就好。我一般都是改成c11。这样就可以了。
参考一下Device/startup_stm32f407xx.s文件,看一下Reset_Handler的实现
AREA |.text|, CODE, READONLY
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
这里这个__main和我们的真正的main不是同一个符号。编译器只要一看到这个符号,就会给你补上一部分初始化代码,再跳转到我们自己的main符号处。详细情况参考MDK __main()代码执行分析。
右键Source Group 1,Add New Item to …,创建main_asm.asm文件。
这里,为了实现段的手动分配,需要简单插一段讲讲.sct链接脚本的用法。这里有很多大牛已经把.sct的语法讲过了。如果是全面的资料,可以去参考ARM的官方资料——《ARM Compiler toolchain Using the Linker》。我就不再赘述.sct的语法。我就简单说说怎么用这个链接脚本吧。
点击魔法棒/Linker。勾掉Use Memory Layout from Target Dialog,这样Scatter File激活。
点Edit可以看到整个.sct文件。初始状态下是这样的。
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00100000 { ; load region size_region
ER_IROM1 0x08000000 0x00100000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00020000 { ; RW data
.ANY (+RW +ZI)
}
}
考虑407还有个片上CCM,开始与0x10000000,大小为64kB(0x10000)。我就做个域(region),名字叫RAM_CCM,输入段是所有的CCM数据。
; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x08000000 0x00100000 { ; load region size_region ER_IROM1 0x08000000 0x00100000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) .ANY (+XO) } RW_IRAM1 0x20000000 0x00020000 { ; RW data .ANY (+RW +ZI) } RAM_CCM 0x10000000 0x00010000 { ; RW data * (CCM) } }
这样,就将段设置好了。
测试一下根据前面做的sct文件,将数据初始化放在CCM中。读出,并放到片内的SRAM上。
area ccm, data user_data1 dcd 0x121234 area data user_data space 100 area text, code main proc export main ldr r0, =user_data ldr r2, =user_data1 ldr r1, [r2] str r1, [r0] ldr r3, [r0] b . bx lr endp end
有必要稍微说明一下,当创建了main()以后,系统就给补上了必要的初始化代码。这部分代码完成了RAM的初始化加载。这也就是为什么dcd 0x121234
可以将数据初始化到RAM上了。
这个程序的调试结果如下所示。
可以看出,数据成功的从CCM上转移到了SRAM上。
好久没有用过KEIL了。重新拿起来还是有点生疏。有以下两点体会:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。