• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# I2C<a name="ZH-CN_TOPIC_0000001052778273"></a>
2
3-   [概述](#section5361140416)
4    -   [接口说明](#section459052019177)
5
6-   [使用指导](#section1695201514281)
7    -   [使用流程](#section1338373417288)
8    -   [打开I2C控制器](#section13751110132914)
9    -   [进行I2C通信](#section9202183372916)
10    -   [关闭I2C控制器](#section19481164133018)
11
12-   [使用实例](#section5302202015300)
13
14## 概述<a name="section5361140416"></a>
15
16-   I2C\(Inter Integrated Circuit\)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。
17-   I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA\(SerialData\)串行数据线以及SCL\(SerialClock\)串行时钟线两根线相连,如[图1 ](#fig1135561232714)所示。
18
19-   I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。数据传输以字节为单位,高位在前,逐个bit进行传输。
20-   I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。
21
22-   I2C接口定义了完成I2C传输的通用方法集合,包括:
23
24    -   I2C控制器管理:  打开或关闭I2C控制器
25    -   I2C消息传输:通过消息传输结构体数组进行自定义传输
26
27    **图 1**  I2C物理连线示意图<a name="fig1135561232714"></a>
28    ![](figure/I2C物理连线示意图.png "I2C物理连线示意图")
29
30
31### 接口说明<a name="section459052019177"></a>
32
33**表 1**  I2C驱动API接口功能介绍
34
35<a name="table1731550155318"></a>
36<table><thead align="left"><tr id="row4419501537"><th class="cellrowborder" valign="top" width="18.63%" id="mcps1.2.4.1.1"><p id="p641050105320"><a name="p641050105320"></a><a name="p641050105320"></a>功能分类</p>
37</th>
38<th class="cellrowborder" valign="top" width="28.03%" id="mcps1.2.4.1.2"><p id="p54150165315"><a name="p54150165315"></a><a name="p54150165315"></a>接口名</p>
39</th>
40<th class="cellrowborder" valign="top" width="53.339999999999996%" id="mcps1.2.4.1.3"><p id="p941150145313"><a name="p941150145313"></a><a name="p941150145313"></a>描述</p>
41</th>
42</tr>
43</thead>
44<tbody><tr id="row34145016535"><td class="cellrowborder" rowspan="2" valign="top" width="18.63%" headers="mcps1.2.4.1.1 "><p id="p229610227124"><a name="p229610227124"></a><a name="p229610227124"></a>I2C控制器管理接口</p>
45</td>
46<td class="cellrowborder" valign="top" width="28.03%" headers="mcps1.2.4.1.2 "><p id="p19389143041518"><a name="p19389143041518"></a><a name="p19389143041518"></a>I2cOpen</p>
47</td>
48<td class="cellrowborder" valign="top" width="53.339999999999996%" headers="mcps1.2.4.1.3 "><p id="p8738101941716"><a name="p8738101941716"></a><a name="p8738101941716"></a>打开I2C控制器</p>
49</td>
50</tr>
51<tr id="row5632152611414"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p143890309153"><a name="p143890309153"></a><a name="p143890309153"></a>I2cClose</p>
52</td>
53<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p573815197171"><a name="p573815197171"></a><a name="p573815197171"></a>关闭I2C控制器</p>
54</td>
55</tr>
56<tr id="row15108165391412"><td class="cellrowborder" valign="top" width="18.63%" headers="mcps1.2.4.1.1 "><p id="p91084533141"><a name="p91084533141"></a><a name="p91084533141"></a>I2c消息传输接口</p>
57</td>
58<td class="cellrowborder" valign="top" width="28.03%" headers="mcps1.2.4.1.2 "><p id="p13901730101511"><a name="p13901730101511"></a><a name="p13901730101511"></a>I2cTransfer</p>
59</td>
60<td class="cellrowborder" valign="top" width="53.339999999999996%" headers="mcps1.2.4.1.3 "><p id="p12738111912171"><a name="p12738111912171"></a><a name="p12738111912171"></a>自定义传输</p>
61</td>
62</tr>
63</tbody>
64</table>
65
66>![](../public_sys-resources/icon-note.gif) **说明:**
67>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
68
69## 使用指导<a name="section1695201514281"></a>
70
71### 使用流程<a name="section1338373417288"></a>
72
73使用I2C设备的一般流程如[图2](#fig166181128151112)所示。
74
75**图 2**  I2C设备使用流程图<a name="fig166181128151112"></a>
76
77
78![](figure/zh-cn_image_0000001123509750.png)
79
80### 打开I2C控制器<a name="section13751110132914"></a>
81
82在进行I2C通信前,首先要调用I2cOpen打开I2C控制器。
83
84DevHandle I2cOpen\(int16\_t number\);
85
86**表 2**  I2cOpen参数和返回值描述
87
88<a name="table7603619123820"></a>
89<table><thead align="left"><tr id="row1060351914386"><th class="cellrowborder" valign="top" width="20.66%" id="mcps1.2.3.1.1"><p id="p14603181917382"><a name="p14603181917382"></a><a name="p14603181917382"></a><strong id="b16510829133012"><a name="b16510829133012"></a><a name="b16510829133012"></a>参数</strong></p>
90</th>
91<th class="cellrowborder" valign="top" width="79.34%" id="mcps1.2.3.1.2"><p id="p36031519183819"><a name="p36031519183819"></a><a name="p36031519183819"></a><strong id="b65222293309"><a name="b65222293309"></a><a name="b65222293309"></a>参数描述</strong></p>
92</th>
93</tr>
94</thead>
95<tbody><tr id="row1960431983813"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p3604719123817"><a name="p3604719123817"></a><a name="p3604719123817"></a>number</p>
96</td>
97<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p221392414442"><a name="p221392414442"></a><a name="p221392414442"></a>I2C控制器号</p>
98</td>
99</tr>
100<tr id="row11410612183019"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p460381915385"><a name="p460381915385"></a><a name="p460381915385"></a><strong id="b4349113243013"><a name="b4349113243013"></a><a name="b4349113243013"></a>返回值</strong></p>
101</td>
102<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p96031619153812"><a name="p96031619153812"></a><a name="p96031619153812"></a><strong id="b63502322308"><a name="b63502322308"></a><a name="b63502322308"></a>返回值描述</strong></p>
103</td>
104</tr>
105<tr id="row15410111273017"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p1060418195389"><a name="p1060418195389"></a><a name="p1060418195389"></a>NULL</p>
106</td>
107<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p760471912388"><a name="p760471912388"></a><a name="p760471912388"></a>打开I2C控制器失败</p>
108</td>
109</tr>
110<tr id="row1241081213303"><td class="cellrowborder" valign="top" width="20.66%" headers="mcps1.2.3.1.1 "><p id="p5604719133811"><a name="p5604719133811"></a><a name="p5604719133811"></a>设备句柄</p>
111</td>
112<td class="cellrowborder" valign="top" width="79.34%" headers="mcps1.2.3.1.2 "><p id="p3604181933818"><a name="p3604181933818"></a><a name="p3604181933818"></a>打开的I2C控制器设备句柄</p>
113</td>
114</tr>
115</tbody>
116</table>
117
118假设系统中存在8个I2C控制器,编号从0到7,那么我们现在获取3号控制器
119
120```
121DevHandle i2cHandle = NULL;  /* I2C控制器句柄 /
122
123/* 打开I2C控制器 */
124i2cHandle = I2cOpen(3);
125if (i2cHandle == NULL) {
126    HDF_LOGE("I2cOpen: failed\n");
127    return;
128}
129```
130
131### 进行I2C通信<a name="section9202183372916"></a>
132
133消息传输
134
135int32\_t I2cTransfer\(DevHandle handle, struct I2cMsg \*msgs, int16\_t count\);
136
137**表 3**  I2cTransfer参数和返回值描述
138
139<a name="table1934414174212"></a>
140<table><thead align="left"><tr id="row1134415176216"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p13295152320217"><a name="p13295152320217"></a><a name="p13295152320217"></a><strong id="b17389641205115"><a name="b17389641205115"></a><a name="b17389641205115"></a>参数</strong></p>
141</th>
142<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p1295112352115"><a name="p1295112352115"></a><a name="p1295112352115"></a><strong id="b19401541175118"><a name="b19401541175118"></a><a name="b19401541175118"></a>参数描述</strong></p>
143</th>
144</tr>
145</thead>
146<tbody><tr id="row5344101702113"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p19295132382111"><a name="p19295132382111"></a><a name="p19295132382111"></a>handle</p>
147</td>
148<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1051172572919"><a name="p1051172572919"></a><a name="p1051172572919"></a>I2C控制器设备句柄</p>
149</td>
150</tr>
151<tr id="row17344171722117"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p9295122332113"><a name="p9295122332113"></a><a name="p9295122332113"></a>msgs</p>
152</td>
153<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p202951238218"><a name="p202951238218"></a><a name="p202951238218"></a>待传输数据的消息结构体数组</p>
154</td>
155</tr>
156<tr id="row45812466213"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1659246112117"><a name="p1659246112117"></a><a name="p1659246112117"></a>count</p>
157</td>
158<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p259124622119"><a name="p259124622119"></a><a name="p259124622119"></a>消息数组长度</p>
159</td>
160</tr>
161<tr id="row04701426105110"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p17295142322113"><a name="p17295142322113"></a><a name="p17295142322113"></a><strong id="b2159044145115"><a name="b2159044145115"></a><a name="b2159044145115"></a>返回值</strong></p>
162</td>
163<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p142959232211"><a name="p142959232211"></a><a name="p142959232211"></a><strong id="b16160044135114"><a name="b16160044135114"></a><a name="b16160044135114"></a>返回值描述</strong></p>
164</td>
165</tr>
166<tr id="row74701226125110"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p929532313211"><a name="p929532313211"></a><a name="p929532313211"></a>正整数</p>
167</td>
168<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p829512237217"><a name="p829512237217"></a><a name="p829512237217"></a>成功传输的消息结构体数目</p>
169</td>
170</tr>
171<tr id="row204701126195115"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p12958234217"><a name="p12958234217"></a><a name="p12958234217"></a>负数</p>
172</td>
173<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1295192312112"><a name="p1295192312112"></a><a name="p1295192312112"></a>执行失败</p>
174</td>
175</tr>
176</tbody>
177</table>
178
179I2C传输消息类型为I2cMsg,每个传输消息结构体表示一次读或写,通过一个消息数组,可以执行若干次的读写组合操作。
180
181```
182int32_t ret;
183uint8_t wbuff[2] = { 0x12, 0x13 };
184uint8_t rbuff[2] = { 0 };
185struct I2cMsg msgs[2]; /* 自定义传输的消息结构体数组 */
186msgs[0].buf = wbuff;    /* 写入的数据 */
187msgs[0].len = 2;        /* 写入数据长度为2 */
188msgs[0].addr = 0x5A;    /* 写入设备地址为0x5A */
189msgs[0].flags = 0;      /* 传输标记为0,默认为写 */
190msgs[1].buf = rbuff;    /* 要读取的数据 */
191msgs[1].len = 2;        /* 读取数据长度为2 */
192msgs[1].addr = 0x5A;    /* 读取设备地址为0x5A */
193msgs[1].flags = I2C_FLAG_READ /* I2C_FLAG_READ置位 */
194/* 进行一次自定义传输,传输的消息个数为2 */
195ret = I2cTransfer(i2cHandle, msgs, 2);
196if (ret != 2) {
197    HDF_LOGE("I2cTransfer: failed, ret %d\n", ret);
198    return;
199}
200```
201
202>![](../public_sys-resources/icon-caution.gif) **注意:**
203>-   I2cMsg结构体中的设备地址不包含读写标志位,读写信息由flags成员变量的读写控制位传递。
204>-   本函数不对消息结构体个数count做限制,其最大个数度由具体I2C控制器决定。
205>-   本函数也不对每个消息结构体中的数据长度做限制,同样由具体I2C控制器决定。
206>-   本函数可能会引起系统休眠,不允许在中断上下文调用
207
208### 关闭I2C控制器<a name="section19481164133018"></a>
209
210I2C通信完成之后,需要关闭I2C控制器,关闭函数如下所示:
211
212void I2cClose\(DevHandle handle\);
213
214**表 4**  I2cClose参数和返回值描述
215
216<a name="table72517953115"></a>
217<table><thead align="left"><tr id="row1525793312"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p115402031153111"><a name="p115402031153111"></a><a name="p115402031153111"></a>参数</p>
218</th>
219<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p65406313319"><a name="p65406313319"></a><a name="p65406313319"></a>参数描述</p>
220</th>
221</tr>
222</thead>
223<tbody><tr id="row1926109193116"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p105419317318"><a name="p105419317318"></a><a name="p105419317318"></a>handle</p>
224</td>
225<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1213245577"><a name="p1213245577"></a><a name="p1213245577"></a>I2C控制器设备句柄</p>
226</td>
227</tr>
228</tbody>
229</table>
230
231```
232I2cClose(i2cHandle); /* 关闭I2C控制器 */
233```
234
235## 使用实例<a name="section5302202015300"></a>
236
237本例程以操作开发板上的I2C设备为例,详细展示I2C接口的完整使用流程。
238
239本例拟对Hi3516DV300某开发板上TouchPad设备进行简单的寄存器读写访问,基本硬件信息如下:
240
241-   SOC:hi3516dv300。
242
243-   Touch IC:I2C地址为0x38, IC内部寄存器位宽为1字节。
244
245-   原理图信息:TouchPad设备挂接在3号I2C控制器下;IC的复位管脚为3号GPIO。
246
247本例程首先对Touch IC进行复位操作(开发板上电默认会给TouchIC供电,本例程不考虑供电),然后对其内部寄存器进行随机读写,测试I2C通路是否正常。
248
249>![](../public_sys-resources/icon-note.gif) **说明:**
250>本例程重点在于展示I2C设备访问流程,并验证I2C通路,所以对于设备寄存器读写值不做关注,读写寄存器导致的行为由设备自身决定。
251
252示例如下:
253
254```
255#include "i2c_if.h"          /* I2C标准接口头文件 */
256#include "gpio_if.h"         /* GPIO标准接口头文件 */
257#include "hdf_log.h"         /* 标准日志打印头文件 */
258#include "osal_io.h"         /* 标准IO读写接口头文件 */
259#include "osal_time.h"       /* 标准延迟&睡眠接口头文件 */
260
261/* 定义一个表示TP设备的结构体,存储i2c及gpio相关硬件信息 */
262struct TpI2cDevice {
263    uint16_t rstGpio;             /* 复位管脚 */
264    uint16_t busId;               /* I2C总线号 */
265    uint16_t addr;                /* I2C设备地址 */
266    uint16_t regLen;              /* 寄存器字节宽度 */
267    DevHandle i2cHandle;  /* I2C控制器句柄 */
268};
269
270/* I2C管脚io配置,需要查阅SOC寄存器手册  */
271#define I2C3_DATA_REG_ADDR 0x112f008c /* 3号I2C控制器SDA管脚配置寄存器地址 */
272#define I2C3_CLK_REG_ADDR 0x112f0090  /* 3号I2C控制器SCL管脚配置寄存器地址 */
273#define I2C_REG_CFG 0x5f1             /* 3号I2C控制器SDA及SCL管脚配置值 */
274
275static void TpSocIoCfg(void)
276{
277    /* 将3号I2C控制器对应两个管脚的IO功能设置为I2C */
278    OSAL_WRITEL(I2C_REG_CFG, IO_DEVICE_ADDR(I2C3_DATA_REG_ADDR));
279    OSAL_WRITEL(I2C_REG_CFG, IO_DEVICE_ADDR(I2C3_CLK_REG_ADDR));
280}
281
282/* 对TP的复位管脚进行初始化, 拉高维持20ms, 再拉底维持50ms,最后再拉高维持20ms, 完成复位动作 */
283static int32_t TestCaseGpioInit(struct TpI2cDevice *tpDevice)
284{
285    int32_t ret;
286
287    /* 设置复位管脚方向为输出 */
288    ret = GpioSetDir(tpDevice->rstGpio, GPIO_DIR_OUT);
289    if (ret != HDF_SUCCESS) {
290        HDF_LOGE("%s: set rst dir fail!:%d", __func__, ret);
291        return ret;
292    }
293
294    ret = GpioWrite(tpDevice->rstGpio, GPIO_VAL_HIGH);
295    if (ret != HDF_SUCCESS) {
296        HDF_LOGE("%s: set rst hight fail!:%d", __func__, ret);
297        return ret;
298    }
299    OsalMSleep(20);
300
301    ret = GpioWrite(tpDevice->rstGpio, GPIO_VAL_LOW);
302    if (ret != HDF_SUCCESS) {
303        HDF_LOGE("%s: set rst low fail!:%d", __func__, ret);
304        return ret;
305    }
306    OsalMSleep(50);
307
308    ret = GpioWrite(tpDevice->rstGpio, GPIO_VAL_HIGH);
309    if (ret != HDF_SUCCESS) {
310        HDF_LOGE("%s: set rst high fail!:%d", __func__, ret);
311        return ret;
312    }
313    OsalMSleep(20);
314
315    return HDF_SUCCESS;
316}
317
318/* 基于I2cTransfer方法封装一个寄存器读写的辅助函数, 通过flag表示读或写 */
319static int TpI2cReadWrite(struct TpI2cDevice *tpDevice, unsigned int regAddr,
320    unsigned char *regData, unsigned int dataLen, uint8_t flag)
321{
322    int index = 0;
323    unsigned char regBuf[4] = {0};
324    struct I2cMsg msgs[2] = {0};
325
326    /* 单双字节寄存器长度适配 */
327    if (tpDevice->regLen == 1) {
328        regBuf[index++] = regAddr & 0xFF;
329    } else {
330        regBuf[index++] = (regAddr >> 8) & 0xFF;
331        regBuf[index++] = regAddr & 0xFF;
332    }
333
334    /* 填充I2cMsg消息结构 */
335    msgs[0].addr = tpDevice->addr;
336    msgs[0].flags = 0; /* 标记为0,表示写入 */
337    msgs[0].len = tpDevice->regLen;
338    msgs[0].buf = regBuf;
339
340    msgs[1].addr = tpDevice->addr;
341    msgs[1].flags = (flag == 1) ? I2C_FLAG_READ : 0; /* 添加读标记位,表示读取 */
342    msgs[1].len = dataLen;
343    msgs[1].buf = regData;
344
345    if (I2cTransfer(tpDevice->i2cHandle, msgs, 2) != 2) {
346        HDF_LOGE("%s: i2c read err", __func__);
347        return HDF_FAILURE;
348    }
349    return HDF_SUCCESS;
350}
351
352/* TP寄存器读函数 */
353static inline int TpI2cReadReg(struct TpI2cDevice *tpDevice, unsigned int regAddr,
354    unsigned char *regData, unsigned int dataLen)
355{
356    return TpI2cReadWrite(tpDevice, regAddr, regData, dataLen, 1);
357}
358
359/* TP寄存器写函数 */
360static inline int TpI2cWriteReg(struct TpI2cDevice *tpDevice, unsigned int regAddr,
361    unsigned char *regData, unsigned int dataLen)
362{
363    return TpI2cReadWrite(tpDevice, regAddr, regData, dataLen, 0);
364}
365
366/* I2C例程总入口 */
367static int32_t TestCaseI2c(void)
368{
369    int32_t i;
370    int32_t ret;
371    unsigned char bufWrite[7] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xA, 0xB, 0xC };
372    unsigned char bufRead[7] = {0};
373    static struct TpI2cDevice tpDevice;
374
375    /* IO管脚功能配置 */
376    TpSocIoCfg();
377
378    /* TP设备信息初始化 */
379    tpDevice.rstGpio = 3;
380    tpDevice.busId = 3;
381    tpDevice.addr = 0x38;
382    tpDevice.regLen = 1;
383    tpDevice.i2cHandle = NULL;
384
385    /* GPIO管脚初始化 */
386    ret = TestCaseGpioInit(&tpDevice);
387    if (ret != HDF_SUCCESS) {
388        HDF_LOGE("%s: gpio init fail!:%d", __func__, ret);
389        return ret;
390    }
391
392    /* 打开I2C控制器 */
393    tpDevice.i2cHandle = I2cOpen(tpDevice.busId);
394    if (tpDevice.i2cHandle == NULL) {
395        HDF_LOGE("%s: Open I2c:%u fail!", __func__, tpDevice.busId);
396        return -1;
397    }
398
399    /* 向TP-IC的0xD5寄存器连续写7字节数据 */
400    ret = TpI2cWriteReg(&tpDevice, 0xD5, bufWrite, 7);
401    if (ret != HDF_SUCCESS) {
402        HDF_LOGE("%s: tp i2c write reg fail!:%d", __func__, ret);
403        I2cClose(tpDevice.i2cHandle);
404        return -1;
405    }
406    OsalMSleep(10);
407
408    /* 从TP-IC的0xD5寄存器连续读7字节数据 */
409    ret = TpI2cReadReg(&tpDevice, 0xD5, bufRead, 7);
410    if (ret != HDF_SUCCESS) {
411        HDF_LOGE("%s: tp i2c read reg fail!:%d", __func__, ret);
412        I2cClose(tpDevice.i2cHandle);
413        return -1;
414    }
415
416    HDF_LOGE("%s: tp i2c write&read reg success!", __func__);
417    for (i = 0; i < 7; i++) {
418        HDF_LOGE("%s: bufRead[%d] = 0x%x", __func__, i, bufRead[i]);
419    }
420
421    /* 访问完毕关闭I2C控制器 */
422    I2cClose(tpDevice.i2cHandle);
423    return ret;
424}
425```
426
427