ARM 学习笔记--GPIO 接口GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平S3C2410 共有 117 个 I/O 端口,共分为 A~H 共 8 组:GPA 、 GPB、...、GPHS3C2440 共有 130个 I/O 端口,分为 A~J 共 9 组:GPA、GPB 、...、GPJ 可以通过设置寄存器来确定某个引脚用于输入、输出还是其他特殊功能比如:可以设置 GPH6 作为输入、输出、或者用于串口1 GPIO 硬件介绍1.1 通过寄存器来操作 GPIO 引脚GPxCON 用于选择引脚功能,GPxDAT 用于读/写引脚数据;另外,GPxUP 用于确定是否使用内部上拉电阻x 为 B、... 、 H/J,没有 GPAUP 寄存器1.1.1 GPxCON 寄存器从寄存器的名字可以看出,它用于配置(Configure )-选择引脚功能PORTA 与 PORTB~PORT H/J 在功能选择方面有所不同,GPACON 中每一位对应一根引脚(共 23 根引脚)。
当某位被设为 0 时,相应引脚为输出引脚,此时我们可以在 GPADAT 中相应位写入 0 或是 1 让此引脚为低电平或高电平;当某位被设为 1 时,相应引脚为地址线或用于地址控制,此时 GPADAT 无用一般而言,GPACON 通常 被设为全 1,以便访问外部存储器件PORT B~ PORT H/J 在寄存器操作方面完全相同GPxCON 中每两位控制一根引脚: 00 表示输入、01表示输出、10 表示特殊功能、11 保留不用1.1.2 GPxDAT 寄存器GPxDAT 用于读 /写引脚;当引脚被设为输入时,读此寄存器可知相应引脚的电平状态是高还是低;当引脚被设为输出时,写此寄存器相应位可以令此引脚输出高电平或是低电平1.1.3 GPxUP 寄存器GPxUP:某位为 1 时,相应引脚无内部上拉电阻;为 0 时,相应引脚使用内部上拉电阻上拉电阻的作用在于:当 GPIO 引脚处于第三态(即不是输出高电平,也不是输出低电平,而是呈高阻态,即相当于没接芯片)时,它的电平状态由上拉电阻、下拉电阻确定1.2 访问硬件1.2.1 访问单个引脚单个引脚的操作无外乎 3 种:输出高低电平、检测引脚状态、中断。
对某个引脚的操作一般通过读、写寄存器来完成访问这些寄存器是通过软件来读写它们的地址比如:S3C2410 和 S3C2440 的 GPBCON、GPBDAT寄存器地址都是 0x56000010、0x56000014,可以通过如下的指令让 GPB5 输出低电平define GPBCON (*volatile unsigned long *)0x56000010) //long=int 4 字节;char 1 字节;short 2 字节#define GPBDAT (*volatile unsigned long *)0x56000014)#define GPB5_out (1 >--------------------A0~A19DATA0~DATA15 D0~D15nOE ---------------- ------------------nOEnWE ---------------- ------------------nWEnGCS0 ---------------- ------------------nCES3C2410/S3C2440 缓冲器 NOR Flash(AM29LV800BB)软件如何发起写操作呢,下面有几个例子的代码进行讲解。
1)地址对齐的 16 位读操作unsigned short *pwAddr = (unsigned short *)0x2;unsigned short uwVal;uwVal = *pwAddr;上述代码会向 NOR Flash 发起读操作:CPU 发出的读地址为 0x2,则地址总线ADDR1~ADDR20、A0~A19 的信号都是 1、0... 、0 (CPU 的 ADDR0 为 0,不过 ADDR0 没有接到 NOR Flash 上) NOR Flash 的地址就是 0x1,NOR Flash 在稍后的时间里将地址上的 16 位数据取出,并通过数据总线 D0~D15 发给 CPU2)地址位不对齐的 16 位读操作unsigned short *pwAddr = (unsigned short *)0x1;unsigned short uwVal;uwVal = *pwAddr;由于地址是 0x1,不是 2 对齐的,但是 BANK0 的位宽被设为 16,这将导致异常我们可以设置异常处理函数来处理这种情况在异常处理函数中,使用 0x0、0x2 发起两次读操作,然后将两个结果组合起来:使用地址 0x0 的两字节数据 D0、D1;再使用地址 0x02 读到 D2、D3;最后,D1、D2 组 合成一个 16 位的数字返回给 wVal。
如果没有地址不对齐的异常处理函数,那么上述代码将会出错如果某个 BANK 的位宽被设为 n,访问此 BANK 时,在 总线上永远只会看到地址对齐的 n 位操作3) 8 位读操作unsigned char *pwAddr = (unsigned char *)0x6;unsigned char ucVal;ucVal = *pwAddr;CPU 首先使用地址 0x6 对 NOR Flsh 发起 16 位的读操作,得到两个字节的数据,假设为 D0、D1 ;然后将 D0 取出赋值给变量 ucVal在读操作期间,地址总线 ADDR1~ADDR20、A0~A19 的信号都是1、 1、0、... 、0(CPU 的 ADDR0 为 0,不过 ADDR0 没有接到 NOR Flash 上)CPU 会自动丢弃 D14) 32 位读操作unsigned int *pwAddr = (unsigned int *)0x6;unsigned int udwVal;udwVal = *pwAddr;CPU 首先使用地址 0x6 对 NOR Flsh 发起 16 位的读操作,得到两个字节的数据,假设为 D0、D1 ;再使用地址 0x8 发起读操作,得到两字节的数据,假设为 D2、D3;最后将这 4 个数据组合后赋给变量udwVal。
5) 16 位写操作unsigned short *pwAddr = (unsigned short *)0x6;*pwAddr = 0x1234;由于 NOR Flash 的特性,使得 NOR Flash 的写操作比较复杂——比如要先发出特定的地址信号通知NOR Flash 准备接收数据,然后才发出数据等不过,其总线上的电信号与软件指令的关系与读操作类似,只是数据的传输方向相反2、使用软件来访问硬件当个引脚的操作有 3 种:输出高低电平、检测引脚状态、中断对某个引脚的操作一般通过读写寄存器实现首先我们从点亮 LED 开始,下图选自 mini2440 原理图,LED1-4 分别对应 GPB5-8如果要控制这些 LED,那么我们首先要把 GPBCON 寄存器中 GPB5-8 对应的位设为输出功能,然后写GPBDAT 寄存器的相应位,使这 4 个引脚输出高低电平一般是低电平有效,即高电平时,对应 LED 熄灭,低电平时,对应 LED 点亮访问寄存器的时候,通过 S3C2440 的数据手册查到 GPBCON 和 GPBDAT 寄存器的地址,附数据手册 点击下载GPBCON 为 0x56000010,GPBDAT 为 0x56000014通过下面的代码让 GPB5 输出低电平,点亮 LED1#define GPBCON (*(volatile unsigned long *) 0x56000010) //volatile 修饰符确保每次去内存中读取变量的值,还不是从 cache 或者寄存器中#define GPBDAT (*(volatile unsigned long *) 0x56000014) #define GPB5_OUT (1 led_on_c.disclean:rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o分别汇编 crt0.S 和 led_on_c.c连接目标到 led_on_c_elf,代码段起始地址位 0x00000000转换 ELF 格式到二进制 led_on_c.bin最后转换结果为汇编码方便查看3、测试程序在先前搭建的编译环境中进入代码目录#make得到的 bin 文件,在 win 中使用 dnw 下载到开发板,设置串口波特率,对应端口,8N1,下载地址0x00000000开关拨到 nor flash,打开电源,出现菜单以后,选择 a然后选择 USB PORT-transmit/restore,选择编译好的 bin 文件然后开关拨到 nand 启动,效果如下:(设置 LED1 和 LED4 亮)4、使用按键来控制 LEDK1-K6 如上图对应 GPG,我们使用 K1-K4 操作 LED1-LED4 @******************************************************************************@ File: crt0.S@ 功能:通过它转入 C 程序@****************************************************************************** .text.global _start_start:ldr r0, =0x56000010 @ WATCHDOG 寄存器地址mov r1, #0x0 str r1, [r0] @ 写入 0,禁止 WATCHDOG,否则 CPU 会不断重启ldr sp, =1024*4 @ 设置堆栈,注意:不能大于 4k, 因为现在可用的内存只有 4K,这4k 是 steppingstone,后面会介绍@ nand flash 中的代码在复位后会移到内部 ram 中,此 ram只有 4Kbl main @ 调用 C 程序中的 main 函数halt_loop:b halt_loop下面是 key_led.c 文件#define GPBCON (*(volatile unsigned long *)0x56000010)#define GPBDAT (*(volatile unsigned long *)0x56000014)#define GPGCON (*(volatile unsigned long *)0x56000060)#define GPGDAT (*(volatile unsigned long *)0x56000064)/** LED1-4 对应 GPB5、GPB6、GPB7、GPB8*/#define GPB5_out (1 key_led.disclean:rm -f key_led.dis key_led.bin key_led_elf *.o测试效果。