曹旭辉 发表于 2024-12-3 02:23:05

OpenHarmony(鸿蒙南向)——平台驱动指南【I2C】

往期知识点记载:



[*] 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
[*] 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
[*] 连续更新中……
概述

功能简介

I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简朴、双向二线制同步串行总线。由于其硬件连接简朴、成本低廉,因此被广泛应用于各种短间隔通讯的场景。
运作机制

I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA(SerialData)串行数据线以及SCL(SerialClock)串行时钟线两根线相连(如图1)。
I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的制止条件。数据传输以字节为单元,高位在前,逐个bit举行传输。
I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地点,当主设备需要和某一个从设备通讯时,通过广播的方式,将从设备地点写到总线上,如果某个从设备符合此地点,将会发出应答信号,建立传输。
I2C接口界说了完成I2C传输的通用方法集合,包罗:


[*] I2C控制器管理:打开或关闭I2C控制器
[*] I2C消息传输:通过消息传输布局体数组举行自界说传输
图 1 I2C物理连线示意图
https://img-blog.csdnimg.cn/img_convert/2d3977da5e5703aacf65152e522c83c9.webp?x-oss-process=image/format,png
利用引导

场景介绍

I2C通常用于与各类支持I2C协议的传感器、执行器或输入输出设备举行通讯。
接口说明

I2C模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/i2c_if.h。
表 1 I2C驱动API接口功能介绍
接口名接口描述DevHandle I2cOpen(int16_t number)打开I2C控制器void I2cClose(DevHandle handle)关闭I2C控制器int32_t I2cTransfer(DevHandle handle, struct I2cMsg *msgs, int16_t count)自界说传输 利用流程

利用I2C设备的一般流程如下图所示。
图 2 I2C设备利用流程图
https://img-blog.csdnimg.cn/img_convert/b464fc54f7cc349d36277f3005d10768.webp?x-oss-process=image/format,png
打开I2C控制器

在举行I2C通讯前,首先要调用I2cOpen打开I2C控制器。
DevHandle I2cOpen(int16_t number);
表 2 I2cOpen参数和返回值描述
参数参数描述numberint16_t类型,I2C控制器号返回值返回值描述NULL打开I2C控制器失败设备句柄打开的I2C控制器设备句柄 假设体系中存在8个I2C控制器,编号从0到7,以下代码示例为获取3号控制器:
DevHandle i2cHandle = NULL;// I2C控制器句柄

// 打开I2C控制器
i2cHandle = I2cOpen(3);
if (i2cHandle == NULL) {
    HDF_LOGE("I2cOpen: i2c open fail.\n");
    return NULL;
}
举行I2C通讯

消息传输
int32_t I2cTransfer(DevHandle handle, struct I2cMsg *msgs, int16_t count);
表 3 I2cTransfer参数和返回值描述
参数参数描述handleDevHandle类型,I2C控制器设备句柄msgs布局体指针,待传输数据的消息布局体数组countint16_t类型,消息数组长度返回值返回值描述正整数成功传输的消息布局体数量负数执行失败 I2C传输消息类型为I2cMsg,每个传输消息布局体表示一次读或写,通过一个消息数组,可以执行多少次的读写组合操作。组合读写示例:
int32_t ret;
uint8_t wbuff = { 0x12, 0x13 };
uint8_t rbuff = { 0 };
struct I2cMsg msgs;      // 自定义传输的消息结构体数组
msgs.buf = wbuff;          // 写入的数据
msgs.len = 2;            // 写入数据长度为2
msgs.addr = 0x5A;          // 写入设备地址为0x5A
msgs.flags = 0;            // 传输标记为0,默认为写
msgs.buf = rbuff;          // 要读取的数据
msgs.len = 2;            // 读取数据长度为2
msgs.addr = 0x5A;          // 读取设备地址为0x5A
msgs.flags = I2C_FLAG_READ // I2C_FLAG_READ置位
// 进行一次自定义传输,传输的消息个数为2
ret = I2cTransfer(i2cHandle, msgs, 2);
if (ret != 2) {
    HDF_LOGE("I2cTransfer: i2c transfer fail, ret:%d\n", ret);
    return HDF_FAILURE;
}
   注意:


[*] I2cMsg布局体中的设备地点不包罗读写标志位,读写信息由flags成员变量的读写控制位转达。
[*] 本函数不对消息布局体个数count做限定,其最大个数度由具体I2C控制器决定。
[*] 本函数也不对每个消息布局体中的数据长度做限定,同样由具体I2C控制器决定。
[*] 本函数可能会引起体系休眠,不允许在制止上下文调用
关闭I2C控制器

I2C通讯完成之后,需要关闭I2C控制器,关闭函数如下所述:
void I2cClose(DevHandle handle);
表 4 I2cClose参数和返回值描述
参数参数描述handleDevHandle类型,I2C控制器设备句柄 关闭I2C控制器示例:
I2cClose(i2cHandle); // 关闭I2C控制器
利用示例

