RT-Thread的I2C总线驱动结构分析、移植及应用

2017-01-05 01:40
单片机与嵌入式系统应用 2016年12期
关键词:核心层时序嵌入式

高 培

(福建对外经济贸易职业技术学院 信息技术系,福州 350016)



RT-Thread的I2C总线驱动结构分析、移植及应用

高 培

(福建对外经济贸易职业技术学院 信息技术系,福州 350016)

针对RT-Thread操作系统下I2C总线驱动展开研究,对驱动结构进行介绍与分析。以STM32F407VG上的软件I2C驱动移植为例介绍了驱动移植步骤,并通过STM32F407VG读写24LC02B的实例,详细介绍I2C编程步骤及技术细节。最后通过实验验证I2C驱动移植及编程的有效性。实验结果表明,RT-Thread操作系统下的I2C总线驱动结构简洁,且易于移植及进行程序设计。

RT-Thread;I2C;驱动结构;移植;应用

引 言

RT-Thread嵌入式实时操作系统(Real-Time Operation System,RTOS)是国人自创的开源实时操作系统,借鉴了VxWorks、μc/os、RTXC(Real-Time eXecutive in C)等成熟的RTOS的优点,又具有自己的特点,在功能及性能方面不逊色于以上系统[1]。当前RT-Thread嵌入式实时操作系统在许多嵌入式设备上特别是物联网方面得到了广泛应用[2-5]。I2C(Inter-Integrated Circuit)总线是一种由Philips公司开发的两线式串行总线(一根时钟线,一根数据线),I2C总线可以使具有I2C总线接口的设备相互连接,它采用主从访问模式,主设备通过总线访问从设备。I2C总线具有接口线少,控制方式简单,器件封装形式小,降低了成本。因此,在嵌入式系统中有着广泛的应用[6-7]。

RT-Thread下的I2C总线驱动设计类似于Linux,但比Linux更加简洁。本文对RT-Thread(1.2.0版本)下的I2C总线驱动结构进行分析,介绍了I2C总线驱动的工作原理和移植方法。最后,以STM32F407VG连接2K位串行CMOS EEPROM(24LC02B)为例[8-9],介绍了RT-Thread及I2C总线驱动移植及应用程序设计。

1 I2C总线驱动结构

RT-Thread下的I2C总线驱动架构分为(如图1所示):设备层(i2c_dev.c,位于DeviceDrivers目录下)、总线核心层(i2c_core.c,位于DeviceDrivers目录下)、软件方式I2C接口层(i2c-bit-ops.c,位于DeviceDrivers目录下)、I2C硬件驱动层(移植目标,本项目中为stm32_i2c.c,位于Drivers目录下)、I2C外设驱动层或应用程序。

图1 RT-Thread下I2C总线驱动架构

1.1 I2C总线设备层(i2c_dev.c)

设备层(i2c_dev.c)是操作系统与总线核心层间的接口,同时规范了I2C总线设备的读写接口,一般用于I2C总线设备驱动。

设备层(i2c_dev.c)将I2C总线的操作抽象为基本操作接口(初始化、读操作、写操作、控制等),主要函数如表1所列。

表1 i2c_dev.c主要函数

常用的接口函数如下所示:

static rt_err_t i2c_bus_device_control(rt_device_t dev,rt_uint8_t cmd,void *args); // 控制函数

static rt_size_t i2c_bus_device_write(rt_device_t dev,rt_off_t pos,const void *buffer,rt_size_t count); //写操作函数

static rt_size_t i2c_bus_device_read(rt_device_t dev,rt_off_t pos, void *buffer, rt_size_t count); //读操作函数

其中,dev为I2C总线设备rt_device_t类型结构体指针,cmd为操作类型,args为操作类型所对应的数据(详见i2c_dev.c),pos包含操作方式与操作地址(分别对应pos的高十六位和低十六位),buffer为操作缓存首地址,count为缓存数据长度。

1.2 I2C总线核心层(i2c_core.c)

总线核心层(i2c_core.c)可作为应用程序或者I2C外设驱动的接口,是操作系统完成初始化及配置I2C驱动及应用程序或者I2C外设驱动实现I2C配置及通信的媒介。该层所涉及的主要函数见表2。

表2 总线核心层(i2c_core.c)主要函数

需要说明的是,应用程序或者驱动向系统申请指定I2C的控制权需要通过总线核心层的rt_i2c_bus_device_find函数,其具体形式如下所示:

struct rt_i2c_bus_device *rt_i2c_bus_device_find (const char *bus_name);

