微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 基于嵌入式Linux 系统的高速设备驱动程序实现

基于嵌入式Linux 系统的高速设备驱动程序实现

时间:03-24 来源:互联网 点击:

1 Linux驱动程序的研究现状

嵌入式系统已越来越广泛应用于通信领域。而Linux操作系统因为其内核小、开源以及可灵活裁剪等优点,在嵌人式设备中得到了广泛的应用。下面首先介绍嵌入式linux系统驱动程序的一般结构。

1.1 传统的驱动程序结构简介

Linux操作系统最基本的组成部分包括资源管理器、调度程序、介于硬件和应用软件之间的接口、网络管理器和文档系统管理器。本文主要阐述介于硬件和应用软件之间的接口——设备驱动程序的实现。

对于多数字符设备而言,其功能主要是数据的传输。驱动程序操作的一般流程是:当read()函数被系统调用时,首先对中断寄存器进行配置,并开中断,并进入中断等待函数。此时系统会调用schedule()函数,进行其他进程的执行。一旦有中断的产生,则根据中断寄存器判断是否为设备的读寄存器中断,即是否有数据到达。若是,则将该数据从寄存器所在的地址读入,并送至相应的内存。

1.2 传统驱动程序结构存在的问题

当设备的数据量足够大时,中断将会十分的频繁,而中断服务程序将会被反复的调用,这会使得系统长时间的处于核心态中,而无法相应其他进程的请求,且极大地增加了CPU 的负担。这在高速率、大吞吐量数据传输的应用中,是无法容忍的。

因此,我们不得不考虑针对现有的驱动程序的数据传输程序结构进行改进,以适应高速率的数据传输的需要。

2 Linux高速设备驱动的实现

2.1 采用DMA方式的驱动程序

首先使用DMA 的数据传输方式对原有的结构进行改进。

DMA(direct memory access)是直接存储器访问的意思,它可以让I/O设备上的数据直接与系统的内存进行通信访问,而不需要处理器的参与,大大降低了CPU的负荷,对于需要进行除数据传输外其他一些数据处理的嵌入式处理器是很有帮助的。程序执行步骤如下:

1. 配置寄存器,指示硬件开始传输数据;开中断,进程进入睡眠等待;

2. 硬件将数据写入DMA存储器,完成后产生中断;

3. 唤醒进程,中断服务程序进行中断的处理(如将数据传输到用户态内存)。

操作流程如图1所示。这一结构的驱动程序,相对于不使用DMA方式而言,能够很大降低CPU的占用率。但是,该驱动程序结构也有个明显的缺陷:当硬件进行DMA传输时,该进程进入了睡眠等待,只有等到中断之后,才能唤醒进程,这也意味着在DMA 的过程中,我们无法对该进程的其他线程做任何操作。换句话说,其他的线程也会被阻塞住。当数据量很大且对这些读取的数据处理复杂度很高时,很可能会造成以下的问题:在长时间的用户态上数据处理期间,有新的数据到达硬件,而核心态无法及时进行下一次的DMA读取操作,数据因此而丢失。这将是很严重的。特别,如果我们使用wait_for_interrupt ()函数进行中断的等待,甚至会使整个系统被阻塞,这对于多线程编程是不可接受的。

图1 DMA操作的驱动流程图

图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()继续读取的话,显然会造成数据的错误,因此采用信号量是必须的。当信号

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top