历史上的今天
返回首页

历史上的今天

今天是:2024年12月29日(星期日)

2021年12月29日 | iTOP-4412嵌入式开发板ioremap控制GPIO寄存器

2021-12-29 来源:eefocus

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,1],n=1,2x1:2x1+1,就是 bit[2,3]依次类
推。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:映射后得到的虚拟地址。

编译的小知识-volatile关键字
在 C语言中,编译器在进行编译优化时,如果发现多次获取同一变量的代码之间没有对
这个变量进行操作,例如:
int j = 10;
int call_first = j;
……(大段代码,但是没有对 j 进行操作)
int call_sec = j;

编译器会自动将 call_first 的值给 call_sec,而不会再回头去取 j的值。如果涉及寄存器,
那就很容易出错。
涉及到寄存器的地址,C 语言中提供了volatile 关键字。它能影响编译器编译的结果,它会
通知编译器,volatile 定义的变量是随时可能发生变化的,与 volatile 变量有关的运算,不要
进行编译优化,以免出错。如果上面的变量使用 volatile 定义,那么每次使用它的时候必须从
j 的地址中读取,因而编译器生成的可执行码会重新从j 的地址读取数据放在变量 call_sec
中。
代码
本节的代码需要有文档前面的知识,以及模块注册和卸载的知识。
驱动源码
代码文件 dri_ioremap.c。基础知识前面已经介绍了很多,代码的注释也很多,就不额外
的代码分析了。
//sch:KP_COL0→GPL2_0
/*GPL2→
datasheet:GPL2CON,GPL2DAT,GPL2PUD
Add = Base Address+Offset
GPL2CON = 0x1100_0000 + 0x0100 = 0x11000000 + 0x0100

s3c_gpio_cfgpin
GPL2DAT = 0x1100_0000 + 0x0104 = 0x11000000 + 0x0104
gpio_set_value
GPL2PUD = 0x1100_0000 + 0x0108 = 0x11000000 + 0x0108
*/
/*GPL2_0→
datasheet:GPL2CON[0] GPL2DAT[0] GPL2PUD[0]
GPL2CON[0] [3:0] →output 0x0
GPL2DAT 0 or 1
GPL2PUD[0] 0x3
*/
/*
寄存器不一定都是 32 位的,也有 16 和 8 位的
写寄存器的时候需要注意
*/
#include
#include
#include
volatile unsigned long virt_addr, phys_addr;//用于存放虚拟地址和物理地址
volatile unsigned long *GPL2CON, *GPL2DAT, *GPL2PUD;//用于存放三个寄存器的地址
void gpl2_device_init(void)
{
//0x11000100 + 0x10 包括全所有的 IO 引脚寄存器地址
phys_addr = 0x11000100;
//0x11000100=GPL2CON
//在虚拟地址空间中申请一块长度为 0x10 的连续空间
//这样,物理地址 phys_addr 到 phys_addr+0x10 对应虚拟地址 virt_addr 到 virt_addr+0x10
virt_addr =(unsigned long)ioremap(phys_addr, 0x10);
//指定需要操作的寄存器的地址
GPL2CON = (unsigned long *)(virt_addr + 0x00);
GPL2DAT = (unsigned long *)(virt_addr + 0x04);
GPL2PUD = (unsigned long *)(virt_addr + 0x08);
}
//led 配置函数,配置开发板的 GPIO 的寄存器
void gpl2_configure(void)

