首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

基于ARM芯片的高速数据传输的设备驱动实现方案(2)

基于ARM芯片的高速数据传输的设备驱动实现方案(2)

2.2 驱动程序的进一步改进
基于以上几点,为了能够在Linux中实现高速设备的数据通信,对驱动程序结构作出进一步改进的设计。
在设备驱动程序的实现上,采用生产者-消费者模型与循环缓存相结合的结构。将从硬件设备到核心态内存的DMA传输看作生产者,而从核心态内存搬移到用户态的数据传输过程看作消费者;同时为DMA传输分配的核心态内存采用循环链的结构。
在驱动程序中,将read()函数作为设备读操作的主函数,实现消费者的功能。当read()每次被调用时,从DMA缓存链中读取当前指针所指的内存数据,通过copy_to_user()函数,将数据传出核心态,复制到用户态内存,以便后续的数据处理。
而在驱动程序中,Irq_service()函数实现生产者的功能,当有中断产生后,系统进入Irq_service(),表明一次DMA的传输结束,并且在Irq_service()中,设置下一次DMA传输的参数,包括DMA传输的数据大小、DMA传输的目标内存。之后,调用interrupt_sleep_on()函数,使得系统进入进程调度,等待下一次DMA的操作完成。一旦完成,就会产生中断并重复以上的过程。因此,作为生产者的Irq_service()函数,只要初始化后,就会在中断的触发下不断被调用。换句话说,只要有数据到达硬件设备,就会不断将其通过DMA的方式读入到核心态的循环缓存中。我们可以将DMA缓存在允许的情况下,开的大一些,因为当接收的数据呈现一种突发的状态时,较小的缓冲池可能由于不能及时地将数据取走而溢出,造成数据的丢失。
与此同时,还有个问题必须注意,即当read()函数将缓存池中的数据都搬完之后,仍然没有DMA的输入。此时,read()继续读取的话,显然会造成数据的错误,因此采用信号量是必须的。当信号量表明,DMA的缓存已空时,若应用程序调用read()进行读数据的话,将不做任何操作,并返回已读数据量为0。当信号量表明DMA的缓存为满时,将DMA读入的数据丢弃,并设置buff_full = 0。
除此以外,我们还必须对Linux驱动进行以下步骤的操作:设备的注册和注销、设备的打开和释放。通过register_chrdev()函数向系统注册设备的设备号,在设备使用结束后,可以使用unregister_chrdev()从内核注销设备,释放主设备号。在设备注册之后,由open()函数打开设备,close()释放设备。在驱动的初始化中,需要对DMA进行首次设置,以及缓存的分配。我们可以调用 get_free_pages()函数进行内存页面的分配,它会给DMA分配内存中连续的页面,这对于DMA是必须的,因为DMA操作的物理地址是连续的。在内存分配之后,我们进行中断的配置,通过调用函数request_irq()。接着调用request_dma() 函数对DMA进行申请注册。
最后,有一点不得不引起我们的重视,即DMA一致性问题。DMA一致性的问题是指当进行数据DMA方式读入时,由于没有经过CPU的处理,因此CPU的CACHE会认为该地址的内存没有被重写过,而实际该内存所存储的数据已被改变;当CPU需要处理该内存的数据时,由于认为数据没有改变,会直接调用CACHE内的数据,造成数据错误,一般表现为数据的重复。在实际操作中,我们可以通过禁用该内存的CACHE功能,来避免错误。在新版的Linux内核中提供dma_alloc_coherent()和dma_free_coherent()函数进行DMA一致性内存的分配。
以上就是我们针对高速设备驱动改进的程序代码结构。该驱动程序结构通过将核心态的DMA操作与数据到拷贝以及用户态上数据的处理独立开来,依靠信号量进行相互的制约,可以有效的避免高速设备DMA操作的频繁性和大数据量处理的较长时间之间的矛盾。驱动程序的流程如图2所示。
3 应用实例
下面我们以视频会议系统为例,介绍基于以上结构的高速设备驱动程序的实现。
在视频会议系统中,AT91RM9200通过SPI接口与TI DM642 DSP芯片的McBSP接口相连进行图像数据的传输。由于数据吞吐量很大,采用一般结构甚至是一般的DMA结构的驱动程序都无法满足数据的接收要求,造成数据无法实时的数据处理。我们针对该系统的特点,对驱动程序按照以上结构作出改进,不但大大减轻了ARM处理器的负荷,同时能够有效的进行大数据量的传输和处理。
表1 驱动程序改进前后对比表
继承事业,薪火相传
返回列表