嵌入式Linux驱动开发(I2C专题)(七)

2023-11-08

使用GPIO操作I2C设备_IMX6ULL

参考资料:

  • Linux文档
    • Linux-5.4\Documentation\devicetree\bindings\i2c\i2c-gpio.yaml
    • Linux-4.9.88\Documentation\devicetree\bindings\i2c\i2c-gpio.txt
  • Linux驱动源码
    • Linux-5.4\drivers\i2c\busses\i2c-gpio.c
    • Linux-4.9.88\drivers\i2c\busses\i2c-gpio.c

1. 硬件连接

  • IMX6ULL:把I2C模块接到GPIO
    在这里插入图片描述

2. 根据原理图编写设备树

2.1 原理图

在这里插入图片描述

2.2 编写设备树
i2c_gpio_100ask {
	compatible = "i2c-gpio";
	gpios = <&gpio4 20 0 /* sda */
		     &gpio4 21 0 /* scl */
		    >;
	i2c-gpio,delay-us = <5>;	/* ~100 kHz */
	#address-cells = <1>;
	#size-cells = <0>;
};

把上述代码,放入arch/arm/boot/dts/100ask_imx6ull-14x14.dts的根节点下面。

3. 确认内核已经配置了I2C-GPIO

查看内核目录下的.config,如果未设置CONFIG_I2C_GPIO,上机实验时需要配置内核、编译I2C-GPIO驱动。

4. 上机实验

4.1 设置工具链
  • IMX6ULL

    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabihf-
    export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
    
