按照数据手册所说的,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倍!
请教一下大家,有没有做过相应的测试,是不是代码出了什么问题呢?