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

文章目录

  • 一、前言
  • 二、系列文章
  • 三、准备工作
    • 3.1 挑选I2C引脚
    • 3.2 测试设备:QMI8658C
  • 四、编写设备树节点
    • 4.1 查找MUX
    • 4.2 修改i2c1引脚配置
      • 4.2.1 修改前
      • 4.2.2 修改后
  • 五、编译、烧录dt.img
    • 5.1 烧录后效果
  • 六、编写test程序
    • 6.1 创建文件
    • 6.2 源码:Android.mk
    • 6.3 源码:i2c-slaver.c
    • 6.4 编译test程序
  • 七、测试
    • 7.1 部署 i2c-slaver
    • 7.2 运行 i2c-slaver

一、前言

本文是系列文章的第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

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

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

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

3.2 测试设备:QMI8658C

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

  • 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 #

图示:

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

六、编写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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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

图示如下:
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动_第4张图片

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 # 

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

图示如下:
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动_第5张图片

你可能感兴趣的:(Android设备驱动开发,驱动开发,android,嵌入式硬件)