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

第4章
I2C总线设备驱动开发

I2C总线是PHILIPS公司开发的一种半双工、双向二线制同步串行总线。本章将带领读者了解I2C总线设备驱动的开发,分为硬件I2C总线和软件I2C总线两部分。

I2C是以主从的方式工作的,I2C主从连接图如图4-1所示。其中,Vdd表示电源,R p 表示上拉电阻。在总线上有2个主设备(Master)和3个从设备(Slave),主设备是两个MCU,从设备分别为I2C接口的一些模块或器件,如LCD、EEPROM、A/D转换器。I2C允许同时有多个主设备存在,例如图中的2个主设备。每个连接到总线上的器件都有唯一的地址,如3个从设备都有自己的地址。主设备通过从设备的地址来选择要通信的对象。主设备启动数据传输并产生时钟信号,对从设备进行寻址,但是同一时刻只允许有一个主设备。

图4-1 I2C主从连接图

在嵌入式领域中,一般将MCU作为主设备,通过I2C总线与其他从设备进行通信。MCU内部一般会内置I2C硬件控制器,用来控制I2C总线并与从设备通信。RT-Thread将这种能够控制I2C总线的外设抽象为I2C总线设备。一个I2C总线设备对应一条I2C总线,也对应着一个I2C硬件控制器。

I2C总线传输数据时只需两根信号线:一根是双向数据线SDA(Serial Data),另一根是I2C主设备产生的时钟线SCL(Serial Clock)。这两根信号线的时序可以由I2C硬件控制器产生,也可以由GPIO模拟产生,所以I2C总线设备驱动将以这两种类型为基础进行讲解。

4.1 I2C层级结构

I2C层级结构如图4-2所示。

图4-2 I2C层级结构图

1)应用层一般是由开发者编写的业务代码,这一层处于I2C设备驱动框架层之上,通过调用I2C设备驱动框架提供的统一接口完成具体业务代码的编写,如EEPROM、I2C液晶屏等的驱动代码。

2)I2C设备驱动框架层是抽象出的通用的软件层,和平台无关,向应用层提供统一的接口供应用层调用。I2C设备驱动框架源码位于components\drivers\i2c中,包含以下文件。

①i2c_core.c/i2c_dev.c:I2C核心代码,包含为应用层提供的I2C收发通用通信接口rt_i2c_transfer,为总线驱动层提供的I2C总线设备结构struct rt_i2c_bus_device,为硬件I2C总线设备驱动提供的操作方法struct rt_i2c_bus_device_ops,以及注册接口rt_i2c_bus_device_register。

②i2c-bit-ops.c:软件I2C总线设备框架,实现时序控制、发送和接收框架、操作方法struct rt_i2c_bit_ops,以及注册接口rt_i2c_bit_add_bus。

3)I2C总线设备驱动层的实现与平台相关,分为硬件I2C驱动和GPIO模拟I2C驱动。源码位于具体bsp目录下,与bsp相关,下面是两种驱动的操作方法。

①软件I2C总线设备驱动:需要实现软件I2C总线设备的操作方法struct rt_i2c_bit_ops,实例化软件I2C总线设备,然后调用rt_i2c_bit_add_bus注册I2C总线设备。

②硬件I2C总线设备驱动:需要实现硬件I2C总线设备的操作方法struct rt_i2c_bus_device_ops,实例化硬件I2C总线设备,然后调用rt_i2c_bus_device_register注册I2C总线设备。

4)最下面一层是使用I2C接口的硬件模块,如I2C接口的液晶屏、传感器等。这些模块通过I2C通信协议与MCU进行通信。

4.2 I2C总线设备结构

总线设备结构struct rt_i2c_bus_device的实现如下所示,该设备结构也将作为硬件I2C总线设备与软件I2C总线设备的基类使用。

其中大部分参数仅供设备框架内部使用,只有ops参数定义了和硬件相关的操作方法。ops也常被称作操作方法。下面分别讲述硬件与软件I2C总线设备的驱动实现。

4.3 硬件I2C总线设备驱动开发

一款芯片可以选择实现硬件I2C总线设备驱动,也可以选择实现软件I2C总线设备驱动,这取决于项目需求以及使用便利程度。硬件I2C总线设备驱动开发,向上对接I2C设备驱动框架,向下可调用厂商提供的I2C库函数进行数据的传输。我们先了解硬件I2C总线设备驱动开发步骤,之后学习如何实例化一个硬件I2C总线设备。

(1)硬件I2C总线设备驱动开发步骤

硬件I2C总线设备驱动开发的主要任务是实例化一个或者多个I2C总线设备,实现I2C总线设备操作方法,然后注册I2C总线设备。驱动文件一般命名为drv_hw_i2c.c。本章将会以NXP lpc54114为例,讲解硬件I2C总线设备驱动的具体实现。

(2)实例化设备

