LED,键盘,AD驱动程序开发

原文: http://blog.sina.com.cn/s/blog_4083b2d70100bnlf.html

一:硬件平台及系统平台

CPU: S3C2410A

SDRAM: 64M

FLASH: K9F1208(64MB)

NET: CS8900

友善之臂2410,优龙2410.参考原理图,编写相应的程序.原理是一样的.只要改下GPIO端口及相应的地址就可以了.后面涉及到的程序是针对优龙2410版子的程序.

二:使用的内核版本:LINUX2.6.24 

交叉编译工具版本:arm-linux-gcc 3.4.1

 

三:实验步骤

 

1. 拷贝一个移植好的内核(可以参考陈亮的内核移植笔记或网上的步骤,自己动手做一个内核),放到虚拟机的根目录下.

2.  解压:zxvf linux-2.6.24.tar.gz大概需要2分钟的时间.

3.  编译一次: make (即:[root@229 linux-2.6.24]# make)然后配置:makemenuconfig

(即:[root@229 linux-2.6.24]# make menuconfig)

一般在内核移植的时候我们已经加上键盘,鼠标的支持了,如果没有的话,在makemenuconfig  的时候可以自己再加上,以后我们需要什么新的驱动,也可以在这个时候加上对该驱动的支持.对键盘,鼠标的支持

到此为止编译驱动的准备工作做好了 ,否则编译驱动会出现很多错误.

四:编写驱动程序.

1.  驱动程序结构:

五:实际程序如下:

 

1        LED 驱动程序

 

 #include<linux/module.h>#include<linux/kernel.h>#include<linux/fs.h>#include<linux/errno.h>#include<linux/types.h>#include<linux/fcntl.h>#include<linux/cdev.h>#include<linux/version.h>#include<linux/vmalloc.h>#include<linux/ctype.h>#include<linux/pagemap.h>#include<asm/io.h>#include<asm/irq.h>#include<asm/signal.h>#include<asm/hardware.h>#include<asm/uaccess.h>#include<asm/arch/regs-gpio.h>#include<linux/ioctl.h>#include "demo.h"MODULE_AUTHOR("fgj");MODULE_LICENSE("Dual BSD/GPL");#define LED_SI_OUT__raw_writel(0x5500,S3C2410_GPFCON)#defineLED_SI_H1  __raw_writel(0x80,S3C2410_GPFDAT)#defineLED_SI_L1  __raw_writel(~0x80,S3C2410_GPFDAT)#defineLED_SI_H2  __raw_writel(__raw_readl(S3C2410_GPFDAT)|(1<<6),S3C2410_GPFDAT)#defineLED_SI_L2  __raw_writel(__raw_readl(S3C2410_GPFDAT)&(~(1<<6)),S3C2410_GPFDAT)#defineLED_SI_H3  __raw_writel(__raw_readl(S3C2410_GPFDAT)|(1<<5),S3C2410_GPFDAT)#defineLED_SI_L3  __raw_writel(__raw_readl(S3C2410_GPFDAT)&(~(1<<5)),S3C2410_GPFDAT)#defineLED_SI_H4  __raw_writel(__raw_readl(S3C2410_GPFDAT)|(1<<4),S3C2410_GFBDAT)#defineLED_SI_L4  __raw_writel(__raw_readl(S3C2410_GPFDAT)&(~(1<<4)),S3C2410_GPFDAT)#define LED_OFF   __raw_writel(__raw_readl(S3C2410_GPFDAT)|(15<<4),S3C2410_GPFDAT)   #define COMMAND_LEDOFF 0#define COMMAND_LEDON 1struct DEMO_dev *DEMO_devices;static unsigned char demo_inc=0;int DEMO_open(struct inode *inode, struct file*filp){structDEMO_dev *dev;if(demo_inc>0)return -ERESTARTSYS;demo_inc++;dev =container_of(inode->i_cdev, struct DEMO_dev,cdev);filp->private_data = dev;return0;}int DEMO_release(struct inode *inode, struct file*filp){demo_inc--;return0;}int DEMO_ioctl(struct inode *inode, struct file*filp,unsigned int line_num, unsigned long arg){switch(line_num){case 7:{  LED_OFF;LED_SI_L1;printk("ioctl1\n");return0;          }case 8:{LED_OFF;LED_SI_L2;printk("ioctl2\n");return0;          }case 9:{LED_OFF;LED_SI_L3;printk("ioctl3\n");return0;          }case 10:{LED_OFF;LED_SI_L4;printk("ioctl4\n");return0;          }default:{printk("ioctl error successfully\n");return -EFAULT;}} }struct file_operations DEMO_fops = {.owner=   THIS_MODULE,.ioctl=   DEMO_ioctl,.open=    DEMO_open,.release=  DEMO_release,};void DEMO_cleanup_module(void){dev_t devno= MKDEV(DEMO_MAJOR, DEMO_MINOR);if(DEMO_devices){cdev_del(&DEMO_devices->cdev);kfree(DEMO_devices);}unregister_chrdev_region(devno,1);}int DEMO_init_module(void){intresult;dev_t dev =0;dev =MKDEV(DEMO_MAJOR, DEMO_MINOR);result =register_chrdev_region(dev, 1, "DEMO");if (result< 0){printk(KERN_WARNING "DEMO: can't get major %d\n", DEMO_MAJOR);return result;}DEMO_devices= kmalloc(sizeof(struct DEMO_dev), GFP_KERNEL);if(!DEMO_devices){result = -ENOMEM;goto fail;}memset(DEMO_devices, 0, sizeof(struct DEMO_dev));cdev_init(&DEMO_devices->cdev,&DEMO_fops);DEMO_devices->cdev.owner = THIS_MODULE;DEMO_devices->cdev.ops =&DEMO_fops;result =cdev_add (&DEMO_devices->cdev, dev,1);if(result){printk(KERN_NOTICE "Error %d adding DEMO\n", result);goto fail;}LED_SI_OUT;return0;fail:DEMO_cleanup_module();returnresult;}module_init(DEMO_init_module);module_exit(DEMO_cleanup_module);

使用说明:我们对内存每个地址的访问的时候不能直接用writel(__raw_readl(S3C2410_GPFDAT)|(1<<6),S3C2410_GPFDAT)

或者#define S3C2410_ADCCON 0x58000000 等

因为我们对内存的访问的时候要用虚拟内存映射技术所以要使用如下的程序:

 

__raw_writel(__raw_readl(S3C2410_GPFDAT)|(1<<6),S3C2410_GPFDAT)

#define S3C2410_ADCCON (0x58000000)

adccon = ioremap(S3C2410_ADCCON,0x00000004);

0x00000004 是指字节长度.

网上有很多程序是关于linux2.4内核的,与2.6内核的驱动程序写法不一样.编译时有时候通不过,比如当编译报错没有定义:SA_INTERRUPT时候

我们可以使用命令:grep  -R  -n  'SA_INTERRUPT'  /linux-2.6.24/include

因此可以在程序中加上该语句:# define SA_INTERRUPT 0x20000000.

 

 编写Makefile

 

#linux derive develop#makefileCC= /usr/local/arm/3.4.1/bin/arm-linux-gccifneq ($(KERNELRELEASE),)obj-m :=led.oelseKDIR :=/linux-2.6.24PWD :=$(shell pwd)default:$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modulesendifclean:@rm -rfled_test*.o   

编写不同的驱动程序的时候 Makefile基本不用改变 只需要把该句obj-m :=led.o进行修改就可以了.最后一句是对make clean的支持 清除生成的不必要的文件.

板子上运行结果如下:

 

2      键盘驱动程序(头文件略)

参考资料:《嵌入式Linux驱动程序设计从入门到精通》 冯国进编著,2008.

MODULE_AUTHOR("fgj");MODULE_LICENSE("Dual BSD/GPL");static int irqArray[4]={IRQ_EINT0,IRQ_EINT2,IRQ_EINT11,IRQ_EINT19};void initButton(void){writel((readl(S3C2410_GPGCON)&(~((3<<22)|(3<<6))))|((2<<22)|(2<<6)),S3C2410_GPGCON);       //GPG11,3 set EINTwritel((readl(S3C2410_GPFCON)&(~((3<<4)|(3<<0))))|((2<<4)|(2<<0)),S3C2410_GPFCON);    //GPF2,0 set EINTwritel((readl(S3C2410_EXTINT0)&(~(6|(6<<8)))),S3C2410_EXTINT0);writel((readl(S3C2410_EXTINT0)|(0|(0<<8))),S3C2410_EXTINT0);   //set eint0,2 falling edge intwritel((readl(S3C2410_EXTINT1)&(~(6<<12))),S3C2410_EXTINT1); }
void polling_handler(unsigned long data){intcode=-1;writel(readl(S3C2410_SRCPND)&0xffffffda,S3C2410_SRCPND);//clearsrcpnd 0 2 11 19mdelay(1);//扫描按键表,根据中断号,找出所按下的按键。writel(readl(S3C2410_GPBDAT)|0x80,S3C2410_GPBDAT);//set GPB76 to10writel(readl(S3C2410_GPBDAT)&0xffffffBf,S3C2410_GPBDAT);//...// }writel(readl(S3C2410_SRCPND)&0xffffffda,S3C2410_SRCPND);//clearsrcpnd 0 2 11 19mdelay(1);writel(readl(S3C2410_GPBDAT)|0x40,S3C2410_GPBDAT);//set GPB76 to01writel(readl(S3C2410_GPBDAT)&0xffffff7f,S3C2410_GPBDAT);//...// }for (i = 0;i <4; i++) {if (request_irq(irqArray[i], &simplekey_interrupt,0x20000000, "simplekey", NULL)) {printk("request button irq failed!\n");return -1;}  }  

硬件接口电路如下:


友善之臂用到的GPIO(EINT0…等)端口不一样,根据硬件接口电路,参照数据手册,在涉及到的端口上,相应的修改下程序就可以了.此程序还可以注释掉很多没必要的部分.涉及到set GPB76 to 01的都可以注释掉,因为该程序用GPB7GPB6来回置低的办法,而我们直接让,键盘接地

我们只用到4个键盘而,程序用到8个键盘,我们也没必要判断是哪一列键盘按下.修改应该简单,不过还没编译验证过.所以程序还可以精简很多.但该程序完全可以实现我们要的功能,只是多做了一些无用功而已.

原始程序有部分错误,如:设置下降沿触发的时候应该用:

writel((readl(S3C2410_EXTINT1)&(~(6<<12))),S3C2410_EXTINT1);//set eint11 falling

writel((readl(S3C2410_EXTINT1)|(0<<12)),S3C2410_EXTINT1);该语句貌似没用,应该可以注释掉.可以编译试试.

 

板子上运行结果如下:

 

3       AD转换程序:(因为文字过长,有删节)

 

# //预分频倍数

#define PRESCALER 19

#define S3C2410_ADCCON (0x58000000)

#define S3C2410_ADCTSC (0x58000004)

static ssize_t adc_read(struct file *filp, char*buf, size_t count, loff_t *f_pos)

{

;

}

//temp1 =(int)filp->private_data;

local_irq_save(flags);

writel((readl(S3C2410_CLKCON) |S3C2410_CLKCON_ADC),S3C2410_CLKCON); //时钟使能

//outl(AdcrSave | (1u <_u32 ?temp) | (1u<< 24), S3C2410_ADCCON);

printk("temp0=%d\n",temp0);

//开始AD转换

writel(temp0|0x01, adccon);

//等待AD转换完成

while((readl(adccon) & 0x01) != 0);

//等待AD数据写入ADCDAT0

//for(j=0;j<50;j++)

//while((readl(adccon) & (0x1< _u60 ? 15)) == 0);

//mdelay(100);

printk("adccon = %d, adctsc = %d, adcdly = %d, adcdat0 = %d,adcdat1= %d, adcupdn = %d\n", readl(adccon), readl(adctsc),readl(adcdly), readl(adcdat0), readl(adcdat1), readl(adcupdn));

// }

temp =readl(adcdat0);

temp2 = temp&0x3ff;

);

printk("adc device installed, with major %d\n",ADC_MAJOR_NR);

adccon = ioremap(S3C2410_ADCCON,0x00000004);

adctsc = ioremap(S3C2410_ADCTSC,0x00000004);

void adc_cleanup(void)

{

iounmap(adccon);

iounmap(adctsc);

iounmap(adcdly);

iounmap(adcupdn);

unregister_chrdev(ADC_MAJOR_NR, DEVICE_NAME);

}

这个程序我们花的时间最长:参照网上的程序,然后调试,至少花了一个星期的时间.

开始主要是有2点没弄清楚:

* 1.     内存映射机制.

开始我们直接#define adccon (0x58000000)

结果编译的时候就通不过,打印出不能操作内存地址的错误.后来我们知道了是没有利用,内存映射机制.改用如上ioremap(adccon);方式就ok了

* 2.     开启时间使能

修改了第一部之后,能编译成.ko文件了,运行结果出现了错误.根本没有进行转换,不管输入什么,输出都为0.

writel((readl(S3C2410_CLKCON) |S3C2410_CLKCON_ADC),S3C2410_CLKCON); //时钟使能

加上该语句后,AD转换器才真正的工作.实际运行结果如下:

 

Temp2 (即adc)为转换结果.

 

驱动程序和QT结合是一个很好的方向,我们的下一步,可以在QT上实现该驱动程序.

 

查看设备号码方法:cat /proc/devices

嵌入式Linux LED,键盘,AD驱动程序开发相关推荐

  1. linux cached释放_正点原子Linux第四十一章嵌入式Linux LED驱动开发实验

    1)资料下载:点击资料即可下载 2)对正点原子Linux感兴趣的同学可以加群讨论:935446741 3)关注正点原子公众号,获取最新资料更新 第四十一章嵌入式Linux LED驱动开发实验 上一章我 ...

  2. 【正点原子Linux连载】第四十一章 嵌入式Linux LED驱动开发实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  3. 【正点原子MP157连载】第二十一章 嵌入式Linux LED驱动开发实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  4. 嵌入式linux中断驱动,嵌入式Linux下硬件中断驱动程序的开发.pdf

    嵌入式Linux下硬件中断驱动程序的开发.pdf 2003 年 6 月 航空精密制造技术 Jun. 2003 第 39 卷 第 3 期 AVIATION PRECISION MANUFACTURING ...

  5. 嵌入式linux系统中设备驱动程序

    嵌入式linux系统中设备驱动程序是内核的一部分,完成对设备初始.读写操作和控制等功能.驱动程序隐藏了 硬件设备的具体细节,对不同的设备提供一致的接口,这些接口通过file_Operation结构来定 ...

  6. 嵌入式linux ASoC架构声卡驱动开发

    嵌入式linux ASoC架构声卡驱动开发 文章目录 嵌入式linux ASoC架构声卡驱动开发 需求分析 ASoC架构下声卡驱动代码结构 codec驱动 snd_soc_register_codec ...

  7. Linux下PCI设备驱动程序开发 --- PCI驱动程序实现(三)

    <script type="text/javascript"> </script><script type="text/javascript ...

  8. 嵌入式linux矩阵键盘,基于嵌入式Linux的矩阵键盘驱动程序开发

    O 引 言 随着以计算机技术.通信技术和软件技术为核心的信息技术的发展,嵌入式系统在各个行业中得到了广泛的应用.嵌入式系统已成为当今IT行业的焦点之一.而在嵌入式系统中,键盘是重要的人机交互设备之一. ...

  9. 嵌入式 Linux LED 驱动开发实验

    41.1 Linux 下 LED 灯驱动原理 Linux 下的任何外设驱动,最终都是要配置相应的硬件寄存器.所以本章的 LED 灯驱动最 终也是对 I.MX6ULL 的 IO 口进行配置,与裸机实验不 ...