4.2 编译、替换设备树
  • 编译设备树:
    在Ubuntu的IMX6ULL内核目录下执行如下命令,
    得到设备树文件:arch/arm/boot/dts/100ask_imx6ull-14x14.dtb

    make dtbs
    
  • 复制到NFS目录:

    $ cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/
    
  • 开发板上挂载NFS文件系统

    • vmware使用NAT(假设windowsIP为192.168.1.100)

      [root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 
      192.168.1.100:/home/book/nfs_rootfs /mnt
      
    • vmware使用桥接,或者不使用vmware而是直接使用服务器:假设Ubuntu IP为192.168.1.137

      [root@100ask:~]#  mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
      
  • 更新设备树

    [root@100ask:~]# cp /mnt/100ask_imx6ull-14x14.dtb /boot
    [root@100ask:~]# sync
    
  • 重启开发板

4.3 编译I2C-GPIO驱动
1. 配置内核

在IMX6ULL内核源码目录下执行make menuconfig命令,如下配置内核:

Device Drivers  --->
    I2C support  --->
        I2C Hardware Bus support  --->
            <M> GPIO-based bitbanging I2C      // 输入M,编译为模块        
2. 编译模块

设置工具链后,在内核目录下执行:

make modules   // 得到 drivers/i2c/busses/i2c-gpio.ko
5. 测试

在开发板上执行:

[root@100ask:~]# i2cdetect -l    // 加载i2c-gpio.ko前只看到2条I2C BUS
i2c-1   i2c             21a4000.i2c                             I2C adapter
i2c-0   i2c             21a0000.i2c                             I2C adapter
[root@100ask:~]#
[root@100ask:~]# insmod /mnt/i2c-gpio.ko   
[   45.067602] i2c-gpio i2c_gpio_100ask: using pins 116 (SDA) and 117 (SCL)
[root@100ask:~]# i2cdetect -l     // 加载i2c-gpio.ko后看到3条I2C BUS
i2c-1   i2c             21a4000.i2c                             I2C adapter
i2c-4   i2c             i2c_gpio_100ask                         I2C adapter
i2c-0   i2c             21a0000.i2c                             I2C adapter
[root@100ask:~]#
[root@100ask:~]# i2cdetect -y 4     // 检测到0x50的设备
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
[root@100ask:~]#
[root@100ask:~]# i2cset -f -y 4 0x50 0 0x55   // 往0地址写入0x55
[root@100ask:~]# i2cget -f -y 4 0x50 0        // 读0地址
0x55

具体芯片的I2C_Adapter驱动分析

参考资料:

  • Linux内核真正的I2C控制器驱动程序
    • IMX6ULL: Linux-4.9.88\drivers\i2c\busses\i2c-imx.c
    • STM32MP157: Linux-5.4\drivers\i2c\busses\i2c-stm32f7.c

1. I2C控制器内部结构

1.1 通用的简化结构

在这里插入图片描述

1.2 IMX6ULL的I2C控制器内部结构

在这里插入图片描述

1.3 STM32MP157的I2C控制器内部结构

在这里插入图片描述

2. I2C控制器操作方法

  • 使能时钟、设置时钟
  • 发送数据:
    • 把数据写入tx_register,等待中断发生
    • 中断发生后,判断状态:是否发生错误、是否得到回应信号(ACK)
    • 把下一个数据写入tx_register,等待中断:如此循环
  • 接收数据:
    • 设置controller_register,进入接收模式,启动接收,等待中断发生
    • 中断发生后,判断状态,读取rx_register得到数据
    • 如此循环

3. 分析代码

3.1 设备树
  • IMX6ULL: arch/arm/boot/dts/imx6ull.dtsi

    i2c1: i2c@021a0000 {
    		#address-cells = <1>;
    		#size-cells = <0>;
    		compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
    		reg = <0x021a0000 0x4000>;
    		interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
    		clocks = <&clks IMX6UL_CLK_I2C1>;
    		status = "disabled";   // 在100ask_imx6ull-14x14.dts把它改为了"okay"
    };
    
  • STM32MP157: arch/arm/boot/dts/stm32mp151.dtsi

    i2c1: i2c@40012000 {
    		compatible = "st,stm32mp15-i2c";
    		reg = <0x40012000 0x400>;
    		interrupt-names = "event", "error";
    		interrupts-extended = <&exti 21 IRQ_TYPE_LEVEL_HIGH>,
    							  <&intc GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
    		clocks = <&rcc I2C1_K>;
    		resets = <&rcc I2C1_R>;
    		#address-cells = <1>;
    		#size-cells = <0>;
    		dmas = <&dmamux1 33 0x400 0x80000001>,
    			   <&dmamux1 34 0x400 0x80000001>;
    		dma-names = "rx", "tx";
    		power-domains = <&pd_core>;
    		st,syscfg-fmp = <&syscfg 0x4 0x1>;
    		wakeup-source;
    		status = "disabled";   // 在stm32mp15xx-100ask.dtsi把它改为了"okay"
    };
    
3.2 驱动程序分析

读I2C数据时,要先发出设备地址,这是写操作,然后再发起读操作,涉及写、读操作。所以以读I2C数据为例讲解核心代码。

  • IMX6ULL:函数i2c_imx_xfer分析:
    在这里插入图片描述

  • STM32MP157:函数stm32f7_i2c_xfer分析
    这函数完全有驱动程序来驱动:启动传输后,就等待;在中断服务程序里传输下一个数据,知道传输完毕。

    • 启动传输
      在这里插入图片描述
    • 通过中断进行后续传输
      在这里插入图片描述
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式Linux驱动开发(I2C专题)(七) 的相关文章

  • 无法连接到 Azure Ubuntu VM - 公钥被拒绝

    我们在 Azure 上使用 Ubuntu VM 一段时间了 很少遇到任何问题 然而 其中一台虚拟机最近出现了问题 出乎意料的是 Ubuntu VM 开始拒绝公钥 ssh i azure key email protected cdn cgi
  • 安装 JDK 时出错:keytool 命令需要已安装的 proc fs (/proc)。 Linux 的 Windows 子系统

    我尝试在 Linux 的 Windows 子系统 Ubuntu 14 04 上安装 Oracle JDK 1 7 但出现以下错误 the keytool command requires a mounted proc fs proc Jav
  • Linux 中有没有一种轻量级的方法来获取当前进程数?

    我希望我的 基于 C C 的 程序显示一个数字指示器 指示本地系统上当前有多少个进程 将经常查询正在运行的进程数值 例如每秒一次 以更新我的显示 有没有一种轻量级的方法来获取该数字 显然我可以调用 ps ax wc l 但我不想强迫计算机生
  • 我可以在 Ubuntu 上使用 Homebrew 吗?

    我只是尝试使用 Homebrew 和 Linuxbrew 在我的 Ubuntu 服务器上安装软件包 但都失败了 这就是我尝试安装它们的方法 sudo apt get install build essential curl git m4 r
  • 通过名称获取进程ID

    我想在 Linux 下获得一个给定其名称的进程 ID 有没有一种简单的方法可以做到这一点 我还没有在 C 上找到任何可以轻松使用的东西 如果追求 易于使用 char buf 512 FILE cmd pipe popen pidof s p
  • 虚拟内存澄清——大连续内存的分配

    我有一个应用程序 我必须在 Windows 上分配 使用运算符 new 相当大的内存空间 数百 MB 该应用程序是 32 位 我们现在不使用 64 位 即使在 64 位系统上也是如此 我启用了 LARGEADDRESSAWARE 链接器选项
  • 如何在C程序中直接改变显存映射来绘制像素(无需库函数)

    是否可以通过使用 C 程序更改 RAM 中屏幕 视频即监视器 内存映射中的值来显示黑点 我不想使用任何库函数 因为我的主要目标是学习如何开发简单的操作系统 我尝试访问起始屏幕内存映射 即 0xA0000 在 C 中 我尝试运行该程序 但由于
  • 重新链接匿名(未链接但打开)文件

    在 Unix 中 可以创建匿名文件的句柄 例如 使用 creat 创建并打开它 然后使用 unlink 删除目录链接 留下一个带有 inode 和存储的文件 但没有可能的方法重新打开它 此类文件通常用作临时文件 通常这就是 tmpfile
  • 删除 Python 中某些操作的 root 权限

    在我的 Python 脚本中 我执行了一些需要 root 权限的操作 我还创建并写入文件 我不想由 root 独占所有 而是由运行我的脚本的用户独占所有 通常 我使用以下命令运行脚本sudo 有办法做到上述吗 您可以使用以下方式在 uid
  • 使用 hcitool 扫描低功耗蓝牙?

    当我运行此命令时 BLE 设备扫描仅持续 5 秒 sudo timeout 5s hcitool i hci0 lescan 输出显示在终端屏幕中 但是 当我将输出重定向到文件以保存广告设备的地址时 每次运行该命令时 我都会发现该文件是空的
  • 使用 terminfo 的终端颜色?

    我正在编写一个 C 类 允许在终端中使用颜色 我希望它适用于每个终端 在支持真彩色 24 位 的终端上打印 在支持它的终端上具有 256 色 6x6x6 其他都是基本的 16 种颜色 我曾经使用 termcap 编写过一次 C 函数 并且我
  • 路由是否会影响具有绑定源地址的套接字?

    假设我有两个网络接口 eth0有地址10 0 0 1 eth1有地址192 168 0 1 Using route or ip route add我已将其设置为路由 所有地址至eth0 1 2 3 4只为了eth1 所以数据包到1 2 3
  • %config(noreplace) 文件上出现意外的 RPM 冲突

    我正在创建我自己的RPM using rpmbuild My RPM 包含配置文件哪个应该永远不会被覆盖 即使 RPM 包含这些配置文件的新版本 为了存档这个 我用以下标签标记了它们 config noreplace opt mypacka
  • 如何从外部模块导出符号?

    我在内核源代码树之外进行编码 有两个模块 第一个printt有一个功能printtty 将字符串打印到当前 tty 以及第二个模块hello这会调用printtty 在初始化期间 我已经添加了EXPORT SYMBOL printtty 在
  • Linux mremap 不释放旧映射?

    我需要一种方法将页面从一个虚拟地址范围复制到另一个虚拟地址范围 而无需实际复制数据 范围很大 延迟很重要 mremap 可以做到这一点 但问题是它也会删除旧的映射 由于我需要在多线程环境中执行此操作 因此我需要旧映射能够同时使用 因此稍后当
  • VSCODE 在 Linux 上不适用于我

    刚刚了解 VSCODE 很高兴尝试一下 我下载 解压并运行可执行文件 我得到 Code 2183 0429 201254 ERROR browser main loop cc 170 Running without the SUID san
  • 为什么 proc/ID/maps 有多个共享库条目

    我正在查看嵌入式Linux下的proc ID maps 我注意到一些共享库在进程的内存映射中出现了几次 为什么会这样呢 40094000 400d9000 r xp 00000000 b3 09 723 system lib libc so
  • X 服务器使用什么像素格式?

    X 服务器使用什么像素格式 RGBA ARBG BGRA 如果有任何特定格式的话 Update 我专门寻找有关颜色分量顺序和位模式的信息 你的意思是帧缓冲区格式 或者所有支持的像素图格式 无论是哪一种 都取决于您的图形硬件 驱动程序和配置
  • shell中基于正则表达式的颜色突出显示输出

    我想知道是否可以用颜色突出显示与某些字符串匹配的 shell 命令的输出 例如 如果我运行 myCommand 输出如下 gt myCommand DEBUG foo bar INFO bla bla ERROR yak yak 我希望所有
  • Linux shell 标题大小写

    我正在编写一个 shell 脚本并有一个如下所示的变量 something that is hyphenated 我需要在脚本中的各个点使用它 如下所示 something that is hyphenated somethingthati

随机推荐

  • kettle调用存储过程_Kettle(PDI)客户端工具Spoon详解

    概述 PDI 客户端 Spoon 是一个您安装在工作台上的桌面应用程序 使您能够构建转换和作业或安排作业何时运行 启动PDI客户端 Pentaho目录启动PDI客户端 启动Pentaho服务器 导航到安装PDI的文件夹 例如 pentaho
  • [Java]远程下载文件并读取实例方法

    简单的文件下载后读取显示 该方法可返回内容的结果集 一般适用于文本文档的下载 以供学习交流 远程下载文件并读取返回p param filePath 文件网络地址 如http www baidu com 1 txt return String
  • linux花生壳

    动态域名解析 花生壳 ddns dns dhcp 配置dhcp服务 在服务端 yum install dhcp y cp usr share doc dhcp 4 2 5 dhcpd conf example etc dhcp dhcpd
  • 【Unity编程】欧拉角与万向节死锁(图文版)

    Unity编程 欧拉角与万向节死锁 图文版 标签 unity万向节死锁欧拉角欧拉旋转 2017 03 11 17 08 5361人阅读 评论 4 收藏 举报 分类 Unity标准编程导引 13 版权声明 本文为博主原创文章 欢迎转载 请保留
  • 联宝盒子算法迁移

    直接把这个盒子的算法包 迁移到另一个新盒子 第一步 将算法库的第三方库 放置到该路径下 2 第二步运行 但是报错了 找不到库 如下图 但是文件夹该路径下有这个库 直接运行代码 报错如下 ImportError libopenblas so
  • 日期格式转换工具类(线程安全)

    import java text ParseException import java time import java time format DateTimeFormatter import java time temporal Chr
  • 国网DLT698.45协议——采集系统、数据交换(一)

    国网DLT698 45协议 采集系统 数据交换 面向对象协议 对于国网698协议 是一种面向对象的通信协议 用于远程监控和控制电力系统中的设备 面向对象使得对协议的思考更趋向于正常思维 使计算机中描述的抽象世界于现实世界中能够更好的对应起来
  • VirtualBox虚拟机安装64位Linux系统(Ubuntu)

    如果在VirtualBox中安装64位的Linux操作系统时提示如下错误 This kernel needs a x86 64 CPU but only detects an i386 CPU 解决方法如下 第一步 重启计算机 进入Bios
  • 基于ABB工业机器人工作站的设计———毕业设计

    基于ABB工业机器人搬运工作站的设计 通过RobotStudio软件来 模拟机器人灌装液体 混合液体并封装的过程 去年的毕业设计和毕业论文 还一些不了解的老师没见过 还说感觉很高级 感觉这个题目 目前还算是比较新 可以直接拿来用 还有一些关
  • 手机号码的正则表达式

    手机号码的正则表达式可以是这样的 13 0 9 14 5 7 15 0 3 5 9 17 0 3 5 8 18 0 9 166 198 199 147 d 8 这个正则表达式可以匹配大多数中国大陆的手机号码 包括 13 14 15 17 1
  • java.net.SocketException: Software caused connection abort: recv failed 异常分析

    关键字 recv failed java net SocketException Software caused connection abort recv failed at java net SocketInputStream sock
  • SMTP端口选择

    SMTP Port 25 465 587 or 2525 how to choose the right SMTP Port 原文地址 https pepipost com blog 25 465 587 2525 choose the r
  • 如何有理有据地给元宇宙泼一盆冷水?

    从来没有一个词像 元宇宙 一样如此虚无缥缈 如此镜花水月却受到如此热烈的追捧 元宇宙和之前的科技概念不同 以前 在科技圈的一个概念至少是明确而又具体的 比如 区块链 5G 3D打印 然而 元宇宙不是 它虚幻缥缈而错综复杂 一如 浑元形意拳
  • TypeScript基本类型、类、封装、继承、泛型、接口、命名空间

    简介 前几篇介绍了Vue3的Composition API Vue Router pinia Vue3能更好支持TS 因此 本节将介绍TS 详细描述了TS的优缺点 安装 如何配置自动编译 tsconfig json的常用配置 使用webpa
  • HTML-CSS(四十一)animation动画

    animation属性 animation name 设置动画的名字 自定义的 animation duration 动画的持续时间 animation delay 动画的延迟时间 animatio iteration count 动画的重
  • 集合学习总结

    集合 1 java集合框架概述 1 集合 數組都是多個數據存儲操作的結構 簡稱java容器 說明 主要指的存儲是內存層面的存儲 不涉及到持久化的存儲 可以分為Collection和Map兩種 Collection接口 單列數據 定義了存取一
  • (GAE)Google App Engine入门程序——helloworld

    参考资料 http blog xuming net gae tutorial 官网例子 https developers google com appengine docs python gettingstartedpython27 hel
  • 编译器优化–4--消除无用和不可达代码

    编译器优化 4 消除无用和不可达代码 概述 有时候 程序包含的一些计算不具有外部可见的效应 如果编译器能够确定给定操作不会影响程序的结果 那么它完全可以消除该操作 大多数程序员都不会有意编写这种代码 但是 这种代码在大多数程序中作为编译器中
  • CSDN高校俱乐部介绍-CSDN高校俱乐部-专题视频课程

    CSDN高校俱乐部介绍 6621人已学习 课程介绍 本课程旨在让更多学生了解CSDN高校俱乐部的服务宗旨 活动形式和人才选拔模式 作为服务于当代大学生学习与成长的IT技术学习型组织 俱乐部有别于一般技术类社团 在活动内容 活动形式以及行业对
  • 嵌入式Linux驱动开发(I2C专题)(七)

    使用GPIO操作I2C设备 IMX6ULL 参考资料 Linux文档 Linux 5 4 Documentation devicetree bindings i2c i2c gpio yaml Linux 4 9 88 Documentat