您的位置:首页 > 编程语言 > C语言/C++

ARM嵌入式学习--OK6410裸板程序--2.GPIO控制LED跑马灯(从ARM汇编跳转到C语言)

2014-02-11 17:30 495 查看
第一个部分中,完全使用ARM汇编来控制LED,完全使用汇编来编写大的系统存在理论可行性(当然现实中也有完全使用汇编实现的操作系统),但是汇编理解起来太困难,编写起来很复杂,太琐碎,所以肯定会想要使用理解性更好的C语言来编写大部分代码,那么哪些代码用汇编编写?哪些用C语言编写呢?

从工程实践中可以得出一些结论:

1.跟具体硬件紧密相关的功能,对这部分功能,无需保持可移植性。

2.对C语言编译后的代码没有信心,或者必须进行特别优化时,必须依靠人工优化代码时。

3.相对的是,如果需要保持可移植性,那么必须把平台无关的功能通过底层的部分汇编代码进行隔绝,其他代码通过C语言来编写。

功能原理和电路图见第一篇。

代码:

汇编代码完成硬件初始化,包括内存基地址和大小设定,WatchDog关闭,设置栈,然后跳转到C代码中。

start.S

// 启动代码
.global _start

_start:

// 把外设的基地址告诉CPU
ldr r0, =0x70000000                                         //对于6410来说,内存(0x00000000~0x60000000),外设(0x70000000-0x7fffffff)
orr r0, r0, #0x13                                           //外设大小:256M
mcr p15,0,r0,c15,c2,4                               //把r0的值(包括了外设基地址+外设大小)写给cpu

// 关看门狗
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]

// 设置栈,0x0c002000内存地址映射到SoC内部的SRAM中,速度较快
ldr sp, =0x0c002000

// 调用C函数点灯
bl main

halt:
b halt


C语言用来实现具体的流水灯功能:

main.c

// 功能:c实现流水灯

// 延时
void delay()
{
volatile int i = 0x100000;
while (i--);
}

int main()
{
int i = 0x01;

// 配置引脚
volatile unsigned long *gpkcon0 = (volatile unsigned long *)0x7F008820;
volatile unsigned long *gpkdat = (volatile unsigned long *)0x7F008824;

*gpkcon0 = 0x00001111;

// 跑马灯
while (1)
{
*gpkdat = i;
i = i << 1;
if (i == 0x100)
i = 0x01;
delay();
}

return 0;
}


led.bin: start.o main.o
arm-linux-ld -Ttext 0x50000000 -o led.elf $^
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led_elf.dis
%.o : %.S
arm-linux-gcc  -nostdlib -o $@ $< -c

%.o : %.c
arm-linux-gcc  -nostdlib -o $@ $< -c

clean:
rm *.o *.elf *.bin *.dis  -rf


编译后下载到开发板中,运行,具体运行方法见第一篇。运行效果可以看到四个LED灯依次熄灭,然后点亮。

总结:

1.汇编代码完成必要的硬件初始化功能,从C语言也会被编译为汇编来说,C语言理论上也能完成这项工作,但是却没有这样做的必要,因为这部分代码无需可移植性,并且汇编比C代码更可控,效率更高。

2.在上层功能上来说,C代码可读性优秀,比汇编代码可理解性要好,而且可移植性也更好,如果要把本文代码移植到另外一个SoC上去,只需修改汇编部分,C基本无需修改。

3.汇编代码中设置了栈,这部分是为C代码的运行准备好条件,因为C语言的代码编译后的局部变量,参数等都依赖栈才能够工作。这也是和第一篇纯汇编代码有所区别的地方。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: