购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第3章
PIN设备驱动开发

PIN设备又称GPIO(General Purpose Input Output,通用输入/输出)设备,又简称为I/O口,指MCU上的I/O引脚。RT-Thread将通用I/O抽象为PIN设备,以实现通用I/O口的功能。MCU的通用I/O一般用于读取引脚的输入电平或者控制引脚的输出电平,进而控制MCU的外围电路。常用硬件连接图如图3-1所示,图中MCU外接的是LED和KEY。

图3-1 LED/KEY的硬件连接图

在图3-1中,LED_R/G/B、KEY0/1/2均直连MCU GPIO口。图3-1a所示为MCU输出高低电平,以控制LED亮灭;图3-1b所示为MCU检测高低电平,以判断按键是否按下。

RT-Thread的PIN设备抽象了I/O口的基本功能,而I/O口的基本功能如下。

1)通过读取引脚的电平检测引脚外部输入情况,输入情况分为输入浮空、输入上拉、输入下拉、模拟输入。

2)设置引脚输出电平,输出情况分为开漏输出、推挽式输出。

3)检测外部中断:当I/O外部输入的电平变化时,可以触发给I/O引脚设置的中断。

以上I/O基本操作均被抽象为P I N设备。除了通用I/O之外,片上外设复用功能被RT-Thread抽象为其他外设,如第2章的UART设备,以及后续章节讲解的其他外设。

3.1 PIN层级结构

PIN的层级结构如图3-2所示。

1)应用层一般是由开发者编写的业务代码,通过调用PIN设备框架提供的统一接口完成具体的业务代码编写,如LED、蜂鸣器的驱动代码。

2)PIN设备驱动框架层和平台无关,是通用的软件层,向应用层提供统一的接口供应用层调用。PIN设备驱动框架源码是pin.c,位于RT-Thread源码的components\drivers\misc文件夹中,PIN设备驱动框架的功能有以下两点。

①PIN设备驱动框架向应用层提供PIN设备管理接口,即rt_pin_read、rt_pin_write、rt_pin_mode等(接口名均使用rt_前缀),应用程序使用这些接口来操作硬件引脚。

②PIN设备驱动框架向PIN设备驱动提供PIN设备操作方法接口struct rt_pin_ops(具体如pin_get、pin_mode、pin_write、pin_read、pin_attach_irq、pin_detach_irq、pin_irq_enable),PIN设备驱动需要实现这些接口。除此之外,该层还向PIN设备驱动提供PIN设备注册接口rt_device_pin_register, PIN设备驱动需要调用该接口进行设备注册。

3)PIN设备驱动层的实现与具体硬件平台相关,通过调用厂商提供的库函数或寄存器来操作具体的硬件GPIO口。PIN设备驱动源码文件drv_gpio.c放置在具体的BSP目录下,与BSP相关。PIN设备驱动需要实现PIN设备的操作方法接口struct rt_pin_ops,这些操作方法提供了访问和控制PIN硬件的能力。该驱动也负责调用rt_device_pin_register函数来注册PIN设备到操作系统中。

图3-2 PIN层级结构图

4)最下面一层是与硬件GPIO口相连接的常用模块,有LED、按键、蜂鸣器等。

我们再来看一下PIN设备驱动的具体开发步骤。PIN设备驱动开发主要任务是实现PIN设备操作方法rt_pin_ops,然后注册PIN设备。驱动文件一般命名为drv_gpio.c。本章将会以STM32的PIN设备驱动为例讲解PIN驱动的具体实现。

3.2 实现PIN设备的操作方法

1.操作方法原型

PIN设备的操作方法rt_pin_ops定义在PIN设备框架中,包含了和硬件相关的操作方法,其结构体原型如下:

(1)成员说明

1)pin_get:获取某个PIN的引脚编号。

2)pin_mode:将某个引脚初始化为对应的工作模式。

3)pin_write:设置某个引脚的输出电平。

4)pin_read:读取某个引脚的电平。

5)pin_attach_irq:中断操作,为某个引脚绑定一个中断回调函数,使能中断后,当中断到来时调用该函数。

6)pin_irq_enable:中断操作,开启或关闭中断。

7)pin_detach_irq:中断操作,脱离某个引脚的中断回调函数。

(2)引脚编号的作用

不同厂商对引脚的定义不相同,确定一个引脚所需的参数也不同,举例如下。

1)ST:引脚由PORT名和PIN名组成,PORT名为英文字母A~Z,PIN名为数字0~15,如PA0、PB5。如果使用STM32的HAL库来控制某一个引脚,需要提供如下类型的参数组合:(GPIO_TypeDef*GPIOx, uint16_t GPIO_Pin)。

