设备驱动在AWbus-lite中驱动设备正常工作

ZLG致远电子 2018-06-12 09:06 次阅读

本文导读

一个硬件设备正常工作的前提是系统中存在对应的驱动。AWorks提供了大量常用硬件设备的驱动,用户通常不需要开发驱动。为了使读者对设备驱动有一定的理解,本文介绍了设备驱动相关的基础概念,展示了设备驱动在AWbus-lite中驱动设备正常工作的原理。

本文为《面向AWorks框架和接口的编程(上)》第三部分软件篇——第13章——第3小节:设备驱动。

13.3  设备驱动

上面讨论了如何通过Method机制获得具体设备提供的LED服务,系统能够从某一设备获得LED服务的前提是,该硬件具有提供LED服务的能力。一个硬件设备相关的功能,需要通过设备驱动才能体现出来,进而为系统服务。为此,在LED设备驱动中,需要实现一个LED服务,以供上层获取。

13.3.1  基础驱动信息

AWBus-lite对设备驱动进行了高度的抽象,定义了驱动的基本结构,一个设备驱动相关的信息统一使用一个结构体常量进行描述。其中包含了诸多信息,比如:驱动名、驱动初始化入口、驱动提供的Method对象等。开发驱动的核心即完成一个结构体常量的定义。

不同总线下的设备驱动需要提供的驱动信息可能不同,对应的驱动信息类型也就不同。但无论什么总线下的设备驱动,其驱动信息类型均是从基础驱动信息类型派生而来的,也就是说,无论什么设备驱动,都需要提供AWBus-lite定义的基础驱动信息,即使需要扩展其它驱动信息,也只能在基础驱动信息的基础上进行扩展。

由于所有设备驱动均会提供基础驱动信息,因此,AWBus-lite可以方便的对所有驱动进行统一的管理。基础驱动信息的类型为struct awbl_drvinfo,具体定义详见程序清单13.19。

程序清单13.19 struct awbl_drvinfo类型定义(awbl_lite.h)

要实现一个驱动,需要定义一个该类型结构体,并完成各个成员的赋值。下面,首先对各个成员的含义作简要介绍。

1.  AWBus-lite版本号

awb_ver表示该驱动支持的AWBus-lite版本号,当前AWBus-lite的版本号为:AWBL_VER_1,其在awbus_lite.h文件中定义如下:

在新开发驱动时,将awb_ver设置为AWBL_VER_1即可。

2.  总线ID

bus_id表示总线ID,该值由总线类型和设备类型两部分组成。总线类型与设备描述中的总线类型概念一致,其表示了该驱动所驱动的设备挂在何种总线上,常见总线类型详见表12.1。实际中,在进行驱动和设备的匹配操作时,只有当驱动信息中的总线类型与设备描述中的总线类型一致时,才会继续判定设备名和驱动名是否一致,只有当两者完全相同时,驱动和设备才会判定为匹配。设备类型表明该驱动对应的设备是普通设备还是特殊设备(总线控制器),若是总线控制器,则其驱动的设备又会扩展出另外一条总线。设备类型可能的取值详见表13.4。

表13.4 设备类型宏定义

bus_id的值为总线类型和设备类型的或值(C语言的“|”运算符)。特别地,若一个设备是普通设备,则设备类型可以省略,即

AWBL_DEVID_DEVICE宏可以被省略。

例如,对于使用GPIO直接控制的LED设备驱动,GPIO是一种片内外设,当前并没有将GPIO视为一种总线,在AWBus-lite中,由GPIO直接驱动的设备也视为挂在PLB上的一种设备。因而总线类型为:AWBL_BUSID_PLB,同时,LED设备只是一个普通设备,并非总线控制器,因而设备类型为AWBL_DEVID_DEVICE。bus_id的值即为:

AWBL_BUSID_PLB | AWBL_DEVID_DEVICE

(或省略AWBL_DEVID_DEVICE,直接设定为

AWBL_BUSID_PLB)。

对于i.MX28x的I²C驱动,其驱动的设备是片内外设,挂在PLB总线上,因而总线类型为:AWBL_BUSID_PLB。同时,i.MX28x 中的I²C设备又是一种总线控制器,可以扩展出一条I²C总线,因而设备类型为:

AWBL_DEVID_BUSCTRL。bus_id的值即为:

AWBL_BUSID_PLB | AWBL_DEVID_BUSCTRL。

对于PCF85063设备驱动,其驱动的设备挂在I²C总线上,因而总线类型为:AWBL_BUSID_I²C。同时,PCF85063是一个普通设备,并非总线控制器,因而设备类型为AWBL_DEVID_DEVICE。bus_id的值即为:

AWBL_BUSID_I²C | AWBL_DEVID_DEVICE

(或省略AWBL_DEVID_DEVICE,直接设定为

AWBL_BUSID_I²C)。

3.  驱动名

p_drvname表示该驱动的名字。在设备描述中,使用了“设备名”用来描述设备的名字,在系统启动时,会为每个设备寻找合适的驱动,当驱动的总线类型和设备描述中的总线类型一致时,将会把“驱动名”与“设备名”进行比对,完全一致时,将视为驱动与设备匹配,进而将该驱动和对应的设备进行绑定。在AWBus-lite中,当一个驱动和设备匹配后,驱动名和设备名势必是完全一致的,因而在匹配后可以直接将驱动名作为设备名。

对于使用GPIO控制的LED设备驱动,其驱动名可以定义为:

4.  驱动入口点

设备在使用前,需要完成必要的初始化操作,例如,对于使用GPIO控制的LED设备,需要在初始时将引脚配置为输出模式。作为设备驱动,必须提供相关的初始化函数以完成设备的初始化。驱动入口点p_busfuncs即用于提供初始化函数的入口,其为指向struct awbl_drvfuncs类型结构体常量的指针,struct awbl_drvfuncs类型定义详见程序清单13.20。

程序清单13.20 struct awbl_drvfuncs类型定义(awbus_lite.h)

