论文部分内容阅读
【摘要】实时操作系统QNX在工业领域中的应用越来越广泛,在高速数据采集方面QNX能最大限度地发挥实时操作系统的优势。本文介绍了QNX下PEX8311多路实时数据采集驱动的开发流程。详细阐述了驱动程序和应用程序之间利用共享内存方式完成进程通信的具体实现方法。最后,应用程序采用无锁环形缓存进行多路数据分发的实现。该方法也为其他操作系统实现多路实时数据采集驱动程序提供了一种全新的方法。
【关键词】QNX;PCI;共享内存;PEX8311;环形缓存
1.QNX多路实时采集卡
多路实时采集卡由基于PCI接口PEX8311和FPGA的连接组成。FPGA可以同时采集16路数据,每路数据采样率达到200k且每路可以单独设置采用率,因此最高采用率可以达到3.2M。PEX8311采用DMA工作模式中的demand方式将采集到的数据传输给运行在CPU上的QNX。驱动程序利用QNX实时性高的特点把采集到的数据实时存入到用户程序和驱动程序都可以访问的共享存储空间中。驱动进程和应用进程利用共享内存方式交换采集数据,避免了不必要的中间环节,节省了系统开销,增强了系统的实时性。
2.采集卡驱动设计
(1)资源管理器交互建立
资源管理器是QNX操作系统实现与用户程序交互数据的通道,应用程序中使用到的open(),close(),read(),write()等函数通过资源管理器接口映射到底层函数对硬件相应的操作。实现流程如下:
dispatch_create();函数实现用户程序与资源管理器交互所需要的通道
iofunc_func_init();该函数初始化应用程序功能函数层接口
iofunc_attr_init ();该函数初始化设备属性接口
resmgr_attach ();该函数向进程管理器注册,并使设备在命名空间中产生相应的名称。
(2)硬件资源管理和分配
和其他操作系统类似,QNX提供了丰富的PCI接口函数,可
以方便地注册、管理、使用PCI设备。具体流程如下:
ThreadCtl(); 设置线程对IO端口进行操作的权限
pci_attach(); 连接到QNX提供的PCI服务上
pci_attach_device();
devinit.port=inf.CpuBaseAddress[0]+(j*0x200);
devinit.intr=inf.Irq;
探测PCI设备并取得相应设备的资源,如设备首地址、中断等。
port_regbase=mmap_device_memory();
设备首地址映射到内存地址,访问设备寄存器用port_regbase+offset即可。
(3)中断注册
QNX提供了两种连接中断的接口:
Int InterruptAttachEvent(int intr,const struct sigevent *event,unsigned flags);
Int InterruptAttach(int intr,const struct sigevent*(*handler)(void*, int ), const void *area, int size, unsigned flags);
其中intr代表了中断向量号,在读取设备信息时已经被初始化在了info变量中。两个函数分别有自己的优缺点,在具体设计中应视具体情况而定。InterruptAttachEvent()函数用法简单,运行在用户空间,可以启动单独的线程去处理特定任务,优点是其应用接近linux操作系统可以方便程序移植,缺点是当中断发生时会引起上下文切换,从而使降低效率。对于InterruptAttach()函数而言,中断处理函数首先将原线程打断,然后判断中断是否需要建立新的线程处理此任务还是原线程处理此任务,所以对于不是自己要处理的中断,可以减少上下文切换的开支。本论文中采样InterruptAttach()函数处理中断,具体操作流程如图1所示。
图1 InterruptAttach处理过程
为了减少系统调度开销,采用图1的调度策略,即中断返回并没有创建新的线程来处理中断后的大量数据交换,而是在原线程中处理这些数据。
图2 共享内存示意图
(4)共享内存
驱动进程和应用进程采用共享内存的方式传递采集到的数据,PEX8311采用DMA方式,传输数据块中包含16路的采集数据,其每次传输的数据块长度为D_size,其中,由于每路的采集率可以设置为不同的采集率,所以传输数据块中包含各路的信息量可以是不同的,例如:第一路采样率为200k,第十路采样率为100k,那么数据块中包含第一路和第十路的数据量为2:1,图2表示共享内存的示意图,共享内存的大小为Shm_size=Shm_end–Shm_start,写指针W_ptr和读指针R_ptr沿着内存增加的方向移动,当到达共享内存底部时环回到顶端,读写指针在共享内存初始化时赋值为顶端地址,写指针W_ptr只能被中断程序修改,读指针只能被应用程序修改。所以在共享内存使用上不需要信号量,只需保证写指针W_ptr不超过读指针R_ptr即可。
当PEX8311用DMA每传输完一个数据块后产生一个中断,在中断服务程序中,除了做一些中断保护外,对共享内存的处理描述代码如下:
bufFlag = 1;
W_ptr += D_size;
if(W_ptr >= Shm_start + Shm_size)
【关键词】QNX;PCI;共享内存;PEX8311;环形缓存
1.QNX多路实时采集卡
多路实时采集卡由基于PCI接口PEX8311和FPGA的连接组成。FPGA可以同时采集16路数据,每路数据采样率达到200k且每路可以单独设置采用率,因此最高采用率可以达到3.2M。PEX8311采用DMA工作模式中的demand方式将采集到的数据传输给运行在CPU上的QNX。驱动程序利用QNX实时性高的特点把采集到的数据实时存入到用户程序和驱动程序都可以访问的共享存储空间中。驱动进程和应用进程利用共享内存方式交换采集数据,避免了不必要的中间环节,节省了系统开销,增强了系统的实时性。
2.采集卡驱动设计
(1)资源管理器交互建立
资源管理器是QNX操作系统实现与用户程序交互数据的通道,应用程序中使用到的open(),close(),read(),write()等函数通过资源管理器接口映射到底层函数对硬件相应的操作。实现流程如下:
dispatch_create();函数实现用户程序与资源管理器交互所需要的通道
iofunc_func_init();该函数初始化应用程序功能函数层接口
iofunc_attr_init ();该函数初始化设备属性接口
resmgr_attach ();该函数向进程管理器注册,并使设备在命名空间中产生相应的名称。
(2)硬件资源管理和分配
和其他操作系统类似,QNX提供了丰富的PCI接口函数,可
以方便地注册、管理、使用PCI设备。具体流程如下:
ThreadCtl(); 设置线程对IO端口进行操作的权限
pci_attach(); 连接到QNX提供的PCI服务上
pci_attach_device();
devinit.port=inf.CpuBaseAddress[0]+(j*0x200);
devinit.intr=inf.Irq;
探测PCI设备并取得相应设备的资源,如设备首地址、中断等。
port_regbase=mmap_device_memory();
设备首地址映射到内存地址,访问设备寄存器用port_regbase+offset即可。
(3)中断注册
QNX提供了两种连接中断的接口:
Int InterruptAttachEvent(int intr,const struct sigevent *event,unsigned flags);
Int InterruptAttach(int intr,const struct sigevent*(*handler)(void*, int ), const void *area, int size, unsigned flags);
其中intr代表了中断向量号,在读取设备信息时已经被初始化在了info变量中。两个函数分别有自己的优缺点,在具体设计中应视具体情况而定。InterruptAttachEvent()函数用法简单,运行在用户空间,可以启动单独的线程去处理特定任务,优点是其应用接近linux操作系统可以方便程序移植,缺点是当中断发生时会引起上下文切换,从而使降低效率。对于InterruptAttach()函数而言,中断处理函数首先将原线程打断,然后判断中断是否需要建立新的线程处理此任务还是原线程处理此任务,所以对于不是自己要处理的中断,可以减少上下文切换的开支。本论文中采样InterruptAttach()函数处理中断,具体操作流程如图1所示。
图1 InterruptAttach处理过程
为了减少系统调度开销,采用图1的调度策略,即中断返回并没有创建新的线程来处理中断后的大量数据交换,而是在原线程中处理这些数据。
图2 共享内存示意图
(4)共享内存
驱动进程和应用进程采用共享内存的方式传递采集到的数据,PEX8311采用DMA方式,传输数据块中包含16路的采集数据,其每次传输的数据块长度为D_size,其中,由于每路的采集率可以设置为不同的采集率,所以传输数据块中包含各路的信息量可以是不同的,例如:第一路采样率为200k,第十路采样率为100k,那么数据块中包含第一路和第十路的数据量为2:1,图2表示共享内存的示意图,共享内存的大小为Shm_size=Shm_end–Shm_start,写指针W_ptr和读指针R_ptr沿着内存增加的方向移动,当到达共享内存底部时环回到顶端,读写指针在共享内存初始化时赋值为顶端地址,写指针W_ptr只能被中断程序修改,读指针只能被应用程序修改。所以在共享内存使用上不需要信号量,只需保证写指针W_ptr不超过读指针R_ptr即可。
当PEX8311用DMA每传输完一个数据块后产生一个中断,在中断服务程序中,除了做一些中断保护外,对共享内存的处理描述代码如下:
bufFlag = 1;
W_ptr += D_size;
if(W_ptr >= Shm_start + Shm_size)