之前我发贴问过,s3c2440自带的AD采样频率到底能够达到多少?因为我自己编写的驱动,测试出来采样频率只有1K左右。后来在裸机上测试,在ADS开发环境下测试AD采样频率其实可以在100K以上的,后来看了一下资料,说是驱动里面的copy to user()函数需要在内核空间与用户空间之间来回拷贝,花费了大量时间,要提高采样频率,一个可行的方法是采用mmap。然后我再AD驱动里面增加mmap接口,代码如下:
static int s3c2440adc_mmap(struct file *filp, struct vm_area_struct *vma)
{
if (remap_pfn_range(vma, vma->vm_start, ADC_CTL_BASE, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
printk("the physis address is %dl\n", vma->vm_pgoff);
return 0;
}
其中ADC_CTL_BASE为0x58000000,为ADCCON的物理地址;
然后在用户程序里面调用mmap,代码如下:
if( (fd = open("/dev/s3c2440_adc", O_RDWR, 0666)) < 0 )
{
perror("open:");
exit(1);
}
map_base = mmap(NULL,0x14,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
for (i=0;i<LOOP;i++)
{
ADCCON = (volatile int*)(map_base + S3C2410_ADCCON);
ADCDATA = (volatile int*)(map_base + S3C2410_ADCDAT0);
*ADCCON = START_ADC(0,255);
do
{
result = *ADCCON;
}
while((unsigned int)result & 0x01);
do
{
result = *ADCCON;
}
while(!(((unsigned int)result) & 0x8000));
data = (*ADCDATA) & 0x3ff;
printf("AIN=%dmv\n",data*3300/1024);
}
程序在while(!(((unsigned int)result) & 0x8000));处死循环,无法继续,原因应该是地址映射有误,用户程序根本没有读写到AD寄存器;mmap函数的写法出现了问题,不知道是哪里出现了问题?
后来,我又改用映射/dev/mem文件,用户程序可以读取AD寄存器,代码如下:
if((fd=open("/dev/mem",O_RDWR|O_SYNC))<0)
{
perror("open:");
exit(1);
}
map_base = mmap(NULL,0x14,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x58000000);
for (i=0;i<LOOP;i++)
{
ADCCON = (volatile int*)(map_base + S3C2410_ADCCON);
ADCDATA = (volatile int*)(map_base + S3C2410_ADCDAT0);
*ADCCON = START_ADC(0,255);
do
{
result = *ADCCON;
}
while((unsigned int)result & 0x01);
do
{
result = *ADCCON;
}
while(!(((unsigned int)result) & 0x8000));
data = (*ADCDATA) & 0x3ff;
printf("AIN=%dmv\n",data*3300/1024);
}
此时,能够正确读到AD的寄存器了,并打印出AD值,但有两个问题,一是采样速度依然没有上去,速度还不足1K,把物理地址映射到用户空间,采样频率应该有所提高才对,为什么一直上不去呢?二是部分数据有问题,大概4到5个数据之后就会有一个错误数据,估计是触摸屏驱动的干扰;
明明芯片本身可以达到100K以上的采样频率,在ADS环境下可以实现,怎么样才能在linux环境下实现呢?