【发布时间】:2013-03-25 09:39:02
【问题描述】:
我正在开发一种需要 DMA 操作才能将大数据帧传输到主存储器的采集设备。现在我假设目标是一个连续的内存区域,所以我在引导时分配它(比如 1 MB),如ldd2-ch13 的“自己动手分配”部分所述。然后驱动程序可以通过调用 ioremap() 访问该区域。
当前系统的工作方式如下:
内存映射控制寄存器使用户空间应用程序能够启动/停止设备
启动后,设备开始以约 8MB/s 的速度连续(循环)将采集的数据传输到分配的内存区域。
- 保留的内存区域大小为两帧,以便使用double-buffering technique。
- 传输完整帧后,设备会触发中断。
我开发了一个简单的 char 驱动程序,它提供了一个阻塞的 read() 函数,这样用户空间就可以在每次收到中断时读取一个新的数据帧。
在运行了一些测试之后,我意识到用户空间应用程序在运行以下代码时会丢失一些帧:
for(i=0;i<NUM_FRAMES;i++) {
read(dev_d,buf,FRAME_SIZE);/*Read frame*/
for(j=0;j<FRAME_SIZE;j++) /*File dump*/
fprintf(fp,"%d",buf[j]);
fprintf(fp,"\n");
}
我怀疑应用程序的进程在两次后续读取之间处于休眠状态,从而允许设备重写应该已经读取的内存位置。
由于我没有内核开发经验,我想知道如何为此类设备实现驱动程序以确保同步的正确方法。基本上我正在尝试为实时采集设备实现一个简单的共享内存通信,我需要保证操作系统能够读取所有采集的数据帧。
【问题讨论】:
-
您写道数据速率约为 8MB/s,但帧大小和帧速率是多少?您的
read()速率必须与该帧速率一样快。您的“文件转储”循环效率不高。这是一个经典的实时问题:您必须以比到达速度更快的速度处理数据,或者缓冲该数据。网络接口增加了对 N 缓冲区或环的双缓冲。也许您还必须使用多线程,即始终有一个待处理的read()请求的专用输入线程。 -
您能否详细说明
splice()解决方案?这是让驱动程序直接写入特定文件而无需任何用户空间干预的某种方式吗? -
是的,完全正确。如果你想传输到一个文件,那么你打开你的acquisition设备和一个文件。您可以控制读取/写入的数据量,因此如果您知道块大小,则可以插入/注释自己的框架。没有从内核到用户到内核内存的复制。数据将直接从驱动程序传输到文件。文件可以是串口等其他设备
-
" 我认为问题在于用户空间进程可能已进入睡眠状态" -- 是的,这是一个问题,因为您有 513 个系统调用执行 I /O 在每个
read()之间。您所犯的“新手错误” 并未意识到执行低效 I/O 所消耗的周期。尝试fprintf()ing 仅前 4 个字节,看看是否仍有跳帧。然后评估需要进行什么样的实际处理,以及每帧可能需要多长时间。 在担心实施细节之前,请确保您有一个可行的顶层方案或全局。 -
fprintf()仅用于调试,还是您个人将实时查看这些数据?为什么不能将这些帧中的每一帧写成一个块 512 字节的原始二进制数据,而不是将每个字节 实时转换为十进制?这就是我所说的“大图”:如果您要保存帧,只需将其保存为原始文件,然后将其转换为离线或低优先级的后台进程。 “你知道吗……”——我不得不承认我对splice()一无所知。 "读一帧..." -- 这是你的驱动程序;您告诉我们如何/何时满足读取请求!
标签: c linux linux-kernel operating-system linux-device-driver