本例程以操作开发板上的I2C设备为例,详细展示I2C接口的完备利用流程。
本例拟对Hi3516DV300开发板上TouchPad设备举行简朴的寄存器读写访问,基本硬件信息如下:


[*] SOC:hi3516dv300。
[*] Touch IC:I2C地点为0x38,IC内部寄存器位宽为1字节。
[*] 硬件连接:TouchPad设备挂接在3号I2C控制器下;IC的复位管脚为3号GPIO。
本例程首先对Touch IC举行复位操作(开发板上电默认会给TouchIC供电,本例程不考虑供电),然后对其内部寄存器举行随机读写,测试I2C通路是否正常。
   说明:
本示例重点在于展示I2C设备访问流程,并验证I2C通路,所以对于设备寄存器读写值不做关注,读写寄存器导致的行为由设备自身决定。
示例如下:
#include "i2c_if.h"          /* I2C标准接口头文件 */
#include "gpio_if.h"         /* GPIO标准接口头文件 */
#include "hdf_log.h"         /* 标准日志打印头文件 */
#include "osal_io.h"         /* 标准IO读写接口头文件 */
#include "osal_time.h"       /* 标准延迟&睡眠接口头文件 */

/* 定义一个表示TP设备的结构体,存储i2c及gpio相关硬件信息 */
struct TpI2cDevice {
    uint16_t rstGpio;             /* 复位管脚 */
    uint16_t busId;               /* I2C总线号 */
    uint16_t addr;                /* I2C设备地址 */
    uint16_t regLen;            /* 寄存器字节宽度 */
    DevHandle i2cHandle;/* I2C控制器句柄 */
};

/* I2C管脚io配置,需要查阅SOC寄存器手册*/
#define I2C3_DATA_REG_ADDR 0x112f008c /* 3号I2C控制器SDA管脚配置寄存器地址 */
#define I2C3_CLK_REG_ADDR 0x112f0090/* 3号I2C控制器SCL管脚配置寄存器地址 */
#define I2C_REG_CFG 0x5f1             /* 3号I2C控制器SDA及SCL管脚配置值 */

static void TpSocIoCfg(void)
{
    /* 将3号I2C控制器对应两个管脚的IO功能设置为I2C */
    OSAL_WRITEL(I2C_REG_CFG, IO_DEVICE_ADDR(I2C3_DATA_REG_ADDR));
    OSAL_WRITEL(I2C_REG_CFG, IO_DEVICE_ADDR(I2C3_CLK_REG_ADDR));
}

/* 对TP的复位管脚进行初始化, 拉高维持20ms, 再拉底维持50ms,最后再拉高维持20ms, 完成复位动作 */
static int32_t TestCaseGpioInit(struct TpI2cDevice *tpDevice)
{
    int32_t ret;

    /* 设置复位管脚方向为输出 */
    ret = GpioSetDir(tpDevice->rstGpio, GPIO_DIR_OUT);
    if (ret != HDF_SUCCESS) {
      HDF_LOGE("%s: set rst dir fail!:%d", __func__, ret);
      return ret;
    }

    ret = GpioWrite(tpDevice->rstGpio, GPIO_VAL_HIGH);
    if (ret != HDF_SUCCESS) {
      HDF_LOGE("%s: set rst hight fail!:%d", __func__, ret);
      return ret;
    }
    OsalMSleep(20);

    ret = GpioWrite(tpDevice->rstGpio, GPIO_VAL_LOW);
    if (ret != HDF_SUCCESS) {
      HDF_LOGE("%s: set rst low fail!:%d", __func__, ret);
      return ret;
    }
    OsalMSleep(50);

    ret = GpioWrite(tpDevice->rstGpio, GPIO_VAL_HIGH);
    if (ret != HDF_SUCCESS) {
      HDF_LOGE("%s: set rst high fail!:%d", __func__, ret);
      return ret;
    }
    OsalMSleep(20);

    return HDF_SUCCESS;
}

