4412裸机程序之点亮LED
看一下Tiny4412原理图:
在Tiny4412核心板上有4个可编程控制LED,我们来点亮led1, led1右边接3.3V电源,左边接GPM4_0接口,把GPM4_0设成低电平led灯亮,设成高电平led灯灭。
GPM4_0叫GPIO(通用输入输出接口)属于4412片内外设,每个片内外设都有相应的特殊功能寄存器可以控制,通过4412的启动流程可以看出,cpu上电时特殊功能寄存器被映射在(0x1000_0000~0x1400_0000)范围内,
直接读写这些寄存器地址就可以控制GPIO接口。
GIPO叫做通用输入输出接口,就是一个GPIO接口可以配置成多种用途,可以配置成输入接口,输出接口,特殊功能接口(如camera接口)。
找到4412 datasheet第6章,GPM4_0由(GPM4CON[0],GPM4DAT[0])控制,寄存器地址分别是0x1100_02E0,0x1100_02E4 。
首先把GPM4CON[0]的[3:0]位写0x1把GPM4_0配置成输出接口,再把GPM4DAT第0位写1就能输出高电平,写0就输出低电平。下面看代码怎么写。为了方便观察我们做个闪烁的效果,就是灯一闪一灭循环。make编译后生成led.bin用sd_fuse工具烧到开发板启动。
汇编可以看书 《汇编语言程序设计——基于ARM体系结构(文全刚)和ARM体系结构与编程
..text
.globl _start
_start:
/*
* set GPM4_0 as output
*/
ldr r0, =0x110002E0 // GPM4CON的地址是0x110002E0
ldr r1, [r0] // 先读出原值
bic r1, r1, #0xf // 清除bit[3:0]
orr r1, r1, #1 // 设置bit[3:0]为0b0001
str r1, [r0] // 写入GPM4CON
leds_loop:
/*
*set GPM4_0 as Low
*/
ldr r0, =0x110002E4 // GPM4DAT的地址是0x110002E4
ldr r1, [r0] // 读出原值
bic r1, r1, #1 // 清除bit[0]为0,led亮
str r1, [r0] // 写入GPM4_0
ldr r2,=0xffffff
bl delay
orr r1, r1, #0xf
str r1, [r0] // 写1 led灭
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就可以完成函数的返回
C语言实现:
//start.S
.text
.globl _start
_start:
ldr sp, =0x02027800 // 调用C函数之前必须设置栈,栈用于保存运行环境,给局部变量分配空间
// 参考ROM手册P14, 我们把栈指向BL2上方1K处(1K已经够用),
// 即:0x02020000 (iRAM基地址) + 5K(iROM代码用) + 8K(BL1用) + 16K(BL2用) + 1K(用作栈))
bl main
// 调用main函数
halt_loop:
b halt_loop
//led.c文件
//led.c文件
#define GPM4CON (*(volatile unsigned int *)0x110002E0)
#define GPM4DAT (*(volatile unsigned int *)0x110002E4)
void delay(volatile int time)
{
for(; time > 0; time-- )
;
}
int main(void)
{
unsigned long tmp = 0;
/*
* set GPM4_0 as output
*/
tmp = GPM4CON;
tmp &= ~0xffff;
tmp |= 0x1111;
GPM4CON = tmp;
while(1){
/* GPM4_0 output low */
GPM4DAT &= ~0xf; //4个灯亮
delay(9999999);
GPM4DAT |= 0xf; // 4个灯灭
delay(9999999);
}
return 0;
}
代码位置:https://github.com/cyj1988jyc/luoji4412