ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenHarmony I2C驱动开发实战:从协议原理到排障清单

OpenHarmony I2C驱动开发实战:从协议原理到排障清单 1. 先把 I2C 协议讲透后面排障才不至于抓瞎如果你做过一点嵌入式对 I2C 应该不陌生。它只有两根线SCL时钟和 SDA数据却能挂上一堆设备——温湿度传感器、加速度计、EEPROM、触摸屏控制器、电源管理 IC甚至部分显示屏。在 OpenHarmony 的硬件驱动框架HDF里I2C 也是接入这些外设最常用的总线之一。我见过不少朋友第一次在 OpenHarmony 上适配外设时卡在最基础的地方设备的 7 位地址到底怎么填读写标志是怎么用的为什么我的读取数据全是 0xFF这些问题的答案不在任何 IDE 里而在协议本身。这篇教程不会画一堆看起来很漂亮但实际毫无用处的架构图我直接把 I2C 的时序、寻址、ACK 机制讲明白然后在 OpenHarmony 的 HDF 框架里给一个可运行的驱动示例最后把排障办法和常见问题整理成一份可以直接对着查的清单。写这篇文章的初衷是我自己在开发中也踩过不少坑——有一次为了查一个 NACK 老半天最后发现是 SCL 和 SDA 信号线在排线里颠倒了这种低级失误如果能被这篇文章提前拦截也算值了。你先别急着开板子把协议这几页读透后面写代码和调试都会顺很多。1.1 两根线的约定SCL 和 SDA 的平时状态与起始/停止条件I2C 的总线上SCL 是时钟线SDA 是数据线两根线都是开漏输出外部必须接上拉电阻。你可以把 SCL 想成节拍器SDA 就是唱歌的人——节拍器不给拍子歌手不能乱唱对应到协议里SDA 上的电平变化永远发生在 SCL 为低电平的时候SCL 高电平期间 SDA 必须保持稳定主机才能在 SCL 上升沿附近把数据采样进去。这条规则听着简单但就是很多人踩坑的地方。总线的空闲状态是 SCL 和 SDA 都为高。从空闲状态进入通信要先发一个起始条件START在 SCL 为高的时候SDA 从高拉低。反过来通信结束时要发停止条件STOPSCL 为高时SDA 从低拉高。这两个条件是协议里唯一允许“在 SCL 高电平时改变 SDA”的例外。读时序图的时候你只要抓住这两个跳变基本上就能定位一帧数据从哪里开始、到哪里结束。还有一种情况叫重复起始条件Repeated START就是主机在没有发 STOP 的情况下再次拉低 SDA 发起下一个起始。这种写法在“先写寄存器地址再读数据”的复合操作里非常常见。很多传感器芯片的读取流程都是这样的主机先发一个写操作把要读的寄存器地址告诉从机然后不停止总线立刻再发一个读操作去取数据。如果这里漏了重复起始从机可能根本不知道你要切到读模式返回的数据自然就是乱的。1.2 第一个字节从来不是数据地址字节和 R/W 位I2C 通信的第一个字节是地址字节不是数据。这个字节的高 7 位是从机地址最低位是读写方向位R/W。方向位为 0 表示主机要写为 1 表示主机要读。比如一个传感器从机地址是 0x48那主机发送的第一个字节应该是 0x48 或 0x49取决于你想要写还是读。很多新手在这里犯迷糊芯片手册上写的是 7 位地址 0x48但你用逻辑分析仪抓到的第一个字节往往是 0x90 或 0x91换算一下就会发现0x48 左移一位后再加减 1正好是 0x90 和 0x91。这就是地址移位问题有的 API 直接传 7 位地址有的 API 要求传 8 位地址即已经包含方向位的字节搞混了设备就永远不会 ACK。地址字节发出去之后如果总线上有设备地址匹配从机会在第 9 个时钟周期拉低 SDA发出一个应答位 ACK如果没有设备应答SDA 在第 9 个时钟就是高电平也就是 NACK。主机收到 NACK 通常会终止这次传输。排障的时候如果你用逻辑分析仪看到地址字节后面跟的是高电平基本可以断定地址不对、设备没上电、或者 SDA/SCL 接反了。这三个原因占了 I2C 问题的八成。1.3 读操作和写操作的完整数据流写操作比较好理解主机发起始条件然后发送地址字节方向位为 0从机 ACK接着主机逐字节发送数据从机每收一个字节就回一个 ACK全部发完主机发停止条件。这时你写进去的是连续的字节流具体怎么解释这些字节完全由从机芯片决定——有些芯片第一个字节是寄存器地址后面是数据有些芯片要求先写设备配置再写数据没有统一标准。所以看芯片手册比背协议重要。读操作稍微绕一点。大部分 I2C 传感器是这么干的主机先发一个写操作把目标寄存器地址写进从机然后发一个重复起始条件再发一个带读方向的地址字节从机 ACK 之后开始把寄存器内容放到 SDA 上同时时钟由主机继续产生。这里注意读阶段每个字节结束后的 ACK 是由主机产生的——主机如果想继续读下一个字节就拉低 SDA 表示 ACK如果不想读了就保持 SDA 高电平给出 NACK然后发停止条件。你如果不小心在最后一个字节给了 ACK 而不是 NACK从机可能会继续传输下一个字节导致时序错乱总线状态就变得非常诡异。1.4 速度模式、时钟延展和那些不常见但麻烦的细节I2C 有标准模式 100kHz、快速模式 400kHz、快速模式 1MHz 和高速模式 3.4MHz。OpenHarmony 的 I2C 控制器驱动一般都会在设备树或配置里写明频率但实际跑多少还要看总线上最慢设备的承受能力。如果传感器只支持 100kHz你把控制器配成 400kHz它可能偶尔工作、偶尔丢数据这种随机性问题最难查。所以我建议调试初期强制降到 100kHz先把功能跑通再提速度。个人经验先把速度降下来排障时间和头发保存量有直接关系。时钟延展Clock Stretching是个容易被忽略但关键时刻救命的机制某些从机处理数据需要时间它会把 SCL 拉低强制主机等待主机必须检测 SCL 一直为低的情况直到从机释放 SCL 才继续产生时钟。多数硬件 I2C 控制器会自动处理但软件模拟 I2C 或者某些简化驱动不会。如果你的 OpenHarmony 设备接了类似旧型号的触摸屏控制器偶尔出现延迟但功能正常大概率就是时钟延展没被正确支持。你可以在驱动里开启 SCL 超时检测如果一个时钟周期内 SCL 没释放就主动报错而不是无限等下去。2. OpenHarmony 里 I2C 怎么接入框架、配置与 APIOpenHarmony 的设备驱动走的是 HDFHardware Driver Foundation硬件驱动框架I2C 控制器驱动和 I2C 从设备驱动都被纳入了这套框架。对应用开发者来说你面对的是标准化的 HDF API不需要关心底层寄存器怎么操作对驱动开发者来说你写的是平台驱动或外设驱动配置则在 HCS 配置文件中完成。我建议先把 HDF 的几个核心概念分清楚设备节点、设备句柄、以及驱动与设备之间的绑定。2.1 HDF 下的 I2C 设备驱动结构在 HDF 里I2C 外设驱动的核心任务是在设备管理器中注册一个设备节点然后实现 Init、Dispatch、Release 这些回调。Init 里通常要做的第一件事就是通过 I2C 模块的接口打开 I2C 控制器获得一个 DevHandle。这个 DevHandle 就是你之后所有读写操作的凭据相当于一把“钥匙”。如果你在 Init 阶段拿不到 DevHandle大概率是控制器编号配错了或者驱动没有加载成功。要注意的是HDF 把“控制器”和“外设”分得很开。I2C 控制器驱动由芯片厂商提供负责最底层的时序产生你的外设驱动是建立在控制器之上的“客户”。打个比方控制器是高速公路外设就是收费站——高速路修得再好收费站的标识不清车一样会在出口堵死。所以外设驱动里的地址、寄存器、读写流程必须完全匹配芯片手册这部分框架帮不了你。2.2 设备配置从 device_info.hcs 开始HCS 是 OpenHarmony 的配置描述语言类似设备树的角色。你要让系统知道“这个板子上有一个叫 imx6ull_i2c3 的 I2C 控制器”通常会在对应的 HCS 文件里加一个设备节点。我摘一段常见的配置结构说明device_i2c3 :: device { device_id :: 3; device_name :: i2c_3; device_type :: i2c; module_name :: hisi_i2c; // 具体控制器驱动模块 device_match_attr :: i2c_config_3; i2c_config_3 :: { busId 3; freq 100000; // 100kHz baseAddr 0x111f0000; irqNum 28; } }这段配置的意思是这个控制器挂在 busId 为 3 的总线时钟频率 100kHz寄存器基地址是 0x111f0000。实际板子上具体写多少必须查芯片手册和板级原理图不能抄。常见的错误有两种一是 busId 写错导致打开的不是你想用的控制器二是 freq 配得太高从机跟不上。你在调试时如果发现 Init 阶段返回超时先回头检查这里的 freq 是不是被配成了几 MHz。2.3 I2cOpen、I2cRead、I2cWrite、I2cTransfer 的用法和差异OpenHarmony 的 HDF 提供了 device_i2c_if.h 头文件里面的核心 API 主要有这几个I2cOpen(busId)打开指定 busId 对应的 I2C 控制器返回 DevHandle。I2cClose(handle)关闭控制器释放资源。I2cRead(handle, addr, buf, len)从某个从机地址读取 len 字节到 buf。I2cWrite(handle, addr, buf, len)向从机地址写入 len 字节。I2cTransfer(handle, msgs, count)一次传输包含多个消息的数组支持复合操作。单看 API 名字很简单但实际坑在细节。I2cRead 和 I2cWrite 是针对“只读”或“只写”的简单场景设计的从机地址直接传 7 位地址即可。而 I2cTransfer 支持你构造一组消息实现“先写寄存器地址再读数据”这种复合传输。两种方式的地址处理可能不完全一致——有些版本底层会自动左移一位有些不会。这导致我在不同 SDK 之间搬运代码时经常要留意地址参数。最稳的做法是在调试阶段用逻辑分析仪抓一次总线波形看地址字节到底是多少然后反推 API 对地址做了怎样的处理。2.4 消息结构体里的 flags 到底怎么设在 I2cTransfer 中核心是消息结构体。OpenHarmony HDF 里的结构体定义大致是这样不同版本字段名可能略有差异但语义一致typedef struct { uint16_t addr; uint32_t len; uint32_t flags; void *buf; } I2cMsg;flags 是控制消息方向的关键。我常用的几个标志是标志含义使用建议I2C_FLAG_READ读方向总线上的数据由从机发给主机在读取寄存器数据时使用I2C_FLAG_WRITE写方向数据由主机发给从机大多数写操作使用I2C_FLAG_NOSTART消息开始前不产生起始条件配合重复起始时使用避免多一个 START我见过最头疼的问题出现在读操作上如果一条消息标了 READ 却没标 NOSTART控制器的行为可能是在这条消息前又发一次起始条件结果一个读操作变成了两个独立的事务从机状态机就直接懵了。所以遇到奇怪的读取结果先把 flags 逐位检查一遍。另一个技巧是不需要手动处理 7 位地址左移的问题因为很多驱动里 addr 字段直接填 7 位地址底层会自动处理但你最好还是用逻辑分析仪验证一次。3. 动手写一个 I2C 传感器驱动OpenHarmony 实战理论知识说完了下面我以一颗常见的 I2C 温度传感器 TMP102 为例把整个驱动开发流程走一遍。TMP102 的地址是 0x48默认读温度需要先写寄存器指针0x00然后读两个字节高位在前。这块芯片简单、资料多拿来做 I2C 驱动入门非常合适。3.1 硬件连接和地址确认上电前先做三件事第一步是看原理图确认传感器芯片的 ADDR0 引脚接线。TMP102 的地址引脚接 GND 时从机地址是 0x48接 VCC 时是 0x49接 SDA 时是 0x4A接 SCL 时是 0x4B。如果你板子上把 ADDR0 接到了 GND但代码里却把地址填成 0x4B设备永远不会 ACK。这种低级问题用万用表一量就能提前发现。第二步是量电压。传感器的 VCC 必须等于你 I2C 总线所在电源域的电压通常都是 3.3V 或者 1.8V。如果传感器是 3.3V 供电但主控的 I2C 上拉电阻接到了 1.8V那 SCL/SDA 的高电平只有 1.8V芯片能否识别就看它的输入阈值了。这种电平不匹配经常导致“偶尔能通信、大多数时候超时”的诡异现象。第三步是确认上拉电阻。I2C 总线的 SCL 和 SDA 每根线都要有上拉电阻常见值是 4.7kΩ。如果板子设计失误漏了上拉总线空闲时电平拉不高通信必然失败。反过来如果上拉太强比如 200Ω总线驱动能力不足波形圆润得跟电容充放电一样也会导致采样失败。再快速提一句如果你用的是评估板从主控到传感器模块之间可能有一根杜邦线或者排线线一长寄生电容就大波形边沿变缓400kHz 下很容易出错。这种情况下要么降频到 100kHz要么换更短更粗的线。别笑我有一个项目就是被 20 厘米的杜邦线折磨了两天。3.2 核心代码打开设备、写寄存器指针、读温度我把简化的驱动代码写出来尽量贴近 HDF 的风格#include device_i2c_if.h #define TMP102_ADDR 0x48 #define TMP102_REG_TEMP 0x00 #define TEMP_BUF_LEN 2 static DevHandle g_i2cHandle NULL; static int32_t Tmp102ReadTemp(int16_t *temp) { int32_t ret; uint8_t regAddr TMP102_REG_TEMP; uint8_t data[TEMP_BUF_LEN] {0}; I2cMsg msgs[2]; msgs[0].addr TMP102_ADDR; msgs[0].len 1; msgs[0].flags 0; // 写方向先发寄存器指针 msgs[0].buf regAddr; msgs[1].addr TMP102_ADDR; msgs[1].len TEMP_BUF_LEN; msgs[1].flags I2C_FLAG_READ; // 读方向读两个字节 msgs[1].buf data; // 一次 Transfer 完成“写指针 读数据”的复合操作 ret I2cTransfer(g_i2cHandle, msgs, 2); if (ret ! 2) { return -1; } *temp (int16_t)((data[0] 8) | data[1]); return 0; } int32_t Tmp102Init(void) { g_i2cHandle I2cOpen(3); // 对应 busId 3 if (g_i2cHandle NULL) { return -1; } return 0; }代码本身不长但有几个位置要说明第一个消息是写方向flags 置 0 即可第二个消息是读方向需要显式设置 I2C_FLAG_READ。I2cTransfer 的返回值有些驱动里返回消息数有些返回字节数我在拿到一份新 SDK 时会先打日志确认返回值语义再决定怎么判断成功。另一个容易错的是寄存器指针和数据字节的顺序——先写 0x00再读两字节如果你前面写成了别的内容读回来的可能就是 EEPROM 里的随机数据。温度值的高位在前格式需要仔细处理data[0] 是高字节data[1] 是低字节温度精度是 0.0625 摄氏度。实际用的时候还要把低 4 位当作分数位处理但这属于芯片数据手册的内容就不展开了。重点是你会发现在 HDF 里操作 I2C所有读写都是通过这一个 I2cTransfer 函数完成并没有各种花哨的接口理解消息数组的组织方式就理解了八成。3.3 字节序、寄存器指针和错误码的细节用 I2C 读传感器数据最常见的坑之一就是字节序。TMP102 是高位在前其他传感器可能是低位在前。如果你读回来一个数值怪到离谱比如 0xABCD先把高低字节交换试试。注意有些驱动里包含一个 registerLength 字段用于指定寄存器地址的宽度有的是 1 字节有的是 2 字节必须在配置里写对。关于错误码HDF 的函数返回值如果是负数通常对应 I2C 传输超时、设备无 ACK、参数非法等。我建议在 Init 接口里加一层日志打印把 handle、addr、ret 都打出来这样排障时能快速分清是“没打开控制器”“地址不可达”还是“真正读到了脏数据”。HDF 本身有一套日志接口你可以在代码里加上HDF_LOGE之类的宏层次会更清晰。这节末尾想强调一点OpenHarmony 的 I2C API 在不同发布版本之间存在过命名和语义调整我看到过I2cRead、I2cWrite被标记为废弃或建议改用I2cTransfer的情况。所以如果你手头的 SDK 版本比较老不要看到我上面代码就盲目照抄一定要先看当前版本的 device_i2c_if.h 头文件把函数签名和消息结构体确认清楚再动手。4. I2C 排障实录从现象到根源写到这里我已经把协议和代码都过了一遍。但真正让 I2C 开发痛苦的从来不是写代码而是排障。下面这些问题是过去几年里我在不同项目上反复遇到的每一次都刻骨铭心。我按“现象 → 排查 → 根因”的方式写你可以直接对着查。4.1 读取全是 0xFF先查地址、供电和 SCL/SDA 有没有接反这是最经典的现象。你用 I2cRead 读传感器温度结果 buffer 里全是 0xFF看起来像“读到了空数据”。第一次遇到时我第一反应是传感器坏了后来发现大多数情况下根本不是。最常见的原因是设备地址不对。从机地址如果写错主机发出的地址字节根本没人应答但有的控制器读操作在没有 ACK 时会直接把 SDA 释放采样到的就是高电平于是读回来全是 1。0xFF 这个值其实就是在告诉你“总线上没有任何设备响应”。所以看到 0xFF第一件事不是换传感器而是用 I2C 扫描工具检查 0x48 附近有没有设备 ACK。在 OpenHarmony 上你可以在调试串口敲一段测试代码把所有地址都试一遍看哪个地址有 ACK。第二个原因是供电没到位。传感器如果没上电内部电路不工作数据和时钟引脚都是浮空状态读回来大概率也是 0xFF。量一下 VCC 引脚电压比核对地址还要快。第三个原因就是 SCL 和 SDA 接反了。这个用逻辑分析仪看波形最容易识别如果 SCL 和 SDA 的波形特征完全不像时钟和数据该有的样子八成是两根线对调了。我第一次踩这个坑时还以为是芯片型号配错了后来发现线被杜邦线转接排搞反了。4.2 波形显示地址字节后面跟着 NACK缩小到“地址、供电、上拉”三类如果你手上有逻辑分析仪看到地址字节之后紧跟着的高电平 NACK问题范围就缩小很多了。NACK 的意思是总线上没有设备响应这个地址。你先确认地址没错、供电正常然后检查这条总线上是否还有其他设备占用了相同地址。有些芯片的地址引脚是悬空的内部上拉或者下拉会给出一个默认地址结果和你的传感器冲突。在这种情况下常常是“两个设备都 ACK”或者“后上电的设备干扰了第一个设备的应答”表现就是不稳定或 NACK。还有一种被我忽略过的情况芯片处于复位状态。比如某些传感器有复位引脚被拉低后芯片内部时钟没起来自然不响应 I2C。检查这些控制引脚的电平和时序在上电后增加一段延时再初始化驱动能解决相当一部分“上电后立刻读失败”的案例。4.3 偶发失败和波形边沿圆润检查上拉电阻、总线长度和频率电信号问题比逻辑问题更难查。如果你用示波器观察 SCL 和 SDA发现上升沿不是直角而是圆弧形说明总线电容太大或者上拉电阻太强。常见于传感器通过长排线连接到主控的场景。你可以用万用表量一下 SCL 对地的电容正常单个设备的小型总线应该在几十 pF 级别如果超过 300pF上升沿就会被拖慢。解决方式有两种一是降低通信频率把 400kHz 改成 100kHz二是减小上拉电阻比如把 4.7kΩ 换成 2.2kΩ增强驱动能力。注意不要一下子降到 1kΩ有些主控的 GPIO 驱动能力有限反而会损伤引脚。我通常先在 100kHz 下确认通信稳定再把频率往上调直到出现错误然后回退到上一个稳定档位。这个方法可能不够“科学”但非常实用。4.4 OpenHarmony 驱动返回负数错误码从日志和 errno 里找线索如果 I2cTransfer 返回的是负数通常不是传感器问题而是主控侧的问题。常见的是I2C_TRANSFER_TIMEOUT——控制器发起了传输但没收到完整时序超时返回。这种情况要先确认你打开的 I2C 控制器有没有正确初始化时钟尤其当主控的 I2C 控制器时钟来自某个 PLL 分频时如果分频配错SCL 频率可能完全不对甚至没有时钟输出。另外也可能是引脚复用PinMux没配导致 I2C 控制器的信号没有真正出现在板级引脚上。你可以用示波器量一下 SCL 引脚有没有波形如果有波形但传输超时问题在协议或从机如果根本没波形问题在控制器配置。遇到负返回我建议先加打印把 handle、busId、消息条数和每个消息的 addr、flags 打出来。很多时候你会发现之前的事情都答对了只是消息结构体里一个字段没初始化被随机值填充了。C 语言里局部变量不初始化这种事一旦发生表现就是“换了编译器就没问题”。4.5 用逻辑分析仪快速定位你要看的那几个关键位置逻辑分析仪是排查 I2C 最有力的工具有条件一定要用。设置采样率建议 10MHz 以上触发条件选 SDA 下降沿这样能第一时间抓起始条件。抓到波形后先从起始条件开始跟着 SCL 数时钟。第一个字节应该是地址字节确认高 7 位是不是目标地址最低位是不是你要的方向。然后数第 9 个时钟看 SDA 是不是被拉低——这就是 ACK。如果在地址阶段没有 ACK问题在寻址或物理层如果 ACK 后数据阶段才出现 NACK问题可能在你请求了不存在的寄存器或者设备不支持继续读。再看停止条件是否正常出现有没有多余的 START 或 STOP这条最能暴露 flags 配错导致的复合操作问题。不管用哪种逻辑分析仪我建议养成的习惯是每次新接一个 I2C 设备先抓一次完整的读写时序保存下来留档。以后出问题一对比就知道是哪一步的行为变了。这种“标准波形思维”比任何经验都管用。5. 常见问题速查与个人经验小结下面这份表格整理了我多年调试 I2C 过程中踩过的典型问题直接对照排查即可。现象可能原因排查和解决读取全部 0xFF地址错误、设备未上电、SCL/SDA 接反量供电扫描地址检查接线用逻辑分析仪看波形地址阶段 NACK地址冲突、复位引脚拉低、总线被其他设备占用确认地址唯一检查复位引脚短接排除干扰偶发通信失败总线电容大、上拉电阻不合适、频率过高降低频率换 2.2k 上拉缩短连接线读回数据错乱、寄存器偏了读操作缺少重复起始、flags 配错检查 I2cMsg 中 READ 和 NOSTART 的组合驱动返回超时控制器配置错误、引脚复用错误、时钟错示波器看 SCL 波形检查 HCS 配置和 PinMux只能写不能读复合操作没用 I2cTransfer或读消息被错误拆分使用一组 msgs 完成写读不要拆成两次独立操作上电后第一次通信失败从机上电初始化时间长在驱动 Init 中增加延时比如 50ms 再访问总线挂死、SCL 拉低不放时钟延展未处理、从机异常开启超时机制复位从机或断电重启5.1 从一次触摸屏调试里学到的经验有一回我调试一个 GT911 触摸屏控制器现象非常诡异上电后偶尔能读到触摸点但只要一进入休眠再唤醒I2C 通信就彻底断了。当时我怀疑是驱动忘了重新配置寄存器加了无数句重发初始化代码都没解决。后来用示波器抓唤醒后的波形发现第一次 I2C 写操作一直等 NACK——地址字节发出去了但屏幕上电后控制器还没准备好要额外几十毫秒才能恢复。最后在触摸屏驱动的唤醒流程里加了一个 100ms 的延时再也没出过问题。这个案例给我的教训是I2C 调试不要老想着“一定是协议哪里错了”先说物理和时序再谈逻辑。尤其是带电源管理功能的芯片、带复位脚的芯片、带休眠唤醒功能的芯片这类设备的状态切换往往会把主机“晾在一边”。你只要在关键流程前后加延时或者查询状态很多疑难杂症会自动消失。5.2 我建议的 I2C 驱动开发流程如果你要接一个新的 I2C 传感器我的建议流程是这样的第一步确认硬件连接和地址用万用表或逻辑分析仪保证物理层正常。第二步用一个最简单的读寄存器操作验证单次写读是否通不用一上来就写完整驱动。第三步把单次操作封装成 Transfer 形式用逻辑分析仪确认波形正确。第四步再补错误处理、重试机制和日志。最后第五步接入 OpenHarmony 的设备框架做成标准的 HDF 驱动节点。这个过程看起来很慢但恰恰是最快的。我见过太多人跳过前两步直接写完整驱动最后在框架层、协议层、物理层三层问题混合在一起排查那才叫真的地狱模式。I2C 本身不复杂复杂的是它连接的设备和周边环境把底层烂熟于心再配合趁手的工具绝大多数问题半小时内都能定位。最后再分享一个小习惯我在工程的通用排障目录里放了一个 i2c_probe 测试模块可以手动指定 busId 和从机地址做读写测试。每次遇到怀疑是 I2C 问题的情况就先跑这个模块把“驱动代码问题”和“硬件总线问题”的分界线划出来。这个模块帮我省下的时间可能比写这个教程还多。
返回列表