天天看點

linux adc驅動 視訊,ARM-Linux驅動--ADC驅動(中斷方式)

原标題:ARM-Linux驅動--ADC驅動(中斷方式)

硬體平台:FL2440

核心版本:2.6.28

主機平台:Ubuntu 11.04

核心版本:2.6.39

原創作品,轉載請标明出處:http://blog.csdn.net/yming0221/archive/2011/06/26/6568937.aspx

這個驅動寫了好久,因為原來的Linux核心編譯的時候将 驅動編譯進核心了,而觸摸屏驅動裡的ADC中斷在注冊的時候類型選擇的是

IRQF_SAMPLE_RANDOM,不是共享類型,是以,自己寫的 在每次open的時候,總提示ADC中斷注冊失敗。

解決方案:

重新配置核心,選擇觸摸屏驅動以子產品的形式編譯,而不是直接編譯進核心,這樣Linux在啟動的時候不會自動加載觸摸屏驅動,當然,IRQ_ADC中斷号不會被占用。這樣可以測試自己寫的ADC驅動了。

以下是驅動源代碼:

view plainprint?

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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_HAND ;

}

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("Fai 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檔案:

view plainprint?

obj-m := adc.o

KERNELDIR ?= / /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

以下是測試代碼:

view plainprint?

#include

#include

#include

#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

結果如下:

linux adc驅動 視訊,ARM-Linux驅動--ADC驅動(中斷方式)

可以看出,調節ad轉換器上的旋鈕,看到AD轉換值的變化,說明驅動工作正常。

責任編輯: