一、控制原理说明
先看一下原理图
如上图可知,Tiny4412有4个用户LED灯,控制它们四个引脚分别是GPM4_0~ GPM4_3,由原理可知,当IO引脚为高电平时,LED灯灭,当IO引脚为低电平时LED亮。我们要做的工作就是设置GPM4_0~ GPM4_3为输出功能,且控制且输出电平高低即可。
二、程序说明
1.led.S
由原理图可知,程序只进行了两步操作;
第一步:设置GPM4_0GPM4_3相对应的控制寄存器GPM4CON,使GPM4_0 GPM4_3四个引脚为输出功能。
第二步:设置其对应的数据寄存器GPM4DAT对应的4个bit位为0,使GPM4_0~ GPM4_3为低电平,4个LED灯全亮,等待一段时间将第0位设置为0,其余位设置为1,这样只有第一个灯亮;等待一段时间将第1位设置为0,其余位设置为1,这样只有第二个灯亮;等待一段时间将第2位设置为0,其余位设置为1,这样只有第三个灯亮;等待一段时间将第3位设置为0,其余位设置为1,这样只有第四个灯亮;等待一段时间使GPM4_0~ GPM4_3全为高电平,4个LED灯全灭。这样就实现了跑马灯效果。
程序代码中,也有相关解释这里不做过多说明。
.text
.globl _start
_start:
/*
* set GPM4 as output
*/
ldr r0, =0x110002E0 // GPM4CON的地址是0x110002E0
ldr r1, [r0] // 先读出原值
bic r1, r1, #0xff00 // 清除bit[15:8]
bic r1, r1, #0xff // 清除bit[7:0]
orr r1, r1, #0x1100 // 设置bit[15:8]为0b00010001
orr r1, r1, #0x11 // 设置bit[7:0]为0b00010001
str r1, [r0] // 写入GPM4CON
/*
* set GPM4DAT as Low For leds
*/
ldr r0, =0x110002E4 // GPM4DAT的地址是0x110002E0
ldr r1, [r0] // 读出原值
leds_loop:
bic r1, r1, #0xf // 清除bit[0-3]为0 全亮
str r1, [r0] // 写入GPM4DAT
ldr r2,=0xffffff
bl delay
orr r1, r1, #0xe // 设置bit[0]为0 LED1亮
str r1, [r0] // 写入GPM4DAT
ldr r2,=0xffffff
bl delay
bic r1, r1, #0x3 // 设置bit[1]为0 LED2亮
orr r1, r1, #1
str r1, [r0] // 写入GPM4DAT
ldr r2,=0xffffff
bl delay
bic r1, r1, #0x6 // 设置bit[2]为0 LED3亮
orr r1, r1, #2
str r1, [r0] // 写入GPM4DAT
ldr r2,=0xffffff
bl delay
bic r1, r1, #0xc // 设置bit[3]为0 LED4亮
orr r1, r1, #4
str r1, [r0] // 写入GPM4DAT
ldr r2,=0xffffff
bl delay
orr r1, r1, #0xf
str r1, [r0] // 写入GPM4DAT 全灭
ldr r2,=0xffffff
bl delay
b leds_loop
halt_loop:
b halt_loop
delay:
//跑马灯延时程序
sub r2,r2,#1 //sub 减法
cmp r2,#0x0 //将r0 与0比较
bne delay //b是跳 ne 是不相等 ,不相等就跳到delay
mov pc,lr //lr 里存的是调用函数时的下一条指令,让Pc指针指向lr就可以完成函数的返回
- MakeFile说明
led.bin : led.S
arm-linux-gcc -c -o led.o led.S
arm-linux-ld -Tled.lds -N led.o -o led.elf
arm-linux-objcopy -O binary -S led.elf led.bin
arm-linux-objdump -D -m arm led.elf > led.dis
clean:
rm -f *.dis *.bin *.elf *.o
- 链接脚本led.lds说明
SECTIONS {
. = 0x02023400;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data*) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
本文不对链接脚本的具体语法进行介绍,读者可以自已自行google了解
第2行表示程序的连接地址从0x02023400开始,这表示我们的程序运行之前应该位于内存地址0x02023400字节处,
BL1会把 BL2复制到0x02023400地址处,再启动它。
第 3~6行,表示从 0x02023400 开始,依次排放程序的代码段、 只读数据段、数据段、BSS段。
三、程序编译及烧写
.编译
通过FTP或者其他工具将led.s、Makefile、led.lds 三个文件上传到服务器上去,输入make命令进行编译将得到led.bin文件。
2.烧写
将SD卡插入电脑,并让VmWare里的Ubuntu识别出来,然后执行如下命令:
sudo ./sd_fusing.sh /dev/sdb …/01.led/led.bin
如图所示,SD卡烧写成功,将SD卡插到Tiny4412开发板上,并设置为SD卡启动,这时你就会看到LED灯在闪烁。
说明:sd_fusing.sh是一个shell脚本,这个脚本文件,一键烧写程序到 SD 卡中。我们分析该脚本程序,发现其核心命令就3条
dd iflag=dsync oflag=dsync if=/work/4412/tools/E4412_N.bl1.bin of=$1 seek=$signed_bl1_position
dd iflag=dsync oflag=dsync if=./bl2.bin of=$1 seek=$bl2_position
sync
第 1行的命令用于将E4412_N.bl1.bin烧写到 SD卡的第 1个扇区 (扇区从 0编号 );
第 2行的命令用于将bl2.bin烧写到SD卡的第17个扇区;
第 3行的命令用于将内存缓冲区数据写入磁盘.
E4412_N.bl1.bin(BL1) 是由三星原厂提供, 没有源码;
bl2.bin 是通过 mkbl2 工具处理源文件得到,具体实现如下:
./mkbl2 leds_on.bin bl2.bin 14336
mkbl2 是用来生成 bl2.bin 的工具,通过编译 V310-EVT1-mkbl2.c 文件得到,具体如下:
gcc -o mkbl2 V310-EVT1-mkbl2.c
通过分析 V310-EVT1-mkbl2.c源码,我们可以知道它主要做了这些工作:
1). 从源文件中读取14K 的数据到 Buf 当中;
2). 处理 Buf 中前14332 字节的数据,得到 4字节的checksum ;
3). 组装 Buf 中前 14332 字节的数据和 4字节的 checksum,得到一个新的 14K 的 Buf 数据;
4). 将 3) 中构建的Buf 数据写到bl2.bin文件中
四、上电实验
如下图所示,可以看到4个led轮流着点亮及熄灭
原文地址:http://www.techbulo.com/1313.html#button_file