历史上的今天
今天是:2025年03月23日(星期日)
2021年03月23日 | S3C6410开发板adc驱动代码分析及测试代码分析
2021-03-23 来源:eefocus
在本文中,我们对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 blockn");
return -ENOMEM;
}
adc_clock = clk_get(NULL, "adc");
if (!adc_clock) {
printk(KERN_ERR "failed to get adc clock sourcen");
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"tinitializedn");
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 openedn");
return 0;
}
设备打开代码实现了内核阻塞等待队列的初始化,还有adc通道号的初始化。
4、设备关闭
设备关闭代码比较简单,如下所示。
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
DPRINTK("adc closedn");
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, %dn", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);
value = adc_data;
__ADC_locked = 0;
mini6410_adc_release_io();
} else {
value = -1;
}
len = sprintf(str, "%dn", 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("%sn",buf);
sleep(1);
}
close(fd);
return 0;
}
代码中,首先打开adc端口,然后进入while(1)循环,在循环中,每隔1秒读取一次ad值,并将ad值打印到终端中。
史海拾趣
|
二、关于嵌入式系统方向 嵌入式系统无疑是当前最热门最有发展前途的IT应用领域之一。嵌入式系统用在一些特定专用设备上,通常这些设备的硬件资源(如处理器、存储器等)非常有限,并且对成本很敏感,有时对实时响应要求很高等。特别是随着消费家 ...… 查看全部问答> |
|
在蓝牙协议中,主从设备间只支持一条ACL链路和三条SCO链路,是不是就是说在某一时刻,主从服务间只有一个服务使用这个ACL链路??? 如题,现在很急的一个问题, 想请教高手, 蓝牙协议中的主从设备间只支持一条ACL链路和三条SCO链路,是不是就是等价于说在某一时刻,主从服务间只有一个服务使用这个ACL链路??? 举个例子就是,某一时刻文件传输服务和蓝 ...… 查看全部问答> |
|
S3C2440 SPI接收问题请教, 程序代码如下所示. 我通过示波器能够抓到MISO,MOSI的正确波形,说明数据发送和接收都是正确的,可就是2440寄存器SPRDAT0没有数值,始终是0. 各位大侠估计什么原因?ARM MISO管脚显示信号都是正确的,相应接收寄存器却 ...… 查看全部问答> |
|
最近做仿真软件开发,要求实时性很强,为了方便开发和用户使用,就不想换操作系统,看到可以在Windows下使用RTX来实现,只是我同用过,哪位大侠用过,说下~~ … 查看全部问答> |
|
题目是:同时用两个定时器控制蜂鸣器发声,定时器0控制频率,定时器1控制同个频率持续的时间,间隔300ms输出1k(hz)的方波。 我的代码是:#include #include #define uint unsigned int #define uchar unsigned char uint t1=0,t2=0; sbit b ...… 查看全部问答> |
|
奇怪!下面函数通不过? { uchar a; a=1; if( a!=1 ) break; } 错误提示:COMJM.C(64): error C171: \'break\': ...… 查看全部问答> |
|
这几天拼命在学这个了! 学了几遍,因为学完的比较早,做题过的也比较早,后来就只看资料了,没有想到当时忘记把图截完了! 当时以后系统可以在后台统计! 麻烦管理员朋友帮忙查看一下!辛苦了!!… 查看全部问答> |