/* 基于I2cTransfer方法封装一个寄存器读写的辅助函数, 通过flag表示读或写 */
static int TpI2cReadWrite(struct TpI2cDevice *tpDevice, unsigned int regAddr,
    unsigned char *regData, unsigned int dataLen, uint8_t flag)
{
    int index = 0;
    unsigned char regBuf = {0};
    struct I2cMsg msgs = {0};

    /* 单双字节寄存器长度适配 */
    if (tpDevice->regLen == 1) {
      regBuf = regAddr & 0xFF;
    } else {
      regBuf = (regAddr >> 8) & 0xFF;
      regBuf = regAddr & 0xFF;
    }

    /* 填充I2cMsg消息结构 */
    msgs.addr = tpDevice->addr;
    msgs.flags = 0; /* 标记为0,表示写入 */
    msgs.len = tpDevice->regLen;
    msgs.buf = regBuf;

    msgs.addr = tpDevice->addr;
    msgs.flags = (flag == 1) ? I2C_FLAG_READ : 0; /* 添加读标记位,表示读取 */
    msgs.len = dataLen;
    msgs.buf = regData;

    if (I2cTransfer(tpDevice->i2cHandle, msgs, 2) != 2) {
      HDF_LOGE("%s: i2c read err", __func__);
      return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

/* TP寄存器读函数 */
static inline int TpI2cReadReg(struct TpI2cDevice *tpDevice, unsigned int regAddr,
    unsigned char *regData, unsigned int dataLen)
{
    return TpI2cReadWrite(tpDevice, regAddr, regData, dataLen, 1);
}

/* TP寄存器写函数 */
static inline int TpI2cWriteReg(struct TpI2cDevice *tpDevice, unsigned int regAddr,
    unsigned char *regData, unsigned int dataLen)
{
    return TpI2cReadWrite(tpDevice, regAddr, regData, dataLen, 0);
}

/* I2C例程总入口 */
static int32_t TestCaseI2c(void)
{
    int32_t i;
    int32_t ret;
    unsigned char bufWrite = { 0xFF, 0xFF, 0xFF, 0xFF, 0xA, 0xB, 0xC };
    unsigned char bufRead = {0};
    static struct TpI2cDevice tpDevice;

    /* IO管脚功能配置 */
    TpSocIoCfg();

    /* TP设备信息初始化 */
    tpDevice.rstGpio = 3;
    tpDevice.busId = 3;
    tpDevice.addr = 0x38;
    tpDevice.regLen = 1;
    tpDevice.i2cHandle = NULL;

    /* GPIO管脚初始化 */
    ret = TestCaseGpioInit(&tpDevice);
    if (ret != HDF_SUCCESS) {
      HDF_LOGE("%s: gpio init fail!:%d", __func__, ret);
      return ret;
    }

    /* 打开I2C控制器 */
    tpDevice.i2cHandle = I2cOpen(tpDevice.busId);
    if (tpDevice.i2cHandle == NULL) {
      HDF_LOGE("%s: Open I2c:%u fail!", __func__, tpDevice.busId);
      return -1;
    }

    /* 向TP-IC的0xD5寄存器连续写7字节数据 */
    ret = TpI2cWriteReg(&tpDevice, 0xD5, bufWrite, 7);
    if (ret != HDF_SUCCESS) {
      HDF_LOGE("%s: tp i2c write reg fail!:%d", __func__, ret);
      I2cClose(tpDevice.i2cHandle);
      return -1;
    }
    OsalMSleep(10);

    /* 从TP-IC的0xD5寄存器连续读7字节数据 */
    ret = TpI2cReadReg(&tpDevice, 0xD5, bufRead, 7);
    if (ret != HDF_SUCCESS) {
      HDF_LOGE("%s: tp i2c read reg fail!:%d", __func__, ret);
      I2cClose(tpDevice.i2cHandle);
      return -1;
    }

    HDF_LOGE("%s: tp i2c write&read reg success!", __func__);
    for (i = 0; i < 7; i++) {
      HDF_LOGE("%s: bufRead[%d] = 0x%x", __func__, i, bufRead);
    }

    /* 访问完毕关闭I2C控制器 */
    I2cClose(tpDevice.i2cHandle);
    return ret;
}
末了

经常有很多小同伴诉苦说:不知道学习鸿蒙开发哪些技能?不知道需要重点把握哪些鸿蒙应用开发知识点?
为了可以或许资助到大家可以或许有规划的学习,这里特殊整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技能的学习门路,包罗了鸿蒙开发必把握的焦点知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技能、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、体系定制移植等等)鸿蒙(HarmonyOS NEXT)技能知识点。
https://i-blog.csdnimg.cn/direct/f94d1fce216a40caa550531c282b816b.png#pic_center
《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

怎样快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……
https://i-blog.csdnimg.cn/direct/43225e87b7a54407a65b8250b9ee94c8.png
鸿蒙开发口试真题(含参考答案):

https://i-blog.csdnimg.cn/direct/86cc41a1de0247329011c1537e67be11.png
《OpenHarmony源码剖析》:



[*]搭建开发环境
[*]Windows 开发环境的搭建
[*]Ubuntu 开发环境搭建
[*]Linux 与 Windows 之间的文件共享
[*]……
[*]体系架构分析
[*]构建子体系
[*]启动流程
[*]子体系
[*]分布式使命调理子体系
[*]分布式通讯子体系
[*]驱动子体系
[*]……
https://img-blog.csdnimg.cn/img_convert/b2a7c0f56b33ef83d8199a6e53e443f2.png
OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

https://img-blog.csdnimg.cn/img_convert/35b4e458bb0a8a3bb1c75278c7493fd5.jpeg
https://i-blog.csdnimg.cn/direct/92382879269940889c578d20dd5b6641.gif#pic_center

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: OpenHarmony(鸿蒙南向)——平台驱动指南【I2C】