本章目标:
    掌握嵌入式开发的步骤:编程、编译、烧写程序、运行
    通过GPIO的操作了解软件如何控制硬件
5.1 GPIO硬件介绍
    S3C2440A有130个多功能输入/输出口引脚,分为A~J共9组:GPA、GPB、...、GPH、GPJ。
5.1.1 管脚相关的寄存器
    对于这几组GPIO引脚,它们的寄存器是相似的:
① GPxCON:用于选择管脚功能;
    x为A、B、...、H、J 
    PORTA与PORTB~PORTJ在功能选择上有所不同,GPACON中每一位对应一根引脚(共23根引脚)。
    当某位被设为0时,对应的引脚为输出引脚;
    当某位被设为1时,对应的引脚为地址线或用于地址控制,此时GPADAT无用。
    一般而言,GAPCON通常被设为全1,以方便访问外部存储器件。本章不使用PORTA。
    PORTB~PORTJ在寄存器操作方面完全相同。GPxCON中每两位控制一根引脚。
00:表示输入、01:表示输出、10:表示特殊功能、11:表示保留不用。
② GPxDATA:用于读写管脚数据;
    x为A、B、...、H、J
    当引脚被设为输入时,读此寄存器可知对应引脚的电平状态是高还是低;
    当引脚被设为输出时,写此寄存器对应位,可令此引脚输出高电平或低电平。
③ GPxUP    :用于确定是否使用内部上拉电阻。
    x为B、...、H、J,没有GPAUP寄存器。
    某位为1时,相应引脚无内部上拉电阻;某位为0时,相应引脚使用内部上拉电阻
5.1.2 怎么使用软件来访问硬件
1.访问单个引脚
    操作种类:输出高/低电平、检测引脚状态、中断。
    如下图所示,JZ2440原理图中LED和按键的连接。

    

   
   
     可以设置GPFCON寄存器将GPF4、GPF5、GPF6设为输出功能,然后写GPFDAT寄存器的
相应位使得这3个引脚输出高电平或低电平。
    还可以设置GPFCON寄存器将GPF0、GPF2、GPG3、GPG11设置为输入功能,然后通过读
出GPFDAT/GPGDAT寄存器并判断相应位电平状态来确定各个按键是否按下。
    访问寄存器的方法:通过软件,读写它们的地址。
    比如,S3C2440的GPBCON、GPBDAT寄存器地址是0x5600 0010、0x56000014,可以通
过如下指令让GPF4输出低电平,点亮LED(D10)。
配置GPF4模式
5.2 GPIO操作实例:LED和按键
5.2.1 硬件设计
    如上图所示。
5.2.2 程序设计及代码详解
     本小节有3个实例,通过读写GPIO寄存器来驱动LED、获取按键状态。先使用汇编程序编写
一个简单的点亮LED的程序,然后使用C语言实现了更复杂的功能。
    1.实例1:使用汇编代码点亮1个LED
    源程序为/work/hardware/led_on/led_on.S。它只有7条指令,简单地点亮LED。
 #define GPFCON (*(volatile unsigned long *) 0x56000050)
#define GPFDAT (*(volatile unsigned long *) 0x56000054)
#define GPF4_out (1 << 4*2)
GPFCON = GPF4_out; //GPF4引脚设为输出
GPFDAT &= ~( << ); //GPF4输出低电平

GPF4 配置

    实例分为4个步骤:编译源程序、生成可执行程序、烧写程序、运行程序。
    先看看源程序:led_on.S: 
 .text
.global _start
_start:
LDR R0,=0x56000050 @R0设为GPFCON寄存器
MOV R1, #0x00000100 @0b
STR R1,[R0] @设置GPF4为输出口,位[:] =
LDR R0,=0x56000054 @R0设置GPFDAT寄存器
MOV R1, #0x0000000 @此值改为0x00000010( )可以让LED全熄灭
STR R1,[R0] @GPF4输出0,点亮LED
MAIN_LOOP:
B MAIN_LOOP

