基于FriendlyARM开发板mini2440的AD驱动 本实验编写ADC驱动程序并加到内核中对内核进行配置和编译生成内核镜像文件后烧写到开发板在开发板运行测试驱动程序。前提需要掌握ADC驱动的程序框架熟悉掌握设备驱动中并发控制机制并知道如何将驱动静态添加到内核一、实验设备与软件环境1、操作系统Linux虚拟机、Red Hat Enterprise Linux 6.3。2、硬件平台FriendlyARM开发板mini2440。3、软件SecureCRT 8.1。4、内核版本linux 2.6.32.2。二、操作的具体流程编写ADC驱动程序的源文件adc.c1在/opt /shiyan目录下创建lesson_adc文件夹①在/opt/shiyan目录下右击鼠标打开终端②输入“mkdir lesson_adc”创建一个名为lesson_adc的文件夹2输入“cd lesson_adc”命令进入lesson_adc目录下3输入gedit adc.c4编写adc.c代码源代码见附录12. 拷贝驱动代码与修改文件1拷贝把/opt /shiyan/lesson_adc/目录下的驱动代码adc.c拷到/opt/FriendlyARM/mini2440/linux-2.6.32.2/drivers/char路径下2修改/opt/FriendlyARM/mini2440/linux-2.6.32.2/drivers/char目录下的Kconfig文件和Makefile文件①修改Kconfig文件左图为修改前右图为修改后②修改Makefile文件左图为修改前右图为修改后3.回到内核目录在命令行执行make menuconfig找到刚刚添加的ADC驱动Devices Driver → Character Devices→ ADC空格选上并保存退出4.执行make zImage生成内核镜像文件zImage5.将镜像文件zImage烧写到开发板上6.编辑编译应用程序源代码见附录21在/opt /shiyan/lesson_adc目录下编辑应用程序adc_test.c2在/opt /shiyan/lesson_adc目录下执行arm-linux-gcc adc_test.c -o adc_test命令生成adc_test文件7.打开secureCRT接上mini2440开发板输入“rz”命令添加zImage和adc_test文件8.将测试程序和镜像文件传输到开发板后修改文件权限后输入“adc-test”运行旋转开发板上的W1可调电阻蓝色按钮运行结果如下三、操作异常问题与解决方案异常问题:在secureCRT上运行时输入./adc_test显示“Open ADC Device Faild”。解决方案将“./adc_test”改为“adc-test”即可四、实验总结在实验中编写ADC驱动程序并加到内核中对内核进行配置和编译生成内核镜像文件后烧写到开发板在开发板运行测试驱动程序,最终结果是在secureCRT上输入“adc-test”旋转开发板上的W1可调电阻蓝色按钮会出现不同的数值顺时针旋转数值变大反之数值变小。五、附录附录1#include plat/nand.h#include linux/miscdevice.h#include asm/irq.h#include mach/hardware.h#include linux/kernel.h#include mach/regs-gpio.h#include linux/module.h#include linux/fs.h#include linux/types.h#include linux/delay.h#include linux/moduleparam.h#include linux/slab.h#include linux/errno.h#include linux/ioctl.h#include linux/cdev.h#include linux/string.h#include linux/list.h#include linux/pci.h#include asm/uaccess.h#include asm/atomic.h#include asm/unistd.h#include linux/interrupt.h#include linux/ioport.h#include linux/io.h#include mach/gpio-fns.h#includelinux/sched.h#includelinux/init.h#includeasm/io.h#includelinux/uaccess.h#define DEVICE_NAME “my2440_adc”static DECLARE_WAIT_QUEUE_HEAD(adc_waitq);static volatile int ev_adc 0;static int adc_data;static void __iomem *adc_base;static struct clk *adc_clk;DECLARE_MUTEX(ADC_LOCK);static irqreturn_t adc_irq(int irq, void *dev_id){if(!ev_adc){adc_data readl(adc_base S3C2410_ADCDAT0) 0x3ff;ev_adc 1;wake_up_interruptible(adc_waitq);}return IRQ_HANDLED;}static int adc_open(struct inode *inode, struct file *file){int ret;ret request_irq(IRQ_ADC, adc_irq, IRQF_SHARED, DEVICE_NAME, 1);if (ret){printk(KERN_ERR “IRQ%d error %d\n”, IRQ_ADC, ret);return -EINVAL;}return 0;}static void start_adc(void){unsigned int tmp;tmp (1 14) | (255 6) | (0 3);/* 0 1 00000011 000 0 0 0/writel(tmp, adc_base S3C2410_ADCCON);tmp readl(adc_base S3C2410_ADCCON);tmp tmp | (1 0); /0 1 00000011 000 0 0 1 */writel(tmp, adc_base S3C2410_ADCCON);}static ssize_t adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){if (down_trylock(ADC_LOCK)){return -EBUSY;}if(!ev_adc){if(filp-f_flags O_NONBLOCK){return -EAGAIN;}else{start_adc();wait_event_interruptible(adc_waitq, ev_adc);}}ev_adc 0;copy_to_user(buffer, (char *)adc_data, sizeof(adc_data));up(ADC_LOCK);return sizeof(adc_data);}static int adc_release(struct inode *inode, struct file *filp){return 0;}static struct file_operations adc_fops {.owner THIS_MODULE,.open adc_open,.read adc_read,.release adc_release,};static struct miscdevice adc_miscdev {.minor MISC_DYNAMIC_MINOR,.name DEVICE_NAME,.fops adc_fops, };static int __init adc_init(void){int ret;adc_clk clk_get(NULL, “adc”);if (!adc_clk){printk(KERN_ERR “failed to find adc clock source\n”);return -ENOENT;}rch/arm/plat-s3c/clock.c涓?/clk_enable(adc_clk);adc_base ioremap(S3C2410_PA_ADC, 0x20);if (adc_base NULL){printk(KERN_ERR “Failed to remap register block\n”);ret -EINVALgoto err_noclk;}ret misc_register(adc_miscdev);if (ret)printk(KERN_ERR “cannot register miscdev on minor%d (%d)\n”, MISC_DYNAMIC_MINOR, ret);goto err_nomap;}printk(DEVICE_NAME initialized!\n);return 0;clk_disable(adc_clk);clk_put(adc_clk);err_nomap:iounmap(adc_base);return ret;}static void __exit adc_exit(void){free_irq(IRQ_ADC, 1);iounmap(adc_base);if (adc_clk){clk_disable(adc_clk);clk_put(adc_clk);adc_clk NULL;}misc_deregister(adc_miscdev);}附录2adc_test.c#include stdio.h#include stdlib.h#include errno.hint main(int argc, char **argv){int fd;fd open(/dev/my2440_adc, 0);if(fd 0){printf(“Open ADC Device Faild!\n”);exit(1);}while(1){int ret;int data;ret read(fd, data, sizeof(data));if(ret ! sizeof(data)){if(errno ! EAGAIN){printf(“Read ADC Device Faild!\n”);}continue;}else{printf(“Read ADC value is: %d\n”, data);}}close(fd);return 0;}