不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动

简介: 本文是系列文章的第三篇,展示了如何在Android系统中利用现有的i2c bus驱动,通过编写设备树节点和应用层的控制代码,实现对基于i2c bus的Slaver设备(如六轴陀螺仪模块QMI8658C)的控制,而无需编写设备驱动代码。

一、前言

本文是系列文章的第3篇,介绍如何利用内核中现有的i2c bus驱动,在最少的代码量上,做到对slaver设备的控制。基于现有的i2c bus驱动,我们可直接在应用层编写slaver设备的控制代码!如此,大大降低了设备驱动的开发难度。当然,工资还是得照样领!

本文开发板基于Amlogic T972平台, Android 9.0

二、系列文章

第1篇 :不写一行代码(一):实现安卓基于GPIO的LED设备驱动

第2篇 :不写一行代码(二):实现安卓基于PWM的LED设备驱动

第3篇:不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动

三、准备工作

3.1 挑选I2C引脚

从芯片datasheet,结合开发板可用插座脚,如下所示,可挑选GPIOZ_1(SDA)、GPIOZ_2(SCL)作为实验对象

图一:Amlogic T972 Datasheet

image

图二:开发板J31引出的两排引脚

image

3.2 测试设备:QMI8658C

找了半天,没有更简单的i2c模块(例如基于I2C接口的热传感器,寄存器会很简单),只有一个六轴陀螺仪模块,所以就将就用吧!

image

  • VCC 3.3V – 红线
  • GND – 黑线
  • SCL2 – 黄线,连接GPIOZ_2(排针J31的PIN9)
  • SDA2 – 绿线 ,连接GPIOZ_1(排针J31的PIN8)
  • 白色和蓝色未使用

四、编写设备树节点

4.1 查找MUX

默认情况下,GPIOZ_1和GPIOZ_2是普通的GPIO引脚,无法作为I2C引脚来使用,所以我们需要修改这两个引脚的MUX配置,这些配置都是原厂已经写好的,我们只需找出来,然后填入到i2c1的控制器配置中即可。

//文件:common\arch\arm\boot\dts\amlogic\mesontl1.dtsi

    i2c1_z_pins:i2c1_z {
   
   
        mux {
   
   
            groups = "i2c1_sda_z",
                "i2c1_sck_z";
            function = "i2c1";
            bias-pull-up;
            drive-strength = <3>;
        };
    };

    /*
     * i2c sleep mode1: set the gpio the input
     * in this scene, pull up power is off
     */
    i2c1_z_pins_slp_input:i2c1_z_slp_input {
   
   
        mux {
   
   
            groups = "GPIOZ_1", "GPIOZ_2";
            function = "gpio_periphs";
            input-enable;
            bias-disable;
        };
    };

4.2 修改i2c1引脚配置

4.2.1 修改前

&i2c1 {
   
   
    status = "okay";
    clock-frequency = <300000>;
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&i2c1_h_pins>; //未修改前,i2c1模块MUX连接的PIN脚不是GPIOZ_1和GPIOZ_2
    pinctrl-1 = <&i2c1_h_pins_slp_input>;//未修改前,i2c1模块MUX连接的PIN脚不是GPIOZ_1和GPIOZ_2

// …… 略 …… 
//添加测试所用设备的DTS节点描述
    i2c_tof_geo@6a {
   
   
        compatible = "test_i2c, i2c";
        reg = <0x6a>;
        status = "okay";
    };
};

4.2.2 修改后

&i2c1 {
   
   
    status = "okay";
    clock-frequency = <300000>;
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&i2c1_z_pins>; //选用GPIOZ_1和GPIOZ_2的PIN脚配置,GPIOZ_1和GPIOZ_2将连通i2c1控制器模块
    pinctrl-1 = <&i2c1_z_pins_slp_input>;

// …… 略 …… 
//添加测试所用设备的DTS节点描述,测试设备的slaver address=0x6A
    i2c_tof_geo@6a {
   
   
        compatible = "test_i2c, i2c";
        reg = <0x6a>;
        status = "okay";
    };
};

五、编译、烧录dt.img

参考系列文章第一篇(第四节):不写一行代码(一):实现安卓基于GPIO的LED设备驱动