led_on.S

    Makefile内容如下:
 led_on.bin:led_on.S                                        @make指令比较led_on.bin和led_on.S的时间,决定是否执行下面的命令
arm-linux-gcc -g -c -o led_on.o led_on.S @编译
arm-linux-ld -Ttext 0x0000 -g led_on.o -o led_on_elf @链接
arm-linux-objcopy -O binary -S led_on_elf led_on.bin @把ELF格式的可执行文件led_on_elf转换成二进制格式文件led_on.bin
clean:
rm -f led_on.bin led_on_elf *.o

Makefile

    注意:Makefile文件中相应的命令行前一定要有一个制表符
    2.实例2:使用C语言代码点亮1个LED
    源程序为/work/hardware/led_on_c目录下。
    C语言执行的第一条指令并不在main函数中。生成一个C程序的可执行文件时,编译器通常会在我们
的代码中加上几个被称为启动文件的代码——crtl.o、crti.o、crtend.o、crtn.o等,它们是标准库文件。
这些代码设置C程序的堆栈等,然后调用main函数。它们依赖于操作系统,在裸板上这些代码无法执行,
需要自己写一个。
    这段代码很简单,只有6条指令。自己编写的crt0.S文件内容如下:
 @************************************
@File:crt0.S
@功能:通过它转入C程序
@************************************
.text
.global _start
_start:
ldr r0, =0x56000010 @WATCHDOG寄存器地址
mov r1, #0x0
str r1, [r0] @写入0,禁止WATCHDOG ldr sp, =* @设置堆栈,注意不能大于4k,因为现在可用内存只有4kB
@NAND Flash中的代码在复位后会移到内部ram(只有4kB)
bl main
halt_loop:
b halt_loop

crt0.S

    上面设置堆栈指针后,就可以调用C函数main了。C函数执行前,必须设置栈。
    现在可以很容易写出控制LED的程序了。main函数在led_on_c.c文件中,代码如下:
 #define GPFCON (*(volatile unsigned long *) 0x56000050)
#define GPFDAT (*(volatile unsigned long *) 0x56000054)
#define GPF4_out (1 << 4*2) int main()
{
GPFCON = GPF4_out; //GPF4引脚设为输出
GPFDAT &= ~( << ); //GPF4输出低电平 return ;
}

led_on_c.c

    最后来看看Makefile:
 led_on_c.bin:crt0.S led_on_c.c
arm-linux-gcc -g -c -o crt0.o crt0.S
arm-linux-gcc -g -c -o led_on_c.o led_on_c.c
arm-linux-ld -Ttext 0x0000000 -g crt0.o led_on_c.o -o led_on_c_elf
arm-linux-objcopy -O binary -S led_on_c_elf led_on_c.bin
arm-linux-objdump -D -m arm led_on_c_elf > led_on_c.dis
clean:
rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o

Makefile

    操作步骤如下:
    (1)进入led_on_c目录后,执行如下命令可生成可执行文件led_on_c.bin;
    $make
    (2)使用dnw把led_on_c.bin写入NAND Flash;
    (3)把开发板拨为NAND启动,给开发板上电,可看见LED被点亮。
2.实例3:使用按键来控制LED 
    目录/work/hardware/key_led中的程序功能为:当K1~K3中某个按键被按下时,点亮D10~D12
(v2版电路板只有3个灯)中相应的LED。
    key_led.c代码如下:
 #define GPFCON      (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054) #define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064) /*
* LED1,LED2,LED4对应GPF4、GPF5、GPF6
*/
#define GPF4_out (1<<(4*2))
#define GPF5_out (1<<(5*2))
#define GPF6_out (1<<(6*2)) #define GPF4_msk (3<<(4*2))
#define GPF5_msk (3<<(5*2))
#define GPF6_msk (3<<(6*2)) /*
* S2,S3,S4对应GPF0、GPF2、GPG3
*/
#define GPF0_in (0<<(0*2))
#define GPF2_in (0<<(2*2))
#define GPG3_in (0<<(3*2)) #define GPF0_msk (3<<(0*2))
#define GPF2_msk (3<<(2*2))
#define GPG3_msk (3<<(3*2)) int main()
{
unsigned long dwDat;
// LED1,LED2,LED4对应的3根引脚设为输出
GPFCON &= ~(GPF4_msk | GPF5_msk | GPF6_msk);
GPFCON |= GPF4_out | GPF5_out | GPF6_out; // S2,S3对应的2根引脚设为输入
GPFCON &= ~(GPF0_msk | GPF2_msk);
GPFCON |= GPF0_in | GPF2_in; // S4对应的引脚设为输入
GPGCON &= ~GPG3_msk;
GPGCON |= GPG3_in; while(){
//若Kn为0(表示按下),则令LEDn为0(表示点亮)
dwDat = GPFDAT; // 读取GPF管脚电平状态 if (dwDat & (<<)) // S2没有按下
GPFDAT |= (<<); // LED1熄灭
else
GPFDAT &= ~(<<); // LED1点亮 if (dwDat & (<<)) // S3没有按下
GPFDAT |= (<<); // LED2熄灭
else
GPFDAT &= ~(<<); // LED2点亮 dwDat = GPGDAT; // 读取GPG管脚电平状态 if (dwDat & (<<)) // S4没有按下
GPFDAT |= (<<); // LED3熄灭
else
GPFDAT &= ~(<<); // LED3点亮
} return ;
}

key_led_on.c

    操作步骤如下:
    (1)进入key_led目录后,执行make命令,即可生成可执行文件key_led.bin;
    (2)使用dnw把key_led.bin写入NAND Flash;
    (3)把开发板拨为NAND启动,给开发板上电,可看见LED被点亮。
5.2.3 实例测试
    在烧写程序是要烧到NAND Flash中去的原因:2440中有被称为“Steppingstone”的
4KB内部RAM,当选择从NAND Flash启动CPU时,CPU会通过内部的硬件将NAND 
Flash开始的4KB字节数据复制到这4KB的内部RAM中(此时,内部RAM的起始地址为0),
然后跳到地址0开始执行。
    NOR Flash虽然可以像内存一样进行读操作,但不能像内存一样进行写操作,所以从
NOR Flash启动时,一般先在代码的开始部分使用汇编指令初始化外接的内存器件(外存),
然后将代码复制到外存中,最后跳到外存中继续执行。
    对于小程序,一般将它烧入NAND Flash中,借助CPU内部RAM直接运行。
附:代码:

链接: https://pan.baidu.com/s/1kV24a9L 密码: tfab

