Exynos4412 裸机开发—— 流水灯

       这里我们使用的开发板是4412,开发板4412上有4个LED灯,我们这里可以利用其来做流水灯实验。下面是4个LED的原理图:

Exynos4412 裸机开发—— 流水灯_第1张图片

查看原理图,4412开发板的LED由CPX2_7 CPX1_0 GPF3_4 GPF3_5 四个寄存器来控制,观察电路图,我们需要在IO 口输出高电平才能使LED点亮。

 

一、利用汇编编写程序

        以GPX2为例,通过修改GPX2CON、GPX2DAT 的值来控制LED的亮灭

1、GPX2CON

其地址为0x11000C40:
 Exynos4412 裸机开发—— 流水灯_第2张图片

GPX2CON可以控制8个IO口,LED2是由GPX2_7控制的,所以我们只要设置GPX2CON[7]即可

Exynos4412 裸机开发—— 流水灯_第3张图片

可以看到该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

Exynos4412 裸机开发—— 流水灯_第4张图片
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来编写。

 

二、用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;
	}
}

main.c

#include "exynos_4412.h"
#include "led.h"

void  delay_ms(unsigned int num)
{
    int i,j;
    for(i=num; i>0;i--)
	for(j=1000;j>0;j--)
		;
}
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;
}

 

同时注意的是,这里我们使用的makefile:

#=============================================================================#
CROSS_COMPILE = arm-none-eabi-
NAME =pwm
#CFLAGS += -g   -O0  -mabi=apcs-gnu -mfpu=neon -mfloat-abi=softfp  -fno-builtin \
#			-nostdinc  -I ./include -I ./lib 
CFLAGS=-mfloat-abi=softfp -mfpu=vfpv3 -mabi=apcs-gnu -fno-builtin  -fno-builtin-function -g -O0 -c  -I ./include -I ./lib 			     		                                       
LD	= $(CROSS_COMPILE)ld
CC	= $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
OBJS=./cpu/start.o ./driver/uart.o ./driver/_modsi3.o ./driver/_divsi3.o \
        ./driver/_udivsi3.o ./driver/_umodsi3.o main.o ./lib/printf.o 
#=============================================================================#
all:clean  $(OBJS)
	$(LD)  $(OBJS) -T map.lds -o $(NAME).elf
	$(OBJCOPY)  -O binary  $(NAME).elf $(NAME).bin 
	$(OBJDUMP) -D $(NAME).elf > $(NAME).dis 
%.o: %.S 
	$(CC) $(CFLAGS) -c -o  $@ $<
%.o: %.s 
	$(CC) $(CFLAGS) -c -o  $@ $<
%.o: %.c
	$(CC) $(CFLAGS) -c -o  $@ $<
clean:
	rm -rf $(OBJS) *.elf *.bin *.dis *.o
#============================================================================#

将生成的led.bin 文件烧入开发板 0x40008000处,使用命令 go 0x40008000,则可看到开发板上的LED闪烁了。

你可能感兴趣的:(嵌入式开发,Exynos4412,裸机开发)