BLACKfin的设备驱动

1、概述

     Blackfin处理器的设备驱动程序模型采用了标准化的API,也就是说,所有处理器
和驱动程序均使用相同的API。对开发人员而言,只要一次性掌握这些API,就能一
劳永逸。所有驱动程序均以完全相同的方式作用。这些API也是可扩展的,允许用
户根据需要添加命令、事件和返回码等,其目的是支持绝大多数器件。目前,我们
可以支持的器件包括SPORT串行端口、SPI、PPI、TWI和诸如以太网端口和USB端口
等高级器件。当然,凡事都有例外。虽然我们的驱动程序模型旨在支持绝大多数器
件,但是也会有某些器件不适用于这种模型。不过,这个模型非常适用于我们范围
广泛、种类繁多的设备驱动程序。

 

      我们的工作就是根据官方的设备驱动程序模型来实现自己所需要的设备驱动,

 

#include <services/services.h>  // system service includes
#include <drivers/adi_dev.h>  // device manager includes
#include <drivers/uart/adi_uart.h>  // UART device driver includes

 

 

2、使用片上驱动程序库

      在连接器文件夹中,应当包含适当的系统服务程序库,即libssl库;以及适当的片
上器件的设备驱动程序库,所有此类库均以“libdrv”为前缀。稍后我将演示如何
选择和使用库。这里,我要强烈推荐用户选择连接器属性设置界面上提供的“代码
消除选项”,它会将某个特定应用中毫无用处的代码全部删除,从而大大缩短代码
长度。例如,如果我们仅使用了某个设备驱动程序中的A、B、C函数,那么,该选
项将删除这个设备驱动程序中未使用的D、E和F函数。这个选项能够为嵌入式应用
节省珍贵的代码存储空间。

 

      片上驱动程序库分两种,一种是调试版,一种是发布版。强烈建议用户在项目

开始时,采用调试版驱动程序库。在调试版中,所有编译器优化选项均已禁用;其中包
含了符号信息;并且允许程序员逐行查看源代码,弄清这些代码的作用。此外,调

试版驱动程序库将执行大量的参数检查,因此,如果应用提供的参数中包含错误的
值,调试版库将尽全力检查出这些错误,并返回相应的错误代码。
 
用户在开始时应当采用这种库;范例、演示等通常也采用调试版库来进行演示。
 
当用户认为驱动程序的运行情况达到要求时,可以更换为发布版片上驱动程序库。
在发布版库中,所有编译器优化选项均已启用,因此,应用性能将大幅提升。不过
发布版库中不包括符号信息,因此,程序员很难通过查看源代码,随时了解应用的
执行情况。此外,发布版库只会执行少量的参数检查,因为我们认为,当用户选择
采用发布版库时,很清楚自己在做什么,所以我们也可以卸下繁重的参数检查任
务。用户在项目完成时,才需要使用发布版库。也就是说,利用调试版库进行产品
开发,当应用达到性能目标后,再切换至发布版库。

 

如何选择库?

设备驱动程序采用了与VisualDSP相同的命名约定,所有片上外设的
设备驱动程序库的前缀均为“LIBDRV”,表示面向设备驱动程序的库。紧接着的三
个字符是表明该库适用的处理器的变量。例如,如果紧接着的三个变量为532,则
表示该库适用于BF531、BF532和BF533 Blackfin处理器,变量534则表示适用于
BF534、BF536和BF537处理器,变量561表示适用于BF561双核处理器。
在这个例子
中,省略了再接下来的三个字符。如果驱动程序要求操作系统提供特殊支持,那
么,这三个字符将表明适用于该特定驱动程序的操作系统。目前我们提供的所有设
备驱动程序库都不要求RTOS提供任何特殊支持。所以,在本例中,“bbb”三个字
符为空。我们提供的设备驱动程序既可支持独立式系统,又可用于VDK操作系统。
 
再后面的两个字符用于表明该库的任何特定条件,可以是“d”或“y”或者这两个
字母的组合。
如果这里只有一个“d”字母,则表示该库为调试版;没有“d”字母
则表示该库为发布版;字母“y”则表示该库是适用于芯片异常情况的临时解决方
案。如果库的名称中包含字母“y”,则表示该库包含了适用于各种修订版芯片的
临时解决方案。“dy”字母组合则表示该库是调试版,并且包含了所有的临时解决
方案。如果为空则表示该库不是调试版,也就是说,是发布版库,并且其中不包括
任何临时解决方案。

 

头文件

$/Blackfin/include/drivers

源文件

$/Analog Devices/VisualDSP 5.0/Blackfin/lib/src

库文件

$/Blackfin/lib

例子

