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

Posted 阿迷创客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不写一行代码:实现安卓基于i2c bus的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

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

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 #

图示:

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

图示如下:

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设备驱动的主要内容,如果未能解决你的问题,请参考以下文章

不写一行代码:实现安卓基于PWM的LED设备驱动

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

I2C Bus

/sys/bus/i2c/devices/0-00{}/iio_device

I2C总线

不写一行代码创建Fiori App