本章内容对应视频讲解链接(在线观看):
程序源码在网盘资料“imx6ull 驱动程序配套资料\021-Linux I2C 驱动实验”路径下。
我们可以先来体验一下,在 Linux 上操作 I2C 是多么的容易,我们可以先来看一下系统里面都有哪些 I2C的节点,这里以终结者 imx6ull 开发板为例。如下图所示:
Linux 有一个非常重要的概念叫一切皆文件,那么我们能不能在应用层通过 open 这些节点来操作 I2C 来跟外设 I2C 通信的芯片进行一个数据交流呢?当然是可以的,我们来一起看一下,这里我们以 7 寸 RGB 屏幕上的触摸芯片 FT5X06 为例,迅为所有开发板都是支持迅为 7 寸 RGB 屏幕屏的,所有都是可以进行这个验的。迅为的屏幕除了 4.3 寸和 10.1 寸屏外,其他尺寸的屏幕的触摸芯片都是 FT5X06,都是可以进行这个实验的。
本次实验我们使用的从机为 FT5X06 触摸芯片。 FT5x06 系列 ICs 是单芯片电容式触摸屏控制器 IC,带有一个内置的 8 位微控制器单元(MCU)。采用互电容的方法,在配合的相互的电容式触摸面板,它支持真正的多点触摸功能。FT5x06 具有用户友好的输入的功能,这可以应用在许多便携式设备,例如蜂窝式电话,移动互联网设备,上网本和笔记本个人电脑。FT5x06 系列 IC 包括 FT5206/FT5306/FT5406。FT5x06 可以捕获 5 个触摸点,编写驱动时,只要去获取这几个点的数据,然后上报就可以了。之后我们的实验也是读取的其中一个寄存器,如下图所示,我们可以在 FT5X06 的数据手册上查找到。
我们打开 imx6ull 开发板的底板原理图,我们通过原理图先来确定一下 FT5X06 使用的是哪个 I2C,通过下面的截图我们可以看到在终结者开发板上触摸芯片 FT5X06 使用的是 I2C2。
我们输入如下图所示命令,查找 I2C2 对应的设备节点,我们查找如下图所示:
.
所以 I2C2 设备的地址是 0038,对应的节点是 dev 下面的 i2c-1。如果我们要在终结者的上和触摸芯片FT5X06 进行通信,只要操作 dev 下的 i2c-1 这个节点就可以了。
那我们怎么在应用层操作 I2C 呢?应用层操作 I2C 是以数据包进行交流的,所以我们在应用层就要进行封包的操作。数据包对应的结构体是 i2c_rdwr_ioctl_data,这个结构体定义在 include\uapi\linux\i2c-dev.h 下面:定义如下:
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data
{
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
第一个结构体成员是我们要发送的数据包的指针,第二个结构体成员是发送数据包的个数。
我们来看一下 i2c_msg 结构体的定义,这个结构体是定义在 include\uapi\linux\i2c.h 下面,定义如下:
struct i2c_msg
{
__u16 addr; /* slave address */
__u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
结构体成员 addr 是我们从机的地址,flags 为读写标志位,如果 flags 为 1,则为读,反之为 0,则为写。len 为 buf 的大小,单位是字节。当 flags 为 1 是,buf 就是我们要接收的数据,当 flags 为 0 时,就是我们要发送的数据。
那么我们要怎么设计我们的程序呢?我们来看一下。
/*
* @Author: topeet
* @Description: 应用程序与 I2c 通信
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int fd;
int ret;
/**
* @description: i2c_read_data i2c 读数据
* @param {unsignedint} slave_addr:从机设备的地址
* @param {unsignedchar} reg_addr:寄存器的地址
* @return {*}
*/
int i2c_read_data(unsigned int slave_addr, unsigned char reg_addr)
{
unsigned char data;
//定义一个要发送的数据包 i2c_read_lcd
struct i2c_rdwr_ioctl_data i2c_read_lcd;
//定义初始化 i2c_msg 结构体
struct i2c_msg msg[2] = {
[0] = {
.addr = slave_addr, //设置从机额地址
.flags = 0, //设置为写
.buf = ®_addr, //设置寄存器的地址
.len = sizeof(reg_addr)}, //设置寄存器的地址的长度
[1] = {.addr = slave_addr, //设置从机额地址
.flags = 1, //设置为读
.buf = &data, //设置寄存器的地址
.len = sizeof(data)}, //设置寄存器的地址
};
//初始化数据包的数据
i2c_read_lcd.msgs = msg;
//初始化数据包的个数
i2c_read_lcd.nmsgs = 2;
//操作读写数据包
ret = ioctl(fd, I2C_RDWR, &i2c_read_lcd);
if (ret < 0)
{
perror("ioctl error ");
return ret;
}
return data;
}
int main(int argc, char *argv[])
{
int TD_STATUS;
//打开设备节点
fd = open("/dev/i2c-1", O_RDWR);
if (fd < 0)
{
//打开设备节点失败
perror("open error \n");
return fd;
}
while (1)
{
//i2C 读从机地址为 0x38,寄存器地址为 0x02 的数据
//我们从数据手册中得知 TD_STATUS 的地址为 0x02
TD_STATUS = i2c_read_data(0x38, 0x02);
// 打印 TD_STATUS 的值
printf("TD_STATUS value is %d \n", TD_STATUS);
sleep(1);
}
close(fd);
return 0;
}
编译应用程序程序如下图所示:
我们在挂载 nfs 以后,进入到共享目录/mnt/nfs/imx6ull/38i2c 目录下,运行应用程序,当我们没有触摸屏幕时,如下图所示:
当我们用一根手指触摸时,如下图所示:
当我们用三根手指触摸时,如下图所示:
当我们用五根手指触摸时,如下图所示:
迅为imx6ull开发板:
核心板参数
尺寸:38mm*42mm
PCB:6层
CPU:iMX6ULL ARM Cortex-A7架构 单核
iMX6ULL 商业级:内存:512M 存储:8G EMMC
iMX6ULL 工业级:内存:256M 存储:512M FLASH
工作电压:5V~16V 电压供电
系统支持:Linux-QT系统;Ubuntu core系统;Youcto系统;Buildroot系统;
商业级运行温度:-20℃ ~ +80℃
工业级运行温度:-40℃ ~ +80℃
引脚间距:1.27mm
引角扩展:i.MX6功能全部引出,146PIN脚
连接方式:邮票孔
底板参数
尺寸:12*19cm
PCB:2层
POWER:5V~16V电压供电
SWITCH:电源开关
EEPROM 存储:256字节,掉电后数据不丢失
4G模块:1个 全网通 (选配)
WIFI蓝牙模块:WIFI/蓝牙二合一模块,工作频段 2.4GHz,支持 IEEE802.11bgn 等标准,支持蓝牙 4.0 协议。
LVDS接口:1路(一个是标准HDMI 座(CON3),另一个是 30pin 的 FPC 座(J18), 两个接口实际上是同一路 LVDS 信号,用来连接迅为电子的 LVDS 屏幕)
RGB接口:1路
CAN:2 路 CAN 总线接口
RS485:1 路 RS485 总线接口
MIC:支持录音输入
PHONE:支持耳机输出
USB OTG:1路
USB HOST:2路
USB-UART:1路
mini HDMI:1个(一路标准MINI-HDMI 接口,i.MX6ULL处理器本身没有支持HDMI,通过一个 RGB 转 HDMI 的芯片扩展出HDMI接口,通过该接口来连接HDMI显示器。 )
网口:2路百兆以太网,RJ45 接口
TF卡槽:1个标准TF卡接口
SIM卡槽:1个标准SIM卡接口
T&H接口:温湿度传感器接口
TTL/RS485接口:TTL/RS485接口二选一
BUZZER:1个蜂鸣器
IRDA:1个红外一体化接收头
ADC电位器:支持
DIP SWITCH:8位拨码开关
JTAG:1个(可以通过下载/调试器来调试 i.MX6ULL 处理器)
CAMERA接口:1个 支持500万摄像头
TTL串口接口:20PIN (gpio引出:两个ad,一个spi,一路ttl。一路i2c,5个gpio,5v,3.3v电源)
GPIO接口:20PIN(包括:两路ADC,一路SPI,5个GPIO,一路TTL串口,一路I2C接口。)
重力加速度传感器:支持
红外接收模块:支持
光环境传感器:支持
实时时钟:断电后系统时间不丢失
LED:2个
按键:3个
|