其中,包含了3个函数指针,分别对应了AWBus-lite中三个阶段的初始化动作。由此可见,为了完成一个设备的初始化,驱动需要提供三个初始化函数,分别用于完成设备不同阶段的初始化,各阶段对应的初始化函数将在系统启动过程中被依次调用。各阶段初始化函数的类型是完全一样的,均只有一个指向设备实例的指针作为形参,且均无返回值。即:

例如,对于使用GPIO控制的LED设备驱动,为了完成设备的初始化,需要提供3个初始化函数,结构性范例程序详见程序清单13.21。

程序清单13.21 驱动初始化函数结构性范例程序

其中,__g_awbl_drvfuncs_led_gpio的地址即可作为驱动入口点p_busfuncs的值。各初始化函数的实现将在后文进行详细介绍。

在系统启动时,将根据驱动信息中提供的驱动入口点信息,依次调用各阶段对应的初始化函数,进而完成一个设备的初始化。在调用各初始化函数时,传入形参p_dev的值为设备描述中p_dev的值,其本质上指向了静态定义的设备实例。

在AWBus-lite中,将设备的初始化分为了三个阶段:第一阶段、第二阶段、第三阶段。这样的划分有着极其重要的意义,各阶段对应的初始化函数被系统调用的时机并不相同。

  • 第一阶段

第一阶段为设备初始化过程中最先进入的阶段,在该阶段中,系统总中断被关闭,OS内核服务(如多任务管理)尚未提供,调试串口也尚未准备就绪。作为设备驱动,只能处理一些设备相关的最基本、最简单的操作,不可在本阶段中使用常见的其它服务,比如:执行连接中断、申请信号量、打印调试信息等操作。对于绝大部分普通设备驱动,该阶段对应的函数设置为空,不执行任何操作。

  • 第二阶段

第二阶段为设备初始化的主要阶段,设备相关的绝大部分初始化操作均在该阶段中完成,在第二阶段中,系统相关的服务均已准备就绪,比如:中断、调试串口、信号量、多任务等。可以在第二阶段中使用这些服务。

  • 第三阶段

第三阶段作为第二阶段后的一个阶段,系统相关的服务同样已准备就绪,比如:中断、调试串口、信号量、多任务等。第三阶段主要用于完成比较耗时的初始化操作,第三阶段相关的操作将在一个单独的任务中执行,不会影响系统的整体启动过程。

例如,在某一设备的初始化过程中,有一个特殊的操作需要一分钟才能完成,为了不影响系统的启动效率,可以将该耗时较长的操作放在第三阶段中完成,如此一来,系统同样可以快速启动,进而运行至应用程序入口,即aw_main()。否则,若将该操作放在第二阶段中,则系统必须在第二阶段初始化完成后才能启动完成,接着才能运行至应用程序入口处,导致系统的整个启动过程变慢。

系统启动速度的快慢将直接影响用户体验,以数字示波器为例,传统示波器的开机时间几乎都在30秒甚至1分钟以上,对于现场测试工程师来说,有可能会遗漏稍纵即逝的异常信号,几乎所有的示波器厂商都对这个需求熟视无睹,而广州致远电子有限公司的设计理念却与众不同,使用AWorks助力ZDS系列示波器,使用户从按下电源到开始使用,整个过程仅需要十余秒,其开机时间击败了所有其他品牌的示波器。让用户从按下电源的那一刻起,就能感受到极致的体验。

在AWBus-lite中,巧妙的将一个设备的初始化过程分为了三个阶段,可以使系统的启动速度从结构上得到优化,在大多数中小系统中,系统启动时间都小于1秒。

特别地,在一些设备的初始化过程中,可能并没有耗时较长的操作,此时,可以将第三阶段对应的函数设置为空,不执行任何操作。

5.  Method对象列表

每个设备都是为系统提供某种服务而存在的,其提供了相应的服务,才能被系统、用户所使用。如LED设备可以为系统提供LED服务,为了使系统能够获取到设备提供的LED服务,需要提供相应的Method对象,以指定获取LED服务对应的入口函数。定义一个Method对象的范例详见程序清单13.22。

程序清单13.22 定义Method对象范例程序

一些特殊设备,可能可以为系统提供多种服务,这时,对应驱动中将需要定义多个Method对象,每个Method对象用于获取某一种服务。

为此,AWBus-lite中,将一个驱动定义的所有Method对象存放在一个列表中,并以AWBL_METHOD_END表示列表的结束。驱动信息p_methods即用于指向Method对象列表,范例详见程序清单13.23。

程序清单13.23 定义Method对象列表范例程序

其中,__g_led_gpio_dev_methods即可作为驱动信息中p_methods的值。Method对象的具体定义将在后文详细介绍。

6.  驱动探测函数

在基础驱动信息中,pfunc_drv_probe是一个函数指针,用于指向一个探测函数,用于探测驱动是否支持该设备。其类型为:

由此可见,其指向的函数是具有一个p_dev形参,返回值为布尔类型的函数。

p_dev是指向设备实例的指针,用于指定探测的设备。返回值为布尔类型,返回AW_TRUE时,探测成功;否则,探测失败。

前面提到过系统是如何判定设备与驱动是否匹配的。设备与驱动匹配的首要条件是设备描述中的总线类型与驱动信息中的总线类型一致。在总线类型一致的情况下,可以增加两种额外的判定条件。

一种条件是针对该总线类型的,该总线类型下的设备和驱动,都必须满足该条件。不同总线类型对该条件的定义可能不同,但对于绝大部分总线来说,其判定条件都是:驱动名和设备名是否相同。这也是前面提到系统中使用驱动名和设备名进行匹配判定的原因。需要用户注意的是,这种条件是与具体总线类型相关的,虽然绝大部分总线类型的判定条件都是驱动名和设备名是否相同,但也不排除可能出现某一类型的总线,其不要求设备名和驱动名一致,这种情况极为罕见,如果出现,应该对该类总线作出非常重要的特殊说明。

一种条件是针对某一特定驱动的,这种条件通过驱动提供探测函数来实现。若驱动不需要进行额外的判断,则将pfunc_drv_probe的值设置为NULL。若需要进行额外的判断,则应提供一个有效的探测函数,在探测函数的实现中,若判定驱动和设备匹配,能够支持相应的设备,则应返回AW_TRUE,以告知AWBus-lite系统,驱动和设备是匹配的,进而将设备和驱动进行绑定;若判定驱动和设备不匹配,驱动不支持该设备,则应该返回AW_FALSE,以告知AWBus-lite系统,驱动和设备不匹配。

通常情况下,对于绝大部分驱动而言,并不需要进行的探测,此时,需将pfunc_drv_probe的值设置为NULL。基于此,通常情况下,只要驱动与设备的总线类型和名字一致,均可视为驱动和设备匹配。

以上仅仅对基础驱动信息中各成员的含义进行了简要的介绍,其中的初始化函数,Method对象列表等均还未实际实现,后文将以开发LED设备驱动为例,进一步介绍设备类型的定义、设备信息类型的定义、初始化函数的实现,Method对象的具体实现等。

13.3.2  实际驱动信息

在开发具体的设备驱动时,需要明确该驱动所对应的设备挂在何种总线上,不同总线下的设备对应驱动可能需要提供不同的驱动信息,此时,它们对应的驱动信息类型也是不同的。无论何种总线下的设备驱动,它们的驱动信息类型都是从基础驱动信息派生而来的,以便在基础驱动信息的基础上,扩展一些特殊的总线相关的成员。但在实际中,常见的大多数总线下的设备驱动信息并没有扩展更多的成员,例如,PLB总线下的设备驱动,其对应的驱动信息类型为awbl_plb_drvinfo_t,其定义详见程序清单13.24。

