这几天一直在做2440的AD采样,实际上这个很早以前就做了一部分了,不多之前采集的数据比较少,都在驱动里解决了,但是现在要采集大量的数据,由于在驱动程序中无法用数组保存大量数据(好像我做的时候,数组最大不能大于1000,不知道是不是我做错了,要是我做错了,希望可以有人提醒我),因此希望边在驱动里一边采集数据一边传回到应用程序中去,而考虑到要保证采样速率,因此不能使用copy_to_user(),最后决定使用mmap().
说起使用mmap,还是以前做AD采样的时候一个网友告诉我的,并且很无私的把他的程序给了我,在这里感谢网名“任意球”的朋友,我的程序基本上来自他的代码。
说起2440的AD采样,手册上写的最高是500K,但是我最高只做到160K,并且这个时候还非常的不稳定,大概在100K左右的时候AD采样才比较稳定,难道又是因为不是裸机的原因?
mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。
基于文件的映射,在mmap和munmap执行过程的任何时刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情况下没有得到更新,首次对映射区的第一个页索引时会更新该字段的值。用PROT_WRITE 和 MAP_SHARED标志建立起来的文件映射,其st_ctime 和 st_mtime
在对映射区写入之后,但在msync()通过MS_SYNC 和 MS_ASYNC两个标志调用之前会被更新。
用法:
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags,int fd, off_t offset);
int munmap(void *start, size_t length);
各参数的含义可以参考http://baike.baidu.com/view/1499209.htm
因为我是要在AD中使用mmap,所有首先要写AD驱动,这里的AD驱动和不用mmap的写法是一样的,但是要在驱动里定义下面的mmap函数(和一般的open,read是一样的):
static int s3c2440adc_mmap(struct file *filp, struct vm_area_struct *vma)
{
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_pgoff = ADC_CTL_BASE >> PAGE_SHIFT;
if (remap_pfn_range(vma, vma->vm_start,vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
printk("s3c2440 VMA open, virt %lx, phy %lx\n", vma->vm_start, vma->vm_pgoff<<PAGE_SHIFT);
return 0;
}
接下来就是在自己的QT程序里加上mmap代码:
#define S3C2410_ADCCON 0x00
#define S3C2410_ADCDAT0 0x0C
#define S3C2410_ADCCON_PRSCEN (1<<14)
#define S3C2410_ADCCON_PRSCVL(x) (((x)&0xFF)<<6)
#define S3C2410_ADCCON_SELMUX(x) (((x)&0x7)<<3)
#define S3C2410_ADCCON_ENABLE_START (1<<0)
#define START_ADC(ch, prescale) S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(prescale) \
| S3C2410_ADCCON_SELMUX(ch) | S3C2410_ADCCON_ENABLE_START
unsigned long int i;
void *map_base;
volatile unsigned int *ADCCON;
volatile unsigned int *ADCDATA;
volatile unsigned int result;
unsigned int da
AD_fd = open("/dev/adc",O_RDWR);
map_base = mmap(0,0x20,PROT_READ|PROT_WRITE,MAP_SHARED,AD_fd,0);//映射AD设备文件
ADCCON = ((volatile unsigned int *)map_base+S3C2410_ADCCON); //映射AD控制寄存器
ADCDATA = ((volatile unsigned int *)map_base + 3);//映射数据寄存器
注意这里的“+3”,若是不在QT编译,而是直接使用C语言写的话,这里应该是“+S3C2410_ADCDAT0”,也就是“+12”。至于原因就不说了
FILE *stream;//数据存贮文件
stream = fopen("da
for (i=0;i<LOOP;i++)
{
*ADCCON = 0x4501;
这里本应该是*ADCCON = START_ADC(0,20);写成,并且在C语言这样写编译运行都没有问题,但是在QT里,这部操作后寄存器里的值不对,是什么原因暂时没有去追寻,我干脆把该写的值直接赋给寄存器好了
do
{
result = (*ADCCON);
}
while(result & 0x01);
do//判断AD转换是否完成
{
result = *ADCCON;
}
while(!(result & 0x8000));
da
fprintf(stream,"%d\n",da
}
好了,添加完这些语句,就可以在不影响采样速率的情况下进行AD采样中的实时传输了。