最新文章

  1. vue 后台返回的文件流进行预览_基于 Vue3+Ts 后台前端管理系统Vue3-Admin
  2. oracle散列,在Python中散列一个整数,以匹配Oracle的标准_散列
  3. 湖南vb程序设计二级计算机考试题库答案,计算机二级VB语言程序设计考试题及答案...
  4. 仅靠一杯奶茶钱8.8元,你就能转到人工智能专业?
  5. oracle数据量大时候分区索引思路
  6. python周末吃什么_中午不知道吃什么?用Python爬取美团外卖评论帮你选餐!
  7. docker kafka互通有问题_Docker搭建kafka集群
  8. i12蓝牙耳机使用说明书图片_飞利浦SHB4385 BASS+无线蓝牙耳机晒单 使用体验
  9. 以太坊2.0质押流动性解决方案Lido上线治理工具Lido DAO
  10. 深入V8引擎-Time核心方法之mac篇
  11. ICPC程序设计题解书籍系列之八:(美)斯基纳等:《挑战编程-程序设计竞赛训练手册》
  12. CopyU!v2 已经收录到腾讯软件管家!
  13. ROS+opencv实践-cv_bridge的使用
  14. 小特工具箱新增功能:文档转换、代码转换和AI写诗词
  15. 做视频后期剪辑用什么软件好?4款常用软件推荐
  16. 计算机怎么发音乐,网易云音乐怎么分享音乐给别人的教程
  17. 网易云音乐web/网页版无法播放问题
  18. 使用ADB工具卸载/停用Android系统应用(无需Root)
  19. 日本价值链促进会(IVI)秘书长西冈靖之:日本工业互联网发展情况
  20. 计算系数(二项式定理逆元费马小定理)

热门文章

  1. Ros学习topic——小海龟
  2. Linux自学笔记——Centos系统安装
  3. ACM的fflush(stdin)的问题
  4. Effective C++ ------- virtual
  5. 查看centos当前版本
  6. 项目开发中遇到的小问题及小规范
  7. Console-算法[for,if]-一堆桃子和一只猴子
  8. Web前端开发人员和设计师必读文章推荐【系列六】
  9. 关于 Repeater 控件嵌套的使用。在嵌套中添加 其它控件(如:按钮),并影响其它控件的方法,很重要哦,测试通过。...
  10. SQL中的存储过程中的事务处理。备忘