Linux内核编程(四)gpio寄存器驱动编写


  
   寄存器操作通常使用较少,因为已经有系统的库函数接口供给我们使用。本文主要为了了解如何使用寄存器来编写驱动,这里要根据实际的开发板手册进行编写。

一、c语言位操作

  在操作寄存器前,我们需要复习一下c语言中的位操作。方便我们后续编写gpio寄存器。

1. 按位逻辑运算符

(1) &(按位与):有0为0,全1为1。

int a=153;  // 1001 1001
int b=60;   //0011 1100

a &= b;     //a=a&b;
//(1001 1001) & (0011 1100)
结果为:
a=24        //0001 1000;

(2)|(按位或):有1为1,全0为0。

int a=153;   //1001 1001
int b=60;    //0011 1100

a |= b;     // a= a | b;
//(1001 1001) | (0011 1100)
结果为:
a=189      //1011 1101;

(3)~(非):所有位取反,1变0,0变1。

~(0001 1100)	 //表达式
 (1110 0011)	 // 结果值

(4)^(异或):位值不同为1,相同为0。

(1100 0001) ^ (0101 1011)
结果为:
(1001 1010)

2. 位移运算符

(1)左移:<<

int val = 1;	//0000 0001
val <<= 2;     //(0000 0001) << 2
结果为:
(0000 0100)

(2)右移:>>

int val = 16;   //0001 0000
val >>=3;      //(0001 0000) >> 3
结果为:
(0000 0010)

3. 寄存器位操作用法

(1)置1位( |= ): 将寄存器MODER第8位置1,第21位置1。

  GPIOC->MODER  |= (1<<8);   
  GPIOA ->MODER |= (1<<21);

(2)清0位( &=~ ): 将寄存器OTYPER第4位置0。

GPIOC->OTYPER &=~ (1<<4);

(3)切换位( ^= ): 是指打开已关闭的位,或关闭已打开的位。可以使用按位异或运算符(^)切换位。

val为0000 1111 ,MASK是1011 0110

val ^= MASK;
(0000 1111) ^ (1011 0110)
结果为
(1011 1001)

(4)掩码: 隐藏了val中的其他位。

int val=0xff;  // 1111 1111
int MASK=2;    // 0000 0010
val &= MASK
//val中除了1号位以外的所有位都设置为0。
//1号位的值不变。这个过程叫做使用掩码,掩码中的0隐藏了val中的其他位。

  

二、gpio寄存器编写流程(如操作PG_13口。实现功能:按下key按键时,蜂鸣器响,灯亮。)

具体需要根据开发板手册来使用。这里为了演示如下:

1. 需要操作的寄存器

(1)使得gpio正常使用,一般配置以下寄存器即可:
a.功能寄存器(Port Controller Register)。 //模式
b.数据寄存器 (data Register)。 //读写数据
(2)以下寄存器不配置,使用默认即可。
a.驱动等级寄存器。(Multi-Driving Register) //默认等级1级即可
b.上下拉寄存器。(PULL Register) //默认无上下拉即可。

2. 获取相应模块内存映射的基地址。(端口控制寄存器的基地址如下图所示)

  由于端口寄存器都在PIO模块下,所以需要获取PIO模块的地址作为基地址。

#define PIO (0X01C20800)          //PIO的基地址。

                在这里插入图片描述

3. 获取PG寄存器的起始地址

  如:GPIOG_13端口在PG第1组寄存器 PG Configure Register 1中。要操作GPIOG_13就要获取PG Configure Register 1寄存器的地址。
  寄存器地址:基地址+偏移量。
  PG Configure Register 1的地址为: 0X01C20800 + 0XDC
在这里插入图片描述

4. 地址映射:将物理地址映射为虚拟地址。

  设备的内存或寄存器可能位于物理内存的某个位置,而内核需要通过虚拟地址来访问这些设备内存。ioremap 函数将物理地址空间的某一块区域映射到内核的虚拟地址空间,使得内核可以通过该虚拟地址来访问物理设备的内存区域。
  内核通常使用虚拟地址来访问内存,因为虚拟地址具有更好的管理和保护机制,直接使用物理地址会带来很多复杂的管理工作。尤其是对设备寄存器或共享内存的访问,通常是通过内存映射的方式进行的。ioremap 是访问这些 I/O 内存区域的标准方法。

(1)由于我们可能操作多个PG口,所有我们不妨将整个的PG组进行地址映射。将PG第0组的地址映射即可。
此时PG第0组寄存器起始地址为:0X01C20800 + 0XD8。将该地址作为上述函数的addr参数。
        在这里插入图片描述
  
(2)映射内容的大小:PG组共有9个寄存器。则需要映射大小为36个字节。将该字节数36大小传入size参数中。
      在这里插入图片描述

#define PIO (0X01C20800)          //PIO的基地址。
#define PG_BASE ((PIO)+ 0XD8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值