x86 的学习暂时告个段落, 我开始迈向另一个硬件平台 arm, 使用的是
stm32f4discovery 这块开发板, 比较不满意的是没有 mmu, 192k ram 也实在小了点, 咦
!前一篇 ( http://goo.gl/oVBTGq )提过了阿?那我就再说一次。至少给我 1M 阿!我
实在是不习惯 mcu 的小资源。
重复同样的学习方式, 先来开发第一支作业系统之前的程式, 和 x86 pc 有 bios 不同,
这支程式就是板子开机后第一支执行的程式。比起作业系统之前的程式, 标题取为开机后
的第一支程式听起来似乎威一点, 但是对称之美是很重要的, 所以就这样囉!
和之前一样, 先来个组合语言的版本, 而和 x86 一样, 有不同的组合语言语法 -
arm/gnu, 这里的例子是 gnu arm 组合语言语法。这是 ARM Cortex-M3 嵌入式系统 设计
入门 page 19-3 的范例 - 1 加到 10。
one2ten.S
1 # ARM Cortex-M3 嵌入式系统 设计入门 p 19-3
2 .equ STACK_TOP, 0x20000800
3 .text
4 .global _start
5 .code 16
6 .syntax unified
7 _start:
8 .word STACK_TOP, start
9 .type start, function
10 # let lsb to 1
11
12 start:
13 movs r0, #10
14 movs r1, #0
15
16 loop:
17 adds r1, r0
18 subs r0, #1
19 bne loop
20
21 deadloop:
22 b deadloop
23 .end
编译指令在作业系统之前的程式是很重要的, 一定要列出来:
arm-none-eabi-as -g -mcpu=cortex-m3 -mthumb -o factorial.o factorial.S
arm-none-eabi-ld -Ttext 0x0 -o factorial.elf factorial.o
arm-none-eabi-objcopy -O binary factorial.elf factorial.bin
对于我们的第一支 cortex-m3 程式, 就简单点, 不用 linker script。
再来和 x86 pc 有点不同, 把这程式烧录到 flash (pc 则是复制到软碟或是硬盘), 无法
使用平常的 cp/dd 指令, 得用 openocd/stlink。
flash address : 0x8000000
st-flash write factorial.bin 0x8000000
openocd 指令请参考:Programming STM32 F2, F4 ARMs under Linux: A Tutorial from
Scratch ( http://goo.gl/kZfLQT )
开机后在默认情形下, flash address 会被 map 到 0x0 上, 所以可以简单看成这支程式
是从位址 0 的地方开始。
由于没有使用特定开发板的 IO, 所以应该可以在各家的 cortex-m 系列 的开发板执行
, 也可以用作业系统之前的程式 for stm32f4discovery (0) ( http://goo.gl/oVBTGq )
提到的模拟器来执行。
和 arm v6 以前的架构有点不同, 找书籍/资料时可别看到 arm 就认为是自己要看的资料
。arm 开始干不相容的事情了, 没有 intel 的老旧包袱还真好。
让 stm32f4discovery 一开机就执行的程式要怎么写呢?
L8, L9 就是重点:
L8 的 .word 填上两个 4 个 byte 值, 第一个就是 stack (sp) 的位址, 所以填上什么
数字, stack 位址就从那开始。开机时, cortex-m3 系列会把 0~3 这 4 byte 的值填到
sp。
L8 的 start 则是一开机就会跳到该位址执行程式码, 本范例是 start 的位址, 所以一
开机之后, stack 设好了, 程式也从 start 开始执行。而这 8 个 byte 必须在执行档的
前 8 个 byte。
这是怎么做到的?
arm-none-eabi-ld -Ttext 0x0 表示将 text section 从 0 开始算起, 所以
.word STACK_TOP, start 就会占据执行档的前 8 byte。
descent@debianlinux:stm32_prog$ hexdump -C factorial.bin
00000000 00 08 00 20 09 00 00 00 0a 20 00 21 09 18 01 38 |... .....
.!...8|
00000010 7f f4 fc af ff f7 fe bf
红色 20000800 就是 sp 的值, 从 gdb dump register 可以得证。
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x00000008 in ?? ()
(gdb) file ./
.factorial.S.swp factorial.S.html h.sh stm32.h
.git/ factorial.bin hello.c stm32.ld
.makefile.swp factorial.elf makefile stm32f4xx.h
README.md factorial.o mymain.c stm32f4xx_gpio.h
factorial.S g1.sh q.sh
(gdb) file ./factorial.elf
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from
/home/descent/git/jserv_course/stm32_prog/factorial.elf...done.
(gdb) l
1 # ARM Cortex-M3 嵌入式系统 设计入门 p 19-3
2 .equ STACK_TOP, 0x20000800
3 .text
4 .global _start
5 .code 16
6 .syntax unified
7 _start:
8 .word STACK_TOP, start
9 .type start, function
10 # let lsb to 1
(gdb) l
11
12 start:
13 movs r0, #10
14 movs r1, #0
15
16 loop:
17 adds r1, r0
18 subs r0, #1
19 bne loop
20
(gdb) b 13
Breakpoint 1 at 0xa: file factorial.S, line 13.
(gdb) r
The "remote" target does not support "run". Try "help target" or "continue".
(gdb) c
Continuing.
Breakpoint 1, start () at factorial.S:14
14 movs r1, #0
(gdb) i r
r0 0xa 10
r1 0x0 0
r2 0x0 0
r3 0x0 0
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0。
r12 0x0 0
sp 0x20000800 0x20000800
lr 0x0 0
pc 0xa 0xa
cpsr 0x173 371
(gdb)
蓝色的 00000009 是 start 的位址, 从 objdump 看来明明就是 00000008, 怎么多了个
1。这是 thumb 的关系, 若是 00000008 会让 cpu 以为是在 arm 模式, 会得到一个
Hard Fault Exception。
这就是 L9 的作用, 没有这行, 这个值就会是 00000008。
9 .type start, function
arm-none-eabi-objdump -d factorial.elf
1
2 factorial.elf: file format elf32-littlearm
3
4
5 Disassembly of section .text:
6
7 00000000 <_start>:
8 0: 20000800 .word 0x20000800
9 4: 00000009 .word 0x00000009
10
11 00000008 <start>:
12 8: 200a movs r0, #10
13 a: 2100 movs r1, #0
14
15 0000000c <loop>:
16 c: 1809 adds r1, r1, r0
17 e: 3801 subs r0, #1
18 10: f47f affc bne.w c <loop>
19
20 00000014 <deadloop>:
21 14: f7ff bffe b.w 14 <deadloop>
一样不需要写 dram controller 的 code, lucky!!因为使用的是 sram, 似乎不用写什么
程式码就可直接使用。好了, 解释完毕, 组合语言的部份请自己查阅, 用 openocd/gdb
来 single step 吧!依照惯例, 应该猜得到, 下一篇会是 c 语言的版本 (
http://goo.gl/SAo5MU )。
source code:
https://github.com/descent/stm32f4_prog ( http://goo.gl/eJaoM2 )
ref: ARM Cortex-M3 嵌入式系统 设计入门
// 本文使用 Blog2BBS 自动将Blog文章转成缩址的BBS纯文字 http://goo.gl/TZ4E17 //
blog 原文:
http://descent-incoming.blogspot.tw/2013/04/for-stm32f4-discovery-1-10-asm-version.html