$:/Blackfin/Examples/ADSP-BF537 EZ-Kit Lite/Drivers

 

设计要素

1、我们的设备驱动程序均不使用动态存储器,所有驱动程序的存储空间都是静态分配
的。

2、利用句柄来进行通信或者标识出驱动程序模型中的各个组件。当一个设备驱动
程序打开时,它将向应用传递一个句柄。设备句柄其实就是一个独一无二的身份标识,

表明了保存管理特定设备驱动程序所需的所有信息的存储地址。

3、几乎所有的API函数都会返回一个结果代码。虽然有两个显而易见的例外情况,但
是总的来讲所有函数都会返回一个结果代码。零值表示成功,也就是说,如果设备
驱动程序,确切说是设备驱动程序API调用,返回了一个零值,则表示该调用成功
完成任务。如果应用收到了一个非零值,那么,只要查阅“services.h”文件,就能快速查明
发生了什么错误。这个文件中包含了一系列独一无二的数字,分别是各个系统服务
程序或设备驱动程序将反馈给应用的返回码。然后,再在相应的“.h”文件中查询
该特定值的含义,就能了解该非零值代表了什么错误或信息。

4、应用必须按照特定的步骤执行初始化

      首先要初始化中断管理器,然后初始化EBIU,即外部总线接口单元,然后依次
是电源管理、端口控制、延迟回调、DMA管理器、标志控制、定时器等服务程序,
最后是设备管理器。无需使用的服务程序不用进行初始化。只要按照这个特定顺序
正确地完成所有的初始化,就不会发生任何冲突,应用不会在未完成初始化的情况
下试图调用任何服务程序或设备驱动程序。

5、应用也必须遵循特定的终止顺序。和初始化正好相反

6、关于RTOS的考虑

服务程序或驱动程序与RTOS之间的所有交互作用,均以独立的代码段形式,包含在系统服务程序中。

而被调用的设备驱动程序自身则不具备任何相关性,不论是在RTOS环境下,还是在独立式环境下,

设备驱动程序的API都是完全相同的,所以,当应用在独立式环境和RTOS环境之间进行切换时,无
需对函数调用进行任何更改。

 

6、设备驱动程序API

设备驱动程序向应用程序提供6个接口 以及 设备驱动程序用于通知应用的应用回调函数。

打开 关闭 控制 读 写  读写控制顺序

 

例如当应用想要使用某个驱动程序时,它首先要调用“adi_dev_Open()”函数。

如果应用决定不再需要使用该设备驱动程序,那么,它将调用“adi_dev_Close()”函数。

 

“adi_dev_Close()”函数的功能是有序地关闭和释放应用使用的系统服务程序和硬件。如果应用为传入数
据流或者双向数据流打开了某个设备驱动程序,那么,它将通过
“adi_dev_Read()”函数,从器件读取数据。以连接至摄像头的PPI为例,读取数
据过程就是利用“adi_dev_Read()”函数,通过PPI,读取摄像头捕捉到的数据。
反过来,我们也提供了写函数。写函数的作用是通过设备驱动程序,发送数据。同
样也以刚才的PPI为例,如果要将利用摄像头录制好的视频数据发送至显示器,那
么,可以利用“adi_dev_Write()”函数,通过PPI,将该数据发送至显示器。

 

另外,还有一个“adi_dev_Sequential IO()”函数,允许应用指定特定的读写顺
序。在没有调用“Sequential IO”函数的情况下,应用会尽快完成读操作或写操
作,但两者之间并未实现同步。以DSL调制解调器为例,其下载速度通常比上传速
度更快,也就是说,其读操作的速度比写操作快。
 
对于要求以特定顺序执行读操作和写操作的器件,应用就可以利用
“adi_dev_Sequential IO()”函数,实现以特定的顺序,先执行一些读操作,再
执行一些操作等等。
 
最后一个函数是“adi_dev_Control()”。过去,在版本较早的设备驱动程序中,
这个函数有点像IOCTL或IOCTL函数。这个函数通常用于设置或检测设备驱动程序的
某个参数。我将在稍后举例说明,如何使用“adi_dev_Control()”函数,设置
UART的波特率、停止位等等参数。

 

应用只需要借助这6个函数,就能向设备驱动程序传递信息。而当设备驱动程序需
要向应用反馈信息时,则要通过系统服务程序提供的事件机制和回调机制,与应用
进行异步通信。当设备驱动程序需要通知应用发生了某个事件时,例如缓冲区已处
理完毕或者器件发生错误等等,那么,设备驱动程序将调用应用的回调函数。这就
是应用和设备驱动程序之间的所有API。这6个函数,以及设备驱动程序用于通知应
用的应用回调函数。

 

