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

news/2024/5/10 13:34:08/文章来源:https://blog.csdn.net/yyzsyx/article/details/128438847

文章目录

  • 一、前言
  • 二、系列文章
  • 三、准备工作
    • 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

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.dtsii2c1_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_2pinctrl-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=0x6Ai2c_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.c0 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-slaverLOCAL_SRC_FILES := i2c-slaver.cinclude $(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_READargs.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,一共6byteswhile(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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_240117.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker常用操作命令总结(一)

文章目录一、Docker的应用场景二、Docker 的优点三、Docker 架构四、安装Docker1、更新 apt 包索引2、安装docker3、安装完成之后&#xff0c;运行命令sudo docker info&#xff0c;检查安装状态4、有可能&#xff0c;第一次需要手动启动服务.就需要执行下面的命令&#xff0c;…

图像处理:制作你的专属卡通头像和LOGO(圣诞节特别篇)

目录0 前言1 安装与贴图2 算法原理2.1 计算像素频率2.2 计算像素相对距离2.3 计算合适贴图3 配置功能4 使用&#xff1a;以圣诞老人为例0 前言 Tiler是一种使用各种其他较小图像平铺创建新图像的工具&#xff0c;它与其他马赛克工具不同&#xff0c;因为它可以适应多种形状、大…

基于Xlinx的时序分析与约束(5)----衍生时钟约束

衍生时钟约束语法 衍生时钟&#xff08;Generated Clocks&#xff0c;又称为生成时钟&#xff09;是指由设计中已有的主时钟通过倍频、分频或者相移等操作后产生的新的时钟信号&#xff0c;如由MMCM或PLL或由组合逻辑生成的倍、分频时钟信号。 衍生时钟约束必须指定时钟源&…

【正点原子I.MX6U-MINI移植篇】rootfs移植过程详解(三)

Linux三巨头己经完成了2个了&#xff0c;就剩最后一个rootfs&#xff08;根文件系统&#xff09;了&#xff0c;根文件系统的组成以及如何构建根文件系统是Liux移植的最后一步&#xff0c;根文件系统构建好以后就意味着我们己经拥有了一个完整的、可以运行的最小系统。以后我们…

程序员高手解决问题,都是从正确的提问开始

回顾各大技术网站、社区、问答&#xff0c;我们发现&#xff1a;真正的程序员高手都极度擅长提问。 好的提问不但能得到建设性的解决方案&#xff0c;更加能激发人们的好奇心、创造力和学习的动力。 毫不夸张地说&#xff0c;会提问的程序员一开口就赢了&#xff01; 所以今…

QT基本组件与常用类

目录 一、设计师 Designer&#xff08;掌握&#xff09; 二、布局 Layout 2.1 布局的基本使用&#xff08;掌握&#xff09; 2.2 布局属性&#xff08;掌握&#xff09; 2.3 伸展器&#xff08;掌握&#xff09; 2.4 嵌套&#xff08;掌握&#xff09; 2.5 伸展与策略&#xff…

分布式缓存的四大痛点

目前开发中经常用到的缓存&#xff0c;是我们必不可缺的&#xff0c;他大大的提高了我们整个项目的响应速度和并发量。但是带来好处的同时&#xff0c;也给我们带了了新的问题&#xff1a;缓存穿透、缓存击穿、缓存雪崩以及缓存一致性这么四个问题&#xff0c;也是分布式缓存的…

IT大侦“碳”:VxRail的可持续法宝

环境Environmental      社会责任Social Responsibility      企业治理Corporate Governance      随着碳达峰、碳中和的逐步推进,越来越多的“大厂”或各行业的明星企业都开始重视自己的ESG报告,已然成为了商界新风尚。      可持续发展战略也与前沿技术密切相…

Java项目:Springboot体育器材管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 体育器材管理系统主要包含以下功能&#xff1a; 登录注册&#xff1b; 体育器材管理&#xff1a;显示器材表、显示价目表、显示供应商表&#x…

4.2、网络层提供的两种服务

1、面向连接的虚电路服务 虚电路服务的核心思想&#xff1a;可靠通信由网络自身来保证\color{red}可靠通信由网络自身来保证可靠通信由网络自身来保证 当两台计算机进行通信时&#xff0c;必须建立网络层的连接\color{red}网络层的连接网络层的连接----虚电路VC\color{red}虚…

Java+SpringBoot电影订票系统(含源码+论文+答辩PPT等)

项目功能简介: 该项目采用技术后台&#xff1a;SpringBoot、Spring、Springmvc、Springdata、MySQL数据库、前台&#xff1a;FreeMarker、css、Javascript等&#xff0c;项目含有源码、论文、配套开发软件、软件安装教程、项目发布教程等 项目功能介绍&#xff1a; 本系统主要的…

Hi,运维,你懂Java吗--No.4:JVM-概述

作为运维&#xff0c;你不一定要会写Java代码&#xff0c;但是一定要懂Java在生产跑起来之后的各种机制。 本文为《Hi&#xff0c;运维&#xff0c;你懂Java吗》系列文章 第四篇&#xff0c;敬请关注后续系列文章 欢迎关注 龙叔运维&#xff08;公众号&#xff09; 持续分享运…

筛法(线性筛,厄拉多塞筛)

在前前前前前前…的博客中,我们主要谈了欧拉筛和埃氏筛. 今天我们主要来聊一聊线性筛和厄拉多塞筛(其实和埃氏筛和欧拉筛本质上没区别哎).其实在这两种筛法中厄拉多塞筛最好懂(就连本蒟蒻一看代码就明白了…别看这个名字,容易糊弄人) 首先是厄拉多塞筛"粉墨登场"::…

某农业学校 算法设计与分析-第五次实验-回溯算法

1. 罗密欧与朱丽叶的迷宫问题 问题描述 罗密欧与朱丽叶的迷宫。罗密欧与朱丽叶身处一个mn的迷宫中&#xff0c;如图所示。每一个方格表示迷宫中的一个房间。这mn个房间中有一些房间是封闭的&#xff0c;不允许任何人进入。在迷宫中任何位置均可沿8 个方向进入未封闭的房间。罗…

深度学习常见概念字典(感知机、全连接层、激活函数、损失函数、反向传播、过拟合等)

这一章的所有内容均是为了进入深度学习具体的某某网络而准备的&#xff0c;简单但是非常有必要。 1. 神经网络&#xff08;neural networks&#xff09;的基本组成 1.1 神经元&#xff08;neuron&#xff09; 神经元&#xff08;neuron&#xff09; 是神经网络&#xff08;n…

Djiango实现用户管理增删改成功能实战

1.0定义 前后端不分离模式 前后端分离是指前端页面看到的效果都是由后端控制&#xff0c;即后端渲染HTML页面&#xff0c;前端与后端的耦合度比较高 前后端分离模式 后端仅返回前端所需要的数据&#xff0c;不在渲染HTML页面&#xff0c;不在控制前端的效果&#xff0c;至…

CodeQL代码静态污点分析引擎排查漏洞模式

文章目录前言环境搭建1.1 codeql基础1.2 vscode插件1.3 生成数据库1.4 HelloWorldcodeql语法2.1 语法结构2.2 常用类库2.3 谓词介绍2.4 污点分析漏洞检测3.1 初步结果3.2 解决误报总结前言 对于代码审计的工作&#xff0c;最早期的安全人员会以人工审计的方式来审计项目代码&a…

RabbitMQ 第二天 高级 7 RabbitMQ 高级特性 7.1 消息的可靠投递 7.1.1 confirm【确认模式】

RabbitMQ 【黑马程序员RabbitMQ全套教程&#xff0c;rabbitmq消息中间件到实战】 文章目录RabbitMQ第二天 高级7 RabbitMQ 高级特性7.1 消息的可靠投递7.1.1 confirm【确认模式】第二天 高级 7 RabbitMQ 高级特性 7.1 消息的可靠投递 7.1.1 confirm【确认模式】 在使用 Ra…

【数据预处理】基于Pandas的数据预处理技术【california_housing加州房价数据集】_后9个任务

文章目录一.需求分析二.需求解决2.1 对第一个特征&#xff08;收入中位数&#xff09;排序后画散点图2.2 对第一个特征&#xff08;收入中位数&#xff09;画分位数图并分析2.3 【选做】对所有特征画分位数图并进行分析2.4 使用线性回归方法拟合第一个特征&#xff08;收入中位…

【C语言进阶】指针练习题

写在前面 这是指有关指针的小题 正文 练习一 int main() {int a[5][5];int (*p)[4];pa;printf("%p,%d", &p[4][2]-&a[4][2], &p[4][2]-&a[4][2] );return 0; } 解析&#xff1a; a[4][2]为如图粉色部分&#xff0c;p[4][2]为如图蓝色部分。a的…