首页 Linux驱动修炼之道-ADC驱动

Linux驱动修炼之道-ADC驱动

举报
开通vip

Linux驱动修炼之道-ADC驱动 努力成为 linux kernel hacker 的人李万鹏原创作品,为梦而战。转载请标明 出处 http://blog.csdn.net/woshixingaaa/archive/2011/05/18/6429002.asp x S3C2440 内部 ADC 结构图: 对于 s3c2440 来说,实现 A/D 转换比较简单,主要应用的是 ADC 控制寄存器 ADCCON 和 ADC 转换数据寄存器 ADCDAT0。寄存器 ADCDAT0 的低 10 位用 于存储 A/D 转换后的数据。寄存器 ADCCON ...

Linux驱动修炼之道-ADC驱动
努力成为 linux kernel hacker 的人李万鹏原创作品,为梦而战。转载请标明 出处 http://blog.csdn.net/woshixingaaa/archive/2011/05/18/6429002.asp x S3C2440 内部 ADC 结构图: 对于 s3c2440 来说,实现 A/D 转换比较简单,主要应用的是 ADC 控制寄存器 ADCCON 和 ADC 转换数据寄存器 ADCDAT0。寄存器 ADCDAT0 的低 10 位用 于存储 A/D 转换后的数据。寄存器 ADCCON 的第 15 位用于标识 A/D 转换是否 结束。第 14 位用于使能是否进行预分频,而第 6 位到第 13 位则存储的是预分 频数值,因为 A/D 转换的速度不能太快,所以要通过预分频处理才可以得到正 确的 A/D 转换速度,如我们想要得到 A/D 转换频率为 1MHz,则预分频的值应 为 49。第 3 位到第 5 位 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 示的是 A/D 转换的通道选择。第 2 位可以实现 A/D 转 换的待机模式。第 1 位用于是否通过读取操作来使能 A/D 转换的开始。第 0 位 则是在第 1 位被清零的情况下用于开启 A/D 转换。 驱动代码: 1. #include 2. #include 3. #include 4. #include 5. #include 6. #include 7. #include 8. #include Object 1Object 2Object 3Object 4Object 5Object 6Object 7Object 8Object 9Object 10Object 11Object 12Object 13Object 14Object 15Object 16Object 17Object 18Object 19Object 20Object 21Object 22Object 23Object 24Object 25Object 27Object 28Object 29Object 30Object 31Object 32Object 33Object 34Object 35Object 37Object 38Object 39Object 40Object 41Object 42Object 43 Object 44Object 45 Object 46 Object 47 Object 48 Object 49Object 53 Object 55Object 56Object 57Object 58Object 59 Object 60Object 61Object 62Object 63Object 64Object 65Object 66 Object 67 Object 68 Object 69Object 70Object 71Object 72Object 73Object 74Object 75Object 76Object 77Object 78Object 79Object 80Object 81Object 82Object 83Object 84Object 85Object 86Object 87Object 88Object 89Object 90Object 91Object 92Object 93Object 94Object 95 Object 26 Object 36 9. #include 10.#include 11.#include 12.#include 13.#include 14.#include 15.#include 16.#include 17.#define ADC_MINOR 100 18.#define ADC_NAME "lwp-adc" 19.struct clk *adc_clk; 20.int adc_base; 21.int adc_finish = 0; 22.static int adc_data; 23.DECLARE_WAIT_QUEUE_HEAD(adc_wait); 24. 25.static irqreturn_t adc_interrupt(int irq, void *dev_id){ 26. if(!adc_finish){ 27. adc_data = readl(adc_base + S3C2410_ADCDAT0) & 0x3ff; //ad 转换结束会产生中断, 此时读取 S3C2410_ADCDAT0 的 0~9 位,来获取数据 28. adc_finish = 1; 29. wake_up_interruptible(&adc_wait); //唤醒等待其上的进程 30. } 31. return IRQ_HANDLED; 32.} 33. 34.int myadc_open(struct inode *inode, struct file *file){ 35. int ret; 36. ret = request_irq(IRQ_ADC, adc_interrupt, IRQF_SHARED, ADC_NAME, 1); //这里注册中断, ad 转换结束通知 cpu 有两种方式,一种靠 cpu 轮询标志位,一种靠中断 37. if(ret){ 38. printk("IRQ %d can't get/n", IRQ_ADC); 39. return -1; 40. } 41. return 0; 42.} 43. 44.int myadc_close(struct inode *inode, struct file *file){ 45. return 0; 46. return -ENOENT; 47.} 48. 49.void start_adc(){ //开始 ad 转换 50. int tmp; 51. tmp = 0xff<<6 | 1<<14; //设置预分频使能,值为 255,使用通道 AIN0 52. writel(tmp ,adc_base + S3C2410_ADCCON); 53. tmp = readl(adc_base + S3C2410_ADCCON); 54. tmp |= 1<<0; //使能 AD 转换 55. writel(tmp, adc_base + S3C2410_ADCCON); 56.} 57. 58.ssize_t myadc_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ 59. start_adc(); //要读数据开始 adc 转换 60. wait_event_interruptible(adc_wait, adc_finish); //等待转换结束 61. adc_finish = 0; 62. copy_to_user(buff, (char *)&adc_data, sizeof(adc_data)); //将获得的数据拷贝到用户空间, 数据会在中断程序中获得 63. return sizeof(adc_data); 64.} 65. 66.static struct file_operations adc_ops = { 67. .owner = THIS_MODULE, 68. .open = myadc_open, 69. .release = myadc_close, 70. .read = myadc_read, 71.}; 72. 73.static struct miscdevice adc_misc = { 74. .name = ADC_NAME, 75. .minor = ADC_MINOR, 76. .fops = &adc_ops, 77.}; 78. 79.static int __init my_adc_init(void){ 80. unsigned int ret; 81. adc_clk = clk_get(NULL,"adc"); //由于 ad 转换需要时钟,所以这里获取时钟 82. if(!adc_clk){ 83. printk(KERN_ERR "fail to find adc clk resource!/n"); 84. ret = -1; 85. goto err_clk; 86. } 87. clk_enable(adc_clk); //使能 adc 的时钟 88. adc_base = ioremap(S3C2410_PA_ADC, 20); //获得 ADC 控制寄存器的虚拟地址 89. if(adc_base == 0){ 90. printk(KERN_ERR "fail to ioremap!/n"); 91. ret = -1; 92. goto err_nomap; 93. } 94. ret = misc_register(&adc_misc); //注册这个 adc 为混杂设备 95. if(IS_ERR(ret)){ 96. goto err_register; 97. } 98. return 0; 99. 100.err_register: 101. iounmap(adc_base); 102.err_nomap: 103. clk_disable(adc_clk); 104. clk_put(adc_clk); 105.err_clk: 106. return ret; 107.} 108. 109.static void __exit my_adc_exit(void){ 110. misc_deregister(&adc_misc); 111. free_irq(IRQ_ADC, 1); 112. iounmap(adc_base); 113. clk_disable(adc_clk); 114. clk_put(adc_clk); 115.} 116. 117.module_init(my_adc_init); 118.module_exit(my_adc_exit); 119.MODULE_AUTHOR("liwanpeng"); 120.MODULE_LICENSE("GPL"); 测试代码: 1. #include 2. #include 3. #include 4. 5. int main(int argc, char **argv) 6. { 7. int fd; 8. fd = open("/dev/lwp-adc", 0); 9. if(fd < 0) 10. { 11. printf("Open ADC Device Faild!/n"); 12. exit(1); 13. } 14. while(1) 15. { 16. int ret; 17. int data; 18. ret = read(fd, &data, sizeof(data)); 19. if(ret != sizeof(data)) 20. { 21. if(errno != EAGAIN) 22. { 23. printf("Read ADC Device Faild!/n"); 24. } 25. continue; 26. } 27. else 28. { 29. printf("Read ADC value is: %d/n", data); 30. } 31. } 32. close(fd); 33. return 0; 34.} 实验效果: 分享到:
本文档为【Linux驱动修炼之道-ADC驱动】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_650838
暂无简介~
格式:pdf
大小:185KB
软件:PDF阅读器
页数:5
分类:互联网
上传时间:2012-08-07
浏览量:30