这里我们使用的开发板是4412,开发板4412上有4个LED灯,我们这里可以利用其来做流水灯实验。下面是4个LED的原理图:
图1
3.1利用汇编编写程序 以GPX2为例,通过修改GPX2CON、GPX2DAT 的值来控制LED的亮灭
1、GPX2CON 其地址为0x11000C40: GPX2CON可以控制8个IO口,LED2是由GPX2_7控制的,所以我们只要设置GPX2CON[7]即可 表1 可以看到该4个bit 为0x1 时IO口为输出功能,则我们可以这样设置: LDR R0,=0x11000C40 LDR R1,[R0] BIC R1,R1,#0xf0000000 ORR R1,R1,#0x10000000 STR R1,[R0] 现将[31:28]位清零再置一,则该端口被设置为输出引脚,而至于输出高电平还是低电平,则由GPX2DAT来控制。
2、GPX2DAT 其地址为0x110000C44
表2
GPX2DAT低8位有效,每1个bit控制一个端口输出电平的高低,该位置1,则输出高电平,置0,则输出低电平,为点亮LED,我们可以这样设置: LDR R0,=0x11000C44 LDR R1,[R0] ORR R1,R1,#0x80 STR R1,[R0] 第[7]位置1即可,此时LED被点亮; 同样,该位置0,则LED熄灭: LDR R1,[R0] BIC R1,R1,#0x01 STR R1,[R0] 下面是一个完整的汇编程序,实现LED灯的闪烁(这里以LED3为例): .globl _start .arm _start: LDR R0,=0x11000C20 LDR R1,[R0] BIC R1,R1,#0x0000000f ORR R1,R1,#0x00000001 STR R1,[R0] loop: LDR R0,=0x11000C24 LDR R1,[R0] ORR R1,R1,#0x01 STR R1,[R0] BL delay LDR R1,[R0] BIC R1,R1,#0x01 STR R1,[R0] BL delay B loop delay: LDR R2,=0xfffffff loop1: SUB R2,R2,#0x1 CMP R2,#0x0 BNE loop1 MOV PC,LR .end 其实这里我们可以看到,汇编程序的缺点,就是非常繁琐,而且辨识度差,这段代码,我们看其中一段,根本看不出其实现了什么功能,ARM 裸机程序,我们同样可以用C来编写。
3.2用C 实现流水灯 ARM裸机开发中最重要的就是寄存器的控制,我们如何配置寄存器呢?这里以GPX2为例,我们在头文件里定义下面这个结构体: /* GPX2 */ typedef struct { unsigned int CON; unsigned int DAT; unsigned int PUD; unsigned int DRV; }gpx2; #define GPX2 (* (volatile gpx2 *)0x11000C40 ) 这里将GPX2所用到的寄存器放到一个结构体内,我们看这句 #define GPX2 (* (volatile gpx2 *)0x11000C40 ) 该宏定义是什么意思呢?将0x11000C40 强转成 gpx2 * 类型的地址,并取出该地址里面的值。 则我们可以直接向GPX2.CON里写入数据,便可控制该寄存器 GPX2.CON = GPX2.CON & (~(0xf0000000)) | (0x10000000) 等价于 LDR R0,=0x11000C40 LDR R1,[R0] BIC R1,R1,#0xf0000000 ORR R1,R1,#0x10000000 STR R1,[R0] 可以看出大大加快了我们的开发效率。 下面是开发实例: led.c #include "exynos_4412.h" #include "led.h" void led_init(void) { GPX2.CON = GPX2.CON & (~(0xf0000000)) | 0x10000000; GPX1.CON = GPX1.CON & (~(0x0000000f)) | 0x00000001; GPF3.CON = GPF3.CON & (~(0x000f0000)) | 0x00010000; GPF3.CON = GPF3.CON & (~(0x00f00000)) | 0x00100000; } void led_on(int n) { switch(n) { case 0: GPX2.DAT = GPX2.DAT|0x80; break; case 1: GPX1.DAT = GPX1.DAT|0x01; break; case 2: GPF3.DAT = GPF3.DAT|0x10; break; case 3: GPF3.DAT = GPF3.DAT|0x20; break; } } void led_off(int n) { switch(n) { case 0: GPX2.DAT = GPX2.DAT&(~(0x80)); break; case 1: GPX1.DAT = GPX1.DAT&(~(0x01)); break; case 2: GPF3.DAT = GPF3.DAT&(~(0x10)); break; case 3: GPF3.DAT = GPF3.DAT&(~(0x20)); break; } } void delay_ms(unsigned int num) { int i,j; for(i=num; i>0;i--) for(j=1000;j>0;j--) ; } main.c #include "exynos_4412.h" #include "led.h" int main (void) { int i = 0; led_init (); while (1) { led_on(i%4); led_off((i-1+4)%4); i++; delay_ms(500); } return 0; } exynos_4412.h #ifndef __EXYNOS_4412_H_ #define _EXYNOS_4412_H_ // Exynos-4412 Controller struct exynos4412_gpx1 { unsigned int CON; unsigned int DAT; unsigned int PUD; unsigned int DRV; }; #define GPX1_ADDR ((volatile struct exynos4412_gpx1 *)0x11000C20) #define GPX1 (*GPX1_ADDR) //方式一 struct exynos4412_gpx2 { unsigned int CON; unsigned int DAT; unsigned int PUD; unsigned int DRV; }; #define GPX2_ADDR ((volatile struct exynos4412_gpx2 *)0x11000C40) #define GPX2 (*GPX2_ADDR) //方式二 typedef struct { unsigned int CON; unsigned int DAT; unsigned int PUD; unsigned int DRV; }gpx2; #define GPX2 (* (volatile gpx2 *)0x11000C40 ) struct exynos4412_gpf3 { unsigned int CON; unsigned int DAT; unsigned int PUD; unsigned int DRV; }; #define GPF3_ADDR ((volatile struct exynos4412_gpf3 *)0x114001E0) #define GPF3 (*GPF3_ADDR) #endif led.h #ifndef __LED_H_ #define _LED_H_ void led_init(void); void led_on(int n); void led_off(int n); void delay_ms(unsigned int num) ; #endif Start.S .arm .globl _start _start: B reset NOP NOP NOP NOP NOP NOP NOP reset: LDR SP, =stack_top BL main __die: B __die /** void __delay(void)*/ .global __delay __delay: PUSH {R2, LR} MOV R2, #0x20000000 loop1: SUBS R2, R2, #0x1 BNE loop1 POP {R2, LR} MOV PC, LR .data .space 8192 stack_top: .end Makefile TARGET := my_a9 all: $(TARGET) CROSS_COMPILE := /opt/gcc-4.6.4/bin/arm-none-linux-gnueabi- CC := $(CROSS_COMPILE)gcc CFLAGS += -march=armv7-a -mtune=cortex-a9 ASFLAGS += -march=armv7-a -mtune=cortex-a9 LDFALGS += -march=armv7-a -mtune=cortex-a9 OBJS := $(patsubst %.c, %.o, $(wildcard *.c)) OBJS += $(patsubst %.S, %.o, $(wildcard *.S)) $(TARGET): $(OBJS) $(CC) -o $@ $^ -Tmap.lds -nostdlib $(LDFALGS) $(CROSS_COMPILE)objdump -d $@ > $@.s $(CROSS_COMPILE)objcopy -O binary $@ $@.bin %.o: %.S $(CC) -c $^ -nostdinc $(CFLAGS) %.o: %.c $(CC) -c $^ -nostdinc $(ASFLAGS) install: $(TARGET) #cp $(TARGET).bin /tftpboot clean: rm -f $(TARGET) rm -f $(OBJS) rm -f $(TARGET).s rm -f $(TARGET).bin 将生成的A9.bin 文件烧入开发板 0x40008000处,使用命令 go 0x40008000,则可看到开发板上的LED闪烁了。
原作者:Bruceoxl
|