5.1 烧录后效果

1)烧录后,通过sys-fs系统,切换到如下目录,可以看到设备1-006a,也就是i2c-1的第1个设备,地址为0x6A
x301:/sys # cd bus/i2c/devices/i2c-1/
x301:/sys/bus/i2c/devices/i2c-1 # ls
1-006a delete_device device i2c-dev name new_device of_node power subsystem uevent

(2) 继续进入1-006a设备的目录下,查看其设备树节点名称,可以看到:i2c_tof_geo
x301:/sys/bus/i2c/devices/i2c-1 # cd 1-006a/
x301:/sys/bus/i2c/devices/i2c-1/1-006a # ls
modalias name of_node power subsystem uevent
x301:/sys/bus/i2c/devices/i2c-1/1-006a # cat of_node/name
i2c_tof_geo
x301:/sys/bus/i2c/devices/i2c-1/1-006a #

图示:

在这里插入图片描述

六、编写test程序

6.1 创建文件

如下在AOSP代码的development目录下:

(1)创建目录,姑且就叫 i2c-slaver

(2)创建 Android.mk 和 i2c-slaver.c 文件

szhou@bc04:~/T972/android_x301/source/t962x3-t972-android9.0/development$ tree i2c-slaver/
i2c-slaver/
├── Android.mk
└── i2c-slaver.c

0 directories, 2 files
szhou@bc04:~/T972/android_x301/source/t962x3-t972-android9.0/development$

6.2 源码:Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := i2c-slaver

LOCAL_SRC_FILES := i2c-slaver.c

include $(BUILD_EXECUTABLE)

6.3 源码:i2c-slaver.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/string.h>

static int i2c_trans(int fd, __u8 rw, __u8 cmd, __u32 size, union i2c_smbus_data *data)
{
   
   
    struct i2c_smbus_ioctl_data args;

    args.read_write = rw;//0:I2C_SMBUS_WRITE, 1:I2C_SMBUS_READ
    args.command = cmd;
    args.size = size;
    args.data = data;
    return ioctl(fd,I2C_SMBUS,&args);
}

 static int i2c_write(int fd, __u8 cmd, __u8 value)
 {
   
   
     union i2c_smbus_data data;
     data.byte = value;
     return i2c_trans(fd,I2C_SMBUS_WRITE,cmd, I2C_SMBUS_BYTE_DATA, &data);
 }

 static int  i2c_read(int fd, __u8 cmd, __u32 size, union i2c_smbus_data *data)
 {
   
   
     __u32 i=0;
     if (i2c_trans(fd,I2C_SMBUS_READ,cmd, size, data))
     {
   
   
          printf("i2c_trans failed\n");
         return -1;
     }
     else
     {
   
   
          printf("\n");
         for(i=0; i<size; i++){
   
   
             printf("data[%d]=0x%02X \t", i, data->block[i]);
         }
         printf("\n");
         return 0;
     }
 }


int main()
{
   
   
    int fd;
    union i2c_smbus_data data;

    //打开i2c-1总线控制器
    fd = open("/dev/i2c-1", O_RDWR);
    if (fd == -1)
    {
   
   
        printf("zs, open i2c failed. \n");
        goto fail;

    }

    //访问Slaver地址为0x6A的设备
    if (ioctl(fd, I2C_SLAVE, 0x6A) < 0)
    {
   
   
        printf("zs, open i2c I2C_SLAVE failed. \n");
        goto fail;

    }

    //发送CMD初始化测试用的i2c-slaver设备,是一个陀螺仪,各位请换成自己的i2c设备
    i2c_write(fd, 0x06, 0xB0);
    usleep(300000);
    i2c_write(fd, 0x02, 0x60);
    i2c_write(fd, 0x03, 0x24);
    i2c_write(fd, 0x08, 0x83);

    //读取陀螺仪的X、Y、Z轴的原始数据,各2bytes,一共6bytes
    while(i2c_read(fd, 0x35, 6, &data) != -1){
   
   
        usleep(3*1000*1000); //每3秒读取一次
    } 

fail:
    close(fd);    
    return 0;
}

