使用IO内存控制硬件点亮LED灯

本文介绍了如何在Linux系统中通过IO内存映射控制GPIO来点亮LED灯。详细讲解了IO内存分配、映射、访问以及相关函数的使用,包括ioremap、iounmap、request_mem_region和release_mem_region等。并提供了从裸机控制到内核驱动控制的逐步改进示例代码。
摘要由CSDN通过智能技术生成
 

       Linux中控制GPIO点亮LED的方法有好几种。一种是使用内核提供的专门用来控制GPIO的函数来点亮LED,如:

s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

              s3c2410_gpio_setpin(led_table[i], 0);

一种是通过IO内存获取硬件地址从而控制GPIO来点亮LED,如:

void *ioremap(unsigned long phys_addr, unsigned long size);

void ioumap(void *addr);

这里主要介绍第二种点亮LED方式。

1. 理论支撑

1.1 IO内存分配和映射

1.1.1在使用IO内存之前首先分配IO内存区域。分配和撤销IO内存区域使用的函数如下:

       #include <linux/ioport.h>

       struct resource *request_mem_region(unsigned long start,unsigned long len,char *name);

参数说明:start 分配内存起始地址

                len  分配内存长度

          返回 成功非NULL,否则返回NULL。

相应的释放函数:

              void release_mem_region(unsigned long start,unsigned long len);

 

1.1.2在linux中不能使用实际的物理地址,要对指定的物理地址进行操作必须先将物理地址映射到虚拟地址中。下面的函数就是实现物理地址到虚拟地址的映射:

#include <asm/io.h>

void *ioremap(unsigned long phys_addr, unsigned long size);

参数说明:phys_addr 需要访问的物理内存(寄存器)的首地址

                size       内存区域大小

返回与该段物理地址对应的虚拟地址

      

相应的撤销映射关系的函数是:

void ioumap(void *addr);

 

1.1.3使用IO内存时,request_mem_region函数并不是必须的,该函数只是在内核中标志该内存区域已经分配出去,不能再进行分配出去。但是,这不不是说别的驱动不能再使用该IO内存。至于能不能使用,分下面2种情况:

       1. 两个驱动都用request_mem_region分配相同的IO内存,则两个驱动只能有一个驱动可以使用。

       2. 两个驱动只有一个使用了request_mem_region函数,那么这两个驱动可以同时使用,并可以同时访问该IO内存。

 

1.2 访问IO内存

       ioremap函数的返回值可以直接当做指针(指向对应的物理内存(寄存器)地址)使用,但是这种使用方式不具有可移植性。使用下面的访问IO内存的专用函数符合可移植性要求。

 

从 I/O 内存读取, 使用下列函数之一:

unsigned int ioread8(void *addr);

unsigned int ioread16(void *addr);

unsigned int ioread32(void *addr);

参数:addr是从 ioremap 获得的地址(可能包含一个整数偏移量)

返回值: 从给定 I/O 内存读取的到的值

 

相应的有一系列函数来写 I/O 内存:

void iowrite8(u8 value, void *addr);

void iowrite16(u16 value, void *addr);

void iowrite32(u32 value, void *addr);

参数:value 要写入IO内存值

      addr 所要写入的IO内存地址

 

2. 具体操作与实现

2.1只使用ioremap映射GPIO寄存器实现LED点亮

      

内核模块代码(基于mini2440开发板的4个LED) 如下:

/*************************************************************************/

#include <linux/module.h>

#include <linux/init.h>

#include <asm/io.h>

 

volatile unsigned long virt, phys;//用于存放虚拟地址和物理地址

volatile unsigned long *GPBCON, *GPBDAT, *GPBUP;//用与存放三个寄存器的地址

 

void led_device_init(void)

{

      // 0x56000000 + 0xd0 包揽全所有的IO引脚寄存器地址

       phys = 0x56000000; // 0x56000000=GPACON

       //在虚拟地址空间中申请一块长度为0xd0的连续空间

       //这样,物理地址phys到phys+0xd0对应虚拟地址virt到virt+0xd0

       virt =(unsigned long)ioremap(phys, 0xd0);                                                                                           

       GPBCON = (unsigned long *)(virt + 0x10);//指定需要操作的三个寄存器的地址

       GPBDAT = (unsigned long *)(virt + 0x14);

       GPBUP  = (unsigned long *)(virt + 0x18);

}

//led配置函数,这种是裸板控制寄存器的方式

void led_configure(void)

{

       *GPBCON &= ~(3 << 10)&~(3<<12)&~(3 << 14)&~(3<<16);//GPB12 defaule

       *GPBCON |= (1 << 10)|(1<<12)|(1<<14)|(1<<16); //output

       *GPBUP |= (1 << 5)|(1 <<6)|(1 <<7)|(1 <<8);  //禁止上拉电阻

}

void led_on(void) //点亮led

{

       *GPBDAT &= ~(1 << 5)&~(1 << 6)&~(1 << 7)&~(1 << 8);

}

void led_off(void) //灭掉led

{

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值