arm 裸板驱动入门-LED

1)系统的启动

PC-->BIOS-->引导操作系统--->识别分区 (c盘、d盘等)--->启动应用程序。

嵌入式Linux--->bootloader--->引导linux操作系统--->挂载根文件系统----->启动应用。

2)怎么生成一个可执行程序?

得到一个可执行程序的步骤无非是这么几步: 

1> 编辑文件
2> 编译/链接
3> 烧写测试

  在Windows下有很多的集成开发环境,如ADS.TAR.KEIL等,点点鼠标就帮我们生成了。

  在Linux下也有一些GNU工具链,如gcc之类的,要我们用命令行来运行生成。最后的效果都是一样的。

3)应用程序与裸板程序的差别

以前一直没关心这个main()是怎么执行起来的,只知道一执行就从main()开始执行。然而,这个main函数也只是一个普通的函数而以,main它又被谁调用的呢? 
它是被启动代码调用,裸板没有操作系统,如果我们要在裸板上跑程序的话,这个启动代码也要由我们自己来写。

 启动代码要完成什么功能呢?

1>硬件相关的初始化。
2>调用C函数。

4)裸板点LED

一、写启动代码

1)硬件初始化

 a、设置CPU

    把外设的地址告诉处理器。

 b、关看门狗

    一般是3秒倒数,3秒一到就重启了(是为了防止死机)。

看一下,以下这是个完全汇编的代码例子:

.globl _start
_start:

/* 硬件相关的设置 */
    /* Peri port setup */
    ldr r0, =0x70000000
    orr r0, r0, #0x13
    mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)
    
/* 关看门狗 */
/* 往WTCON(0x7E004000)写0 */
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0]
/* 设置GPMCON让GPM3作为输出引脚 */
	ldr r1, =0x7F008820
	mov r0, #0x1000
	str r0, [r1]

/* 设置GPMDAT让GPM3输出0 */
	ldr r1, =0x7F008824
	mov r0, #0
	str r0, [r1]
halt:
	b halt	
硬件代码实现点灯,汇编实现,_start开始,硬件相关设置---关看门狗---设置GPM3为输出,让它输出0。还要设置cpu,设定外设起始地址,(所谓外设地址就是gpio,uart等寄存器地址,从0x70000000~0x7fffffff)。
1》mcr p15,0,r0,c15,c2,4    //协处理指令,告诉CPU 0x70000000~0x7fffffff是外设的地址。0x70000000是基地址,#0x13表示多大,从ARM11的手册          在arm1176jzfs.pdf中搜索 CP15可以找到

搜索这个 Peripheral Port Memory Remap Register,找到0x13 对应256M.
2》 ldr r0, =0x70000000    //‘=’表明这是条伪汇编指令,最终会被真正的汇编指令代替,用反汇编可以看到最终被mov指令代替。有些汇编指令内容比较复杂,arm一条处理不过来,就会把内容先放在内存哪一个地方,再用ldr从那里读出来。
代码写出来了,怎么编译出来放到板子上运行呢?
进行linux环境,执行#arm-linux-gcc -o start.o start.S -c              -c是只编译不链接,把start.S 编译成 start.o。
#arm-linux-ld -Ttext 0 -o led.elf start.o                        -ld是链接,-Ttext 0 是代码段从0开始
#arm-linux-objcopy -O binary led.elf led.bin             再把.elf 格式的转换成.bin文件

   ELF:可执行链接格式。其实就是Unix下的执行文件和动态库(*.so)和目标文件(*.o)文件格式。
不光是可执行文件(Windows的.exe和Linux下的ELF可执行文件)按照可执行文件格式存储。动态链接库(DLL,Dynamic Linking Library)(Windows的.dll和Linux的.so)及静态链接库(Static Linking Library)(Windows的.lib和Linux的.a)文件都按照可执行文件格式存储。

上拉电阻:接到VCC。

下拉电阻:接到地。

2)调用C函数

上面一个程序是全汇编的,没有用到C的程序,汇编比较麻烦,下面我们来看看用C怎么写。  

.globl _start
_start:

/*设置CPU,把外设地址告诉CPU*/
    /* Peri port setup */
    ldr r0, =0x70000000
    orr r0, r0, #0x13
    mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)
    
/*关看门狗*/
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0]

	/*设置栈*/
	ldr sp, =8*1024
	bl ledBright
halt:
	b halt	
调用c函数前还要设置栈,因为子函数中的变量,参数都是存在栈中的。设置栈很简单,只要让这个sp寄存器指向某块不用的内存就可以了。

我们还要了解一个6410的内部结构,我们现在都是设置的从Nand flash启动。这样一上电,Nand flash前8k的内容就会原原本本的拷贝到内存中。我们的程序很小,暂时就把sp指向8k之上。

启动后就会调用C函数,一般是名为main,但是这个叫什么是没关系的,程序中我们就命名为ledBright.

bl长跳转,后把下条指令的地址存到lr寄存器中。恢复是用ldr pc,lr就可跳回来。

二、写c函数

1)ledBright中实现点灯:

void delay()
{
	volatile int i = 0x10000;
	while (i--);
}
int ledBright()
{
	int i = 0;
	volatile unsigned long *gpmcon = (volatile unsigned long *)0x7F008820;
	volatile unsigned long *gpmdat = (volatile unsigned long *)0x7F008824;
	
	/* gpm0,1,2,3设为输出引脚 */
	*gpmcon = 0x1111;
	while (1)
	{
		*gpmdat = i;
		i++;
		if (i == 16)	i = 0;
		delay();
	}
	return 0;
}
pc:r15    lr:r14       ip: r12       fp:r 11
2)汇编与C语言之间怎么传递参数

它们之间有一个规则,称为ATPCS规则。
第1个参数存在r0,第2、3、4个参数分别存在r1 r2 r3中。如果还有更多参数的话,就存在栈里面。如:
int ledBright(int start, int end, int a, int b, int c, int d)         start存在r0,end a b 分别存在r1 r2 r3中,c d存在栈中。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值