主题 : 关于S3C2440 芯片的AD采样频率问题 复制链接 | 浏览器收藏 | 打印
级别: 侠客
UID: 2177
精华: 0
发帖: 70
金钱: 620 两
威望: 463 点
综合积分: 140 分
注册时间: 2008-10-30
最后登录: 2015-01-12
楼主  发表于: 2009-05-11 20:23

 关于S3C2440 芯片的AD采样频率问题

按照数据手册所说的,S3C2440芯片的AD采样频率可以达到500K/S,最近做了一个测试,发现它的采样频率只有1K左右,不知哪里出了问题,具体测试方法如下:
(1)首先编写了一个AD驱动程序,其中的读代码如下:
static ssize_t s3c2440adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)  
{  
    unsigned long result = 0;  
    unsigned int data[4];
    unsigned int ch;
    
    spin_lock_irq(&s3c2440adc_dev.spinlock);
    
    /*get channel 0~3 data*/
    for( ch = 0; ch < 4; ch++ )
    {
          s3c2440adc_dev.channel = ch;
        iowrite32(START_ADC(s3c2440adc_dev.channel, s3c2440adc_dev.prescale), base_addr + S3C2410_ADCCON);    
        do {
            result = ioread32(base_addr + S3C2410_ADCCON);  /*read control register */  
        }while((unsigned int)result & 0x01);                /*confirm ADC start*/
    
        do {  
            result = ioread32(base_addr + S3C2410_ADCCON);  /*read control register*/  
           }while(!(((unsigned int)result) & 0x8000));         /*confirm ADC finished */

        data[ch] = ioread32(base_addr + S3C2410_ADCDAT0) & 0x3ff; /*save the 10 low bit*/  
        DPRINTK("AIN[%d] = %dmv\n", s3c2440adc_dev.channel, data[ch]*3300/1024);
    }
    copy_to_user(buffer, data, sizeof(data));      /*copy to user space*/  
       spin_unlock_irq(&s3c2440adc_dev.spinlock);
  
    return sizeof(data);
}
在这里,没读一次数据,可以得到4个通道的采样值。
(2)做一个测试程序,将读到的数据写入data_file文档中去,并测试所用时间:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

#define LOOP 10000