硬件I2C总线实例化设备除了定义struct rt_i2c_bus_device之外,还需要包含MCU厂商自定义的I2C结构,我们在注册时还需要传入I2C bus name,所以需要结合rt_i2c_bus_device结构根据实际情况进行扩充,以下是针对LPC芯片的硬件I2C总线设备结构:

以下示例代码仅实现了1个I2C总线设备对象,当需要实现多个对象时,需要增加I2C总线设备对象表,如下所示:

在实例化硬件I2C总线设备之后,接下来按照驱动开发步骤进行该驱动的开发。

4.3.1 实现设备的操作方法

I2C总线设备的rt_i2c_bus_device_ops参数定义了和硬件相关的操作方法,其结构体原型如下。

下面将介绍相关操作方法的作用和实现方法。

1.为设备定义操作方法

驱动开发者需要在驱动文件中实现这些操作方法。如下所示为I2C总线设备定义的操作方法,在硬件驱动中只需要完成I2C的传输。首先使用struct rt_i2c_bus_device_ops实例化一个如下所示的结构,然后实现对应的函数。

2.master_xfer:总线数据传输

操作方法master_xfer是负责硬件I2C总线数据传输的接口,其原型如下所示:

master_xfer方法通过对硬件I2C总线控制器的控制,完成num个消息的传输。master_xfer方法的参数及返回值如表4-1所示。

表4-1 master_xfer方法的参数及返回值

其中,msgs参数存储了需要传输的消息,其结构原型struct rt_i2c_msg在驱动框架中的定义如下所示。其结构中包含了I2C总线设备上挂载的从设备地址、读写标志位、需要读写的数据长度和读写数据的存储地址。

我们来看操作方法master_xfer的实现示例。在实现此操作方法时,需要根据传入的参数num获取传输消息的个数,然后循环调用厂商的库函数提供的I2C传输接口,将需要传输的消息一一传输出去,示例代码如下所示。

4.3.2 注册设备

I2C总线设备的操作方法实现后需要注册设备到操作系统,注册硬件I2C总线设备的接口为rt_i2c_bus_device_register,其原型如下所示:

rt_i2c_bus_device_register接口的参数及返回值如表4-2所示。

表4-2 rt_i2c_bus_device_register接口的参数及返回值

我们来看一个硬件I2C设备实现rt_hw_i2c_init的示例代码,以实现时钟初始化、总线设备初始化、硬件I2C初始化、总线设备注册。

4.3.3 驱动配置

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

1.Kconfig配置

下面参考bsp\lpc54114-lite\drivers\Kconfig文件配置I2C总线设备驱动的相关选项,如下所示:

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

1)BSP_USING_I2C4:I2C总线设备驱动代码对应的宏定义,这个宏控制I2C总线设备驱动相关代码是否会添加到工程中。

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

3)defaulty:表示默认打开BSP_USING_I2C4。

2.SConscript配置

在bsp\lpc54114-lite\drivers\SConscript文件给出了I2C总线设备驱动添加情况下的判断选项,代码如下所示。这是一段Python代码,表示如果定义了宏BSP_USING_I2C4,则drv_hw_i2c.c会被添加到工程的源文件中。

4.3.4 驱动验证

注册设备之后,I2C总线设备将被注册到I/O设备管理器中。在进行驱动验证时需要先查看该驱动是否注册成功,可以编译下载运行添加了驱动的RT_Thread代码,在控制台界面使用list_device命令查看已注册的设备是否包含了I2C总线设备。

若包含I2C总线设备,则表明注册成功,之后可以使用I2C设备驱动框架层提供的统一API对I2C总线设备进行操作。

4.4 软件I2C总线设备驱动开发

软件I2C总线设备驱动使用GPIO模拟时序实现,时序已经在框架i2c-bit-ops.c中实现了,在驱动中只需要实现对应SCL与SDA引脚的设置及获取,并注册为I2C总线设备即可。

软件I2C总线设备驱动开发的主要任务就是实例化一个I2C总线设备,实现I2C总线设备操作方法,然后注册I2C总线设备。驱动文件一般命名为drv_sw_i2c.c,驱动开发人员可以按照如下步骤进行。

1)实例化软件I2C总线设备。

2)实现I2C总线设备的操作方法struct rt_i2c_bus_device_ops。

3)使用rt_i2c_bus_device_register注册软件I2C总线设备。

4)驱动配置。

5)驱动验证。

本节将以STM32的软件I2C总线设备驱动为例讲解I2C总线设备驱动的具体实现。

软件I2C总线设备继承了I2C总线设备基类struct rt_i2c_bus_device,但实例化软件I2C还需存储SDA、SCL、设备名称等信息,并对SDA、SCL引脚执行相应的操作。所以增加struct rt_i2c_bit_ops结构体成员,在其中存储以上所述信息。

每个MCU都可定义多个软件I2C总线设备实例,例如static struct stm32_i2c i2c_obj[6]定义了6个软件I2C总线设备对象。