其中,bus_name为所需申请的I2C总线设备在系统注册时所使用的名字。

此外,总线核心层提供了三种I2C总线操作方式:传输(rt_i2c_transfer)、发送(rt_i2c_master_send)、接收(rt_i2c_master_recv)。其中rt_i2c_transfer是最常用的接口,具有读及写的功能,为驱动或应用程序开发提供了便利。其函数接口如下:rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,struct rt_i2c_msg msgs[],rt_uint32_t num);

其中,bus为所申请到的总线设备的rt_i2c_bus_device类型结构体指针,msgs为需要进行读写操作的rt_i2c_msg类型(需要根据读写时序来安排),num为msgs的维数。rt_i2c_msg结构体具体如下所示:

struct rt_i2c_msg{

rt_uint16_t addr; //设备地址

rt_uint16_t flags; //操作方式

rt_uint16_t len; //读写数据长度

rt_uint8_t *buf; //读写数据的起始地址

};

1.3 软件方式I2C总线接口层(i2c-bit-ops.c)

软件方式I2C总线接口层(i2c-bit-ops.c)提供了使用GPIO来实现I2C总线通信的软件方式接口函数,将I2C总线通信过程中的开始、停止、发送、接收等具体操作规范化。用户移植驱动程序时,无需再设计这些具体操作,只需要完成对应GPIO配置及操作函数(rt_i2c_bit_ops结构体中,详见i2c-bit-ops.h文件)即可,极大地规范并方便了驱动移植。其主要函数见表3。

表3 i2c-bit-ops.c主要函数

1.4 I2C总线硬件驱动层

I2C总线硬件驱动层是I2C总线驱动与硬件间的接口,是I2C总线驱动的具体实现,也是驱动移植时必须完成的主要部分。RT-Thread将具体I2C总线操作抽象并封装为I2C总线设备操作(rt_i2c_bus_device_ops),主要包括三个基本操作:主机传输(master_xfer)、从机传输(slave_xfer)、总线控制(i2c_bus_control),因此对于用户来说,只需要完成所需基本操作的驱动编写即可完成驱动的移植工作。以下分别介绍硬件I2C总线及软件I2C总线的硬件驱动层。

1.4.1 硬件I2C

对于硬件I2C,其总线的读写等具体操作都是通过寄存器的读写来完成的,因此驱动移植时,只需要按照所需操作的接口格式,对照寄存器手册,完成程序编写[10]。对于本文所使用的STM32F407VG,其I2C硬件驱动层主要函数如表4所列。

表4 硬件驱动层(硬件I2C)主要函数

其中,函数rt_hw_i2c_init的功能是初始化I2C总线硬件及驱动,其主要任务为:初始化I2C总线所使用的硬件资源(I2C控制器所涉及的寄存器),并将移植完成的操作函数入口地址等信息通过rt_i2c_bus_device_register函数向系统进行注册。

1.4.2 软件I2C

软件I2C是依据I2C通信时序标准,通过控制GPIO口来实现通信。由于RT-Thread驱动框架中已经将软件方式I2C进行规范,提供标准接口层(i2c-bit-ops.c),因此,软件I2C的移植也得到了简化。与硬件I2C不同,软件I2C的基本操作已经被封装在标准接口层中(i2c-bit-ops.c),驱动移植时无需再重复这些工作,只需要提供标准接口层的具体实现函数(具体形式详见i2c_bit_ops.h文件中的rt_i2c_bit_ops结构体形式),对于本文所使用的STM32F407VG,其I2C硬件驱动层需要移植的主要函数如表5所列。

表5 硬件驱动层(软件I2C)主要函数

此外,对于软件I2C硬件驱动层中的初始化函数(rt_hw_i2c_init),其主要编程工作为:①对I2C接口所使用的两个I/O口进行初始化;②将set_sda等函数指针及延时时间等参数封装入rt_i2c_bit_ops结构中;③调用rt_i2c_bit_add_bus函数,借助rt_i2c_bit_ops结构向标准接口层进行注册,进一步由标准接口层向系统完成总线设备驱动的注册工作。

2 I2C总线驱动移植及应用

本节将详细介绍RT-Thread下的I2C总线驱动移植,并以24LC02B的读写为例,介绍I2C总线驱动应用。本文使用STM32F407VG的PB6和PB7引脚分别作为软件I2C总线的SCL和SDA,以主模式连接24LC02B模块。

2.1 I2C总线驱动移植