6.4 编译test程序

  • 注意:使用局部编译前,一般需要对整个源码做一次完整编译!
  • 生成位置:Install: out/target/product/x301/system/bin/i2c-slaver

编译步骤:

(1) source build/envsetup.sh
(2) lunch your-board
(3) make i2c-slaver

编译打印

root@d185403d1e6f:/home/builder/android_x301/source/t962x3-t972-android9.0# make i2c-slaver
// …… 略 ……
[100% 6/6] Install: out/target/product/x301/system/bin/i2c-slaver

#### build completed successfully (01:48 (mm:ss)) ####

root@d185403d1e6f:/home/builder/android_x301/source/t962x3-t972-android9.0#

七、测试

7.1 部署 i2c-slaver

1)ADB 推送i2c-slaver到板子上
Z:\T972\android_x301\source\t962x3-t972-android9.0\out\target\product\x301\system\bin>adb push i2c-slaver /data/
i2c-slaver: 1 file pushed, 0 skipped. 0.9 MB/s (16016 bytes in 0.016s)2)添加可执行权限
Z:\T972\android_x301\source\t962x3-t972-android9.0\out\target\product\x301\system\bin>adb shell chmod 777 /data/i2c-slaver

图示如下:
image

7.2 运行 i2c-slaver

因为打印默认是输出到串口的,所以运行部分,我们在串口上执行,当然,你也可以通过adb执行,之后dmesg查看打印

130|:/data # ./i2c-slaver                                                      

//  ……  略 ……
data[0]=0x20    data[1]=0xD4    data[2]=0xF5    data[3]=0x4A    data[4]=0xF4    data[5]=0xBF 
[17541.246189@2]- [dhd-wlan0] wl_run_escan : LEGACY_SCAN sync ID: 176, bssidx: 0
data[0]=0x20    data[1]=0xCE    data[2]=0xF5    data[3]=0x4D    data[4]=0xF4    data[5]=0xB9 
//  ……  略 ……

data[0]=0x20    data[1]=0xF7    data[2]=0xF1    data[3]=0x99    data[4]=0xF9    data[5]=0x6E 
^C
130|:/data #

运行效果的图示如下,通过晃动陀螺仪模块,可以看到它的值会大幅变动,如果静置的话,则值能基本保持不变或变化很小

图示如下:
image

相关文章
|
存储 Android开发
如何查看Flutter应用在Android设备上已被撤销的权限?
如何查看Flutter应用在Android设备上已被撤销的权限?
648 64
|
存储 Android开发 数据安全/隐私保护
如何在Android设备上撤销Flutter应用程序的所有权限?
如何在Android设备上撤销Flutter应用程序的所有权限?
836 64
|
缓存 Android开发 开发者
Flutter环境配置完成后,如何在Android设备上运行Flutter应用程序?
Flutter环境配置完成后,如何在Android设备上运行Flutter应用程序?
2379 62
|
开发工具 Android开发 开发者
在Android设备上运行Flutter应用程序时,如果遇到设备未授权的问题该如何解决?
在Android设备上运行Flutter应用程序时,如果遇到设备未授权的问题该如何解决?
913 61
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,使用GPIO和LED子系统来实现LED驱动的教程,包括了DTS设备树配置、驱动源码编写以及如何在用户空间控制LED的亮度和开关。
755 0
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
本文介绍了如何在基于Amlogic T972的Android 9.0系统上使用Platform平台驱动框架和设备树(DTS),实现设备与驱动的分离,并通过静态枚举在设备树中描述设备,自动触发驱动程序的加载和设备创建。
475 0
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
如何使用Amlogic T972安卓9.0系统上的misc框架来简化驱动程序开发,通过misc框架自动分配设备号并创建设备文件,从而减少代码量并避免设备号冲突。
345 0
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
|
Android开发 C语言
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,通过自动分配设备号和自动创建设备节点文件的方式,开发字符设备驱动程序的教程。
391 0
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
|
自然语言处理 Shell Linux
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
本文是关于在Amlogic安卓9.0平台上创建字符设备驱动的教程,详细介绍了驱动程序的编写、编译、部署和测试过程,并提供了完整的源码和应用层调用示例。
584 0
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备

热门文章

最新文章