7、与系统服务程序之间的交互作用

设备驱动程序基于系统服务程序。得益于此,创建设备驱动程序变得轻而易举,同时,

我们也能利用系统服务程序有效管理Blackfin处理器的各种资源,例如DMA。

PPI设备驱动程序在需要通过DMA传输数据时,将调用DMA管理器,打开DMA通道、

提供描述符等等;

 

数据传输

 

简单链接

在简单链接中,缓冲区排成队列等待设备驱动程序处理。

应用可以将任何或全部无缓冲区标记为生成回调,也可以不标记任何缓冲区

 

环回链接

在环回链接中,当设备驱动程序处理完最后一个缓冲区后,

它将自动返回第一个缓冲区,并重新开始新一轮处理。

只有在数据流停止
后,才能向设备驱动程序提供这种采用环回链接的缓冲区。这一点与直接的简单链
接不同。我们刚才已经说过,利用简单链接,应用可以随时随地向设备驱动程序提
供缓冲区。而采用环回链接,则只能在数据流停止后,向设备驱动程序提供缓冲
区。这一点非常重要,因为如果应用正在处理一个缓冲区环回链接,同时又想添加
一个缓冲区,那么,应该将这个缓冲区添加在环中的哪个位置?所以,我们要限制
应用添加缓冲区,只能等该器件上运行的数据流停止后,再添加缓冲区。

一般而言,这种限制不会造成问题。应用通常只在进行初始化时才需要使用环回链
接,应用将向设备驱动程序提供一组需要进行处理的缓冲区,然后,就不再需要为
其重新提供缓冲区。在获得这些缓冲区后,设备驱动程序将循环往复地不断处理这
些缓冲区。这个过程对系统而言,几乎不需要任何开销,应用不再需要调用
“adi_dev_Read()”或“adi_dev_Write()”函数,设备驱动程序将自动地连续不
断地反复处理这些缓冲区。如果设备驱动程序的任务是输出数据,那么,这些缓冲
区将源源不断地向它提供数据;如果设备驱动程序的任务是从器件读取数据,那
么,它可以将数据保存到这些缓冲区中,而永远不必担心会溢出。通过巧妙地利用
回调,应用可以有效地管理这些缓冲区。
 

顺序链接

 

 顺序链接与我们前面讨论过的简单链接很相似,只不
过顺序链接没有为读和写操作分别提供一个排队,而是将所有的缓冲区都放到一个
排队中。在顺序链接中,缓冲区中包含一个字段,表明其传输方向是传入还是传
出。

 

环回顺序链接

 

顺序链接也可以实现环回。这和简单的环回链接有些相似,只不过形成环回的是一
个包含传入缓冲区和传出缓冲区的顺序链接。与普通环回一样,设备驱动程序处理
完链接中的最后一个缓冲区后,将自动返回第一个缓冲区,进行新一轮处理。

 

循环数据流

 

循环数据流方法是我们提供的最后一种数据流方法,这种方法正好对应于DMA的自
动缓冲功能。在使用循环数据流方法时,应用将向设备驱动程序提供一个被划分成
许多子块或子缓冲区的缓冲区。就好像是将一个连续的数据块划分为许多小块,如
幻灯片左侧的这些子缓冲区所示。在使用循环数据流方法时,必须满足一定的限制
条件。Blackfin处理器仅实现了16位宽的循环缓冲区,也就是说,循环缓冲区的长
度不能超过64 Kb。不过,这是一种向设备驱动程序提供数据的非常简单、高效的
方法。

 

选择数据流方法

 

如果应用需要处理的是基于分组
的数据流,通常是突发数据流,如以太网端口、UART和USB等,则应该采用直接的
简单链接。环回链接,适用于稳定的数据流,通常是视频流或音频流。在使用环回
链接时,应用还需要使用数据流指令,以避免出现卡啦声和朴朴声等噪声或信号瞬
时中断,同时还能确保向从器件读取数据的驱动程序提供用于保存数据的缓冲区,
或者向通过器件发送数据的驱动程序源源不断地提供缓冲区。不难想象,在处理音
频流或视频流时,最好的选择就是采用环回链接数据流方法。实现/未实现环回的
顺序链接。这种数据流方法通常用于半双工串行器件,例如,我前面提到过的符合
I2C规范的TWI端口就采用了顺序IO。通过顺序链接,应用可以实现按照预先规定的
特定顺序执行读、写操作。

 

程序次序

 

打开设备驱动程序,配置参数,向其提供缓冲区,发起数据流,当设备驱动程序处
理完毕这些缓冲区后,将向应用发出通知,然后,应用将选择向其提供其他缓冲
区。下面这个过程将周而复始、不断执行。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值