zoukankan      html  css  js  c++  java
  • 迅为imx6ull开发板Linux I2C驱动实验-应用程序与I2C通信

    本章内容对应视频讲解链接(在线观看):
     程序源码在网盘资料“imx6ull 驱动程序配套资料21-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,这个结构体定义在 includeuapilinuxi2c-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 结构体的定义,这个结构体是定义在 includeuapilinuxi2c.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 ");
    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 ", 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个

  • 相关阅读:
    中断与异常
    轻松搞定C语言中复杂的声明
    C/C++中数组转换成指针的情况
    Linux下C程序的内存布局
    Java并发和多线程(二)Executor框架
    Java并发和多线程(一)基础知识
    java项目的划分方式:模块优先还是层优先?
    站在面试官角度看面试
    windows环境搭建禅道项目管理工具
    Linux环境搭建禅道项目管理工具
  • 原文地址:https://www.cnblogs.com/liyue3/p/15539149.html
Copyright © 2011-2022 走看看