开发嵌入式程序一般需要三个步骤:1.看原理图,确定引脚,在此程序中就是找到控制LED的引脚。2. 查阅主芯片手册,确定如何设置控制引脚。3. 写程序。
查看手册过程:
在芯片手册中搜索led找到对应gpio引脚n_LED1,(在芯片引脚连接中,同名网络(net)表示连接在一起),n表示低电平有效,低电平时灯亮。n_LED1连接GPF4,对于引脚的设置一般分为两步首先设置为输出或者输入引脚,其次设置引脚状态,这两个过程分别对应GPFCON和GPFDAT寄存器,查阅手册,截图如下:
GPFCON[9:8]=0b01表示GPF4引脚为输出引脚,GPFDAT[4] = 1表示输出高电平,LED熄灭;= 0表示输出低电平,LED点亮。
S3C2440启动过程:
2440芯片上不仅有cpu还有其他部分:4K的RAM、Nand Flash控制器、GPIO控制器等,上文说到的GPF4引脚就连接GPIO控制器,Nand Flash控制器外接256M大小的Nand Flash,此外芯片也外接2M大小的Nor Flash。
大多数的RAM芯片从0地址开始启动。
Nor 启动:Nor Flash基址为0,片内RAM地址为0X4000000
1. cpu读Nor上第一个指令,每次读取4字节大小指令,指令也就是bin文件并执行。
2. cpu继续往后读其他指令。
Nand Flash启动:片内4K的RAM基址为0,Nor Flash部分彻底不可访问。
1. 2440硬件将Nand Flash的前4K内容复制到片内内存。
2. 然后cpu从0地址(也就是4K的RAM)取出第一条指令执行。
在CPU内部有R0、R1...R15等寄存器,CPU可以直接访问这些寄存器;但是在GPIO控制器中有GPFCON、GPFDAT等寄存器,这些寄存器CPU不可以直接访问,只能以地址的方式来访问。查阅手册得知GPFCON寄存器的地址为0X56000050,GPFDAT寄存器的地址为0X56000054,而GPFCON[9:8]=0b01可知对应值为0X100,GPFDAT[4] = 1对应值为0X10,在写代码之前,先了解几个基本的汇编指令:
LDR:读内存指令 LDR R0, [R1] 假设R1的值为x,这是一个地址值,读取此地址上的数据(四字节),写到R0中
STR:写内存指令 STR R0, [R1] 假设R1的值为x,把R0中的值写到x地址中去(4字节)
B:跳转
MOV:赋值 MOV R0, R1 把R1的值赋给R0,也可以直接赋值比如 MOV R0, #0x100 相当于R0 = 0x100
LDR带=的伪指令 LDR R0,=0x12345678 这是一条伪指令,伪指令是指并不存在这么一条指令,他最终会被拆分成几条真正的RAM指令,结果另R0 = 0x12345678 为什么使用伪指令而不是直接MOV赋值,因为赋值的值太大了,一条指令只有4个字节32位的空间,其中还包含存放指令比如MOV和被赋值R0数值的空间,剩下的空间太小了不足以存放很大的数比如0x12345678,只能存放一些比较小的数也叫立即数。
创建一个led_on.S文件:
/*
* 点亮LED:gpf4
*/
.text
.global _start
_start:
/* 配置GPF4为输出引脚
* 把0x100写到0x56000050上
*/
ldr r1, =0x56000050
ldr r0, =0x100 /* mov r0, #0x100 */
str r0,[r1]
/* 设置GPF4输出高电平 把0x0写到地址0x56000054上*/
ldr r1, =0x56000054
ldr r0, =0 /* mov r0, #0 */
str r0,[r1]
/* 死循环 */
halt:
b halt
上传到Ubunt系统中,执行编译链接生成可执行文件led_on.bin
arm-linux-gcc -c -o Led_on.o Led_on.S
arm-linux-ld -Ttext 0 Led_on.o -o Led_on.elf
arm-linux-objcopy -O binary -S Led_on.elf Led_on.bin
然后将生成的bin文件下载到windows,烧写到Arm芯片中测试。
或者编写Makefile文件,make生成bin文件;make clean执行对应的清除操作。
all:
arm-linux-gcc -c -o Led_on.o Led_on.S
arm-linux-ld -Ttext 0 Led_on.o -o Led_on.elf
arm-linux-objcopy -O binary -S Led_on.elf Led_on.bin
clean:
rm *.bin *.o *.elf