《OK6410-LED驱动程序设计》之使用ioremap实现访问CPU寄存器
来源:互联网 发布:视频刷流量软件 编辑:程序博客网 时间:2024/05/16 01:56
Ok6410开发板LED连接电路图:
从电路图上我们可以看到,发光二极管LED 的一端连接到了ARM 的GPIO,另一端经过一个限流电阻接电源VCC3。当GPIO 口为低电平时,LED 两端产生电压降,这时LED 有电流通过并发光。反之当GPIO 为高电平时,LED 将熄灭。注意亮灭之间要有一定的延时,以便人眼能够区分出来。
4个LED分别连接到核心板上的GPM端:
从上面可以看出4个LED对应的端口:
GPM0->LED1 GPM1->LED2 GPM2->LED3 GPM3->LED4
查看s3c6410芯片手册,端口M对应的三个寄存器地址:
实验相应寄存器 端口配置寄存器
端口数据寄存器
下面我们开始代码部分
I/O 内存访问流程:
1. request_mem_region() 申请IO内存
2. ioremap() 将物理地址映射到虚拟地址
3. ioread8() 、ioread16()、ioread32()、iowrite8()、iowrite16()、iowrite32() 读写
4. iounmap() 释放虚拟内存
5. release_mem_region() 释放IO内存
注意:
1、2 在模块初始化或打开设备时调用
4、5 在模块卸载或关闭设备时调用
request_mem_region()不是必须使用,但建议使用。任务是检查申请的资源是否可用,如果可用则申请成功,并标志为已经使用,其他驱动想再次申请该资源就会失败。
testled.c
#include <linux/init.h>#include <linux/module.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <asm/io.h>#include <linux/ioport.h>#include <asm/uaccess.h>#define DEVICE_NAME "liye_led"/* 定义幻数 */#define LED_IOC_MAGIC 'k'/* 定义命令 */#define LED_ALLOFF _IO(LED_IOC_MAGIC, 0)#define LED_ALLON _IO(LED_IOC_MAGIC, 1)#define LED_SELECTON _IOW(LED_IOC_MAGIC, 2, int)/*定义命令的最大个数*/#define LED_IOC_MAXNR 2#define GPMCON 0x7F008820 //寄存器地址(物理地址)#define GPMDAT 0x7F008824static volatile unsigned long *gpmcon_addr; //经过ioremap映射后的虚拟地址static volatile unsigned long *gpmdat_addr;static void Led_port_init(void){//设置GPM0-GPM3为输出端口//最后结果相当于…0001000100010001,都是输出状态*gpmcon_addr &= (1U<<16); *gpmcon_addr |= (1U<<0)|(1U<<4)|(1U<<8)|(1U<<12); //全亮 低电平亮*gpmdat_addr &= (1U<<4);}static void led_all_on(void ){//*gpmdat_addr &= (1U<<4);这个也是可以的,一样的*gpmdat_addr &= 16; }static void led_all_off(void){*gpmdat_addr |= ~(1U<<4);}static void led_select_on(unsigned int led_nu){led_all_off();*gpmdat_addr &= ~(led_nu);}static int led_open(struct inode * inode , struct file * filp){return 0;}static int led_release(struct inode * inode, struct file *filp){return 0;}static int led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){int ret = 0;int err = 0;int ioarg = 0; /* 检测命令的有效性 */ if (_IOC_TYPE(cmd) != LED_IOC_MAGIC) return -EINVAL; if (_IOC_NR(cmd) > LED_IOC_MAXNR) return -EINVAL; /* 根据命令类型,检测参数空间是否可以访问 */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT;switch (cmd){case LED_ALLOFF://全灭led_all_off();break;case LED_ALLON://全亮led_all_on();break;case LED_SELECTON://根据参数有选择的凉__get_user(ioarg,(int *)arg);//获得用户空间数据led_select_on(ioarg);break;default:ret = -EINVAL;break;}return ret;}static const struct file_operations led_fops ={.owner = THIS_MODULE,.open = led_open,.release = led_release,.unlocked_ioctl = led_ioctl,};static struct miscdevice led_dev ={.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &led_fops,};static int __init led_init(void){ int ret; //申请IO内存,不是必须的。if (!request_mem_region(GPMCON, 8, "leds")){ret = -EBUSY;goto request_mem_failed;} gpmcon_addr = ioremap(GPMCON, 4);//将物理地址映射为虚拟地址if (NULL == gpbcon_addr){ret = -EIO;printk("gpmcon remap failed\n");goto con_map_failed;}gpmdat_addr = ioremap(GPMDAT, 4);if (NULL == gpmdat_addr){ret = -EIO;printk("gpmdat remap failed\n");goto dat_map_failed;}printk("gpmcon_addr remap on %p\n", gpmcon_addr);printk("gpmdat_addr remap on %p\n", gpmdat_addr); Led_port_init();//初始化led灯ret = misc_register(&led_dev);//注册一个混杂设备驱动,主设备号为10if (ret){printk("misc_register failed\n");goto failed;} printk("leds init\n");return 0; failed:iounmap(gpmdat_addr);dat_map_failed:iounmap(gpmcon_addr);con_map_failed:release_mem_region(GPMCON, 8);request_mem_failed:return ret;}static void __exit led_exit(void){iounmap(gpmdat_addr); //取消映射iounmap(gpmcon_addr);release_mem_region(GPMCON, 8); //释放I/O内存misc_deregister(&led_dev);//注册混杂设备,主设备号为10 printk("leds exit\n");}MODULE_LICENSE("GPL");MODULE_AUTHOR("liye");module_init(led_init);module_exit(led_exit);
test.c
#include <stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include <linux/ioctl.h>/* 定义幻数 */#define LED_IOC_MAGIC 'k'/* 定义命令 */#define LED_ALLOFF _IO(LED_IOC_MAGIC, 0)#define LED_ALLON _IO(LED_IOC_MAGIC, 1)#define LED_SELECTON _IOW(LED_IOC_MAGIC, 2, int)int main(){ int fd = 0; int cmd; int arg = 0; int choice; int flag=0; /*打开设备文件*/ fd = open("/dev/liye_led",O_RDWR); if (fd < 0) { printf("Open Dev liye_led Error!\n"); return -1; } while(1) {printf("\n********MENU**********\n");printf(" [0] LED all off \n");printf(" [1] LED all on \n");printf(" [2] Select LED \n");printf(" [3] Exit \n");printf("**********************\n\n");printf("Enter the choice: ");scanf("%d",&choice);switch(choice){case 0:cmd=LED_ALLOFF;break;case 1:cmd=LED_ALLON;break;case 2:printf("Enter the arg (0=<arg<=15) : ");scanf("%d",&arg);cmd=LED_SELECTON;break;case 3:flag=1;break;default:printf("Input Error\n");flag=2;break;} if(flag==1)break;if(flag==2){flag=0;continue;}if(ioctl(fd,cmd,&arg)<0){printf("Call ioctl error!\n");return -1;} } close(fd); return 0; }
Makefile
ifneq ($(KERNELRELEASE),)obj-m := testled.oelseKDIR := /home/liye/forlinux/linux-2.6.36all:make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-install:cp testled.ko test /home/liye/forlinux/rootfs/courseclean:rm -f *.o *.ko *.mod.c *.mod.o *.order *.symversendif
- 《OK6410-LED驱动程序设计》之使用ioremap实现访问CPU寄存器
- mini2440 LED驱动 (用ioremap实现访问CPU寄存器)
- mini2440 LED驱动 (用ioremap实现访问CPU寄存器)
- 驱动案例一:mini2440 LED驱动 (用ioremap实现访问CPU寄存器)
- 《OK6410-LED驱动程序设计》之使用系统定义的宏
- ok6410之lcd驱动程序设计
- 关于ok6410 LED and BEEP驱动程序之我见
- OK6410 Linux下LED驱动程序
- OK6410之裸机led
- Linux下的led驱动程序,ok6410
- OK6410之ADC驱动程序
- 《OK6410-蜂鸣器驱动程序设计》之阻塞型字符设备
- Linux3.6.7在OK6410平台的移植(五)字符设备驱动程序之LED
- Linux设备驱动程序之三 ---- LED驱动程序的实现
- LED驱动程序设计
- Led驱动程序的设计
- led驱动程序设计
- LED驱动程序设计
- NSString 转换为变量使用
- log4j.properties参数
- 北京户口迁移记
- VS2010不能正确加载 'VSTS for Database Professionals Sql Server Data-tier Application'包解决方法
- JQuery【斑马线效果】
- 《OK6410-LED驱动程序设计》之使用ioremap实现访问CPU寄存器
- Invalidate和UpdateWindow的区别
- OPENSSL 颁发证书出错
- J2SE基础夯实系列之通过例子看六种异常处理的陋习
- JQuery【可编辑的表格】
- HttpGet和HttpPost的区别
- String类小结
- 平台之战:京东,拿什么来跟天猫拼?
- poj 1274