2)NXP: LPC系列引脚名也是由PORT名和PIN名组成,但是PORT名由数字组成,如PIO0_0、PIO2_15。如果使用其提供的库函数来控制某一个引脚,需要提供的参数组合为(GPIO_Type*base, uint32_t port, uint32_t pin)。

若是在应用层直接使用各厂商提供的写法,则应用层代码不可能具有良好的通用性。为了使基于PIN设备驱动框架开发的应用代码兼容各个硬件平台,于是给每个引脚进行编号(0、1、2……),每个编号代表唯一一个引脚,这样基于PIN设备驱动框架开发的代码就有了良好的通用性。引脚编号可以直接使用MCU的引脚编号,也可以自定义一个引脚编号表,自定义编号表的编号顺序不一定和MCU引脚编号相同。

2.为设备定义操作方法

驱动开发者需要在驱动文件中实现这些操作方法。以STM32为例,首先使用struct rt_pin_ops实例化一个如下所示的结构,然后实现对应的函数。

3.pin_get:获取引脚编号

操作方法pin_get是用于获取某个PIN引脚编号的接口,其原型如下所示:

pin_get方法的参数及返回值如表3-1所示。

表3-1 pin_get方法的参数及返回值

注意,用户对PIN设备的操作主要是通过引脚编号,不同厂商为芯片引脚定义的名称不同,如ST的是PA0,NXP的是PIO0_0,在RT-Thread中,使用“.”作为PORT名与PIN名的分割,将它们统一为PA.0、P0.0。

驱动开发者在实现该操作方法时,需要根据传入的name参数,返回匹配的引脚编号数值。

我们来看一个获取引脚编号的示例,以下是STM32 PIN设备实现的pin_get接口的部分代码,我们可通过MCU引脚排列规律得出引脚编号。

4.pin_mode:设置引脚工作模式

操作方法pin_mode是用于设置引脚工作模式的接口,如上/下拉模式或输入/输出模式,其原型如下所示:

pin_mode方法的参数如表3-2所示。

表3-2 pin_mode方法的参数

其中,参数device表示PIN的设备句柄,因为PIN设备在实现时每一个引脚都会由引脚编号进行代替,所以device参数目前不再使用。

在表3-2中,mode的取值如下所示。驱动需要根据指定的模式对MCU的引脚进行相应的配置。驱动框架提供的模式有以下几种:

需要注意的是,mode参数会从应用层传入,驱动层需要根据以上mode的值完成对应的操作。

如下是设置引脚工作模式的示例,可根据上面的5种模式对引脚进行设置,即STM32 PIN驱动的pin_mode接口实现。

其他芯片的驱动可以参考如上代码完成pin_mode这个操作方法。

5.pin_write:设置引脚电平

操作方法pin_write是用于设置引脚的电平状态的接口,通过传入的引脚编号和引脚电平状态,对引脚进行设置,其原型如下所示:

pin_write方法的参数如表3-3所示。

表3-3 pin_write方法的参数

我们来看一个在STM32上实现pin_write接口的示例代码,首先根据引脚编号获取引脚编号映射表的索引,索引包含引脚的端口信息和引脚信息,之后调用库函数修改引脚电平状态。

6.pin_read:读取引脚电平

操作方法pin_read是用于读取引脚电平状态的接口,通过传入的引脚编号获取该引脚的状态,并将状态返回,其原型如下所示:

pin_read方法的参数及返回值如表3-4所示。

表3-4 pin_read方法的参数及返回值

我们来看一个在STM32上实现pin_read方法的示例,首先根据引脚编号获取引脚编号映射表的索引,索引包含引脚的端口信息和引脚信息,之后调用库函数读取引脚电平状态,最后返回该状态。

7.pin_attach_irq:引脚绑定中断

操作方法pin_attach_irq用于给某一个引脚绑定中断回调函数,该方法在实现时需要根据中断触发方式实现中断功能,触发方式有上升沿触发、下降沿触发等,还需绑定引脚中断回调函数,用于触发中断之后执行的动作,其原型如下所示:

pin_attach_irq方法的参数及返回值如表3-5所示。

表3-5 pin_attach_irq方法的参数及返回值

在表3-5中,引脚中断触发模式有5种宏定义值,若遇到芯片不支持的模式,在驱动中直接返回错误即可。

回调函数指针hdr需要被保存起来,例如保存在一张中断回调函数表中(方法不限于此),与引脚编号和中断触发模式等属性一一对应,待中断触发时,通过查表调用绑定的回调函数,完成中断的执行,以下是中断回调函数表。

