您的位置:首页 > 运维架构 > Linux

arm-linux --ADC驱动(中断方式)

2015-06-15 08:58 471 查看
</pre>硬件平台:FL2440<p></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">内核版本:2.6.28</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">主机平台:Ubuntu 11.04</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">内核版本:2.6.39</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">这个驱动写了好久,因为原来的Linux内核编译的时候将触摸屏驱动编译进内核了,而触摸屏驱动里的ADC中断在注册的时候类型选择的是</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> </p><pre style="white-space: pre-wrap; word-wrap: break-word; font-size: 14.399999618530273px; line-height: 26px; background-color: rgb(255, 255, 255);">IRQF_SAMPLE_RANDOM,不是共享类型,所以,自己写的ADC驱动在每次open的时候,总提示ADC中断注册失败。


解决方案:

重新配置内核,选择触摸屏驱动以模块的形式编译,而不是直接编译进内核,这样Linux在启动的时候不会自动加载触摸屏驱动,当然,IRQ_ADC中断号不会被占用。这样可以测试自己写的ADC驱动了。

以下是驱动源代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h> /*创建设备节点*/
#include <linux/clk.h>
#include <linux/wait.h> /*定义DECLARE_WAIT_QUEUE_HEAD*/
#include <linux/irqreturn.h> /*定义了irqreturn_t等*/
#include <linux/interrupt.h> /*request_irq disable_irq enable_irq*/
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>  /*其中包含了#include "mach/irqs.h" */
#include <plat/regs-adc.h>
#include <mach/regs-clock.h>
#define ADC_MAJOR 102
#define ADC_NAME "my_adc"
#define SUCCESS 0
static int adc_open(struct inode *,struct file *);
static int adc_release(struct inode *,struct file *);
static int __init adc_init(void);
static int __exit adc_exit(void);
static ssize_t adc_read(struct file *,char *,size_t,loff_t *);
volatile unsigned long adc_con;
unsigned long adc_dat0;
int flag;//等待任务完成标志
unsigned long buf;//存放转换完成的数据
//声明等待队列
DECLARE_WAIT_QUEUE_HEAD(adc_wait);
struct clk *adc_clk;
static irqreturn_t adc_interrupt(int irq,void * dev_id)//中断处理程序
{
if(flag==0)
{
buf=(readw(adc_dat0) & 0x3ff );//读取转换完成的数据
flag=1;
wake_up_interruptible(&adc_wait);//唤醒等待其上的进程
printk("Read value is %ld/n",buf);
}
return IRQ_HANDLED;
}
struct file_operations  adc_ops =
{
.owner	=	THIS_MODULE,
.read	    =   adc_read,
.open	=   adc_open,
.release	=	adc_release,
};
static int __init adc_init(void)
{
int ret;
adc_clk = clk_get(NULL,"adc");//获取时钟
clk_enable(adc_clk);//使能时钟

ret=register_chrdev(ADC_MAJOR,ADC_NAME,&adc_ops); //注册设备
if(ret<0)
{
printk("register device fail/n");
return ret;
}
adc_con=(unsigned long)ioremap(0x58000000,4);
adc_dat0=(volatile unsigned long)ioremap(0x58000000+S3C2410_ADCDAT0,4);
if( !(adc_con & adc_dat0) )
{
printk("Failed to ioremap/n");
goto handle;
}
printk("Initialized.../n");
return SUCCESS;
handle:
unregister_chrdev(ADC_MAJOR,ADC_NAME);
return -1;
}
static int adc_open(struct inode * inode,struct file * file) //打开设备函数
{
//注册中断
int ret;
//disable_irq(IRQ_ADC);
//enable_irq(IRQ_ADC);
ret=request_irq(IRQ_ADC,adc_interrupt,IRQF_SHARED,ADC_NAME,1);//注册中断 IRQ_ADC在 mach/irqs.h中定义
if(ret<0)
{
printk("IRQ %d can not request/n",IRQ_ADC);
return ret;
}
return SUCCESS;
}
static int adc_release(struct inode * inode,struct file * file) //关闭设备函数
{
free_irq(IRQ_ADC,1);//释放中断
return SUCCESS;
}
static ssize_t adc_read(struct file *file,
char * buffer,
size_t length,
loff_t * offset)//设备读取函数
{

writew((1<<14)|(0x31<<6),adc_con);       //设置ADCCON
writew((readw(adc_con) | 0x1),adc_con);  //启动AD转换
wait_event_interruptible(adc_wait,flag);
flag=0;
}
static int __exit adc_exit(void) //驱动卸载函数
{
iounmap(adc_con);
iounmap(adc_dat0);
unregister_chrdev(ADC_MAJOR,ADC_NAME);
clk_disable(adc_clk);
clk_put(adc_clk);
printk("The adc is unintialized/n");
return SUCCESS;
}
module_init(adc_init);
module_exit(adc_exit);
MODULE_LICENSE("GPL");


Makefile文件:

obj-m := adc.o

KERNELDIR ?= /arm/linux-2.6.28.7-2440

PWD := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:

rm -f *.o *.ko *.order *.symvers read

read:

arm-linux-gcc -o read read_adc.c

测试程序:

#include <stdio.h>

#include <stdlib.h>

#include <sys/time.h>

#define ADC_DEVICE "/dev/my_adc"

int main()

{

int ret;

unsigned int data;

ret=open(ADC_DEVICE,0);

if(ret<0)

{

printf("Open adc fail/n");

return ret;

}

for(;;)

{

//printf("cnt=%d/n",cnt);

read(ret,&data,sizeof(data));

//printf("The value is %d/n",data);

}

close(ret);

return 0;

}

首先新建设备:

mknod /dev/my_adc c 102 32

然后插入驱动 insmod adc.ko

运行测试程序./read

结果如下:



可以看出,调节ad转换器上的旋钮,看到AD转换值的变化,说明驱动工作正常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: