S3C6410开发板adc驱动代码分析及测试代码分析

        在本文中,我们对S3C6410开发板adc驱动代码的实现过程进行分析,然后通过一个实例对adc功能进行测试。在本文的资源中包含了设备驱动的源码和测试的源码。

一、设备驱动源码分析

        adc的设备驱动主要实现了模块的初始化、模块的卸载、设备打开、设备关闭、设备读取的功能。

1、模块初始化

        模块的初始化的源码如下所示。

static int __init dev_init(void)
{
	int ret;

	base_addr = ioremap(SAMSUNG_PA_ADC, 0x20);
	if (base_addr == NULL) {
		printk(KERN_ERR "Failed to remap register block\n");
		return -ENOMEM;
	}

	adc_clock = clk_get(NULL, "adc");
	if (!adc_clock) {
		printk(KERN_ERR "failed to get adc clock source\n");
		return -ENOENT;
	}
	clk_enable(adc_clock);
	
	/* normal ADC */
	ADCTSC = 0;

	ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
	if (ret) {
		iounmap(base_addr);
		return ret;
	}

	ret = misc_register(&misc);

	printk (DEVICE_NAME"\tinitialized\n");
	return ret;
}

这段代码主要实现的功能是是能adc的始终,并且开启了adc的中断功能,最后使用misc_register()函数向内核注册adc的混杂设备。adc的中断初始化过程将adc的中断号与中断处理函数、中断描述结构体绑定在一起。其中,IRQ_ADC是中断号,adcdone_int_handler是中断处理函数,adcdev是指向中断描述结构体的指针,当启用了adc转换后并转换完成后,中断会把相应的中断描述结构体保持下来,并转到adcdone_int_handler函数去处理中断。

        adcdone_int_handler()函数的源码如下所示。

static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
	if (__ADC_locked) {
		adc_data = ADCDAT0 & 0x3ff;

		ev_adc = 1;
		wake_up_interruptible(&adcdev.wait);

		/* clear interrupt */
		__raw_writel(0x0, base_addr + S3C_ADCCLRINT);
	}

	return IRQ_HANDLED;
}

这段代码的功能是将adc的转换结果保存到adc_data变量中,并将阻塞的等待队里唤醒。

2、模块卸载

        模块的卸载代码如下所示

static void __exit dev_exit(void)
{
	free_irq(IRQ_ADC, &adcdev);
	iounmap(base_addr);

	if (adc_clock) {
		clk_disable(adc_clock);
		clk_put(adc_clock);
		adc_clock = NULL;
	}

	misc_deregister(&misc);
}

代码实现的功能是关闭adc的中断功能,禁能adc的始终,并且将adc的混杂设备从内核中取消注册。

3、设备打开

        adc的设备打开代码如下所示。

static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
	init_waitqueue_head(&(adcdev.wait));

	adcdev.channel=0;
	adcdev.prescale=0xff;

	DPRINTK("adc opened\n");
	return 0;
}

 设备打开代码实现了内核阻塞等待队列的初始化,还有adc通道号的初始化。

4、设备关闭

        设备关闭代码比较简单,如下所示。

static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
	DPRINTK("adc closed\n");
	return 0;
}

代码没有做任何操作,只是打印了一串字符串。

5、设备读取

        设备读取的代码如下所示。

static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
	char str[20];
	int value;
	size_t len;

	if (mini6410_adc_acquire_io() == 0) {
		__ADC_locked = 1;

		START_ADC_AIN(adcdev.channel, adcdev.prescale);

		wait_event_interruptible(adcdev.wait, ev_adc);
		ev_adc = 0;

		DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);

		value = adc_data;

		__ADC_locked = 0;
		mini6410_adc_release_io();
	} else {
		value = -1;
	}

	len = sprintf(str, "%d\n", value);
	if (count >= len) {
		int r = copy_to_user(buffer, str, len);
		return r ? r : len;
	} else {
		return -EINVAL;
	}
}

读取代码首先使能了adc转换功能,然后阻塞等待转换完成,转换完成后会进入中断进行数据读取,在中断中会将读取函数中的阻塞唤醒。唤醒后读取函数读取adc返回的数据,并将ad值转换成字符串str,最后将str复制给用户程序中的buf。

二、测试代码分析

        编写了一个简单的测试代码对adc的驱动进行测试,代码如下。

int main()
{
	int fd;
	char buf[10];
	
	fd = open("/dev/adc",O_RDONLY);

	while(1)
	{
		read(fd,buf,10);		
		printf("%s\n",buf);
		sleep(1);
	}

	close(fd);
	return 0;
}

代码中,首先打开adc端口,然后进入while(1)循环,在循环中,每隔1秒读取一次ad值,并将ad值打印到终端中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值