除此之外,驱动开发人员需完成相应的中断处理函数。以CORTEX-M为例,若PA0引脚开启外部中断,并进行外部触发,则需实现如下类似代码:

下面以STM32 PIN为例讲解引脚绑定中断。

1)实现中断回调函数表(方法不限于此),如STM32最多有16条外部中断线,即最多可同时打开16个外部中断,所以中断回调函数表初始化如下所示:

2)STM32 PIN驱动pin_attach_irq接口的部分代码如下所示,首先根据pin引脚编号获取到中断回调函数表的索引,然后为回调表对应索引的元素赋值。

当使能中断,触发外部中断时,进入中断并调用回调函数。需要注意的是,进出中断时必须分别调用rt_interrupt_enter()和rt_interrupt_leave()。

8.pin_irq_enable:引脚中断使能控制

操作方法pin_irq_enable用于设置引脚的中断开关状态,其原型如下所示:

pin_irq_enable方法的参数及返回值如表3-6所示。

表3-6 pin_irq_enable方法的参数及返回值

来看一个引脚中断使能控制的示例,PIN驱动根据参数enabled开启或者关闭引脚中断。STM32 PIN驱动pin_irq_enable方法的部分代码如下所示。

9.pin_detach_irq:引脚脱离中断

操作方法pin_detach_irq是用于脱离引脚绑定的中断回调函数的接口,该方法根据传入的引脚编号,脱离该引脚已经绑定的中断回调函数,其原型如下所示:

pin_detach_irq方法的参数及返回值如表3-7所示。

表3-7 pin_detach_irq方法的参数及返回值

引脚脱离中断示例如下所示,PIN驱动根据参数引脚编号,重置对应的引脚中断回调函数表。STM32 PIN驱动的pin_detach_irq方法的部分代码如下所示。

3.3 注册PIN设备

PIN设备的操作方法都实现后,需要注册设备到操作系统,注册时提供PIN设备的名称和操作方法作为入参,注册PIN设备的接口原型如下所示:

rt_device_pin_register接口的参数与返回值如表3-8所示。

表3-8 rt_device_pin_register接口的参数与返回值

STM32 PIN驱动注册PIN设备的代码片段如下所示。

其中,stm32_pin_ops是在3.2节实现设备的操作方法时定义的,保存了PIN所有操作方法的函数指针。

3.4 驱动配置

下面是具体的驱动配置细节。

1.Kconfig配置

下面参考bsp/stm32/stm32f407-atk-explorer/board/Kconfig文件对PIN驱动进行相关配置,如下所示:

我们来看看一些关键字段的意义。

❏BSP_USING_GPIO: PIN驱动代码对应的宏定义,这个宏控制决定PIN驱动相关代码是否会添加到工程中。

❏RT_USING_PIN: PIN驱动框架代码对应的宏定义,这个宏控制PIN驱动框架的相关代码是否会添加到工程中。

❏defaulty: BSP_USING_GPIO宏默认打开。

2.SConscript配置

HAL_Drivers/SConscript文件给出了PIN驱动添加情况的判断选项,代码如下所示。这是一段Python代码,表示如果定义了宏BSP_USING_GPIO, drv_gpio.c会被添加到工程的源文件中。

3.5 驱动验证

驱动开发者完成驱动的编写后,还需进行驱动的验证,保证编写的驱动可以正常使用,PIN驱动验证流程如下所示。

编写的驱动会将PIN设备注册到系统中,此时PIN设备将在I/O设备管理器中存在。验证设备功能时,我们需要运行代码,将代码编译下载到开发板中,然后在控制台中使用list_device命令查看已注册的设备,此时已经包含PIN设备,如下所示。

之后则可以使用PIN设备驱动框架层提供的统一API对PIN进行操作了。

若开发板上有按键或者LED灯,可以编写简单的测试代码来对驱动进行测试验证。如ART-Pi开发板上有两个LED灯,其中蓝灯D2连接在PE4引脚上,可以使用PIN框架提供的API来控制PE4引脚的电平状态,从而控制LED灯的亮灭了,测试代码如下:

代码运行效果:开发板上的蓝灯D2会周期性闪烁。

3.6 本章小结

本章讲解了如何开发PIN设备驱动、如何将PIN设备对接到设备驱动框架、如何验证PIN设备驱动是否可用。 vWgoZTwl6M4oJP+txs5OfnYxeJ0YWZ7qHHRharP37ksOx5kX9TsfuNn58Or1/MJG

点击中间区域
呼出菜单
上一章
目录
下一章
×