GPIO 的寄存器通过 ioremap函数转换之后,可以通过直接控制虚拟地址来控制物理地址(寄存器的实际地址),这样就实现 GPIO的读和写以及其它任意功能。 需要的基础知识 虚拟地址和物理地址 内存管理单元概念 linux 驱动模块的加载 主要内容 GPIO 的寄存器文档详细介绍和说明 函数 ioremap的用法 使用 ioremap实现对 GPIO的控制 硬件 以 LED2(靠近蜂鸣器的 LED)为例,介绍原理图以及Datasheet 中对应的寄存器。 原理图 打开底板原理图 pdf文档,如下图所示,选取 LED2,网络标号是 KP_COL0。 通过查找网络标号 KP_COL0,发现 KP_COL0接到连接器上,如下图所示。 打开核心板 pdf文档,查找网络标号 KP_COL0,找到exnoys4412 芯片对应的GPIO, 如下图所示。 如上图所示,这个管脚对应的 GPIO是 GPL2_0。 打开 4412 的 Datasheet,找到 GPIO对应的章节,在第六章。 寄存器 在第六章中有对应的小节“6.2 Register Description ”,在“6.2.1 Registers Summary ” 中可以找到 GPL2对应的寄存器,如下图所示。 如上图所示,通过阅读寄存器的描述文字,可以清楚需要控制的寄存器为 GPL2CON(配 置寄存器),GPL2DAT(数据寄存器,对应输出模式,寄存器写0 输出低电平,写 1输出高 电平),GPL2PUD(上拉和下拉配置,输出需要上拉),其它几个寄存器不需要使用,默认 即可。 寄存器地址一般由基地址和偏移地址组成,通过上图中的“Offset”可以发现三个寄存器 GPL2CON,GPL2DAT,GPL2PUD的偏移地址分别是 0x0100,0x0104,0x0108 exnoys4412 中GPIO 寄存器最大是32 位,同时也可以是16 位或者是 8 位,这一点在 对寄存器操作的时候需要用到。通过上图中的“Reset Value”,可以发现三个寄存器 GPL2CON,GPL2DAT,GPL2PUD的复位之后的值是 0x0000_0000,0x00,0x5555,那 么这几个寄存器的值分别是 32 位,8 位,16 位。 寄存器GPL2CON 在 Datasheet 中搜关键字“GPL2CON”,如下图所示,可以发现这个寄存器的基地址是 0x1100_0000 。那么GPL2CON 寄存器的物理地址 phy = 0x11000000 + 0x0100。 LED2 对应的 GPIO是 GPL2中的 Bit0,那么找到 GPL2CON[0](就在上图的表格中,下 翻即可找到),如下图所示。 如上图所示,GPL2CON 寄存器的[3:0]这低四位写 0x0 则是输入模式,0x1 则是输出模 式。LED2 显然需要配置为输出模式,那么 GPL2CON 寄存器的bit[3:0]需要写 0x1。 寄存器GPL2DAT 在 Datasheet 中搜关键字“GPL2DAT”,如下图所示,可以发现这个寄存器的基地址是 0x1100_0000 。那么GPL2DAT 寄存器的物理地址 phy = 0x11000000 + 0x0104 。 通过上图中 Description 部分,可以看到这段英文“When configuring as output port, the pin state should be same as the corresponding bit.”翻译成中文就是“IO 被配置为 输出模式,寄存器中写 0则输出低电平,写 1 则输出高电平”。那么GPL2DAT 寄存器的 bit 0 位写0 灯则灭,写 1 则亮。 寄存器GPL2PUD 在 Datasheet 中搜关键字“GPL2PUD”,如下图所示,可以发现这个寄存器的基地址是 0x1100_0000 。那么GPL2PUD寄存器的物理地址 phy = 0x11000000 + 0x0108。 如上图所示,先介绍“Bit”部分,“[2n + 1:2n] n = 0 to7”表示 n 可以取 0-7,分别 对应 8个 pin 脚,n=0,2x0:2x0+1,就是bit[0,,n=1,2x1:2x1+1,就是 bit[2,依次类 推。GPL2[0]则n=0,需要对 bit[0,1]进行操作。 这里有一点需要说明,如下图所示,红色框中“Disables”应该是Enables,这是三星 Datasheet 中的一个小错误。 综上所述,需要对 GPL2PUD寄存器的bit[0 1]写 0x3。 代码中所需资源小结 代码中需要寄存器的物理地址、寄存器长度、对应位的值,如下表所示。 软件部分 本节主要内容为软件知识,在介绍代码之前,会先简单介绍一下 ioremap函数,C 语言 中的 volatile 关键字。 ioremap函数 物理地址和虚拟地址之间需要使用 ioremap函数进行映射,将物理地址映射成虚拟地址 之后对虚拟地址操作就相当于对物理地址进行操作,也就是直接对寄存器进行操作。 映射函数 void *ioremap(unsigned long phys_addr, unsigned long size) phys_addr:要映射的起始的IO 地址 size:要映射的空间的大小。 取消映射函数 void iounmap(void * addr) addr:映射后得到的虚拟地址。
|