JZ2440 裸机驱动 第5章 GPIO接口的更多相关文章

  1. JZ2440 裸机驱动 第12章 I2C接口

    本章目标: 了解I2C总线协议: 掌握S3C2410/S3C2440中I2C接口的使用方法: 12.1 I2C总线协议及硬件介绍 12.1.1 I2C总线协议 1 I2C总线的概念 2 I2C总线的信 ...

  2. JZ2440 裸机驱动 第14章 ADC和触摸屏接口

    本章目标:     了解S3C2410/S3C2440和触摸屏的结构:     了解电阻触摸屏的工作原理和等效电路图:     了解S3C2410/S3C2440触摸屏控制器的多种工作模式:     ...

  3. JZ2440 裸机驱动 第13章 LCD控制器(1)

    本章目标  了解LCD显示器的接口及时序: 掌握S3C2410/S3C2440 LCD控制器的使用方法: 了解帧缓冲区的概念,掌握如何设置帧缓冲区来显示图像: 13.1 LCD和LCD控制器 13.1 ...

  4. JZ2440 裸机驱动 第10章 系统时钟和定时器

    本章目标      了解S3C2410/S3C2440的时钟体系结构     掌握通过设置MPLL改变系统时钟的方法     掌握在不同的频率下设置存储控制器的方法     掌握PWM定时器的用法   ...

  5. JZ2440 裸机驱动 第6章 存储控制器

    本章目标:     了解S3C2410/S3C2440地址空间的布局     掌握如何通过总线形式访问扩展的外设,比如内存.NOR Flash.网卡等 ························ ...

  6. JZ2440 裸机驱动 第13章 LCD控制器(2)

    13.2 TFT LCD显示实例 13.2.1 程序设计     本实例的目的是从串口输出一个菜单,从中选择各种方法进行测试,比如画线. 画圆.显示单色.使用调色板等. 13.2.2代码详解     ...

  7. JZ2440 裸机驱动 第9章 中断体系结构

    本章目标:     了解ARM体系CPU的7种工作模式     了解S3C2410/S3C2440中断体系结构     掌握S3C2410/S3C2440的中断服务程序的编写方法 9.1 S3C241 ...

  8. JZ2440 裸机驱动 第8章 NAND Flash控制器

    本章目标  了解NAND Flash 芯片的接口 掌握通过NAND Flash控制器访问NAND Flash的方法 8.1 NAND Flash介绍和NAND Flash控制器使用     NAND ...

  9. JZ2440 裸机驱动 第7章 内存管理单元MMU

    本章目标:     了解虚拟地址和物理地址的关系:     掌握如何通过设置MMU来控制虚拟地址到物理地址的转化:     了解MMU的内存访问权限机制:     了解TLB.Cache.Write ...

随机推荐

  1. 20145221 《Java程序设计》第八周学习总结

    20145221 <Java程序设计>第八周学习总结 教材学习内容总结 第十五章部分 - 通用API 通用API 日志: 日志对信息安全意义重大,审计.取证.入侵检测等都会用到日志信息 日 ...

  2. ngular6开发不完全笔记(三)-- 报错指南

    router Uncaught Error: Template parse errors: 'router-outlet' is not a known element: If 'router-out ...

  3. Java多线程,线程交替执行

    两个线程,一个打印1-100的奇数,一个打印1-100的偶数:要求:线程1打印5个之后,线程2开始打印,线程2打印5个之后,线程1再开始打印,以此循环. Code: package com.qhong ...

  4. 使用git一张图就够了

    现在,版本控制工具中,git逐步成为主流.他的分散式的特性是它超越svn渐渐独霸江湖.如果你还不熟悉git,通过本文,你有个最基本最实用的理解:如果你熟悉git,温故而知新,为你加深对git的理解 g ...

  5. 在 php 中使用 strace、gdb、tcpdump 调试工具

    转自:http://www.syyong.com/php/Using-strace-GDB-and-tcpdump-debugging-tools-in-PHP.html 在 php 中我们最常使用调 ...

  6. R语言绘制正太分布图,并进行正太分布检验

    正态分布 判断一样本所代表的背景总体与理论正态分布是否没有显著差异的检验.   方法一概率密度曲线比较法 看样本与正太分布概率密度曲线的拟合程度,R代码如下: #画样本概率密度图s-rnorm(100 ...

  7. JSP 表单处理

    JSP 表单处理 我们在浏览网页的时候,经常需要向服务器提交信息,并让后台程序处理.浏览器中使用 GET 和 POST 方法向服务器提交数据. GET 方法 GET方法将请求的编码信息添加在网址后面, ...

  8. 056——VUE中vue-router之路由参数的验证处理保存路由安全

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. c# winform 操作oracle数据库的Blob字段,把图片存储到数据库,保存图片到数据库

    ///c# winform 操作oracle数据库的Blob字段,把图片存储到数据库,保存图片到数据库 闲话不多说,直接上代码 using System; using System.Collectio ...

  10. 面筋: 奇虎360 c++ 后台开发 实习生 面试

    投的是360上海的商业化部门,岗位是C++服务端开发实习生,记录一下面试历程: 视频面试,但是是有代码框让你写代码的. 一面: Q:先说一下个人信息,做过的项目 A:.......... Q:先写个翻 ...