int main (void)
{
    int fd, size,j;
    unsigned int data[4];
    FILE *stream;
    clock_t start, finish;
    double duration;
    unsigned long int i;

    if( (fd = open("/dev/s3c2440_adc", O_RDWR, 0666)) < 0 )
    {
        perror("open:");
        exit(1);
    }

    if( (stream = fopen("data_file", "a+")) == NULL )
    {    
        printf("cant't not open file:data_file\n");
        exit(1);
    }
    else
    {
        start = clock();

        for(i=0;i<LOOP;i++)    
        {
            if( (size = read (fd,data,sizeof(data))) < 0 )
            {
                perror("read:");
                exit(1);
            }
            else
            {
                if ( (size = fprintf(stream,"%d,%d,%d,%d\n",data[0],data[1],data[2],data[3])) < 0 )
                    printf("can't not write data_file!\n");
            }
        }
    }
    
    finish = clock();
    duration = (double)( finish-start )/(double)CLOCKS_PER_SEC;
    printf( "the duration time is %f\n",duration );
    
    fclose(stream);
    exit(0);
}
在这里,LOOP=10K,最后打印出来的duration居然是41.2S,也就是4个通道同时采集时,每个通道频率只有两百多个字节。
(3)我以为是将读到的数据写入文本,可能花了一些时间,于是,我将写进文档部分的代码去掉,只是读,出来的时间39秒多,而将读的部分代码去掉,只是将数据写入文档,运行时间只需要0.57秒,那就证明了时间都花费在读的消耗上。
(4)然后,我改变驱动的预分频系数,启动信息中显示peripheral的频率是50.625MHz,原驱动中预分频系数是255,我将预分频系数改为20(数据手册说AD转换频率最大支持2.5MHz,采一次数据需要5个转换周期,因此最大支持单通道500K/S),但奇怪的是测试程序出来的duration只比原先的略小,为40.2S,原理上预分频系数变小了10倍多,采样时间应该发生很大的变化才对,为什么时间还是差不多呢?
(5)然后我又猜想,会不会是通道之间切换浪费了大量的时间,于是我将驱动改为每次都只读一个通道,驱动读程序如下:
static ssize_t s3c2440adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)  
{  
    unsigned long result = 0;  
    unsigned int data;
    
    spin_lock_irq(&s3c2440adc_dev.spinlock);
    
    iowrite32(START_ADC(s3c2440adc_dev.channel, s3c2440adc_dev.prescale), base_addr + S3C2410_ADCCON);    
       do {
           result = ioread32(base_addr + S3C2410_ADCCON);  /*read control register */  
       }while((unsigned int)result & 0x01);                /*confirm ADC start*/
    
       do {  
           result = ioread32(base_addr + S3C2410_ADCCON);  /*read control register*/  
       }while(!(((unsigned int)result) & 0x8000));         /*confirm ADC finished */

    data = ioread32(base_addr + S3C2410_ADCDAT0) & 0x3ff; /*save the 10 low bit*/  
       DPRINTK("AIN[%d] = %dmv\n", s3c2440adc_dev.channel, data*3300/1024);
    
    copy_to_user(buffer, &data, sizeof(data));      /*copy to user space*/  
       spin_unlock_irq(&s3c2440adc_dev.spinlock);
  
    return sizeof(data);
}
这样每次读一个通道的数据,出来的时间是10.31S,基本上是原来的四分之一秒,也就是说明了切换通道并没有浪费时间。但为什么采样频率会这么低了(不过采样到的数据确没有问题),比datasheet上所说的足足少了500倍!
请教一下大家,有没有做过相应的测试,是不是代码出了什么问题呢?
-
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
1楼  发表于: 2009-05-11 20:34
我只看datasheet上寄存器的定义,从来不相信上面所说的性能
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
级别: 侠客
UID: 4843
精华: 0
发帖: 102
金钱: 810 两
威望: 554 点
综合积分: 204 分
注册时间: 2009-03-31
最后登录: 2012-11-14
2楼  发表于: 2009-05-11 21:10
估计程序其它代码的执行占用了不少时间。
级别: 新手上路
UID: 31873
精华: 0
发帖: 6
金钱: 30 两
威望: 6 点
综合积分: 12 分
注册时间: 2010-11-06
最后登录: 2017-09-13
3楼  发表于: 2010-11-15 08:44
楼主解决没有啊     求办法
级别: 新手上路
UID: 8230
精华: 0
发帖: 12
金钱: 85 两
威望: 32 点
综合积分: 24 分
注册时间: 2009-08-15
最后登录: 2015-04-07
4楼  发表于: 2011-02-24 20:37
500k是可以的曾经用过,应该是寄存器设置问题
级别: 新手上路
UID: 42310
精华: 0
发帖: 9
金钱: 45 两
威望: 9 点
综合积分: 18 分
注册时间: 2011-04-07
最后登录: 2011-09-29
5楼  发表于: 2011-05-16 10:21
哪位大虾说500k 曾经用过?能分享一下驱动程序和上层测试程序吗?
小弟一直有一事不曾明白,我看过论坛里的关于adc的帖子,都是在底层设置ADCCON的0位手动开启,大家之所以出现连续读数是因为上层测试程序要么用for循环连续打开read函数要么用startTimer()连续打开,这和在底层设置预分频是毫无关系的,所以和采样率无关,顶多和代码执行时间有关。要在底层设置ADCCON设置【1】位为读取连续采样才有可能达到预计采样率。小弟是这么认为的,急求大虾指导。
s3c6410求助
加油!!
级别: 新手上路
UID: 49461
精华: 0
发帖: 2
金钱: 10 两
威望: 2 点
综合积分: 4 分
注册时间: 2011-06-12
最后登录: 2011-06-13
6楼  发表于: 2011-06-12 09:21
我想用S3C2440上面自带的ADC和滑动变阻器,连续转动滑动变阻器,然后将A/D值写入一个.txt文档里,读256个数就停止,再对这些数进行FFT变换。不知道怎么实现啊~大家帮帮忙~
级别: 新手上路
UID: 38131
精华: 0
发帖: 46
金钱: 230 两
威望: 46 点
综合积分: 92 分
注册时间: 2011-02-22
最后登录: 2015-08-05
7楼  发表于: 2013-03-03 20:43
..值得关注一下。。
学习
级别: 新手上路
UID: 85742
精华: 0
发帖: 25
金钱: 125 两
威望: 25 点
综合积分: 50 分
注册时间: 2013-01-08
最后登录: 2014-02-26
8楼  发表于: 2013-12-15 22:01
楼主精神值得学习