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  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> **说明:** 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 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> **注意:** 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> **说明:** 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