4.4.1 实现设备的操作方法

软件I2C总线设备的操作方法结构体原型如下:

1.为设备定义操作方法

rt_i2c_bit_ops为STM32软件I2C总线设备定义了操作方法,其实现如下所示,操作方法的名字可以自定义:

在上述结构体中,data元素用来存储SDA引脚、SCL引脚、设备名称等硬件相关信息,在默认情况下配置为RT_NULL,在实际使用过程中根据具体的设备重新赋值,参见下文。stm32_set_sda、stm32_set_scl是设置SDA、SCL引脚电平的操作方法名,stm32_get_sda、stm32_get_scl是获取SDA、SCL引脚电平的操作方法名,delay_us是软件I2C时序延时使用的,用于设置SDA/SCL微秒级别的延时时间段。timeout是超时时间,单位是一个系统时钟,用于判断SCL信号线是否在规定时间内满足起始条件和终止条件,默认值为100。

接下来,我们先实现data元素,再定义设备对象,最后分别实现这些操作方法。

rt_i2c_bit_ops中的data需要保存SDA引脚编号、SCL引脚编号以及设备名称,这样在执行set_sda与get_sda时,才能通过data元素找到SDA引脚并对其进行操作,SCL也相同。

STM32 data元素的实现示例如下:

soft_i2c_config包含各个I2C总线设备的配置信息,在设备注册时,该soft_i2c_config将赋值给私有数据data元素。

根据soft_i2c_config计算设备数量,并申请i2c_obj数组,以定义多个软件I2C总线设备对象,如下所示:

2.set_sda:设置SDA引脚电平

操作方法set_sda的作用是设置SDA引脚电平,其原型如下所示:

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

表4-3 set_sda方法的参数

以下示例代码是STM32 I2C总线设备的操作方法set_sda的实现,先获取SDA引脚对应的引脚号,然后操作对应的引脚,完成SDA引脚电平的设置。

3.set_scl:设置SCL引脚电平

操作方法set_scl是用于设置SCL引脚电平的接口,其原型如下所示:

set_scl方法的参数如表4-4所示。

表4-4 set_scl方法的参数

以下示例代码是STM32 I2C总线设备的操作方法set_scl的实现,先获取SCL对应的引脚号,然后设置对应的引脚电平,完成SCL引脚电平的设置。

4.get_sda:获取SDA引脚电平

操作方法get_sda的作用是获取SDA引脚电平,其原型如下所示:

表4-5 get_sda方法的参数

get_sda方法的参数如表4-5所示。

以下示例代码是STM32 I2C总线设备的操作方法get_data的实现,首先拿到SDA引脚,然后读取该引脚的电平。

5.get_scl:获取SCL引脚电平

操作方法get_scl的作用是获取SCL引脚电平,其接口原型如下所示:

其中参数data存储着设备的config信息,通过data参数可以获取SCL引脚号,进而获取对应的引脚电平。

以下示例代码是STM32 I2C总线设备的操作方法get_scl的实现,首先拿到SCL引脚,然后读取该引脚的电平。

6.udelay:延时函数

操作方法udelay的作用是提供微秒级延时,用于设置I2C总线设备的时序延时,udelay接口参数us表示延时时间,函数原型如下所示。

I2C时序延时不能使用RT-Thread提供的rt_thread_delay这类函数,这类函数是会进行线程挂起和恢复的,并且其延时单位较大,一般在毫秒级别。而I2C的时序延时时间在微秒级别,且不能被线程打断,所以需要使用硬件定时器实现微秒级别的延时。

在STM32中使用SysTick实现udelay函数微秒级延时的示例如下所示。

4.4.2 注册设备

接下来需要注册软件I2C总线设备到操作系统,注册接口如下所示:

rt_i2c_bit_add_bus接口的参数及返回值如表4-6所示。

表4-6 rt_i2c_bit_add_bus接口的参数及返回值

STM32注册软件I2C总线设备的部分代码如下。

软件I2C总线设备驱动配置与验证和硬件I2C总线设备驱动配置与验证相似,不再赘述。需要注意的是,在访问I2C从设备时,从设备的地址需要去掉读写位。

4.5 本章小结

本章讲解了I2C总线设备驱动开发,分为硬件I2C总线驱动和软件I2C总线驱动两部分。

1)硬件I2C总线驱动是直接驱动I2C硬件控制器,需要实现总线数据传输函数。

2)软件I2C总线驱动是不使用MCU中的I2C硬件控制器,而是使用GPIO对I2C的时序进行模拟,需要完成I2C时序中一些拉高/拉低电平的动作,即SDA与SCL引脚电平的设置和获取。

在具体实现I2C总线设备驱动时,只需要根据硬件资源或项目需求选择其中一种方式实现即可。 THr1sgDnoEAYGVtMjH71MkD6Oea7QRBg6CnP3Hsl0zIbOW8ZDemHl+Ey9Pmi7U5B

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