11.1 GPIO 介绍
11.1.1 GPIO 管脚
GPIO 即是输入输出端口,S3C2440A 包含了 130 个多功能输入/输出口引脚并且它们为如下显示的八个端口:
端口 A(GPA):25 位输出端口
端口 B(GPB):11 位输入/输出端口
端口 C(GPC):16 位输入/输出端口
端口 D(GPD):16 位输入/输出端口
端口 E(GPE):16 位输入/输出端口
端口 F(GPF):8 位输入/输出端口
端口 G(GPG):16 位输入/输出端口
端口 H(GPH):9 位输入/输出端口
端口 J(GPJ):13 位输入/输出端口
GPIO 的功能即是用于 CPU 采集外设信号(INPUT),CPU 输出控制信号(OUTPUT),还有一种功能称为管脚复用功能,即是 GPIO 用于其他信号功能,比如地址,串口等共呢个,GPIO 属于 SOC 的内部外设。
GPIO 的使用需要寄存器配置。
11.1.2 GPIO 寄存器
端口配置寄存器:GPACON --- GPJCON,即配置输入或是输出,还是配置为第三功能
端口数据寄存器:GPADAT---GPJDAT,用于数据的写入或读取
端口上拉寄存器:GPBUP---GPJUP,端口上拉寄存器控制每个端口组的使能/禁止上拉电阻。
当相应位为 0 时使能引脚的上拉电阻。当为 1 时禁止上拉电阻。
如果使能了上拉电阻,那么上拉电阻与引脚的功能设置无关(输入、输出、DATAn、EINTn 等等)
杂项控制寄存器:
此寄存器控制睡眠模式,USB 引脚和 CLKOUT 选择的数据端口上拉电阻。
外部中断控制寄存器:
24 个外部中断由各种信号方式触发。
EXTINT 寄存器为外部中断请求配置信号触发方式为低电平触发、高电平触发、下降沿触发、上升沿触发或双边沿触发。
由于每个外部中断引脚包含一个数字滤波器,中断控制可以确认请求信号是否长于 3 个时钟。
11.2 GPIO 控制 LED
11.2.1 原理图
从原理图上可以看出,三个灯的控制是由 GPF4 - GPF6 控制的。
由于 LED 由 3.3V 高电平供电,则 GPF4- GPF6 引脚必须要设置为低电平,形成压差点亮 LED
11.2.2 GPF 控制寄存器
GPF 主要涉及到三个寄存器:
GPFCON:端口配置寄存器,配置各个 I/O 管脚是输入/输出功能,还是第三功能,此寄存器的地址是 0x56000050
GPFDAT:数据寄存器,用于管脚发送或是接收数据,地址是 0x56000054
GPFUP:上拉寄存器,地址为 0x56000058,需要才用这个寄存器
注意 GPF 控制器的复位值,初始化值即是此值。
具体配置查看芯片手册
11.3 汇编控制 LED
指令的执行时间:
一般单片机指令执行时间是固定的,参考手册,而在高性能的嵌入式 SOC 中,指令执行时间与各方面的因素有关,比如:缓存,内存,硬盘上的传输开销,指令开销,所以在高性能 SOC 上讨论指令的执行时间没有意义。
考虑到多发射、超标量、超流水线、乱序执行、追踪缓存等设计越来越复杂,仅评价单条指令耗时比单片机要困难得多
更由意义的指标是经过统计分析的 CPI、MIPS 数据。
1MHz = 1us
1GHz = 1ns
一般情况下,裸机中精确延时采用定时器,如果延时在 20 us 下的话,定时器不是太合适,需要汇编辅助完成
如果更小的时间要求,那么表示硬件无法满足当前需求
11.4 C语言控制 LED
makefile
1 # 获取当前工作目录
2 CURRDIR = $(shell pwd)
3
4 # 头文件所在目录
5 INCDIR = $(CURRDIR)
6
7 # 交叉编译工具链的绝对路径
8 CROSS_COMPILE = ~/work/s3c2440/tools/gcc-3.4.5-glibc-2.3.6/bin/arm-linux-
9
10 # 编译器工具
11 AS = $(CROSS_COMPILE)as
12 LD = $(CROSS_COMPILE)ld
13 CC = $(CROSS_COMPILE)gcc
14 CPP = $(CC) -E
15 AR = $(CROSS_COMPILE)ar
16 NM = $(CROSS_COMPILE)nm
17 STRIP = $(CROSS_COMPILE)strip
18 OBJCOPY = $(CROSS_COMPILE)objcopy
19 OBJDUMP = $(CROSS_COMPILE)objdump
20
21 # 编译器标识位设置
22 CFLAGS :=
23 AFLAGS :=
24 LDFLAGS :=
25 CFLAGS :=
26 AFLAGSL :=
27
28 # 目标文件设置
29 objs := startup.o led.o
30
31 all: clean s3c2440.bin
32
33
34 # 执行编译的过程
35 s3c2440.bin: $(objs)
36 $(LD) -Ttext 0x00000000 -o s3c2440_elf $^
37 $(OBJCOPY) -O binary -S s3c2440_elf $@
38 $(OBJDUMP) -D -m arm s3c2440_elf > s3c2440.dis
39
40
41 %.o:%.c
42 $(CC) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -ffreestanding -c -o $@ $<
43
44 %.o:%.S
45 $(CC) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -ffreestanding -c -o $@ $<
46
47 clean:
48 rm -f *.bin *_elf *.dis *.o
startup.S
1 .text
2 .global _start
3
4 _start:
5 ldr r0, =0x53000000 @ WATCHDOG寄存器地址
6 mov r1, #0x0
7 str r1, [r0] @ 写入0,禁止WATCHDOG,否则CPU会不断重启
8
9 ldr sp, =1024*4 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K
10 @ nand flash中的代码在复位后会移到内部ram中,此ram只有4K
11
12 bl main @ 调用 C 程序的 main 函数
13
14 halt_loop:
15 b halt_loop
led.c
1 /**
2 * 将0x56000050 强转为 unsigned long 型指针,并取这个地址的值
3 * volatile 关键字:防止编译器优化,在应用层上多线程变量,在嵌入式中外设寄存器
4 */
5 #define GPFCON (*(volatile unsigned long *)0x56000050)
6 #define GPFDAT (*(volatile unsigned long *)0x56000054)
7 #define GPFUP (*(volatile unsigned long *)0x56000058)
8
9 /** 设置 GPFCON 的 4 5 6 引脚为输出 */
10 #define GPF4_OUT (1 << (4 * 2))
11 #define GPF5_OUT (1 << (5 * 2))
12 #define GPF6_OUT (1 << (6 * 2))
13
14 static void delay_ms(unsigned long ms);
15
16 int main(void)
17 {
18 /** 将LED1-3对应的GPF4/5/6三个引脚设为输出 */
19 GPFCON = GPF4_OUT | GPF5_OUT | GPF6_OUT;
20
21 unsigned long i = 0;
22 while(1){
23 delay_ms(500);
24 GPFDAT = (~(i<<4)); // 根据i的值,点亮LED1,2,4
25 if(++i == 8)
26 i = 0;
27 }
28 }
29
30 static void delay_ms(unsigned long ms)
31 {
32 unsigned int i;
33
34 while(ms--) {
35 for(i = 0; i < 1200; i++);
36 }
37 }