程序清单13.24 awbl_plb_drvinfo_t类型定义(awbl_plb.h

对于I²C总线下的设备驱动,其对应的驱动信息类型为awbl_i2c_drvinfo_t,其定义详见程序清单13.25。

程序清单13.25 awbl_i2c_drvinfo_t类型定义(awbl_i2cbus.h)

由此可见,这些总线下的设备驱动,并没有扩展额外的成员,均是对基础驱动信息的简单继承。即使如此,出于结构性考虑,为了便于后续扩展,每种总线都单独定义了相应的驱动信息类型。用户仅需了解到,开发不同总线下的设备驱动时,它们对应的驱动信息类型可能是不同的,需要查看总线对应的实际驱动信息类型,以判断在开发驱动时,除了提供基础驱动信息外,是否还需要提供其它额外的信息。

13.3.3  定义设备类型

通过前面对硬件设备列表的介绍可知,在硬件设备的描述中,需要使用驱动定义的具体设备类型定义一个设备实例,用于为设备分配必要的内存空间,设备相关的状态、变量、属性等相关数据都可以存放在该设备实例中。

在AWBus-lite中,所有具体设备类型均是从基础设备类型struct awbl_dev派生而来的,在定义设备类型时,基础设备类型的成员应该作为设备类型的第一个成员,基于此,可以定义LED设备类型为:

显然,要完成LED设备类型的定义,重点是考虑需要定义哪些其它成员。LED设备的核心功能是为系统提供LED服务,回顾LED服务的具体类型定义,详见程序清单13.26。

程序清单13.26 LED服务类型定义(awbl_led.h)

LED服务类型作为一个结构体类型,显然,需要占用一定的内存空间,由于每个LED设备均能提供LED服务,因此,可以将LED服务作为LED设备类型的一个成员。当需要为系统上层提供LED服务时,只需要将LED服务中的各个成员正确赋值,提交给上层即可。基于此,可以更新LED设备类型的定义,详见程序清单13.27。

程序清单13.27 LED设备类型的定义

当前仅仅从LED的主要功能出发,完成了LED设备类型的定义,若在开发过程中,发现需要在设备类型中增加新的成员,可以随时动态添加。在设备描述中,如需定义一个设备实例,直接使用该类型定义一个设备实例即可,例如:

13.3.4  定义设备信息类型

通过前面对硬件设备列表的介绍可知,在硬件设备的描述中,需要提供硬件设备信息。硬件设备信息的具体类型同样由相应的驱动定义。

在使用LED设备时,往往需要用户提供一些必要的信息,例如,在使用GPIO控制LED时,需要知道各个LED对应的引脚信息,即使用哪些GPIO引脚控制相应的LED。同时,对于不同的硬件电路,点亮LED对应的GPIO输出电平可能是不同的,可能是输出低电平点亮LED,也可能是输出高电平点亮LED,此外,不同硬件设备中,LED的数目也可能存在差异,这些都是与具体硬件相关的。

为了便于对这些信息进行修改、配置,可以定义一个信息结构体类型,以包含所有需要由用户提供的信息,即:

特别的,在部分平台中,使用GPIO前,可能需要一些特殊的平台相关的操作,比如:使能时钟、申请GPIO的使用权、配置GPIO的特殊模式等。由于具体平台相关的操作当前并不能确定,为此,可以由用户提供一个平台初始化函数,以在必要时,通过该函数完成平台相关的初始化操作。基于此,在设备信息类型中新增一个函数指针成员,用以指向用户提供的平台初始化函数,即:

新增的pfn_plfm_init是一个函数指针,指向的函数是无参数、无返回值的函数,用于完成在使用LED前需要完成的平台相关的初始化操作。在一些情况下,可能不需要执行任何平台相关的初始化操作,则可以将其值设置为NULL。

上面主要基于硬件层面定义了设备信息中的各个成员,此外,LED主要的功能是提供LED服务,在LED服务中,需要提供的一个重要信息是LED服务信息,其主要包含了LED设备中各个LED的编号信息,LED服务信息的定义详见程序清单13.28。

程序清单13.28 LED服务信息类型定义

由此可见,LED服务信息中包含了起始编号和结束编号,用户通过设定起始编号和结束编号,就可以为设备中的每个LED分配一个唯一ID。为了存放用户分配的ID信息,可以在设备信息类型中新增一个LED服务信息成员,设备信息完整的定义详见程序清单13.29。

程序清单13.29 LED设备信息类型完整定义

在EPC-AW280开发套件中,板载了两个LED,标识分别为RUN、Error,对应的引脚分别为PIO2_6、PIO2_5,等效原理图详见图13.2,由此可见,当GPIO输出低电平时,对应的LED点亮,GPIO输出高电平时,对应的LED熄灭。若为两个LED分配的ID号分别为0、1,则在设备描述中,LED设备信息的定义范例详见程序清单13.30。

图13.2 板载LED电路

程序清单13.30 LED设备信息定义范例

13.3.5  实现三个阶段的初始化函数

在一个设备使用前,需要完成设备相关的初始化操作,例如,对于LED驱动,可能需要将GPIO设置为输出模式等。在基础驱动信息中,使用了驱动入口点指定驱动提供的初始化函数,其结构性代码详见程序清单13.21,共需实现3个初始化函数,分别对应3个阶段。

需要特别注意的是,虽然各阶段初始化函数的形参类型均为awbl_dev_t *,但实际上,在系统调用各初始化函数时,传入形参p_dev的值为设备描述中p_dev的值,其本质上指向了静态定义的设备实例。对于GPIO控制型LED设备,其设备实例的实际类型为struct awbl_led_gpio_dev(具体定义详见程序清单13.27),在使用p_dev时,可以将其强制转换为指向实际设备实例的指针,以访问设备实例中的各个成员。范例程序详见程序清单13.31。

程序清单13.31 将p_dev转换为指向实际设备实例的指针

在初始化时,往往还需要获得用户为设备提供的相关信息,AWBus-lite提供了通过p_dev获取硬件设备描述的宏:AWBL_DEVHCF_GET(),其返回值即为const struct awbl_devhcf *类型的指向硬件设备描述的指针,struct awbl_devhcf类型的定义详见程序清单12.2,其中包含了设备名、设备单元号、所处总线、设备信息等常见的信息,使用范例详见程序清单13.32。

程序清单13.32 AWBL_DEVHCF_GET()宏的使用范例程序

程序中,只要获得了设备描述,即可通过指针获得设备描述中的其它成员信息,但通常情况下,可能只需要获得设备描述中某一个成员的信息,此时,为了简化获取步骤,AWBus-lite提供了直接获取设备描述中某一成员的辅助宏,详见表13.5。

表13.5 获取设备相关信息的辅助宏(awbus_lite.h)

特别地,在设备描述中,设备实例信息的类型为const void *,而实际上,p_devinfo指向的是具体设备信息,对于GPIO控制型LED设备,其设备信息的实际类型为

struct awbl_led_gpio_param(具体定义详见程序清单13.29),因此,在使用设备实例信息时,可以将其强制转换为指向实际设备信息的指针,以便访问实际设备信息中的成员。例如:

1.  第一阶段初始化函数实现

第一阶段通常无需作任何操作,该阶段对应的始化函数往往为空,详见程序清单13.33。

程序清单13.33 第一阶段初始化函数实现范例

2.  第二阶段初始化函数实现

第二阶段为初始化设备的主要阶段,可以在该阶段中完成GPIO模式设置、初始电平设置等初始化相关操作,范例程序详见程序清单13.34。

程序清单13.34 第二阶段初始化函数实现范例

程序中,将所有LED对应的引脚设置为了输出模式,并将初始电平设置为了设备信息中active_low的值,以使LED初始处于熄灭状态。例如,active_low的值为1,则表示引脚输出低电平时点亮LED,而初始时,将输出电平设置为了

active_low的值,即高电平,从而熄灭了LED。为了更清楚的理解这个关系,可以列举出active_low的值和GPIO输出电平对LED状态的影响,详见表13.6。由此可见,当active_low的值和GPIO输出电平相同时,LED熄灭,否则,LED点亮。因此,初始时,将GPIO输出电平设置为active_low的值,确保了LED初始处于熄灭状态。

表13.6 LED状态的影响因素

3.  第三阶段初始化函数实现

第三阶段通常用于耗时较长的初始化操作,由于LED设备初始化中,并没有任何比较复杂、耗时的操作,因此,第三阶段无需作任务处理,设定为空即可,详见程序清单13.35。

程序清单13.35 第三阶段初始化函数实现范例

实现了各阶段初始化函数后,可以定义一个struct awbl_drvfuncs类型的常量,以将所有初始化函数整合在一起,作为基础驱动信息中驱动入口点的值。详见程序清单13.36。

程序清单13.36  定义struct awbl_drvfuncs类型的常量

其中,__g_awbl_drvfuncs_led_gpio即可作为驱动入口点p_busfuncs的值。

为了简化程序,可以在定义

struct awbl_drvfuncs类型的常量时,将空函数对应的指针直接设定为NULL。例如,在程序清单13.36中,由于第一阶段和第三阶段对应的初始化函数是空函数,没有作任何操作,因此,可以将pfunc_dev_init1和pfunc_dev_connect的值设置为NULL,更新后的struct awbl_drvfuncs类型常量定义详见程序清单13.37。

程序清单13.37 更新struct awbl_drvfuncs类型的常量定义

13.3.6  实现LED服务

LED设备的主要功能是为系统提供LED服务,在向系统提供LED服务前,需要实现一个LED服务,回顾LED服务类型的定义,详见程序清单13.38。

程序清单13.38 LED服务类型定义(awbl_led.h)

在LED设备实例中,具有一个

struct awbl_led_service 类型的led_serv成员(详见程序清单13.27)。实现LED服务的核心工作就是完成led_serv中各成员的赋值。

1.  p_next成员赋值

在LED服务中,p_next用于系统组织多个LED服务,使它们以链表的形式串接起来,便于统一管理。对于单个LED设备来讲,其仅能提供一个LED服务,p_next的值设置应设置为NULL。设置范例详见程序清单13.39。

程序清单13.39 LED服务中p_next成员赋值范例

2.  p_servinfo成员赋值

在LED服务中,p_servinfo用于指向LED服务信息,通过LED设备信息类型的定义可知,LED服务信息由用户提供,因此,只需将p_servinfo指向设备信息中的LED服务信息,设置范例详见程序清单13.40。

程序清单13.40 LED服务中p_servinfo成员赋值范例

3.  p_servfuncs成员赋值

为了屏蔽底层硬件的差异性,系统为LED设备定义了两个抽象方法,回顾

struct awbl_led_servfuncs类型的定义,详见程序清单13.41。

程序清单13.41 struct awbl_led_servfuncs类型的定义(awbl_led.h)

在LED服务中,p_servfuncs即为指向各抽象方法的具体实现列表。为了完成p_servfuncs成员的赋值,首先需要实现操作LED设备的的两个抽象方法,然后将它们整合到一个

struct awbl_led_servfuncs类型的结构体常量中,抽象方法的实现详见程序清单13.42。

程序清单13.42 LED抽象方法的实现

在各个抽象方法的实现中,都将参数p_cookie直接视为了指向设备的指针,为了便于使用,将p_cookie的类型从void *强制转换为了struct awbl_led_gpio_dev *。实际中,p_cookie的值是由驱动自身决定的,在下一小节p_cookie成员的赋值中将作进一步介绍。

各函数完成的主要功能是根据需要控制LED对应引脚的输出电平,主要分为两个步骤:根据LED的ID得到引脚索引;通过引脚索引,控制相应引脚的输出电平。

LED对应的引脚在设备信息的引脚数组中,数组的起始索引为0,但LED的ID是从LED服务信息中指定的起始编号开始的,为了通过LED的ID获得其对应引脚在数组中的索引,应使用ID号减去起始编号,即:

在__led_gpio_set()函数的实现中,其需要根据参数on的值决定是否点亮LED,点亮LED的电平与设备信息中的active_low有关, 为了更清楚的理解这个关系,可以列举出参数on和active_low的值对GPIO输出电平的影响,详见表13.7。例如,当active_low为0时,表示GPIO输出高电平时点亮LED,此时,若on为1,表示需要点亮LED,则GPIO应输出高电平;若on为0,表示需要熄灭LED,则GPIO应输出低电平。

表13.7 GPIO输出与active_low和on值的关系

由此可见,当active_low和on相同时,GPIO应该输出“0”,而当active_low和on值不同时,GPIO应输出“1”。即:“相同为0,相异为1”,这恰好是一种异或关系,因此,在设置GPIO输出电平时,直接将active_low和on的异或值作为GPIO的输出电平,即:

在__led_gpio_toggle()函数的实现中,仅需翻转GPIO输出电平接口,与设备信息中active_low的值无关,即:

至此,实现了LED服务中的两个抽象方法,并存放在了__g_led_servfuncs常量中,该常量的地址即可直接作为LED服务中p_servfuncs的值,详见程序清单13.43。

程序清单13.43 p_servfuncs成员的赋值

4.  p_cookie成员赋值

在LED服务中,p_cookie用于系统在调用设备实现的抽象方法时,“原封不动”的传递给各个抽象方法的p_cookie参数。这样一来,传入抽象方法中的p_cookie与LED服务中的p_cookie是完全相同的,换句话说,驱动为LED服务中的p_cookie设置了什么值,那么,在系统通过LED服务调用驱动实现的抽象方法时,传入p_cookie参数的值也为该值。

通常情况下,p_cookie都起到一个p_this的作用,用于指向设备自身,为此,直接将LED服务中p_cookie的设置为p_this,详见程序清单13.44。

程序清单13.44 p_cookie成员的赋值

也正因为如此,在程序清单13.42所示的LED抽象方法的实现中,可以直接将p_cookie强制转换为指向设备自身的指针。

至此,清楚了LED服务中各成员应该设置的具体值,可以选择在初始化函数中完成各成员的赋值,比如将相关的赋值语句添加到第二阶段初始化函数中。也可以选择在系统获取LED服务时,再进行相关成员的赋值。显然,在系统获取LED服务时再进行相关成员的赋值,这种方式更优,因为若系统不获取LED服务,那么就不会进行相关成员的赋值,避免了不必要的操作,下面将对这种方法作进一步介绍。

13.3.7  定义Method对象

通过前面对Method机制的介绍可知,为了使LED设备可以向系统提供LED服务,需要定义Method对象,一个Method对象由Method类型标识和一个入口函数构成。已知获取LED服务的Method类型为:awbl_ledserv_get。因此,定义Method对象的关键在于实现一个用于系统获取LED服务的入口函数,范例程序详见程序清单13.45。

程序清单13.45 获取LED服务的入口函数实现范例

基于此,可以完成一个Method对象的定义,即:

为了便于管理,一个驱动提供的所有Method对象应该存放在一个列表中,由于LED设备仅能提供LED服务,因此,Method对象列表中仅包含一个用于获取LED服务的Method对象,详见程序清单13.46。

程序清单13.46 LED设备驱动Method对象列表定义

其中,__g_led_gpio_dev_methods即可作为基础驱动信息中p_methods的值。

13.3.8  注册驱动

通过前面的介绍,LED设备驱动相关的函数均已实现,驱动已经基本开发完成,基于此,可以按照AWbus-lite的定义,使用相应驱动信息结构体类型完成一个驱动信息的定义,用于完整的描述LED驱动。

由GPIO直接控制的LED设备挂在PLB总线上,PLB总线上的所有设备驱动对应的信息结构体类型为awbl_plb_drvinfo_t,其是直接从基础驱动信息类型派生而来的,其定义详见程序清单13.47。

程序清单13.47 awbl_plb_drvinfo_t类型定义(awbl_plb.h)

由此可见,其并未扩展任何其它新的成员,和基础驱动信息是完全一样的,可以定义用于描述LED驱动的信息常量,详见程序清单13.48。

程序清单13.48 定义描述LED驱动的信息常量

完成描述驱动的信息常量定义后,还需要将驱动注册到系统中,以便被系统中相应的设备所使用,AWBus-lite提供了驱动注册函数,用于向系统中注册一个驱动,其函数原型为:

其中,p_drvinfo指向待注册的驱动信息,返回值为标准的错误号,若返回AW_OK,则表示驱动注册成功;若返回-AW_ENOSPC,则表示内存空间不足,驱动注册失败;若返回-AW_ENOTSUP,则表示AWbus-lite不支持该驱动的版本,往往是由于驱动信息中的awb_ver版本号设置有误引起的。例如,注册LED驱动的范例程序详见程序清单13.49。

程序清单13.49 注册LED驱动范例程序

由于__g_drvinfo_led_gpio的类型是从基础驱动信息类型派生而来的,两者类型并不完全相同,为了避免警告,可以将__g_drvinfo_led_gpio的地址转换为struct awbl_drvinfo *类型。

显然,是否注册驱动应该是由用户决定的,只有当需要使用某一设备时,才应将相应的驱动注册到系统中。为了使用户可以在需要使用LED驱动时再注册驱动,比较容易想到的方法可能是将__g_drvinfo_led_gpio作为一个对外开放的全局变量,引出到驱动文件外部,当用户需要使用LED驱动时,再使用程序清单13.49所示的程序进行注册。但是,__g_drvinfo_led_gpio作为一个结构体常量,可以看作驱动的一个数据,在面向对象的编程中,作为一种良好的编程习惯,应该尽可能避免将数据直接引出到对象外部供其它模块使用,对数据的操作都应该通过相关的接口实现。将过多的数据作为全局变量引出到文件外部,将严重破坏系统的可维护性。同时,对于用户来说,其并不需要访问驱动信息中的相关成员,将整个驱动信息开放给用户也是不必要的。

由于驱动信息仅用于在注册驱动时使用,为此,可以提供一个用于注册LED驱动的专用函数,其实现详见程序清单13.50。

程序清单13.50 注册LED驱动的专用函数

如此一来,驱动信息仅在内部被访问,做到了很好的“封装”。当用户需要使用LED驱动时,直接调用awbl_led_gpio_drv_register()函数即可。

通常情况下,并不需要由用户手动调用该函数,而是将该函数的调用放在模板工程下的

aw_prj_config.c文件中,具体位于

awbl_group_init()函数中,该函数在系统启动时会被自动调用,从而使系统在启动时自动调用awbl_led_gpio_drv_register()函数完成驱动的注册,详见程序清单13.51。

程序清单13.51 系统启动时自动注册驱动的原理

由此可见,用户可以通过是否定义

AW_DRV_AWBL_GPIO_LED宏来确定是否注册LED驱动,在aw_prj_params.h工程配置文件中,只要使能了LED设备,即定义了AW_DEV_GPIO_LED宏,则表示要使用GPIO驱动型LED,此时,将自动完成

AW_DRV_AWBL_GPIO_LED的定义,以此确保当使用LED时,相应驱动会在系统启动过程中被自动注册。核心的原理性程序详见程序清单13.52。

程序清单13.52 自动定义AW_DRV_AWBL_GPIO_LED宏的原理(aw_prj_params.h)

热门推荐

原文标题:AWorks软件篇 — 深入理解 AWbus-lite(设备驱动基础概念)

文章出处:【微信号:ZLG_zhiyuan,微信公众号:ZLG致远电子】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
分享:

评论

相关推荐

以NFC核心板为例讲述基于AWorks平台开发的具体方法

ZLG致远电子推出了一系列“MCU+无线”核心板,本文以NFC核心板为例讲述基于AWorks平台开发....

的头像 ZLG致远电子 发表于 06-22 09:16 113次 阅读
以NFC核心板为例讲述基于AWorks平台开发的具体方法

AWBus-lite的拓扑结构及应用设计

为了管理系统中各式各样的硬件设备(或虚拟硬件设备),AWorks推出了领先的轻量级总线管理框架:AW....

的头像 ZLG致远电子 发表于 06-21 09:10 282次 阅读
AWBus-lite的拓扑结构及应用设计

AWorks外围器件:驱动EEPROM和SPI Nor Flash存储器

一个应用的实现往往离不开大量的外围器件,如存储设备,RTC设备、显示设备等等。为了建立完整的生态系统....

的头像 ZLG致远电子 发表于 06-20 09:01 396次 阅读
AWorks外围器件:驱动EEPROM和SPI Nor Flash存储器

AWorks软件设计,邮箱、消息队列和自旋锁使用方法

本文介绍了邮箱、消息队列和自旋锁的使用方法。信号量只能用于任务间的同步,不能传递更多的信息,为此,A....

的头像 ZLG致远电子 发表于 06-13 09:13 859次 阅读
AWorks软件设计,邮箱、消息队列和自旋锁使用方法

面向AWorks框架和接口编程温度检测模块的软件详细资料概述

AWorks作为一个物联网生态系统,底层需要大量的信号(温度、电压、电流……)采集模块,以实现对外部....

的头像 ZLG致远电子 发表于 06-12 19:27 366次 阅读
面向AWorks框架和接口编程温度检测模块的软件详细资料概述

AWorks中开发设备驱动一般方法

发表于 06-11 16:45 910次 阅读
AWorks中开发设备驱动一般方法

AWorks中开发设备驱动一般方法

本文详细介绍了AWorks中开发设备驱动的一般方法。基于这些通用的方法,用户可以尝试独立开发一些设备....

的头像 ZLG致远电子 发表于 06-11 08:59 583次 阅读
AWorks中开发设备驱动一般方法

嵌入式中,有无操作系统对设备驱动的不同解析

任何一个计算机系统的运行都是系统中软硬件协作的结果,没有硬件的软件是空中楼阁,而没有软件的硬件则只....

发表于 06-06 16:53 71次 阅读
嵌入式中,有无操作系统对设备驱动的不同解析

怎样才能设计出稳定可靠电源

目前市面上的电源模块品类繁多,初期应用都能满足要求,但随着时间的考验就开始经不起考验了。电源作为系统....

的头像 ZLG致远电子 发表于 06-05 09:24 1524次 阅读
怎样才能设计出稳定可靠电源

面向AWorks框架管理文件的方法和数据结构

文件系统是在存储设备中(SD Card、NAND Flash…)组织文件的方法和数据结构,用于管理文....

的头像 ZLG致远电子 发表于 06-05 09:18 749次 阅读
面向AWorks框架管理文件的方法和数据结构

面向AWorks框架时间管理程序设计

实际应用中,时间管理往往是必不可少的。例如:定时完成某件事情、周期性地触发某一动作、测量评估程序运行....

的头像 ZLG致远电子 发表于 05-30 09:33 1200次 阅读
面向AWorks框架时间管理程序设计

I²C总线、UART总线和A/D转换器应用设计

在传统的基于寄存器的开发模式中,使用一个外设往往要阅读英文手册,理解寄存器每一位的含义,一步一步操作....

的头像 ZLG致远电子 发表于 05-28 08:57 2630次 阅读
I²C总线、UART总线和A/D转换器应用设计

基于ARM9、Cortex-A系列高性能SoC无线核心板设计

基于AWorks平台的,集MCU、DDR2、NandFlash、硬件看门狗、无线芯片(Wi-Fi、N....

的头像 ZLG致远电子 发表于 05-21 09:39 1410次 阅读
基于ARM9、Cortex-A系列高性能SoC无线核心板设计

设备驱动模型直观的认识

可以看到,我们在使用kobject、kset、ktype结构,就在sysfs虚拟文件系统下创建(通过....

的头像 嵌入式ARM 发表于 05-18 14:58 384次 阅读
设备驱动模型直观的认识

只需七步,就可了解逻辑分析仪测试

时序和协议是数字系统调试的两大关键点,也是逻辑分析仪最能发挥价值的地方。如何使用逻辑分析仪快速地完成....

的头像 ZLG致远电子 发表于 04-19 09:44 1304次 阅读
只需七步,就可了解逻辑分析仪测试

储能行业如何有效解决电能质量问题?

时下,储能行业正在大力发展,锂离子电池和铅蓄电池是该领域应用最多的两种技术,但除了电池,还有哪些问题....

的头像 ZLG致远电子 发表于 04-11 09:30 1122次 阅读
储能行业如何有效解决电能质量问题?

μC/OS-Ⅱ操作系统设备驱动设计及实际应用举例

基于μC/OS-II的应用系统工作时,首先把CPU初始化;接着进行操作系统初始化,主要完成任务控制块....

发表于 03-30 14:59 99次 阅读
μC/OS-Ⅱ操作系统设备驱动设计及实际应用举例

解决芯片量产问题,MCU成最大焦点

随着越来也多的电子厂商不断为物联网(IoT)推出新产品,全球MCU出货量正出现巨大成长动能。特别是当....

的头像 ZLG致远电子 发表于 03-30 08:49 2328次 阅读
解决芯片量产问题,MCU成最大焦点

详细讲解RT-Thread I2C设备驱动框架及相关函数

本应用笔记以驱动I2C接口的6轴传感器MPU6050为例,说明了如何使用I2C设备驱动接口开发应用程....

的头像 RTThread物联网操作系统 发表于 03-29 10:52 935次 阅读
详细讲解RT-Thread I2C设备驱动框架及相关函数

三句话讲清环路分析,轻松检测控制系统稳定性

尽管环路分析是检测控制系统稳定性的重要手段,但是测试过程中有诸多细节需要注意。如何快速理解环路分析的....

的头像 ZLG致远电子 发表于 03-21 08:04 1408次 阅读
三句话讲清环路分析,轻松检测控制系统稳定性

面对大烧录量和严格性能要求,如何高效快速生产汽车零组件

一辆光鲜亮丽的汽车上有琳琅满目的电子部件,每一个电子部件往往都拥有它自己的芯片,每个芯片又有它独立的....

的头像 ZLG致远电子 发表于 03-19 08:44 2943次 阅读
面对大烧录量和严格性能要求,如何高效快速生产汽车零组件

Zigbee无线模块在流速计上的应用方案

新时代的智慧城市,要求全面提升监控力度和智能化管理水平。我国广阔的水域,将会建设更多无人值班监测点,....

的头像 ZLG致远电子 发表于 03-12 09:40 2765次 阅读
Zigbee无线模块在流速计上的应用方案

如何通过技巧快速进行选型?电源设计浅谈

电容是开关电源中的再普通不过的器件,它可以用来降低纹波噪声,可以用来提高电源的稳定性以及瞬态响应性,....

的头像 ZLG致远电子 发表于 03-10 09:34 3577次 阅读
如何通过技巧快速进行选型?电源设计浅谈

一个好电源设计,为何要非常重视输出纹波噪声

纹波噪声是衡量电源的一个重要指标,一个好的电源必须要把输出纹波噪声控制在一个合理的范围内。但一般有哪....

的头像 ZLG致远电子 发表于 03-05 08:35 2899次 阅读
一个好电源设计,为何要非常重视输出纹波噪声

以太网无法取代CAN的原因是什么?

CAN总线通过物理信号来进行连接,而以太网则是交换机连接。CAN总线的结构非常简单,仅需拉两条线而已....

发表于 03-02 09:48 313次 阅读
以太网无法取代CAN的原因是什么?

如何解决照明灯具的测试测量痛点

家用照明灯具在出厂时,都是需要经过测量装备严格的检测,当照明灯在正常工作或特定模式下时,电压、电流和....

的头像 电子发烧友网工程师 发表于 02-20 03:28 2115次 阅读
如何解决照明灯具的测试测量痛点

电压波动与电压闪变对比分析

电压闪变与波动,两个形影不离的兄弟,经常一起出现在我们的视野中。闪变外向,我们可以从外表觉察到它的变....

的头像 电子发烧友网工程师 发表于 02-16 09:40 1259次 阅读
电压波动与电压闪变对比分析

如何确保对吸尘器的心脏进行可靠“体检”

人类正是由于心脏不断地跳动才得以生存;吸尘器也是一样,只有心脏安好,才能更好的吸尘。人类为了确保身....

的头像 电子发烧友网工程师 发表于 02-15 03:33 1160次 阅读
如何确保对吸尘器的心脏进行可靠“体检”

分析电能质量分析仪一个案例中的测试效果

小到家庭,大到企业,能耗问题一直以来都是大家所关注重视的问题。中国企业的能耗一直很高,国家也努力促使....

的头像 ZLG致远电子 发表于 02-08 09:44 2576次 阅读
分析电能质量分析仪一个案例中的测试效果

深度解析Linux SPI总线和设备驱动架构

SPI控制器不用关心设备的具体功能,它只负责把上层协议驱动准备好的数据按SPI总线的时序要求发送给S....

的头像 嵌入式ARM 发表于 02-07 08:16 1640次 阅读
深度解析Linux SPI总线和设备驱动架构

ZLG致远电子E6000率先支持新国标 电压暂降和短时中断的定义

国家标准2013年第25号批准发布公告,由国网福建电科院负责编制的国家标准《电能质量电压暂降与短时中....

的头像 电子发烧友网工程师 发表于 02-05 11:11 2047次 阅读
ZLG致远电子E6000率先支持新国标 电压暂降和短时中断的定义

电子产品性能提升中,如何防止“安全”掉链子

最火手游“王者荣耀”将玩家分成“青铜、白银、黄金...”等段位。笔者从青铜开始打到最强王者。是不是电....

的头像 ZLG致远电子 发表于 02-05 09:44 2336次 阅读
电子产品性能提升中,如何防止“安全”掉链子

互联网温控器芯片应用及整体方案

LG致远电子基于NXP的KL16、Semtech的SX1278芯片开发的低功耗、高性能的LoraNe....

的头像 周立功单片机 发表于 02-05 09:19 2475次 阅读
互联网温控器芯片应用及整体方案

一款优质电源必然具备:启动性设计

一款优质电源必然具备启动性能好、转换效率高等特点,但你有没有想过宽压电源的输入电压范围那么广,而电源....

的头像 ZLG致远电子 发表于 02-02 09:33 5692次 阅读
一款优质电源必然具备:启动性设计

为什么你的手机实际内存比标称内存要少很多

现在市面上存在NAND FLASH和eMMC这两种的大容量存储介质,就是各类移动终端及手机的主要存储....

发表于 01-29 07:40 1027次 阅读
为什么你的手机实际内存比标称内存要少很多

13.56MHz读写卡模块通信接口及选型指南

论选择I2C 或UART 通信方式,只要基于实例句柄编程,则应用程序与具体的通信方式无关。

的头像 周立功单片机 发表于 01-25 09:09 2598次 阅读
13.56MHz读写卡模块通信接口及选型指南

深入理解AMetal,掌握蜂鸣器和温度采集接口设计

在接口实现中,没有与硬件相关的实现代码,仅仅是简单的调用了抽象方法。抽象方法需要由具体的温度采集设备....

的头像 周立功单片机 发表于 01-17 08:29 3288次 阅读
深入理解AMetal,掌握蜂鸣器和温度采集接口设计

一款基于法拉电容的UPS电路设计思路

您是否有遇到使用中的程序无故丢失?产品调试非常稳定,布置到现场后频繁系统崩溃和数据遗失,亦或产品应用....

的头像 ZLG致远电子 发表于 01-15 09:06 2505次 阅读
一款基于法拉电容的UPS电路设计思路

开发者在的很多管理者,需了解平台产品开发战略

在2017年9月5日深圳举行的“‘名家芯思维’之2017年物联网核心技术和应用国际研讨会”上,周立功....

的头像 ZLG致远电子 发表于 12-13 07:14 3596次 阅读
开发者在的很多管理者,需了解平台产品开发战略

使用AM335x系列芯片该注意哪些问题

ARM研发的路漫长而有趣,众人皆知的开发优势和面对问题时的一筹莫展,让人对ARM又爱又恨,而你与AR....

的头像 ZLG致远电子 发表于 12-13 06:08 4723次 阅读
使用AM335x系列芯片该注意哪些问题

智能灯具中zigbee无线技术方案解析

灯具的控制主要分为开关控制与调光控制。开关控制利用继电器控制灯具的通断电;调光控制利用PWM、模拟信....

的头像 ZLG致远电子 发表于 11-29 06:28 6355次 阅读
智能灯具中zigbee无线技术方案解析

Linux下FPGA设备驱动的实现

引言 Intel公司推出的XScale采用ARM V5TE结构,是Strong ARM的升级换代产品....

发表于 10-30 10:50 91次 阅读
Linux下FPGA设备驱动的实现

《Linux设备驱动开发详解》第7章、Linux设备驱动中的并发控制

《Linux设备驱动开发详解》第7章、Linux设备驱动中的并发控制

发表于 10-27 11:37 69次 阅读
《Linux设备驱动开发详解》第7章、Linux设备驱动中的并发控制

《Linux设备驱动开发详解》第13章、Linux块设备驱动

《Linux设备驱动开发详解》第13章、Linux块设备驱动

发表于 10-27 11:24 63次 阅读
《Linux设备驱动开发详解》第13章、Linux块设备驱动

《Linux设备驱动开发详解》第15章、Linux的I2C核心、总线与设备驱动

《Linux设备驱动开发详解》第15章、Linux的I2C核心、总线与设备驱动

发表于 10-27 11:19 75次 阅读
《Linux设备驱动开发详解》第15章、Linux的I2C核心、总线与设备驱动

VxWorks操作系统的基本组件

VxWorks操作系统的基本组件

发表于 10-26 10:36 94次 阅读
VxWorks操作系统的基本组件

设备驱动

设备驱动

发表于 10-26 10:34 81次 阅读
设备驱动

VxWorks下设备驱动的内核结构层次

VxWorks下设备驱动的内核结构层次

发表于 10-26 10:32 73次 阅读
VxWorks下设备驱动的内核结构层次