本文所使用的RT-Thread 1.2.0版本提供了简单的I2C驱动支持。为了使用该模块,需要将i2c_dev.c、i2c_core.c、i2c-bit-ops.c三个文件添加到工程项目中。之后,在rtconfig.h添加宏定义:

#define RT_USING_I2C

#define RT_USING_I2C_BITOPS

I2C总线驱动移植主要工作在I2C硬件驱动层,该部分主要函数介绍见第1.4.2节。移植工作主要分为: I2C总线驱动硬件初始化及操作方法和延时子程序。

2.1.1 I2C总线驱动硬件初始化及操作方法

I2C总线驱动硬件初始化主要完成I2C总线所涉及的两个I/O引脚的硬件初始化及输入输出操作。对于STM32F407VG,I2C总线驱动硬件初始化函数需要完成的操作如图2所示:①GPIO引脚外设时钟开启;②GPIO引脚模式初始化;③rt_i2c_bus_device和rt_i2c_bit_ops结构体初始化;④借助标准的接口层向系统注册I2C总线(rt_i2c_bit_add_bus)。在系统初始化时(如rt_init_thread_entry中)调用该函数,即可完成I2C总线驱动的硬件及系统初始化。

图2 I2C总线驱动硬件初始化流程图

操作方法主要完成set_sda、set_scl、get_sda、get_scl四种基本操作的移植,用户可以根据处理器手册和库函数编程实现。最后需要将这4个函数的入口地址通过rt_i2c_bit_ops类型结构体形式传递给操作系统。

需要说明的是,向系统注册的I2C总线接口函数如下:

rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus, const char *bus_name);

其中,指针bus是指向包含硬件驱动层信息的rt_i2c_

bus_device类型结构体,name为向系统注册的该I2C总线名,用户可以通过name向系统申请和访问该I2C总线。

2.1.2 延时子程序

延时子程序主要用于实现I2C通信时序,其默认单位为μs,准确的延时子程序有助于正确设置I2C通信速率。对于使用while(i)形式的延时子程序,用户需要根据处理器的频率进行有针对性的调整。

2.2 I2C总线设备驱动应用

24LC02B是一款串行CMOS EEPROM芯片,该芯片使用I2C总线进行读写等控制。其单字节写入时序、随机读取时序分别如图3和图4所示[9]。本节将以在指定位置写入数据,并读取该指定位置数据为例,来详细介绍RT-Thread下I2C总线设备驱动的总线核心层接口函数应用,并验证驱动移植的有效性(I2C设备层一般用于驱动编写,相对复杂,由于篇幅所限,本文使用简洁的总线核心层)。

图3 24LC02B字节写入时序

图4 24LC02B随机读取时序

总线核心层接口函数如第1.2节中介绍,相比总线设备层接口函数,其接口函数格式更简单、直观,方便读写时序的实现。使用总线核心层接口实现24LC02B读写的程序流程图如图5所示。

图5 24LC02B读写程序流程

首先,调用rt_i2c_bus_device_find函数向系统申请所需的总线设备(如图中“i2c1”);正确申请到总线设备后,系统会将该I2C总线设备的rt_i2c_bus_device类型结构体指针返回(如图中存储在dev中),利用该指针和rt_i2c_transfer函数(详见第1.2节)即可实现24LC02B的字节写入与读取操作,其关键是根据读写时序合理设置rt_i2c_msg结构体。

对于指定位置写入数据操作,其写入顺序为:写控制字、写入指定位置地址、写入数据。因此,只需要一个rt_i2c_msg结构体(本程序中使用msg_wr),其具体内容为:

msg_wr.addr =24LC02B;

//24LC02B地址

msg_wr.buf = msg_buf_wr;

msg_wr.flags = RT_I2C_WR; //写操作

msg_buf_wr[0] = 23; //指定写入地址

msg_buf_wr[1]++;

msg_wr.len = 2; //操作数据长度

len = rt_i2c_transfer(dev,&msg_wr,1); //返回写入字符数

对于读取指定位置数据操作,其写入顺序为:写控制字、写入指定位置地址、写控制字、读取数据。注意:两次写控制字间不能有STOP时序。因此不能使用两次rt_i2c_transfer来实现该操作,应该使用两个rt_i2c_msg结构体来实现(本程序中记为使用msg_rd[2]),其具体内容为:

// msg_rd[0]初始化

msg_rd[0].addr = 24LC02B;

//24LC02B地址

msg_rd[0].buf = msg_buf_wr;

msg_rd[0].flags = RT_I2C_WR; //写操作

msg_buf_wr[0] = 23; //指定读取地址