{
//GPL2CON 寄存器,bit0 设置为 1,输出模式
*GPL2CON |= 0x00000001;
//GPL2PUD 寄存器,bit[0:1] 设置为 0x3,上拉模式
*GPL2PUD |= 0x0003;
}
void gpl2_on(void) //点亮 led
{
*GPL2DAT |= 0x01;
}
void gpl2_off(void) //灭掉 led
{
*GPL2DAT &= 0xfe;
}
static int __init led_gpl2_init(void) //模块初始化函数
{
printk("init n");
gpl2_device_init(); //实现 IO 内存的映射
gpl2_configure(); //配置 GPL2 为输出模式
gpl2_on();
printk("led gpl2 openn");
return 0;
}
static void __exit led_gpl2_exit(void) //模块卸载函数
{
printk("exit n");
gpl2_off();
iounmap((void *)virt_addr); //撤销映射关系
printk("led gpl2 closen");
}
module_init(led_gpl2_init);
module_exit(led_gpl2_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dz20160510");
MODULE_VERSION("2016-05-10");

编译脚本
编译脚本 Makefile 代码如下。
#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译 read_gpio.c 这个文件编译成中间文件 read_gpio.o
obj-m += dri_ioremap.o
#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将 Linux 的源码拷贝到目录/home/topeet/android4.0 下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0
#当前目录变量
PWD ?= $(shell pwd)
#make 命名默认寻找第一个目标
#make -C 就是指调用执行的路径
#$(KDIR)Linux 源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules 要执行的操作
all:
make -C $(KDIR) M=$(PWD) modules
#make clean 执行的操作是删除后缀为 o 的文件
clean:
rm -rf *.o

编译运行测试
编译之后,运行 iTOP-4412 开发板最小系统,加载驱动模块,靠近 led 的灯会亮,卸载
模块则会灭。


推荐阅读

史海拾趣

Dynawave Incorporated公司的发展小趣事

在快速发展的过程中,Dynawave意识到企业文化的重要性。他们注重培养员工的团队合作精神和创新能力,鼓励员工积极参与公司的各项活动。同时,公司还建立了完善的激励机制和福利制度,为员工提供了良好的工作环境和发展空间。这些举措增强了员工的归属感和忠诚度,为公司的长期发展奠定了坚实的基础。

Greenliant公司的发展小趣事

随着电动汽车市场的爆发式增长,GPS在2025年决定涉足电动汽车充电基础设施领域。公司推出了一系列快速、智能的电动汽车充电桩,支持多种充电标准和支付方式,满足了不同用户的需求。同时,GPS还开发了充电站管理软件,实现了充电桩的远程监控和运维管理,提高了充电服务的可靠性和便捷性。GPS的电动汽车充电基础设施解决方案在多个城市得到广泛应用,为电动汽车的普及提供了有力支持。

佰宏(BHFUSE)公司的发展小趣事

随着电子产品的不断升级和电路防护需求的提高,佰宏团队不断进行技术研发和产品创新。他们成功开发出了多种严苛环境下的客制化PPTC自恢复保险丝,满足了高精密高标准的电路防护需求。这一技术突破不仅提升了产品的竞争力,也为公司赢得了更多的市场份额。

ADMOS公司的发展小趣事

面对不断变化的市场需求和技术趋势,ADMOS公司始终保持着对创新的热情和追求。公司投入大量资源用于研发新的技术和产品,不断推出具有创新性和竞争力的产品。这些创新成果不仅提升了ADMOS在市场上的竞争力,也为公司的未来发展指明了方向。

DATEL Inc公司的发展小趣事

在竞争激烈的电子行业中,DATEL Inc.始终保持着持续创新的动力。公司不断投入研发资源,推出了一系列具有创新性和竞争力的新产品。同时,DATEL Inc.还注重人才培养和团队建设,积极引进优秀人才,打造了一支高素质的研发团队。这支团队不断创新、追求卓越,为DATEL Inc.的持续发展提供了强有力的支撑。

以上五个故事概要旨在反映DATEL Inc.公司在不同领域的发展情况,但请注意这些故事是基于假设构建的,并非真实事件。如需了解更多关于DATEL Inc.公司的真实故事和发展历程,建议查阅公司官方网站或相关新闻报道。

Custom Components Inc公司的发展小趣事

在电子行业快速发展的背景下,客户对电子元件的定制化需求日益增长。CCI敏锐地捕捉到了这一市场趋势,迅速调整战略方向,将业务重心转向客户定制化服务。

为了满足客户多样化的需求,CCI加强了与客户的沟通与合作,深入了解客户的具体需求和应用场景。公司不仅提供标准产品,还能根据客户的特殊需求进行定制化设计和生产。这种服务模式赢得了客户的广泛认可,CCI的市场份额也随之稳步提升。

问答坊 | AI 解惑

找一款51编程器及下载线资料

我现在手上有AT89C51,不知道用什么方式给它下程序 请各位帮忙…

查看全部问答>

μc/os前景如何,有没有实际应用的价值

能不能找到μc/os的工作,有没有这样的公司…

查看全部问答>

ucLinux里面/bin/目录下的程序不能执行

成功进入ucLinux系统 ls 和 cd命令可以用 但是执行/bin/目录下的程序却执行不了 例如执行ifconfig 打印以下信息 /usr> ifconfig BINFMT_FLAT: Loading file: /bin/ifconfig Mapping is 190000, Entry point is 40, data_start is 8280 Load ...…

查看全部问答>

我的dnw.exe总报内存错误不能用了,谁有最新版DNW.exe或者源程序??

我本来用dnw.exe 0.60c好好的,后来把xp从sp2升级到sp3,dnw就不可以用了,每次都报内存错误,不能用了。 谁有最新的dnw.exe程序或者源程序,发我一份,谢拉!!! 邮箱地址:Baiqiang.Liu@Honeywell.com…

查看全部问答>

一个基于WLAN的嵌入式系统开发项目外包

一个基于无线局域网的远程控制系统项目,欢迎个人、团队参与,详细情况请参见以下说明 项目说明: 该项目由个人操作终端和远程接收控制终端构成,可利用ARM7或ARM9在linux下完成。 要求: 该项目要求开发者(或团队)熟悉ARM CPU, 熟悉无 ...…

查看全部问答>

请教有经验的高手们一个问题

我是一名学计算机科学与技术的学生,现在念大二了,马上大三了,最近在学校实验室里学单片机,想以后搞嵌入式系统这一块,请问我要是想嵌入式软件这方面,需要学习些什么呢?现在学的单片机是不是对我学嵌入式系统软件这方面有帮助呢?   ...…

查看全部问答>

单文档视图程序中动态Create一个PropertySheet到FormView中,怎么样禁掉OK按钮,从而禁止用户关掉PropertySheet

单文档视图程序中动态Create一个PropertySheet到FormView中,会有一个OK按钮,怎么样禁掉OK按钮,从而禁止用户关掉PropertySheet…

查看全部问答>

EE_FPGA 硬件手册 V1.0

部分页面预览   下载链接: …

查看全部问答>

这是怎么回事

segment .bsct size overflow (911) segment .ubsct size overflow (436) 代码编译后出现以上错误 高手帮分析下,由于本人是新手,不知这个出错在哪? 代码可以保证在32K以内(我使用的是STM8S105C6)…

查看全部问答>

如果有多个c源文件,添加后还需要那些操作?

有多个c源文件,添加文件后编译,对于放在非main的文件中的函数,无法识别,但可以看到对别的c源文件也编译了,请问这种情况如何处理? 所有不在main文件中的函数均在头文件中列出,并加了extern…

查看全部问答>