msg_rd[0].len = 1; //操作数据长度

// msg_rd[1]初始化

msg_rd[1].addr = 24LC02B; //24LC02B地址

msg_rd[1].buf = msg_buf_rd;

msg_rd[1].flags = RT_I2C_RD; //读操作

msg_buf_wr[0] = 23; //指定读取地址

msg_rd[0].len = 1; //操作数据长度

len = rt_i2c_transfer(dev,msg_rd,2);

//返回读取到的字节数

由图6所示实验结果可知,程序正确申请到I2C总线设备后,在地址为23处,从0开始写入字节数据,随后读取该地址上的字节数据,通过对比可以看出,读取到的数据与写入数据完全相同。综上所述,本次I2C总线设备的驱动移植是成功的,并且利用I2C总线核心层接口进行24LC02B的读写操作应用也是成功的。

结 语

图6 实验结果

[1] 曹成.嵌入式实时操作系统RT-Thread原理分析与应用[D].青岛:山东科技大学,2011.

[2] 宋天楹,张红梅,冯欢.CAN-RS232转换器在实时操作系统RT-Thread上的实现[J].自动化仪表,2012,33(4):70-72.

[3] 苏宪利,郑一麟.基于RT-thread的机床物联网系统设计与实现[J].组合机床与自动化加工技术,2014(6):69-72.

[4] 张丽彪,骆东佳,张舰航,等.基于RT-Thread和Yeelink的物联网平台开发的应用设计[J].电子技术与软件工程,2015(16):70-70.

[5] 李云红,田冀达,陈航.RT-Thread操作系统的电池管理系统设计[J].单片机与嵌入式系统应用,2015(7):14-17.

[6] 李祥兵,郑扣根.Linux中I2C总线驱动程序的开发[J].计算机工程与设计,2005,26(1):41-43.

[7] 朱南皓,李正祥.嵌入式Linux中I2C设备驱动程序的研究与实现[J].微计算机信息,2010,26(11):67-69.

[8] RT-Thread开发组.RT-Thread编程指南,2014.

[9] Microchip Technology Inc.24LC01B/02B 1K/2K 2.5V CMOS EEPROMs,1995.

[10] STMicroelectronics.RM0090 Reference manual STM32 F405xx, STM32F407xx,STM32F415xx and STM32 F417xx advanced ARM-based 32-bit MCUs,2012.

[4] 邵长彬,李洪亮.用Busybox制作嵌入式Linux根文件系统[J].微计算机信息,2007,23(10-2):48-50.

[5] 查启鹏.基于嵌入式Linux的Flash驱动与文件系统的研究与实现[D].南京:东南大学,2008.

[6] 王学龙.嵌入式Linux系统设计与应用[M].北京:清华大学出版社,2001.

[7] 彭浩,龚杰,秦建敏.基于S3C2440的嵌入式Linux根文件系统构建[J].电子设计工程,2010,18(6):20-22.

[8] 李桂香,常赟杰.嵌入式Linux文件系统研究与应用[J].电脑开发与应用,2010,23(5):5-7.

陈选育(工程师),研究方向为光通信技术、嵌入式软件开发。

(责任编辑:薛士然 收稿日期:2016-06-23)

Structure Analysis,Migration and Application of I2C Bus Driver for RT-Thread

Gao Pei

(Department of Information Technology,Fujian International Business&Economic College,Fuzhou 350016,China)

Aiming at the I2C bus driver of RT-Thread operating system,the structure of I2C bus driver is presented and analyzed.The I2C driver migration process is introduced with the example of the I2C drive migration for STM32F407VG,and by the read/write 24LC02B through STM32F407VG,the I2C programming steps and technical details are introduced.Finally,an experiment is taken to verify the effectiveness of the migration and programming of I2C driver.The experiment results show that the I2C bus driver structure of RT-Thread is simple and easy for migration.

RT-Thread;I2C;driver structure;migration;application

TP316.2

A

�士然

2016-06-17)

猜你喜欢
核心层时序嵌入式
清明
Focal&Naim同框发布1000系列嵌入式扬声器及全新Uniti Atmos流媒体一体机
基于不同建设时序的地铁互联互通方案分析
TS系列红外传感器在嵌入式控制系统中的应用
搭建基于Qt的嵌入式开发平台
基于FPGA 的时序信号光纤传输系统
油田光纤化改造核心层建设方案的探讨
浅谈宽带IP城域网结构规划和建设
校园网核心层设计探究
政府办公区域无线网络覆盖的设计