提交 60ffdfd3 编写于 作者: D duangavin123

update 导入OpenHarmony工程

Signed-off-by: Nduangavin123 <duanxichao@huawei.com>
上级 c3aa90b1

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
# 组件开发 # 组件开发指南
- [组件开发规范](组件开发规范.md) - [组件开发规范](bundles-standard-rules.md)
- [概述](概述.md) - [组件开发指南](bundles-guide.md)
- [组件构成](组件构成.md) - [组件开发指南](bundles-guide-overview.md)
- [组件管理](组件管理.md) - [准备工作](bundles-guide-prepare.md)
- [组件版本](组件版本.md) - [组件开发](bundles-guide-develop.md)
- [发行版](发行版.md) - [组件开发示例](bundles-demo.md)
- [环境变量说明](环境变量说明.md) - [HPM介绍](bundles-demo-hpmdescription.md)
- [环境准备](bundles-demo-environment.md)
- [组件开发指南](组件开发指南.md) - [操作实例](bundles-demo-devsample.md)
- [概述](概述-0.md)
- [准备工作](准备工作.md)
- [组件开发](组件开发.md)
- [组件开发示例](组件开发示例.md)
- [HPM介绍](HPM介绍.md)
- [环境准备](环境准备.md)
- [操作实例](操作实例.md)
# 操作实例<a name="ZH-CN_TOPIC_0000001072143838"></a>
环境准备好后,接下来本文以Hi3861平台为例,演示如何利用HPM进行组件的安装、编译和打包。
1. 执行以下命令,初始化安装目录(目录名可自行设置):
```
mkdir test3861
cd test3861
hpm init -t dist
```
初始化成功则显示:
```
Initialization finished.
```
2. 安装wifi\_iot发行版。
```
hpm install @ohos/wifi_iot
```
安装成功则显示:
```
Installed.
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>Hi3516平台采用下述命令:
>```
>hpm install @ohos/ip_camera_hi3516dv300
>```
>Hi3518平台采用下述命令:
>```
>hpm install @ohos/ip_camera_hi3518ev300
>```
3. 编译打包
```
hpm dist
```
编译成功会显示:
```
{{name}}: distribution building completed.
```
4. 上述所有命令执行成功后,在 ./out 目录下会生成编译结果,开发者可以将编译结果烧录到对应的开发板上进行测试。
# 环境准备<a name="ZH-CN_TOPIC_0000001071315859"></a>
- [linux服务器](#section20979554791)
- [安装Node.js](#section9954105413153)
- [安装HPM](#section15937194904819)
- [安装python环境](#section1621819180417)
- [安装文件打包工具](#section77617165913)
- [安装SCons](#section20558439191516)
## linux服务器<a name="section20979554791"></a>
准备一台装有Ubuntu 16.04 及以上 64 位系统的linux服务器(hpm是支持windows的,但是目前OpenHarmony开源的Hi3861、Hi3516、Hi3518三个解决方案都只支持Ubuntu)。
将linux shell改为bash:
```
ls -l $(which sh)
# 如果指向的不是bash,则按以下方式修改:
# 方法一:执行以下命令,然后选择no
dpkg-reconfigure dash
# 方法二:先删除sh,再重新创建软连接
rm -f /bin/sh
ln -s bash /bin/sh
```
## 安装Node.js<a name="section9954105413153"></a>
>![](../public_sys-resources/icon-note.gif) **说明:**
>如果配置的源的nodejs版本太低,可以执行以下语句后再执行apt-get install:
>```
>curl -L https://deb.nodesource.com/setup_12.x | bash
>```
推荐安装 Node.js 12.x (包含 npm 6.14.4)或更高版本(推荐 12.13.0+):
```
sudo apt-get install nodejs
sudo apt-get install npm
```
查看版本:
```
node --version # 查看nodejs版本
npm --version # 查看npm版本
```
## 安装HPM<a name="section15937194904819"></a>
通过 Node.js 自带的 npm(使用默认的源 https://registry.npmjs.org/ )安装 hpm-cli 命令行工具:
```
npm install -g @ohos/hpm-cli
```
安装完hpm-cli命令行工具后,执行以下命令可以查看hpm配置:
```
hpm config
```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置:
```
registry = https://hpm.harmonyos.com # hpm注册中心地址,下载组件必须
strictSsl = true # 通过https连接时,是否需要校验证书
http_proxy = http://your-proxy-server:port # 配置HTTP代理
https_proxy = http://your-proxy-server:port # 配置HTTPS代理
```
hpm-cli的命令介绍可以参考:[hpm操作命令](bundles-standard-rules.md)
## 安装python环境<a name="section1621819180417"></a>
需使用python3.7以上版本,采用以下命令进行安装:
```
sudo apt-get install python3.8
sudo apt-get install python3-pip
sudo pip3 install setuptools
sudo pip3 install kconfiglib # 建议安装kconfiglib 13.2.0+版本
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>上述方式适用Hi3518和Hi3516两种平台,针对Hi3861平台采用以下方式安装python环境:
>```
>sudo apt-get install python3.8
>sudo apt-get install python3-pip
>sudo pip3 install setuptools
>sudo pip3 install kconfiglib # 建议安装kconfiglib 13.2.0+版本
>sudo pip3 install pycryptodome
>sudo pip3 install six --upgrade --ignore-installed six
>sudo pip3 install ecdsa
>```
如果当前系统中既存在python2又存在python3,参考以下方法将默认python修改为python3:
```
ll `which python`
rm /usr/bin/python
ln -s python3.8 /usr/bin/python
```
## 安装文件打包工具<a name="section77617165913"></a>
采用以下命令进行安装:
```
which mkfs.vfat # 如果没找到,执行以下命令安装
sudo apt-get install dosfstools
which mcopy # 如果没找到,执行以下命令安装
sudo apt-get install mtools
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>Hi3518和Hi3516两种平台需要安装打包工具,Hi3861平台不需要。
## 安装SCons<a name="section20558439191516"></a>
1. 打开Linux编译服务器终端。
2. 运行如下命令,安装SCons安装包。
```
python3 -m pip install scons
```
3. 运行如下命令,查看是否安装成功。如果安装成功,查询结果下图所示。
```
scons -v
```
**图 1** SCons安装成功界面,版本要求3.0.4以上<a name="fig235815252492"></a>
![](figure/SCons安装成功界面-版本要求3-0-4以上-21.png "SCons安装成功界面-版本要求3-0-4以上-21")
>![](../public_sys-resources/icon-note.gif) **说明:**
>Hi3861平台需要安装SCons,Hi3518和Hi3516两种平台不需要。
# 组件开发示例<a name="ZH-CN_TOPIC_0000001157479397"></a>
- **[HPM介绍](bundles-demo-hpmdescription.md)**
- **[环境准备](bundles-demo-environment.md)**
- **[操作实例](bundles-demo-devsample.md)**
# 组件开发<a name="ZH-CN_TOPIC_0000001051690861"></a>
- [创建OpenHarmony组件](#section1976410130540)
- [新建组件](#section717481119145)
- [改造组件](#section102861955201410)
- [从模板创建组件](#section15882846181510)
- [编译组件](#section136732148541)
- [定义编译脚本](#section10274147111610)
- [执行编译](#section879301916172)
- [定义发行版](#section413216495619)
- [定义脚本](#section11503171219190)
- [发行](#section4694125521912)
- [烧录](#section1746331545413)
- [运行调试](#section6742131615549)
## 创建OpenHarmony组件<a name="section1976410130540"></a>
创建OpenHarmony组件有如下几种方式:
- 从头开发一个全新的组件。
- 将一个现有的非组件的代码改造成组件。
- hpm提供了一些组件模板方便快速创建组件。
## 新建组件<a name="section717481119145"></a>
通常情况下,[HPM网站](https://hpm.harmonyOS.com)上能找到您开发常用的组件,如果现有的组件不能完全满足开发,这时可以自己动手开发一个组件。
如果您愿意,可以将组件发布到HPM的仓库中供其他用户使用。假设要在D:/source目录下新建一个全新的组件my-bundle:
可以使用hpm init 创建该组件的脚手架代码,例如,进入D:/source目录,执行如下命令:
```
hpm init -t default -d demo my-bundle
```
会在 source 目录下生成如下文件:
```
mybundle
├── bundle.json # 组件元数据描述文件
├── example # 测试组件功能的示例
│ └── main.c
├── include # 组件的内部头文件
│ └── mybundle.h
├── README.md # 组件的简要说明
└── src # 组件的源代码
└─ mybundle.c
```
接下来根据您的业务需要,实现组件内部的功能代码,完成代码开发后,通过git将代码(包括bundle.json文件)提交到组件代码托管仓库中(如gitee)。
## 改造组件<a name="section102861955201410"></a>
如果您已经有了代码,只是还不满足OpenHarmony的组件结构,需要改造成为hpm的组件包,只需要在当前要改造的代码目录下(例如mybundle2),执行如下命令,会提示您输入组件名称和版本。
```
hpm init
```
1. 输入名称后回车(如mybundle2)。
2. 输入版本后(如1.0.0)回车,在当前组件目录下会生成一个bundle.json文件。
3. 打开bundle.json文件再添加其他的描述,这时候他已经是一个具备可发布的组件了。
```
$ hpm init
Your bundle will be created in dirname E:\demo\mybundle2
? bundle name mybundel2
? version 1.0.0
Init finished!
```
1. 打开bundle.json文件修改其他信息(如作者,代码仓库,代码目录,命令脚本,依赖组件等),如下:
```
{
"name": "mybundle2",
"version": "1.0.0",
"publishAs": "source",
"dirs":{
".":[
"README.md"
],
"src":[
"test.c"
],
"header":[
"header/test.h"
],
"src/common":[
"src/common/foobar.txt"
]
},
"scripts": {
"build": "make -${args}"
},
"dependencies": {
"@ohos/cjson": "^1.0.0",
"@ohos/": "^1.2.0"
}
}
```
## 从模板创建组件<a name="section15882846181510"></a>
hpm 除了提供了默认模板 default和simple两个简单的模板之外,其他模板均存储在服务器端。
可以使用命令hpm search -t template 从服务器端搜索模板。
![](figure/zh-cn_image_0000001051452177.png)
根据description简要中的描述,找到适合的模板,基于模板可以快速创建一个组件的脚手架,执行如下初始化命令(指定-t -d 参数)。
```
hpm init -t {templatename} -d dir name
```
- \{templatename\} :指的是模板名称。
- -d 后面的参数dir:是要创建的组件所存放的路径。
- name:为要创建的组件名称。
## 编译组件<a name="section136732148541"></a>
完成代码开发后,需要对组件进行编译。hpm提供了命令集成的能力,您可以选择任意的适合项目的编译工具(如make,gcc,gn等等)。只需在当前项目的bundle.json文件中定义scripts脚本中的build命令,就可以通过执行hpm build执行编译。
## 定义编译脚本<a name="section10274147111610"></a>
以编译一个app目录下helloworld可执行文件为例:
```
app
├── BUILD.gn
├── include
│ └── helloworld.h
└── src
└── helloworld.c
```
在helloworld.c同级目录下新建一个BUILD.gn
```
touch BUILD.gn
vim BUILD.gn
```
以下是BUILD.gn的样例,仅供参考
```
executable("hello_world") {
sources = [
"src/helloworld.c"
]
include_dirs = [
"include"
]
}
```
>![](../public_sys-resources/icon-note.gif) **说明:**
>- “executable”是gn内置模板,可以用“gn help executable ”查看使用方法。
>- “sources ”是源码路径,“include\_dirs ”是头文件路径。
## 执行编译<a name="section879301916172"></a>
在当前文件夹下,执行编译命令:
```
hpm build
```
在完成一系列的编译动作后,显示build succeed。检查编译的输出结果:
![](figure/zh-cn_image_0000001051770876.png)
## 定义发行版<a name="section413216495619"></a>
发行版是将一组组件组合起来的,编译生成可以运行的OpenHarmony解决方案,里面包含了较多依赖的组件,以及以脚本形式描述如何完整编译、链接这些组件。
## 定义脚本<a name="section11503171219190"></a>
bundle.json中定义
```
{
"name": "my_dist",
"version": "1.0.0",
"publishAs": "distribution",
"scripts": {
"dist": "make -${args}"
},
"base": {
"name": "dist-bundle",
"version": "1.0.0"
},
"envs": {
"args": "x86"
},
"dependencies": {
}
}
```
## 发行<a name="section4694125521912"></a>
在当前发行版根目录下,执行如下命令。
```
hpm dist
```
hpm-cli工具会自动执行编译,打包操作,将根据scripts定义的dist脚本生成镜像文件,如:
```
out
|-xxdist.img
|-xx.file
```
## 烧录<a name="section1746331545413"></a>
发行版的编译结果可以烧录到设备中运行,例如使用hiburn工具进行烧录。在发行版的bundle.json文件配置烧录参数。
```
"scripts": {
"flash": "{$DEP_HIBURN}/hiburn"
},
```
配置烧录相关的参数(参考烧录工具的说明进行配置)。
```
hpm run flash
```
## 运行调试<a name="section6742131615549"></a>
将发行版的镜像烧录到设备中后,就可以启动运行调试了,由于运行调试和具体的开发板和IDE调试工具相关,此处不再详细描述。
# 概述<a name="ZH-CN_TOPIC_0000001051452100"></a>
本章节将简要介绍如何开发OpenHarmony组件和发行版,并通过命令行工具方式完成组件创建、开发、编译、烧录、调试等开发过程。
- 一个组件(bundle)通常和一个代码仓库对应,在代码的基础上增加bundle.json、README文件、LICENSE描述文件。
- 一个发行版(distribution)是由多个组件构成的。发行版中集合了一个完整系统的各种组件(如驱动、内核、框架、应用),可以用于设备的烧录。
**表 1** 组件和发行版的差异对比
<a name="table6287133615412"></a>
<table><thead align="left"><tr id="row17288183614415"><th class="cellrowborder" valign="top" width="16.24162416241624%" id="mcps1.2.4.1.1"><p id="p528818361545"><a name="p528818361545"></a><a name="p528818361545"></a>异同点</p>
</th>
<th class="cellrowborder" valign="top" width="33.31333133313331%" id="mcps1.2.4.1.2"><p id="p1288836247"><a name="p1288836247"></a><a name="p1288836247"></a>组件</p>
</th>
<th class="cellrowborder" valign="top" width="50.44504450445044%" id="mcps1.2.4.1.3"><p id="p112885362418"><a name="p112885362418"></a><a name="p112885362418"></a>发行版</p>
</th>
</tr>
</thead>
<tbody><tr id="row1728813361848"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p2010613564815"><a name="p2010613564815"></a><a name="p2010613564815"></a>应用场景</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1910555184818"><a name="p1910555184818"></a><a name="p1910555184818"></a>面向功能特性开发</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p13871955484"><a name="p13871955484"></a><a name="p13871955484"></a>面向系统开发</p>
</td>
</tr>
<tr id="row676745614472"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p1028816365414"><a name="p1028816365414"></a><a name="p1028816365414"></a>内容</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p428812361042"><a name="p428812361042"></a><a name="p428812361042"></a>功能或特性的实现代码或二进制库</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p328817366417"><a name="p328817366417"></a><a name="p328817366417"></a>依赖的组件清单及编译构建脚本</p>
</td>
</tr>
<tr id="row95114356"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p184894513517"><a name="p184894513517"></a><a name="p184894513517"></a>完整程度</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1951741155"><a name="p1951741155"></a><a name="p1951741155"></a>操作系统的一部分</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p20521542512"><a name="p20521542512"></a><a name="p20521542512"></a>一个完整操作系统版本</p>
</td>
</tr>
<tr id="row13581419518"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p859171059"><a name="p859171059"></a><a name="p859171059"></a>编译后结果</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p259201355"><a name="p259201355"></a><a name="p259201355"></a>组件包</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p459414519"><a name="p459414519"></a><a name="p459414519"></a>系统镜像</p>
</td>
</tr>
</tbody>
</table>
**图 1** 组件和发行版的构成<a name="fig85033524124"></a>
![](figure/组件0924.png)
# 准备工作<a name="ZH-CN_TOPIC_0000001051770836"></a>
- [硬件要求](#section98535485518)
- [安装Node.js和hpm命令行工具](#section106591616205311)
- [更改hpm的配置(可选)](#section71821165412)
- [下载OpenHarmony代码](#section102338221707)
- [安装开发依赖的组件](#section19233183315020)
## 硬件要求<a name="section98535485518"></a>
- 准备设备开发的开发板(如Hi3861、Hi3516DV300、Hi3518EV300)
- 主机电脑(Windows工作台)
- Linux服务器
**图 1** 硬件环境连接关系<a name="fig113816181847"></a>
![](figure/硬件环境连接关系.png "硬件环境连接关系")
## 安装Node.js和hpm命令行工具<a name="section106591616205311"></a>
1. 安装Node.js。
从官网下载并在本地安装Node.js.
推荐安装 [Node.js](https://nodejs.org/) 12.x \(包含 npm 6.14.4\)或更高版本 \(推荐 12.13.0+\)。
2. 通过Node.js自带的npm安装hpm-cli命令行工具。执行以下命令:
```
npm install -g @ohos/hpm-cli
```
3. 安装完成后执行如下命令,显示hpm版本,即安装成功。
```
hpm -V 或 hpm --version
```
4. (可选)如果需要升级hpm版本,请执行如下命令:
```
npm update -g @ohos/hpm-cli
```
## 更改hpm的配置(可选)<a name="section71821165412"></a>
安装完hpm-cli命令行工具后,执行以下命令可以查看hpm配置:
```
hpm config
```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置:
```
registry = https://hpm.harmonyos.com/hpm/registry/api # hpm注册中心地址,下载组件必须
login = https://hpm.harmonyos.com/hpm/auth/pk # hpm处理登录地址,发布组件必须
loginUser = {your-account} # 配置hpm登录账号,发布组件必须
shellPath = C:\WINDOWS\System32\cmd.exe # hpm命令执行使用的shell
globalRepo = C:\Users\yourname\.global # 配置全局安装的组件存放路径
http_proxy = http://your-proxy-server:port # 配置HTTP代理
https_proxy = http://your-proxy-server:port # 配置HTTPS代理
```
hpm-cli的命令介绍可以参考:[hpm操作命令](bundles-guide-overview.md)
## 下载OpenHarmony代码<a name="section102338221707"></a>
参考[《源码获取》](../get-code/sourcecode-acquire.md)
## 安装开发依赖的组件<a name="section19233183315020"></a>
hpm包管理器将常用开发开发工具(如烧录,编译,压缩等)也发布成了组件。可以通过如下命令方式进行安装,执行完该命令后,系统会自动将开发依赖的工具下载安装,且这些组件只需全局安装一次。
```
hpm i -g @ohos/llvm
hpm i -g @ohos/ninja
hpm i -g @ohos/gn
hpm i -g @ohos/hc_gen
hpm i -g @ohos/sysroot
```
这是一组开发工具的组件包(如包含gn,ninja等工具),有了这些开发态的组件,就可以进行常规的源码组件的开发了。
# 组件开发指南<a name="ZH-CN_TOPIC_0000001157319417"></a>
- **[概述](bundles-guide-overview.md)**
- **[准备工作](bundles-guide-prepare.md)**
- **[组件开发](bundles-guide-develop.md)**
此差异已折叠。
# 组件开发指南<a name="ZH-CN_TOPIC_0000001111039520"></a>
- **[组件开发规范](bundles-standard-rules.md)**
- **[组件开发指南](bundles-guide.md)**
- **[组件开发示例](bundles-demo.md)**
# 准备工作<a name="ZH-CN_TOPIC_0000001051770836"></a>
- [硬件要求](#section98535485518)
- [安装Node.js和hpm命令行工具](#section106591616205311)
- [更改hpm的配置(可选)](#section71821165412)
- [下载OpenHarmony代码](#section102338221707)
- [安装开发依赖的组件](#section19233183315020)
## 硬件要求<a name="section98535485518"></a>
- 准备设备开发的开发板(如Hi3861、Hi3516DV300、Hi3518EV300)
- 主机电脑(Windows工作台)
- Linux服务器
**图 1** 硬件环境连接关系<a name="fig113816181847"></a>
![](figures/硬件环境连接关系.png "硬件环境连接关系")
## 安装Node.js和hpm命令行工具<a name="section106591616205311"></a>
1. 安装Node.js。
从官网下载并在本地安装Node.js.
推荐安装 [Node.js](https://nodejs.org/) 12.x \(包含 npm 6.14.4\)或更高版本 \(推荐 12.13.0+\)。
2. 通过Node.js自带的npm安装hpm-cli命令行工具。执行以下命令:
```
npm install -g @ohos/hpm-cli
```
3. 安装完成后执行如下命令,显示hpm版本,即安装成功。
```
hpm -V 或 hpm --version
```
4. (可选)如果需要升级hpm版本,请执行如下命令:
```
npm update -g @ohos/hpm-cli
```
## 更改hpm的配置(可选)<a name="section71821165412"></a>
安装完hpm-cli命令行工具后,执行以下命令可以查看hpm配置:
```
hpm config
```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置:
```
registry = https://hpm.harmonyos.com/hpm/registry/api # hpm注册中心地址,下载组件必须
login = https://hpm.harmonyos.com/hpm/auth/pk # hpm处理登录地址,发布组件必须
loginUser = {your-account} # 配置hpm登录账号,发布组件必须
shellPath = C:\WINDOWS\System32\cmd.exe # hpm命令执行使用的shell
globalRepo = C:\Users\yourname\.global # 配置全局安装的组件存放路径
http_proxy = http://your-proxy-server:port # 配置HTTP代理
https_proxy = http://your-proxy-server:port # 配置HTTPS代理
```
hpm-cli的命令介绍可以参考:[hpm操作命令](组件管理.md)
## 下载OpenHarmony代码<a name="section102338221707"></a>
参考[《源码获取》](../get-code/源码获取.md)
## 安装开发依赖的组件<a name="section19233183315020"></a>
hpm包管理器将常用开发开发工具(如烧录,编译,压缩等)也发布成了组件。可以通过如下命令方式进行安装,执行完该命令后,系统会自动将开发依赖的工具下载安装,且这些组件只需全局安装一次。
```
hpm i -g @ohos/llvm
hpm i -g @ohos/ninja
hpm i -g @ohos/gn
hpm i -g @ohos/hc_gen
hpm i -g @ohos/sysroot
```
这是一组开发工具的组件包(如包含gn,ninja等工具),有了这些开发态的组件,就可以进行常规的源码组件的开发了。
# 发行版<a name="ZH-CN_TOPIC_0000001051770842"></a>
发行版通常是将一系列组件组合起来,成为编译可以运行的OpenHarmony解决方案镜像,里面包含了多个依赖的组件,以及脚本,用于描述如何完整编译、链接这些组件。
发行版本身通常不需要包含功能实现代码,仅包含bundle.json描述(设置publishAs为distribution)和一些编译脚本组成。
因为发行版编译的过程需要系统提供环境变量,所以发行版使用scripts脚本中内置的dist命令:
```
{
"publishAs":"distribution",
"scripts": {
"dist": "script compile command"
}
}
```
编译执行使用如下命令:
```
hpm dist
```
重新定义一个发行版所具有的功能是一个复杂的过程,所以系统允许对发行版进行继承,从而在现有功能的基础上进行定制。继承发行版需要在bundle.json中定义base字段。
```
{
"base": {
"name": "dist_wifi_iot",
"version": "1.0.0"
}
}
```
上述定义表明当前组件继承自发行版组件dist-wifi-iot 1.0.0。
发行版由很多的依赖组件组成,通过bundle.json中的dependencies段来描述,有些依赖是必须的,有些依赖则是根据可以需求增加或删除的。bundle.json中名称前带有?的依赖表示可选依赖,继承它的发行版,可以移除掉该可选组件,再增加别的组件进行替换。
```
{
"dependencies": {
"?my_bundle": "1.0.0"
}
}
```
上述声明表示my\_bundle依赖可以被移除。如果想要移除my\_bundle,在上层依赖方需要使用excludes关键字来进行定义
```
{
"excludes": [ "my_bundle" ]
}
```
依赖被移除后,就不会参入组件的构建过程。只有标记为可选的依赖才能够被移除,强行移除未被标记的依赖会出现错误提示。
# 操作实例<a name="ZH-CN_TOPIC_0000001072143838"></a>
环境准备好后,接下来本文以Hi3861平台为例,演示如何利用HPM进行组件的安装、编译和打包。
1. 执行以下命令,初始化安装目录(目录名可自行设置):
```
mkdir test3861
cd test3861
hpm init -t dist
```
初始化成功则显示:
```
Initialization finished.
```
2. 安装wifi\_iot发行版。
```
hpm install @ohos/wifi_iot
```
安装成功则显示:
```
Installed.
```
>![](public_sys-resources/icon-note.gif) **说明:**
>Hi3516平台采用下述命令:
>```
>hpm install @ohos/ip_camera_hi3516dv300
>```
>Hi3518平台采用下述命令:
>```
>hpm install @ohos/ip_camera_hi3518ev300
>```
3. 编译打包
```
hpm dist
```
编译成功会显示:
```
{{name}}: distribution building completed.
```
4. 上述所有命令执行成功后,在 ./out 目录下会生成编译结果,开发者可以将编译结果烧录到对应的开发板上进行测试。
# 概述<a name="ZH-CN_TOPIC_0000001051452100"></a>
本章节将简要介绍如何开发OpenHarmony组件和发行版,并通过命令行工具方式完成组件创建、开发、编译、烧录、调试等开发过程。
- 一个组件(bundle)通常和一个代码仓库对应,在代码的基础上增加bundle.json、README文件、LICENSE描述文件。
- 一个发行版(distribution)是由多个组件构成的。发行版中集合了一个完整系统的各种组件(如驱动、内核、框架、应用),可以用于设备的烧录。
**表 1** 组件和发行版的差异对比
<a name="table6287133615412"></a>
<table><thead align="left"><tr id="row17288183614415"><th class="cellrowborder" valign="top" width="16.24162416241624%" id="mcps1.2.4.1.1"><p id="p528818361545"><a name="p528818361545"></a><a name="p528818361545"></a>异同点</p>
</th>
<th class="cellrowborder" valign="top" width="33.31333133313331%" id="mcps1.2.4.1.2"><p id="p1288836247"><a name="p1288836247"></a><a name="p1288836247"></a>组件</p>
</th>
<th class="cellrowborder" valign="top" width="50.44504450445044%" id="mcps1.2.4.1.3"><p id="p112885362418"><a name="p112885362418"></a><a name="p112885362418"></a>发行版</p>
</th>
</tr>
</thead>
<tbody><tr id="row1728813361848"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p2010613564815"><a name="p2010613564815"></a><a name="p2010613564815"></a>应用场景</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1910555184818"><a name="p1910555184818"></a><a name="p1910555184818"></a>面向功能特性开发</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p13871955484"><a name="p13871955484"></a><a name="p13871955484"></a>面向系统开发</p>
</td>
</tr>
<tr id="row676745614472"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p1028816365414"><a name="p1028816365414"></a><a name="p1028816365414"></a>内容</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p428812361042"><a name="p428812361042"></a><a name="p428812361042"></a>功能或特性的实现代码或二进制库</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p328817366417"><a name="p328817366417"></a><a name="p328817366417"></a>依赖的组件清单及编译构建脚本</p>
</td>
</tr>
<tr id="row95114356"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p184894513517"><a name="p184894513517"></a><a name="p184894513517"></a>完整程度</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p1951741155"><a name="p1951741155"></a><a name="p1951741155"></a>操作系统的一部分</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p20521542512"><a name="p20521542512"></a><a name="p20521542512"></a>一个完整操作系统版本</p>
</td>
</tr>
<tr id="row13581419518"><td class="cellrowborder" valign="top" width="16.24162416241624%" headers="mcps1.2.4.1.1 "><p id="p859171059"><a name="p859171059"></a><a name="p859171059"></a>编译后结果</p>
</td>
<td class="cellrowborder" valign="top" width="33.31333133313331%" headers="mcps1.2.4.1.2 "><p id="p259201355"><a name="p259201355"></a><a name="p259201355"></a>组件包</p>
</td>
<td class="cellrowborder" valign="top" width="50.44504450445044%" headers="mcps1.2.4.1.3 "><p id="p459414519"><a name="p459414519"></a><a name="p459414519"></a>系统镜像</p>
</td>
</tr>
</tbody>
</table>
**图 1** 组件和发行版的构成<a name="fig85033524124"></a>
![](figures/组件0924.png)
# 概述<a name="ZH-CN_TOPIC_0000001051452141"></a>
- [定义](#section177563344911)
- [组件划分原则](#section2487162541016)
- [组件依赖](#section185955409107)
本文档将介绍组件的基本概念以及如何按照规范定义组件。
## 定义<a name="section177563344911"></a>
OpenHarmony软件以组件\(bundle\)作为基本单元,从系统角度看,凡是运行在OpenHarmony上的软件都可以定义为组件;一般来讲,根据组件的应用范围,可以分为:
- 板级组件:如board、arch、mcu这些与设备硬件相关的组件。
- 系统组件:一组独立功能的集合,如内核、文件系统、框架等。
- 应用组件:直接面向用户提供服务的应用\(如wifi\_iot,ip\_camera\)
从形式上看,组件是为复用而生,一切可以复用的模块都可以定义为组件,可以分为:
- 源代码
- 二进制
- 代码片段
- 发行版
## 组件划分原则<a name="section2487162541016"></a>
原则上应尽可能划分为细颗粒度的组件,以满足最大限度的复用。主要考虑以下几点:
- 独立性:组件的功能应该相对独立,支持独立编译,可以单独对外提供接口和服务;
- 耦合性:如果组件必须依赖其他的组件,才能对外提供服务,应考虑和被依赖的组件合并为一个组件。
- 相关性:如果一组组件共同完成一项功能,且没有被其他组件依赖,未来也没有被依赖的可能,则可以考虑合并为一个组件。
## 组件依赖<a name="section185955409107"></a>
组件的依赖关系分为两种:必选依赖和可选依赖。
- 必选依赖:是指组件A在完成某个功能时,必须引入组件B,调用B的接口或服务配合才能完成。称B为A的必选依赖。
- 可选依赖:是在组件A在完成某个功能时,可以引入组件C,也可以引入组件D。C和D可以相互替换,称C和D为A的可选依赖。
# 环境准备<a name="ZH-CN_TOPIC_0000001071315859"></a>
- [linux服务器](#section20979554791)
- [安装Node.js](#section9954105413153)
- [安装HPM](#section15937194904819)
- [安装python环境](#section1621819180417)
- [安装文件打包工具](#section77617165913)
- [安装SCons](#section20558439191516)
## linux服务器<a name="section20979554791"></a>
准备一台装有Ubuntu 16.04 及以上 64 位系统的linux服务器(hpm是支持windows的,但是目前OpenHarmony开源的Hi3861、Hi3516、Hi3518三个解决方案都只支持Ubuntu)。
将linux shell改为bash:
```
ls -l $(which sh)
# 如果指向的不是bash,则按以下方式修改:
# 方法一:执行以下命令,然后选择no
dpkg-reconfigure dash
# 方法二:先删除sh,再重新创建软连接
rm -f /bin/sh
ln -s bash /bin/sh
```
## 安装Node.js<a name="section9954105413153"></a>
>![](public_sys-resources/icon-note.gif) **说明:**
>如果配置的源的nodejs版本太低,可以执行以下语句后再执行apt-get install:
>```
>curl -L https://deb.nodesource.com/setup_12.x | bash
>```
推荐安装 Node.js 12.x (包含 npm 6.14.4)或更高版本(推荐 12.13.0+):
```
sudo apt-get install nodejs
sudo apt-get install npm
```
查看版本:
```
node --version # 查看nodejs版本
npm --version # 查看npm版本
```
## 安装HPM<a name="section15937194904819"></a>
通过 Node.js 自带的 npm(使用默认的源 https://registry.npmjs.org/ )安装 hpm-cli 命令行工具:
```
npm install -g @ohos/hpm-cli
```
安装完hpm-cli命令行工具后,执行以下命令可以查看hpm配置:
```
hpm config
```
上述命令执行后将会显示hpm的默认配置,您可以根据自己的喜好对默认配置进行修改,以下是hpm的常用配置:
```
registry = https://hpm.harmonyos.com # hpm注册中心地址,下载组件必须
strictSsl = true # 通过https连接时,是否需要校验证书
http_proxy = http://your-proxy-server:port # 配置HTTP代理
https_proxy = http://your-proxy-server:port # 配置HTTPS代理
```
hpm-cli的命令介绍可以参考:[hpm操作命令](组件管理.md)
## 安装python环境<a name="section1621819180417"></a>
需使用python3.7以上版本,采用以下命令进行安装:
```
sudo apt-get install python3.8
sudo apt-get install python3-pip
sudo pip3 install setuptools
sudo pip3 install kconfiglib # 建议安装kconfiglib 13.2.0+版本
```
>![](public_sys-resources/icon-note.gif) **说明:**
>上述方式适用Hi3518和Hi3516两种平台,针对Hi3861平台采用以下方式安装python环境:
>```
>sudo apt-get install python3.8
>sudo apt-get install python3-pip
>sudo pip3 install setuptools
>sudo pip3 install kconfiglib # 建议安装kconfiglib 13.2.0+版本
>sudo pip3 install pycryptodome
>sudo pip3 install six --upgrade --ignore-installed six
>sudo pip3 install ecdsa
>```
如果当前系统中既存在python2又存在python3,参考以下方法将默认python修改为python3:
```
ll `which python`
rm /usr/bin/python
ln -s python3.8 /usr/bin/python
```
## 安装文件打包工具<a name="section77617165913"></a>
采用以下命令进行安装:
```
which mkfs.vfat # 如果没找到,执行以下命令安装
sudo apt-get install dosfstools
which mcopy # 如果没找到,执行以下命令安装
sudo apt-get install mtools
```
>![](public_sys-resources/icon-note.gif) **说明:**
>Hi3518和Hi3516两种平台需要安装打包工具,Hi3861平台不需要。
## 安装SCons<a name="section20558439191516"></a>
1. 打开Linux编译服务器终端。
2. 运行如下命令,安装SCons安装包。
```
python3 -m pip install scons
```
3. 运行如下命令,查看是否安装成功。如果安装成功,查询结果下图所示。
```
scons -v
```
**图 1** SCons安装成功界面,版本要求3.0.4以上<a name="fig235815252492"></a>
![](figures/SCons安装成功界面-版本要求3-0-4以上.png "SCons安装成功界面-版本要求3-0-4以上")
>![](public_sys-resources/icon-note.gif) **说明:**
>Hi3861平台需要安装SCons,Hi3518和Hi3516两种平台不需要。
# 环境变量说明<a name="ZH-CN_TOPIC_0000001054807267"></a>
组件在编译的过程中需要依赖系统提供的环境变量来自定义输出,链接所需二进制文件等等。这里提出的环境变量均指根据需求把所需变量注入脚本执行的上下文中。所以在脚本中可以直接获取到变量的值。下面介绍当前系统存在的几种环境变量。全局变量
全局变量由bundle.json中的envs属性来定义。整个组件中的依赖都可以获取到全局变量定义的值。
```
{
"envs": {
"compileEnv": "arm"
}
}
```
不同组件在引入依赖的过程中可以传入不同的参数,从而使依赖的编译可以满足当前组件的需求。依赖中定义的参数可以在对应依赖脚本执行的上下文中获取到。
```
{
"dependencies": {
"my-bundle": {
"version": "1.0.0",
"mode": "debug"
}
}
}
```
组件在链接二进制文件的时候,需要知道二进制文件在依赖中的路径,所以依赖的路径会作为环境变量传入编译组件中。
传入的环境变量的格式为DEP\_BundleName,BundleName为依赖的名称,例如 DEP\_first\_bundle。
依赖中可以定义标签,对引入的依赖进行分组。在脚本中可以根据标签,获得这一组依赖的路径。定义的标签以\#开头,具体定义的方式为:
```
{
"dependencies": {
"#tool": {
"first-bundle": "1.0.0",
"second-bundle": "1.0.0"
},
"#drivers": {
"xx-bundle": "1.0.0",
"yy-bundle": "1.0.0"
}
}
}
```
系统中存在两个固定环境变量:
- DEP\_OHOS\_BUNDLES:表示ohos\_bundles文件夹所在的路径。
- DEP\_BUNDLE\_BASE:表示最外层组件的路径。
# 组件开发<a name="ZH-CN_TOPIC_0000001051690861"></a>
- [创建OpenHarmony组件](#section1976410130540)
- [新建组件](#section717481119145)
- [改造组件](#section102861955201410)
- [从模板创建组件](#section15882846181510)
- [编译组件](#section136732148541)
- [定义编译脚本](#section10274147111610)
- [执行编译](#section879301916172)
- [定义发行版](#section413216495619)
- [定义脚本](#section11503171219190)
- [发行](#section4694125521912)
- [烧录](#section1746331545413)
- [运行调试](#section6742131615549)
## 创建OpenHarmony组件<a name="section1976410130540"></a>
创建OpenHarmony组件有如下几种方式:
- 从头开发一个全新的组件。
- 将一个现有的非组件的代码改造成组件。
- hpm提供了一些组件模板方便快速创建组件。
## 新建组件<a name="section717481119145"></a>
通常情况下,[HPM网站](https://hpm.harmonyOS.com)上能找到您开发常用的组件,如果现有的组件不能完全满足开发,这时可以自己动手开发一个组件。
如果您愿意,可以将组件发布到HPM的仓库中供其他用户使用。假设要在D:/source目录下新建一个全新的组件my-bundle:
可以使用hpm init 创建该组件的脚手架代码,例如,进入D:/source目录,执行如下命令:
```
hpm init -t default -d demo my-bundle
```
会在 source 目录下生成如下文件:
```
mybundle
├── bundle.json # 组件元数据描述文件
├── example # 测试组件功能的示例
│ └── main.c
├── include # 组件的内部头文件
│ └── mybundle.h
├── README.md # 组件的简要说明
└── src # 组件的源代码
└─ mybundle.c
```
接下来根据您的业务需要,实现组件内部的功能代码,完成代码开发后,通过git将代码(包括bundle.json文件)提交到组件代码托管仓库中(如gitee)。
## 改造组件<a name="section102861955201410"></a>
如果您已经有了代码,只是还不满足OpenHarmony的组件结构,需要改造成为hpm的组件包,只需要在当前要改造的代码目录下(例如mybundle2),执行如下命令,会提示您输入组件名称和版本。
```
hpm init
```
1. 输入名称后回车(如mybundle2)。
2. 输入版本后(如1.0.0)回车,在当前组件目录下会生成一个bundle.json文件。
3. 打开bundle.json文件再添加其他的描述,这时候他已经是一个具备可发布的组件了。
```
$ hpm init
Your bundle will be created in dirname E:\demo\mybundle2
? bundle name mybundel2
? version 1.0.0
Init finished!
```
1. 打开bundle.json文件修改其他信息(如作者,代码仓库,代码目录,命令脚本,依赖组件等),如下:
```
{
"name": "mybundle2",
"version": "1.0.0",
"publishAs": "source",
"dirs":{
".":[
"README.md"
],
"src":[
"test.c"
],
"header":[
"header/test.h"
],
"src/common":[
"src/common/foobar.txt"
]
},
"scripts": {
"build": "make -${args}"
},
"dependencies": {
"@ohos/cjson": "^1.0.0",
"@ohos/": "^1.2.0"
}
}
```
## 从模板创建组件<a name="section15882846181510"></a>
hpm 除了提供了默认模板 default和simple两个简单的模板之外,其他模板均存储在服务器端。
可以使用命令hpm search -t template 从服务器端搜索模板。
![](figures/zh-cn_image_0000001051452177.png)
根据description简要中的描述,找到适合的模板,基于模板可以快速创建一个组件的脚手架,执行如下初始化命令(指定-t -d 参数)。
```
hpm init -t {templatename} -d dir name
```
- \{templatename\} :指的是模板名称。
- -d 后面的参数dir:是要创建的组件所存放的路径。
- name:为要创建的组件名称。
## 编译组件<a name="section136732148541"></a>
完成代码开发后,需要对组件进行编译。hpm提供了命令集成的能力,您可以选择任意的适合项目的编译工具(如make,gcc,gn等等)。只需在当前项目的bundle.json文件中定义scripts脚本中的build命令,就可以通过执行hpm build执行编译。
## 定义编译脚本<a name="section10274147111610"></a>
以编译一个app目录下helloworld可执行文件为例:
```
app
├── BUILD.gn
├── include
│ └── helloworld.h
└── src
└── helloworld.c
```
在helloworld.c同级目录下新建一个BUILD.gn
```
touch BUILD.gn
vim BUILD.gn
```
以下是BUILD.gn的样例,仅供参考
```
executable("hello_world") {
sources = [
"src/helloworld.c"
]
include_dirs = [
"include"
]
}
```
>![](public_sys-resources/icon-note.gif) **说明:**
>- “executable”是gn内置模板,可以用“gn help executable ”查看使用方法。
>- “sources ”是源码路径,“include\_dirs ”是头文件路径。
## 执行编译<a name="section879301916172"></a>
在当前文件夹下,执行编译命令:
```
hpm build
```
在完成一系列的编译动作后,显示build succeed。检查编译的输出结果:
![](figures/zh-cn_image_0000001051770876.png)
## 定义发行版<a name="section413216495619"></a>
发行版是将一组组件组合起来的,编译生成可以运行的OpenHarmony解决方案,里面包含了较多依赖的组件,以及以脚本形式描述如何完整编译、链接这些组件。
## 定义脚本<a name="section11503171219190"></a>
bundle.json中定义
```
{
"name": "my_dist",
"version": "1.0.0",
"publishAs": "distribution",
"scripts": {
"dist": "make -${args}"
},
"base": {
"name": "dist-bundle",
"version": "1.0.0"
},
"envs": {
"args": "x86"
},
"dependencies": {
}
}
```
## 发行<a name="section4694125521912"></a>
在当前发行版根目录下,执行如下命令。
```
hpm dist
```
hpm-cli工具会自动执行编译,打包操作,将根据scripts定义的dist脚本生成镜像文件,如:
```
out
|-xxdist.img
|-xx.file
```
## 烧录<a name="section1746331545413"></a>
发行版的编译结果可以烧录到设备中运行,例如使用hiburn工具进行烧录。在发行版的bundle.json文件配置烧录参数。
```
"scripts": {
"flash": "{$DEP_HIBURN}/hiburn"
},
```
配置烧录相关的参数(参考烧录工具的说明进行配置)。
```
hpm run flash
```
## 运行调试<a name="section6742131615549"></a>
将发行版的镜像烧录到设备中后,就可以启动运行调试了,由于运行调试和具体的开发板和IDE调试工具相关,此处不再详细描述。
# 组件开发指南<a name="ZH-CN_TOPIC_0000001157319417"></a>
- **[概述](概述-0.md)**
- **[准备工作](准备工作.md)**
- **[组件开发](组件开发.md)**
# 组件开发示例<a name="ZH-CN_TOPIC_0000001157479397"></a>
- **[HPM介绍](HPM介绍.md)**
- **[环境准备](环境准备.md)**
- **[操作实例](操作实例.md)**
# 组件开发规范<a name="ZH-CN_TOPIC_0000001111199436"></a>
- **[概述](概述.md)**
- **[组件构成](组件构成.md)**
- **[组件管理](组件管理.md)**
- **[组件版本](组件版本.md)**
- **[发行版](发行版.md)**
- **[环境变量说明](环境变量说明.md)**
# 组件构成<a name="ZH-CN_TOPIC_0000001051930853"></a>
- [代码文件](#section101483489110)
- [说明文件](#section10519101221211)
- [元数据描述文件](#section45511827111211)
一个组件包一般包含如下内容:
- 组件包的代码或库(src目录下的代码文件)
- ohos\_bundles文件夹(存放依赖的组件,安装组件时自动生成,无需提交到代码库)
- 组件包的说明文件\(README.md\)
- 组件包元数据声明文件\(bundle.json\)
- 开源许可文件\(LICENSE\)
```
my-bundle
|_ohos_bundles
|_src
|_bundle.json
|_README.md
|_LICENSE
```
## 代码文件<a name="section101483489110"></a>
组件的代码文件和普通的代码目录没有差异。但要注意的是,组件中对外暴露的接口(头文件),会被其他组件所引用,需要单独在bundle.json的dirs中声明。
## 说明文件<a name="section10519101221211"></a>
README.md,为markdown格式的描述关于组件自述说明文件。([语法参考](https://www.markdownguide.org/getting-started/)\)
为了帮助他人在hpm上找到该组件,并更方便的使用它,在组件的根目录中包含一个README文件。
README文件可能包括如何安装,配置和使用组件包中的实例代码说明,以及可能会对用户有所帮助的任何其他信息。
每个组件的自述文件将显示在hpm系统的组件详情页面的描述中。
## 元数据描述文件<a name="section45511827111211"></a>
bundle.json文件是对当前组件的元数据描述,每个组件中必须包含一个bundle.json文件。
```
{
"name": "@myorg/demo-bundle",
"version": "1.0.0",
"license": "MIT",
"description": "bundle description",
"keywords": ["hos"],
"tags": ["applications", "drivers"],
"author": {"name":"","email":"","url":""},
"contributors":[{"name":"","email":"","url":""},{"name":"","email":"","url":""}],
"homepage": "http://www.foo.bar.com",
"repository": "https://git@gitee.com:foo/bar.git",
"publishAs": "source",
"dirs": {
"src": ["src/**/*.c"],
"headers": ["headers/**/*.h"],
"bin": ["bin/**/*.o"]
},
"scripts": {
"build": "make"
},
"envs": {},
"ohos": {
"os": "2.0.0",
"board": "hi3516",
"kernel": "liteos-a"
},
"rom": "10240",
"ram": "1024",
"dependencies": {
"@myorg/net":"1.0.0"
}
}
```
bundle.json文件具有如下功能:
- name:定义组件的名称,放到组织下, 以@开头,/分割,如:@myorg/mybundle
- version:定义组件版本号,如1.0.0,需满足semver的标准。
- description:一句话对组件进行简要的描述。
- dependencies:定义组件的依赖组件。
- envs: 定义组件编译时所需要的参数,包括全局参数以及依赖所需的参数。
- scripts:定义在当前组件下能够执行的命令(如编译,构建,测试,烧录等)。
- publishAs:定义组件的发布类型(source:源码,binary:二进制,distribution:发行版,code-segment:代码片段)。
- dirs:定义发布时打包的目录结构(如头文件)。
- ram&rom:统计相关信息:预计占用ROM和RAM信息。
- ohos:描述OpenHarmony系统版本、开发板及内核的匹配关系(多个请用英文逗号的“,”分割)。
- 定义其他扩展信息:作者,主页,代码仓库,许可协议,标签,关键字。
- 对于发行版类型,还有个base,可以定义继承自的发行版。
# 组件版本<a name="ZH-CN_TOPIC_0000001051612092"></a>
- [版本号命名规范](#section16893854141310)
- [版本发布](#section43401320171420)
## 版本号命名规范<a name="section16893854141310"></a>
名称需要为全小写字母,中间可以使用中划线或者下划线分隔。比如 "bundle", "my\_bundle"。
版本号的格式为 "主版本号.次版本号.修订号" 或 "主版本号.次版本号.修订号-先行版本号",比如 "1.0.0", "1.0.0-beta",详细规格可以参考 [https://semver.org](https://semver.org/)
## 版本发布<a name="section43401320171420"></a>
为了使组件能被其他开发者使用,组件需要上传到远端仓库。组件上传使用如下命令:
```
hpm publish
```
命令执行以后,系统会对的整个依赖关系进行检查,下载缺失依赖组件。依赖检查完成后,如果发布类型为binary,系统会对整个组件进行编译,生成二进制文件,然后打包上传。如果使其他上传类型,则直接根据定义的打包规则进行打包,然后上传。
注意:发布组件需要用户账号登录,需要先拥有hpm的系统账号后,并注册组织,申请组织认证通过后,才拥有发布的权限。
# 组件管理<a name="ZH-CN_TOPIC_0000001052170830"></a>
- [依赖关系](#section12657593129)
- [hpm操作命令参考](#section1258849181312)
## 依赖关系<a name="section12657593129"></a>
生成基础bundle.json以后,需要继续添加组件依赖来实现更复杂的功能。此时需要知道所依赖组件的名称和版本号,并且把它们定义在bundle.json里面的dependencies字段中。
```
{
"name": "my-bundle",
"version": "1.0.0",
"dependencies": {
"net": "1.0.0"
}
}
```
上述示例中,my-bundle组件依赖于net 1.0.0组件。在全局安装了 hpm CLI 工具之后,执行如下命令可以从远端仓库获取到依赖:
```
hpm install
```
依赖获取以后,会保存到当前组件根目录下到ohos\_bundles文件夹中。组件以及依赖之间会形成一个依赖关系的树状结构。全局安装了 hpm CLI 工具之后,在组件根目录下执行如下命令:
```
username@server MINGW64 /f/showcase/demo/demo
$ hpm list
+--demo@1.0.0
| +--@huawei/media@1.0.2
| +--@demo/sport_hi3518ev300_liteos_a@1.0.0
| | +--@demo/app@4.0.1
| | | +--@demo/build@4.0.1
| | | +--@demo/arm_harmonyeabi_gcc@4.0.0
| | +--@demo/liteos_a@4.0.0
| | | +--@demo/third_party_fatfs@4.0.0
| | | +--@demo/arm_harmonyeabi_gcc@4.0.0
| | +--@demo/init@4.0.0
| | +--@demo/dist_tools@4.0.0
```
还可以使用图的形式,来查看当前组件的依赖关系,执行如下命令:
```
hpm dependencies
```
在当前目录下会生成deps\_visual文件夹,里面包含两个文件,deps.html 和 deps-data.js。在浏览器中打开 deps.html 文件,就可以看到依赖关系的图形化展示\(如下图\)
根据不同的依赖类型,图形结点呈现出不同的颜色。鼠标悬浮在结点上,可以查看当前结点的状态。
**图 1** 组件包依赖关系图<a name="fig4306113315312"></a>
![](figures/组件包依赖关系图.png "组件包依赖关系图")
## hpm操作命令参考<a name="section1258849181312"></a>
组件的全生命周期管理,可以通过hpm命令工具进行操作,hpm的操作命令如下(详细帮助可以执行 hpm -h学习):
**表 1** hpm操作命令
<a name="table10510164515371"></a>
<table><thead align="left"><tr id="row125101745103718"><th class="cellrowborder" valign="top" width="20.95209520952095%" id="mcps1.2.4.1.1"><p id="p1451014454371"><a name="p1451014454371"></a><a name="p1451014454371"></a>命令类别</p>
</th>
<th class="cellrowborder" valign="top" width="30.623062306230626%" id="mcps1.2.4.1.2"><p id="p17510144553716"><a name="p17510144553716"></a><a name="p17510144553716"></a>命令行</p>
</th>
<th class="cellrowborder" valign="top" width="48.42484248424842%" id="mcps1.2.4.1.3"><p id="p65102452371"><a name="p65102452371"></a><a name="p65102452371"></a>含义说明</p>
</th>
</tr>
</thead>
<tbody><tr id="row25106453375"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p151044514378"><a name="p151044514378"></a><a name="p151044514378"></a>版本查询</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1653795113472"><a name="p1653795113472"></a><a name="p1653795113472"></a>hpm -V 或 hpm --version</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p399295684713"><a name="p399295684713"></a><a name="p399295684713"></a>查看hpm-cli 版本号。</p>
</td>
</tr>
<tr id="row651017455374"><td class="cellrowborder" rowspan="2" align="left" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p551054516372"><a name="p551054516372"></a><a name="p551054516372"></a>帮助查询</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p18648167124812"><a name="p18648167124812"></a><a name="p18648167124812"></a>hpm -h 或 hpm --version</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1464811794817"><a name="p1464811794817"></a><a name="p1464811794817"></a>查看命令列表及帮助。</p>
</td>
</tr>
<tr id="row1751016452379"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p16778111111487"><a name="p16778111111487"></a><a name="p16778111111487"></a>hpm -h</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1877811154818"><a name="p1877811154818"></a><a name="p1877811154818"></a>查看命令帮助。</p>
</td>
</tr>
<tr id="row2511945123715"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p3955174864810"><a name="p3955174864810"></a><a name="p3955174864810"></a>创建</p>
<p id="p14511184518374"><a name="p14511184518374"></a><a name="p14511184518374"></a></p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p2046811558481"><a name="p2046811558481"></a><a name="p2046811558481"></a>hpm init bundle</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1646818557481"><a name="p1646818557481"></a><a name="p1646818557481"></a>创建组件工程。</p>
</td>
</tr>
<tr id="row351184593713"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18991313496"><a name="p18991313496"></a><a name="p18991313496"></a>hpm init -t template</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p109912104911"><a name="p109912104911"></a><a name="p109912104911"></a>根据模板创建脚手架工程。</p>
</td>
</tr>
<tr id="row1751164511374"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1351111454374"><a name="p1351111454374"></a><a name="p1351111454374"></a>安装</p>
<p id="p251144513715"><a name="p251144513715"></a><a name="p251144513715"></a></p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p8896182914913"><a name="p8896182914913"></a><a name="p8896182914913"></a>hpm install 或hpm i</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1289692919493"><a name="p1289692919493"></a><a name="p1289692919493"></a>安装bundle.json中依赖的组件。</p>
</td>
</tr>
<tr id="row15511194563712"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17917436134911"><a name="p17917436134911"></a><a name="p17917436134911"></a>hpm install bundle@version</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1891723611494"><a name="p1891723611494"></a><a name="p1891723611494"></a>安装指定组件版本。</p>
</td>
</tr>
<tr id="row21051110155011"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1630384435010"><a name="p1630384435010"></a><a name="p1630384435010"></a>卸载</p>
<p id="p83417161509"><a name="p83417161509"></a><a name="p83417161509"></a></p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p288195017502"><a name="p288195017502"></a><a name="p288195017502"></a>hpm uninstall bundle</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p2088450165014"><a name="p2088450165014"></a><a name="p2088450165014"></a>删除depedencies依赖的组件。</p>
</td>
</tr>
<tr id="row73341617507"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p934161613508"><a name="p934161613508"></a><a name="p934161613508"></a>hpm remove 或hpm rm bundlename</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p234111685016"><a name="p234111685016"></a><a name="p234111685016"></a>删除depedencies依赖的组件。</p>
</td>
</tr>
<tr id="row166449214501"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p8645421125016"><a name="p8645421125016"></a><a name="p8645421125016"></a>查看</p>
<p id="p12645202115014"><a name="p12645202115014"></a><a name="p12645202115014"></a></p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p679412535211"><a name="p679412535211"></a><a name="p679412535211"></a>hpm list 或者 hpm ls</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p07941451526"><a name="p07941451526"></a><a name="p07941451526"></a>显示当前组件/发行版所有的组件树。</p>
</td>
</tr>
<tr id="row1764552105017"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p035818131525"><a name="p035818131525"></a><a name="p035818131525"></a>hpm dependencies</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p19358413135217"><a name="p19358413135217"></a><a name="p19358413135217"></a>生成当前组件/发行版依赖关系图(html格式)。</p>
</td>
</tr>
<tr id="row1553428145020"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p353202845014"><a name="p353202845014"></a><a name="p353202845014"></a>搜索</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1423903005211"><a name="p1423903005211"></a><a name="p1423903005211"></a>hpm search name</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p17239163018524"><a name="p17239163018524"></a><a name="p17239163018524"></a>搜索组件,--json,可以以json格式输出 -type 可以设置搜索组件的类型,包括bundle,distribution,code-segment三种。</p>
</td>
</tr>
<tr id="row135482855018"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p38201311174016"><a name="p38201311174016"></a><a name="p38201311174016"></a>设置hpm配置项</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p279915013522"><a name="p279915013522"></a><a name="p279915013522"></a>hpm config set key value</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p157991450205211"><a name="p157991450205211"></a><a name="p157991450205211"></a>设置配置值,如服务器地址,网络代理。</p>
</td>
</tr>
<tr id="row454172810509"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p111125615215"><a name="p111125615215"></a><a name="p111125615215"></a>hpm config delete key</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p171156105215"><a name="p171156105215"></a><a name="p171156105215"></a>删除配置。</p>
</td>
</tr>
<tr id="row3925233115011"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1250314020555"><a name="p1250314020555"></a><a name="p1250314020555"></a>更新</p>
<p id="p59251633105018"><a name="p59251633105018"></a><a name="p59251633105018"></a></p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1127981305516"><a name="p1127981305516"></a><a name="p1127981305516"></a>hpm update</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p427971311555"><a name="p427971311555"></a><a name="p427971311555"></a>更新当前组件依赖的组件的版本。</p>
</td>
</tr>
<tr id="row692503385015"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p627961317557"><a name="p627961317557"></a><a name="p627961317557"></a>hpm check-update</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p3279121315557"><a name="p3279121315557"></a><a name="p3279121315557"></a>检查依赖的组件版本是否有更新。</p>
</td>
</tr>
<tr id="row1925173385019"><td class="cellrowborder" rowspan="2" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p2925133305014"><a name="p2925133305014"></a><a name="p2925133305014"></a>编译</p>
<p id="p692515335501"><a name="p692515335501"></a><a name="p692515335501"></a></p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p2058919655611"><a name="p2058919655611"></a><a name="p2058919655611"></a>hpm build</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1958920625619"><a name="p1958920625619"></a><a name="p1958920625619"></a>编译组件/发行版。</p>
</td>
</tr>
<tr id="row18925233115016"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1958912618563"><a name="p1958912618563"></a><a name="p1958912618563"></a>hpm dist</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p2058936115611"><a name="p2058936115611"></a><a name="p2058936115611"></a>发行版打包(依赖bundle.json的scripts中的dist脚本)。</p>
</td>
</tr>
<tr id="row59261233155013"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p3926123305011"><a name="p3926123305011"></a><a name="p3926123305011"></a>打包</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1785810219574"><a name="p1785810219574"></a><a name="p1785810219574"></a>hpm pack</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p1485872165714"><a name="p1485872165714"></a><a name="p1485872165714"></a>本地组件打包依赖。</p>
</td>
</tr>
<tr id="row1592653305016"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p84251810125716"><a name="p84251810125716"></a><a name="p84251810125716"></a>烧录</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p7973616175716"><a name="p7973616175716"></a><a name="p7973616175716"></a>hpm run flash</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p20973111612575"><a name="p20973111612575"></a><a name="p20973111612575"></a>烧录固件(依赖bundle.json的scripts中的flash脚本)。</p>
</td>
</tr>
<tr id="row992615339504"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1225172310576"><a name="p1225172310576"></a><a name="p1225172310576"></a>发布</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p198081455105712"><a name="p198081455105712"></a><a name="p198081455105712"></a>hpm publish</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p880885516574"><a name="p880885516574"></a><a name="p880885516574"></a>发布组件,发布的组件在仓库中必须唯一,且版本唯一(需要账号登录)。</p>
</td>
</tr>
<tr id="row5926333135014"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p39267336504"><a name="p39267336504"></a><a name="p39267336504"></a>执行扩展命令</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p9933172588"><a name="p9933172588"></a><a name="p9933172588"></a>hpm run</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p18933476584"><a name="p18933476584"></a><a name="p18933476584"></a>执行bundle.json文件中定义的scripts脚本命令,支持多个命令可用 &amp;&amp; 连接。</p>
</td>
</tr>
<tr id="row122864915206"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p1529124912207"><a name="p1529124912207"></a><a name="p1529124912207"></a>生成秘钥</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p9291492204"><a name="p9291492204"></a><a name="p9291492204"></a>hpm gen-keys</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p429249182012"><a name="p429249182012"></a><a name="p429249182012"></a>生成公钥/私钥对,将公钥配置到HPM服务端,可以实现hpm-cli 免密登录,发布组件。</p>
</td>
</tr>
<tr id="row3556450102011"><td class="cellrowborder" valign="top" width="20.95209520952095%" headers="mcps1.2.4.1.1 "><p id="p35561850172015"><a name="p35561850172015"></a><a name="p35561850172015"></a>生成第三方开源说明</p>
</td>
<td class="cellrowborder" valign="top" width="30.623062306230626%" headers="mcps1.2.4.1.2 "><p id="p1155625018209"><a name="p1155625018209"></a><a name="p1155625018209"></a>hpm gen-notice</p>
</td>
<td class="cellrowborder" valign="top" width="48.42484248424842%" headers="mcps1.2.4.1.3 "><p id="p11557175015205"><a name="p11557175015205"></a><a name="p11557175015205"></a>根据每个组件的说明,生成一份合并后的第三方开源说明的合并文件。</p>
</td>
</tr>
</tbody>
</table>
<a name="table1970943844710"></a>
<table><thead align="left"></thead>
<tbody></tbody>
</table>
# GPIO<a name="ZH-CN_TOPIC_0000001111039556"></a>
- **[GPIO概述](GPIO概述.md)**
- **[GPIO使用指导](GPIO使用指导.md)**
- **[GPIO使用实例](GPIO使用实例.md)**
# GPIO使用实例<a name="ZH-CN_TOPIC_0000001052777597"></a>
本实例程序中,我们将测试一个GPIO管脚的中断触发:为管脚设置中断服务函数,触发方式为边沿触发,然后通过交替写高低电平到管脚,产生电平波动,制造触发条件,观察中断服务函数的执行。
首先需要选取一个空闲的GPIO管脚,本例程基于Hi3516DV300某开发板,GPIO管脚选择GPIO10\_3,换算成GPIO号为83。
读者可以根据自己使用的开发板,参考其原理图,选择一个空闲的GPIO管脚即可。
```
#include "gpio_if.h"
#include "hdf_log.h"
#include "osal_irq.h"
#include "osal_time.h"
static uint32_t g_irqCnt;
/* 中断服务函数*/
static int32_t TestCaseGpioIrqHandler(uint16_t gpio, void *data)
{
HDF_LOGE("%s: irq triggered! on gpio:%u, data=%p", __func__, gpio, data);
g_irqCnt++; /* 如果中断服务函数触发执行,则将全局中断计数加1 */
return GpioDisableIrq(gpio);
}
/* 测试用例函数 */
static int32_t TestCaseGpioIrqEdge(void)
{
int32_t ret;
uint16_t valRead;
uint16_t mode;
uint16_t gpio = 83; /* 待测试的GPIO管脚号 */
uint32_t timeout;
/* 将管脚方向设置为输出 */
ret = GpioSetDir(gpio, GPIO_DIR_OUT);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: set dir fail! ret:%d\n", __func__, ret);
return ret;
}
/* 先禁止该管脚中断 */
ret = GpioDisableIrq(gpio);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: disable irq fail! ret:%d\n", __func__, ret);
return ret;
}
/* 为管脚设置中断服务函数,触发模式为上升沿和下降沿共同触发 */
mode = OSAL_IRQF_TRIGGER_RISING | OSAL_IRQF_TRIGGER_FALLING;
HDF_LOGE("%s: mode:%0x\n", __func__, mode);
ret = GpioSetIrq(gpio, mode, TestCaseGpioIrqHandler, NULL);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: set irq fail! ret:%d\n", __func__, ret);
return ret;
}
/* 使能此管脚中断 */
ret = GpioEnableIrq(gpio);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: enable irq fail! ret:%d\n", __func__, ret);
(void)GpioUnSetIrq(gpio);
return ret;
}
g_irqCnt = 0; /* 清除全局计数器 */
timeout = 0; /* 等待时间清零 */
/* 等待此管脚中断服务函数触发,等待超时时间为1000毫秒 */
while (g_irqCnt <= 0 && timeout < 1000) {
(void)GpioRead(gpio, &valRead);
(void)GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW);
HDF_LOGE("%s: wait irq timeout:%u\n", __func__, timeout);
OsalMDelay(200); /* wait for irq trigger */
timeout += 200;
}
(void)GpioUnSetIrq(gpio);
return (g_irqCnt > 0) ? HDF_SUCCESS : HDF_FAILURE;
}
```
此差异已折叠。
# GPIO概述<a name="ZH-CN_TOPIC_0000001051777586"></a>
- [简介](#section15318165672215)
- [接口说明](#section18977142162418)
## 简介<a name="section15318165672215"></a>
GPIO(General-purpose input/output)即通用型输入输出。通常,GPIO控制器通过分组的方式管理所有GPIO管脚,每组GPIO有一个或多个寄存器与之关联,通过读写寄存器完成对GPIO管脚的操作。
GPIO接口定义了操作GPIO管脚的标准方法集合,包括:
- 设置管脚方向: 方向可以是输入或者输出\(暂不支持高阻态\)
- 读写管脚电平值: 电平值可以是低电平或高电平
- 设置管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式
- 使能和禁止管脚中断:禁止或使能管脚中断
## 接口说明<a name="section18977142162418"></a>
**表 1** GPIO驱动API接口功能介绍
<a name="table1731550155318"></a>
<table><thead align="left"><tr id="row4419501537"><th class="cellrowborder" valign="top" width="19.74%" id="mcps1.2.4.1.1"><p id="p641050105320"><a name="p641050105320"></a><a name="p641050105320"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="32.36%" id="mcps1.2.4.1.2"><p id="p54150165315"><a name="p54150165315"></a><a name="p54150165315"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="47.9%" id="mcps1.2.4.1.3"><p id="p941150145313"><a name="p941150145313"></a><a name="p941150145313"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row34145016535"><td class="cellrowborder" rowspan="2" valign="top" width="19.74%" headers="mcps1.2.4.1.1 "><p id="p229610227124"><a name="p229610227124"></a><a name="p229610227124"></a>GPIO读写</p>
</td>
<td class="cellrowborder" valign="top" width="32.36%" headers="mcps1.2.4.1.2 "><p id="p19389143041518"><a name="p19389143041518"></a><a name="p19389143041518"></a>GpioRead</p>
</td>
<td class="cellrowborder" valign="top" width="47.9%" headers="mcps1.2.4.1.3 "><p id="p8738101941716"><a name="p8738101941716"></a><a name="p8738101941716"></a>读管脚电平值</p>
</td>
</tr>
<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>GpioWrite</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p67306152404"><a name="p67306152404"></a><a name="p67306152404"></a>写管脚电平值</p>
</td>
</tr>
<tr id="row17493124814141"><td class="cellrowborder" rowspan="2" valign="top" width="19.74%" headers="mcps1.2.4.1.1 "><p id="p321814526178"><a name="p321814526178"></a><a name="p321814526178"></a>GPIO配置</p>
</td>
<td class="cellrowborder" valign="top" width="32.36%" headers="mcps1.2.4.1.2 "><p id="p16390153015156"><a name="p16390153015156"></a><a name="p16390153015156"></a>GpioSetDir</p>
</td>
<td class="cellrowborder" valign="top" width="47.9%" headers="mcps1.2.4.1.3 "><p id="p1873761519408"><a name="p1873761519408"></a><a name="p1873761519408"></a>设置管脚方向</p>
</td>
</tr>
<tr id="row10681146181417"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p15390153014151"><a name="p15390153014151"></a><a name="p15390153014151"></a>GpioGetDir</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p974061515406"><a name="p974061515406"></a><a name="p974061515406"></a>获取管脚方向</p>
</td>
</tr>
<tr id="row10288191441518"><td class="cellrowborder" rowspan="4" valign="top" width="19.74%" headers="mcps1.2.4.1.1 "><p id="p13927416134716"><a name="p13927416134716"></a><a name="p13927416134716"></a>GPIO中断设置</p>
</td>
<td class="cellrowborder" valign="top" width="32.36%" headers="mcps1.2.4.1.2 "><p id="p17390113013158"><a name="p17390113013158"></a><a name="p17390113013158"></a>GpioSetIrq</p>
</td>
<td class="cellrowborder" valign="top" width="47.9%" headers="mcps1.2.4.1.3 "><p id="p10314104354416"><a name="p10314104354416"></a><a name="p10314104354416"></a>设置管脚对应的中断服务函数</p>
</td>
</tr>
<tr id="row163795912473"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p523618345323"><a name="p523618345323"></a><a name="p523618345323"></a>GpioUnSetIrq</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1138195912478"><a name="p1138195912478"></a><a name="p1138195912478"></a>取消管脚对应的中断服务函数</p>
</td>
</tr>
<tr id="row155161515124816"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p657344273218"><a name="p657344273218"></a><a name="p657344273218"></a>GpioEnableIrq</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p115163154488"><a name="p115163154488"></a><a name="p115163154488"></a>使能管脚中断</p>
</td>
</tr>
<tr id="row1742119174820"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1865114616324"><a name="p1865114616324"></a><a name="p1865114616324"></a>GpioDisableIrq</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p97421219174820"><a name="p97421219174820"></a><a name="p97421219174820"></a>禁止管脚中断</p>
</td>
</tr>
</tbody>
</table>
>![](public_sys-resources/icon-note.gif) **说明:**
>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
# HDF开发实例<a name="ZH-CN_TOPIC_0000001052451677"></a>
- [添加配置](#section27261067111)
- [编写驱动代码](#section177988005)
- [编写用户程序和驱动交互代码](#section6205173816412)
下面基于HDF框架,提供一个完整的样例,包含配置文件的添加,驱动代码的实现以及用户态程序和驱动交互的流程。
## 添加配置<a name="section27261067111"></a>
在HDF框架的配置文件(例如vendor/hisilicon/xxx/config/device\_info)中添加该驱动的配置信息,如下所示:
```
root {
device_info {
match_attr = "hdf_manager";
template host {
hostName = "";
priority = 100;
template device {
template deviceNode {
policy = 0;
priority = 100;
preload = 0;
permission = 0664;
moduleName = "";
serviceName = "";
deviceMatchAttr = "";
}
}
}
sample_host :: host {
hostName = "sample_host";
sample_device :: device {
device0 :: deviceNode {
policy = 2;
priority = 100;
preload = 1;
permission = 0664;
moduleName = "sample_driver";
serviceName = "sample_service";
}
}
}
}
}
```
## 编写驱动代码<a name="section177988005"></a>
基于HDF框架编写的sample驱动代码如下:
```
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "hdf_log.h"
#include "hdf_base.h"
#include "hdf_device_desc.h"
#define HDF_LOG_TAG "sample_driver"
#define SAMPLE_WRITE_READ 123
int32_t HdfSampleDriverDispatch(
struct HdfDeviceObject *deviceObject, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
HDF_LOGE("%s: received cmd %d", __func__, id);
if (id == SAMPLE_WRITE_READ) {
const char *readData = HdfSbufReadString(data);
if (readData != NULL) {
HDF_LOGE("%s: read data is: %s", __func__, readData);
}
if (!HdfSbufWriteInt32(reply, INT32_MAX)) {
HDF_LOGE("%s: reply int32 fail", __func__);
}
return HdfDeviceSendEvent(deviceObject, id, data);
}
return HDF_FAILURE;
}
void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
{
// release resources here
return;
}
int HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL) {
return HDF_FAILURE;
}
static struct IDeviceIoService testService = {
.Dispatch = HdfSampleDriverDispatch,
};
deviceObject->service = &testService;
return HDF_SUCCESS;
}
int HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
{
if (deviceObject == NULL) {
HDF_LOGE("%s::ptr is null!", __func__);
return HDF_FAILURE;
}
HDF_LOGE("Sample driver Init success");
return HDF_SUCCESS;
}
struct HdfDriverEntry g_sampleDriverEntry = {
.moduleVersion = 1,
.moduleName = "sample_driver",
.Bind = HdfSampleDriverBind,
.Init = HdfSampleDriverInit,
.Release = HdfSampleDriverRelease,
};
HDF_INIT(g_sampleDriverEntry);
```
## 编写用户程序和驱动交互代码<a name="section6205173816412"></a>
基于HDF框架编写的用户态程序和驱动交互的代码如下:
```
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"
#define HDF_LOG_TAG "sample_test"
#define SAMPLE_SERVICE_NAME "sample_service"
#define SAMPLE_WRITE_READ 123
int g_replyFlag = 0;
static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data)
{
const char *string = HdfSbufReadString(data);
if (string == NULL) {
HDF_LOGE("fail to read string in event data");
g_replyFlag = 1;
return HDF_FAILURE;
}
HDF_LOGE("%s: dev event received: %u %s", (char *)priv, id, string);
g_replyFlag = 1;
return HDF_SUCCESS;
}
static int SendEvent(struct HdfIoService *serv, char *eventData)
{
int ret = 0;
struct HdfSBuf *data = HdfSBufObtainDefaultSize();
if (data == NULL) {
HDF_LOGE("fail to obtain sbuf data");
return 1;
}
struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
if (reply == NULL) {
HDF_LOGE("fail to obtain sbuf reply");
ret = HDF_DEV_ERR_NO_MEMORY;
goto out;
}
if (!HdfSbufWriteString(data, eventData)) {
HDF_LOGE("fail to write sbuf");
ret = HDF_FAILURE;
goto out;
}
ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
if (ret != HDF_SUCCESS) {
HDF_LOGE("fail to send service call");
goto out;
}
int replyData = 0;
if (!HdfSbufReadInt32(reply, &replyData)) {
HDF_LOGE("fail to get service call reply");
ret = HDF_ERR_INVALID_OBJECT;
goto out;
}
HDF_LOGE("Get reply is: %d", replyData);
out:
HdfSBufRecycle(data);
HdfSBufRecycle(reply);
return ret;
}
int main()
{
char *sendData = "default event info";
struct HdfIoService *serv = HdfIoServiceBind(SAMPLE_SERVICE_NAME);
if (serv == NULL) {
HDF_LOGE("fail to get service %s", SAMPLE_SERVICE_NAME);
return HDF_FAILURE;
}
static struct HdfDevEventlistener listener = {
.callBack = OnDevEventReceived,
.priv ="Service0"
};
if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) {
HDF_LOGE("fail to register event listener");
return HDF_FAILURE;
}
if (SendEvent(serv, sendData)) {
HDF_LOGE("fail to send event");
return HDF_FAILURE;
}
while (g_replyFlag == 0) {
sleep(1);
}
if (HdfDeviceUnregisterEventListener(serv, &listener)) {
HDF_LOGE("fail to unregister listener");
return HDF_FAILURE;
}
HdfIoServiceRecycle(serv);
return HDF_SUCCESS;
}
```
>![](public_sys-resources/icon-note.gif) **说明:**
>用户态应用程序使用了HDF框架中的消息发送接口,因此在编译用户态程序的过程中需要依赖HDF框架对外提供的hdf\_core和osal的动态库,在gn编译文件中添加如下依赖项:
>deps = \[
>"//drivers/adapter/lite/uhdf/manager:hdf\_core",
>"//drivers/adapter/lite/uhdf/posix:hdf\_posix\_osal",
>\]
# HDF驱动框架<a name="ZH-CN_TOPIC_0000001157319419"></a>
- **[HDF开发概述](HDF开发概述.md)**
- **[驱动开发](驱动开发.md)**
- **[驱动服务管理](驱动服务管理.md)**
- **[驱动消息机制管理](驱动消息机制管理.md)**
- **[配置管理](配置管理.md)**
- **[HDF开发实例](HDF开发实例.md)**
# I2C<a name="ZH-CN_TOPIC_0000001111199458"></a>
- **[I2C概述](I2C概述.md)**
- **[I2C使用指导](I2C使用指导.md)**
- **[I2C使用实例](I2C使用实例.md)**
# I2C使用实例<a name="ZH-CN_TOPIC_0000001052218252"></a>
本例程以操作开发板上的I2C设备为例,详细展示I2C接口的完整使用流程。
本例拟对Hi3516DV300某开发板上TouchPad设备进行简单的寄存器读写访问,基本硬件信息如下:
- SOC:hi3516dv300。
- Touch IC:I2C地址为0x38, IC内部寄存器位宽为1字节。
- 原理图信息:TouchPad设备挂接在3号I2C控制器下;IC的复位管脚为3号GPIO。
本例程首先对Touch IC进行复位操作(开发板上电默认会给TouchIC供电,本例程不考虑供电),然后对其内部寄存器进行随机读写,测试I2C通路是否正常。
>![](public_sys-resources/icon-note.gif) **说明:**
>本例程重点在于展示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[4] = {0};
struct I2cMsg msgs[2] = {0};
/* 单双字节寄存器长度适配 */
if (tpDevice->regLen == 1) {
regBuf[index++] = regAddr & 0xFF;
} else {
regBuf[index++] = (regAddr >> 8) & 0xFF;
regBuf[index++] = regAddr & 0xFF;
}
/* 填充I2cMsg消息结构 */
msgs[0].addr = tpDevice->addr;
msgs[0].flags = 0; /* 标记为0,表示写入 */
msgs[0].len = tpDevice->regLen;
msgs[0].buf = regBuf;
msgs[1].addr = tpDevice->addr;
msgs[1].flags = (flag == 1) ? I2C_FLAG_READ : 0; /* 添加读标记位,表示读取 */
msgs[1].len = dataLen;
msgs[1].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[7] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xA, 0xB, 0xC };
unsigned char bufRead[7] = {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的0xDO寄存器连续读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[i]);
}
/* 访问完毕关闭I2C控制器 */
I2cClose(tpDevice.i2cHandle);
return ret;
}
```
# I2C使用指导<a name="ZH-CN_TOPIC_0000001053058269"></a>
- [使用流程](#section333203315215)
- [打开I2C控制器](#section123631358135713)
- [进行I2C通信](#section11091522125812)
- [关闭I2C控制器](#section13519505589)
## 使用流程<a name="section333203315215"></a>
使用I2C设备的一般流程如[图1](#fig166181128151112)所示。
**图 1** I2C设备使用流程图<a name="fig166181128151112"></a>
![](figures/zh-cn_image_0000001057902344.png)
## 打开I2C控制器<a name="section123631358135713"></a>
在进行I2C通信前,首先要调用I2cOpen打开I2C控制器。
DevHandle I2cOpen\(int16\_t number\);
**表 1** I2cOpen参数和返回值描述
<a name="table7603619123820"></a>
<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>
</th>
<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>
</th>
</tr>
</thead>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
</tbody>
</table>
假设系统中存在8个I2C控制器,编号从0到7,那么我们现在获取3号控制器
```
DevHandle i2cHandle = NULL; /* I2C控制器句柄 /
/* 打开I2C控制器 */
i2cHandle = I2cOpen(3);
if (i2cHandle == NULL) {
HDF_LOGE("I2cOpen: failed\n");
return;
}
```
## 进行I2C通信<a name="section11091522125812"></a>
消息传输
int32\_t I2cTransfer\(DevHandle handle, struct I2cMsg \*msgs, int16\_t count\);
**表 2** I2cTransfer参数和返回值描述
<a name="table1934414174212"></a>
<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>
</th>
<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>
</th>
</tr>
</thead>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<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>
</td>
</tr>
</tbody>
</table>
I2C传输消息类型为I2cMsg,每个传输消息结构体表示一次读或写,通过一个消息数组,可以执行若干次的读写组合操作。
```
int32_t ret;
uint8_t wbuff[2] = { 0x12, 0x13 };
uint8_t rbuff[2] = { 0 };
struct I2cMsg msgs[2]; /* 自定义传输的消息结构体数组 */
msgs[0].buf = wbuff; /* 写入的数据 */
msgs[0].len = 2; /* 写入数据长度为2 */
msgs[0].addr = 0x5A; /* 写入设备地址为0x5A */
msgs[0].flags = 0; /* 传输标记为0,默认为写 */
msgs[1].buf = rbuff; /* 要读取的数据 */
msgs[1].len = 2; /* 读取数据长度为2 */
msgs[1].addr = 0x5A; /* 读取设备地址为0x5A */
msgs[1].flags = I2C_FLAG_READ /* I2C_FLAG_READ置位 */
/* 进行一次自定义传输,传输的消息个数为2 */
ret = I2cTransfer(i2cHandle, msgs, 2);
if (ret != 2) {
HDF_LOGE("I2cTransfer: failed, ret %d\n", ret);
return;
}
```
>![](public_sys-resources/icon-caution.gif) **注意:**
>- I2cMsg结构体中的设备地址不包含读写标志位,读写信息由flags成员变量的读写控制位传递。
>- 本函数不对消息结构体个数count做限制,其最大个数度由具体I2C控制器决定。
>- 本函数也不对每个消息结构体中的数据长度做限制,同样由具体I2C控制器决定。
>- 本函数可能会引起系统休眠,不允许在中断上下文调用
## 关闭I2C控制器<a name="section13519505589"></a>
I2C通信完成之后,需要关闭2C控制器,关闭函数如下所示:
void I2cClose\(DevHandle handle\);
**表 3** I2cClose参数和返回值描述
<a name="table72517953115"></a>
<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>
</th>
<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>
</th>
</tr>
</thead>
<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>
</td>
<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>
</td>
</tr>
</tbody>
</table>
```
I2cClose(i2cHandle); /* 关闭I2C控制器 */
```
# I2C概述<a name="ZH-CN_TOPIC_0000001052778273"></a>
- [简介](#section5361140416)
- [接口说明](#section7606310210)
## 简介<a name="section5361140416"></a>
- I2C\(Inter Integrated Circuit\)总线是由Philips公司开发的一种简单、双向二线制同步串行总线。
- I2C以主从方式工作,通常有一个主设备和一个或者多个从设备,主从设备通过SDA\(SerialData\)串行数据线以及SCL\(SerialClock\)串行时钟线两根线相连,如[图1 ](#fig1135561232714)所示。
- I2C数据的传输必须以一个起始信号作为开始条件,以一个结束信号作为传输的停止条件。数据传输以字节为单位,高位在前,逐个bit进行传输。
- I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。
- I2C接口定义了完成I2C传输的通用方法集合,包括:
- I2C控制器管理: 打开或关闭I2C控制器
- I2C消息传输:通过消息传输结构体数组进行自定义传输
**图 1** I2C物理连线示意图<a name="fig1135561232714"></a>
![](figures/I2C物理连线示意图.png "I2C物理连线示意图")
## 接口说明<a name="section7606310210"></a>
**表 1** I2C驱动API接口功能介绍
<a name="table1731550155318"></a>
<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>
</th>
<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>
</th>
<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>
</th>
</tr>
</thead>
<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>
</td>
<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>
</td>
<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>
</td>
</tr>
<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>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p573815197171"><a name="p573815197171"></a><a name="p573815197171"></a>关闭I2C控制器</p>
</td>
</tr>
<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>
</td>
<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>
</td>
<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>
</td>
</tr>
</tbody>
</table>
>![](public_sys-resources/icon-note.gif) **说明:**
>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
# LCD<a name="ZH-CN_TOPIC_0000001111441852"></a>
- **[LCD开发概述](LCD开发概述.md)**
- **[LCD开发指导](LCD开发指导.md)**
- **[LCD开发实例](LCD开发实例.md)**
# LCD开发实例<a name="ZH-CN_TOPIC_0000001052216238"></a>
添加设备描述配置:
```
/* Display驱动相关的设备描述配置 */
display :: host {
hostName = "display_host";
/* Display平台驱动设备描述 */
device_hdf_disp :: device {
device0 :: deviceNode {
policy = 2;
priority = 200;
permission = 0660;
moduleName = "HDF_DISP";
serviceName = "hdf_disp";
}
}
/* SOC适配层驱动设备描述 */
device_hi35xx_disp :: device {
device0 :: deviceNode {
policy = 0;
priority = 199;
moduleName = "HI351XX_DISP";
}
}
/* LCD器件驱动设备描述 */
device_lcd :: device {
device0 :: deviceNode {
policy = 0;
priority = 100;
preload = 0;
moduleName = "LCD_Sample";
}
device1 :: deviceNode {
policy = 0;
priority = 100;
preload = 2;
moduleName = "LCD_SampleXX";
}
}
}
```
SOC适配层驱动,以Hi35xx系列芯片为例,需要在本层驱动中适配MIPI等和芯片平台相关的配置,示例如下:
```
static int32_t MipiDsiInit(struct PanelInfo *info)
{
int32_t ret;
struct DevHandle *mipiHandle = NULL;
struct MipiCfg cfg;
mipiHandle = MipiDsiOpen(0);
if (mipiHandle == NULL) {
HDF_LOGE("%s: MipiDsiOpen failure", __func__);
return HDF_FAILURE;
}
cfg.lane = info->mipi.lane;
cfg.mode = info->mipi.mode;
cfg.format = info->mipi.format;
cfg.burstMode = info->mipi.burstMode;
cfg.timing.xPixels = info->width;
cfg.timing.hsaPixels = info->hsw;
cfg.timing.hbpPixels = info->hbp;
cfg.timing.hlinePixels = info->width + info->hbp + info->hfp + info->hsw;
cfg.timing.vsaLines = info->vsw;
cfg.timing.vbpLines = info->vbp;
cfg.timing.vfpLines = info->vfp;
cfg.timing.ylines = info->height;
/* 0 : no care */
cfg.timing.edpiCmdSize = 0;
cfg.pixelClk = CalcPixelClk(info);
cfg.phyDataRate = CalcDataRate(info);
/* config mipi device */
ret = MipiDsiSetCfg(mipiHandle, &cfg);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s:MipiDsiSetCfg failure", __func__);
}
MipiDsiClose(mipiHandle);
HDF_LOGI("%s:pixelClk = %d, phyDataRate = %d\n", __func__,
cfg.pixelClk, cfg.phyDataRate);
return ret;
}
```
LCD器件驱动示例如下:
```
#define RESET_GPIO 5
#define MIPI_DSI0 0
#define BLK_PWM1 1
#define PWM_MAX_PERIOD 100000
/* backlight setting */
#define MIN_LEVEL 0
#define MAX_LEVEL 255
#define DEFAULT_LEVEL 100
#define WIDTH 480
#define HEIGHT 960
#define HORIZONTAL_BACK_PORCH 20
#define HORIZONTAL_FRONT_PORCH 20
#define HORIZONTAL_SYNC_WIDTH 10
#define VERTIACL_BACK_PORCH 14
#define VERTIACL_FRONT_PORCH 16
#define VERTIACL_SYNC_WIDTH 2
#define FRAME_RATE 60
/* Panel Info结构体结构体 */
struct PanelInfo {
uint32_t width;
uint32_t height;
uint32_t hbp;
uint32_t hfp;
uint32_t hsw;
uint32_t vbp;
uint32_t vfp;
uint32_t vsw;
uint32_t frameRate;
enum LcdIntfType intfType;
enum IntfSync intfSync;
struct MipiDsiDesc mipi;
struct BlkDesc blk;
struct PwmCfg pwm;
};
/* LCD屏的初始化序列 */
static uint8_t g_payLoad0[] = { 0xF0, 0x5A, 0x5A };
static uint8_t g_payLoad1[] = { 0xF1, 0xA5, 0xA5 };
static uint8_t g_payLoad2[] = { 0xB3, 0x03, 0x03, 0x03, 0x07, 0x05, 0x0D, 0x0F, 0x11, 0x13, 0x09, 0x0B };
static uint8_t g_payLoad3[] = { 0xB4, 0x03, 0x03, 0x03, 0x06, 0x04, 0x0C, 0x0E, 0x10, 0x12, 0x08, 0x0A };
static uint8_t g_payLoad4[] = { 0xB0, 0x54, 0x32, 0x23, 0x45, 0x44, 0x44, 0x44, 0x44, 0x60, 0x00, 0x60, 0x1C };
static uint8_t g_payLoad5[] = { 0xB1, 0x32, 0x84, 0x02, 0x87, 0x12, 0x00, 0x50, 0x1C };
static uint8_t g_payLoad6[] = { 0xB2, 0x73, 0x09, 0x08 };
static uint8_t g_payLoad7[] = { 0xB6, 0x5C, 0x5C, 0x05 };
static uint8_t g_payLoad8[] = { 0xB8, 0x23, 0x41, 0x32, 0x30, 0x03 };
static uint8_t g_payLoad9[] = { 0xBC, 0xD2, 0x0E, 0x63, 0x63, 0x5A, 0x32, 0x22, 0x14, 0x22, 0x03 };
static uint8_t g_payLoad10[] = { 0xb7, 0x41 };
static uint8_t g_payLoad11[] = { 0xC1, 0x0c, 0x10, 0x04, 0x0c, 0x10, 0x04 };
static uint8_t g_payLoad12[] = { 0xC2, 0x10, 0xE0 };
static uint8_t g_payLoad13[] = { 0xC3, 0x22, 0x11 };
static uint8_t g_payLoad14[] = { 0xD0, 0x07, 0xFF };
static uint8_t g_payLoad15[] = { 0xD2, 0x63, 0x0B, 0x08, 0x88 };
static uint8_t g_payLoad16[] = { 0xC6, 0x08, 0x15, 0xFF, 0x10, 0x16, 0x80, 0x60 };
static uint8_t g_payLoad17[] = { 0xc7, 0x04 };
static uint8_t g_payLoad18[] = {
0xC8, 0x7C, 0x50, 0x3B, 0x2C, 0x25, 0x16, 0x1C, 0x08, 0x27, 0x2B, 0x2F, 0x52, 0x43, 0x4C, 0x40,
0x3D, 0x30, 0x1E, 0x06, 0x7C, 0x50, 0x3B, 0x2C, 0x25, 0x16, 0x1C, 0x08, 0x27, 0x2B, 0x2F, 0x52,
0x43, 0x4C, 0x40, 0x3D, 0x30, 0x1E, 0x06
};
static uint8_t g_payLoad19[] = { 0x11 };
static uint8_t g_payLoad20[] = { 0x29 };
struct DsiCmdDesc g_OnCmd[] = {
{ 0x29, 0, sizeof(g_payLoad0), g_payLoad0 },
{ 0x29, 0, sizeof(g_payLoad1), g_payLoad1 },
{ 0x29, 0, sizeof(g_payLoad2), g_payLoad2 },
{ 0x29, 0, sizeof(g_payLoad3), g_payLoad3 },
{ 0x29, 0, sizeof(g_payLoad4), g_payLoad4 },
{ 0x29, 0, sizeof(g_payLoad5), g_payLoad5 },
{ 0x29, 0, sizeof(g_payLoad6), g_payLoad6 },
{ 0x29, 0, sizeof(g_payLoad7), g_payLoad7 },
{ 0x29, 0, sizeof(g_payLoad8), g_payLoad8 },
{ 0x29, 0, sizeof(g_payLoad9), g_payLoad9 },
{ 0x23, 0, sizeof(g_payLoad10), g_payLoad10 },
{ 0x29, 0, sizeof(g_payLoad11), g_payLoad11 },
{ 0x29, 0, sizeof(g_payLoad12), g_payLoad12 },
{ 0x29, 0, sizeof(g_payLoad13), g_payLoad13 },
{ 0x29, 0, sizeof(g_payLoad14), g_payLoad14 },
{ 0x29, 0, sizeof(g_payLoad15), g_payLoad15 },
{ 0x29, 0, sizeof(g_payLoad16), g_payLoad16 },
{ 0x23, 0, sizeof(g_payLoad17), g_payLoad17 },
{ 0x29, 1, sizeof(g_payLoad18), g_payLoad18 },
{ 0x05, 120, sizeof(g_payLoad19), g_payLoad19 },
{ 0x05, 120, sizeof(g_payLoad20), g_payLoad20 },
};
static DevHandle g_mipiHandle = NULL;
static DevHandle g_pwmHandle = NULL;
/* 设置Reset Pin脚状态 */
static int32_t LcdResetOn(void)
{
int32_t ret;
ret = GpioSetDir(RESET_GPIO, GPIO_DIR_OUT);
if (ret != HDF_SUCCESS) {
HDF_LOGE("GpioSetDir failure, ret:%d", ret);
return HDF_FAILURE;
}
ret = GpioWrite(RESET_GPIO, GPIO_VAL_HIGH);
if (ret != HDF_SUCCESS) {
HDF_LOGE("GpioWrite failure, ret:%d", ret);
return HDF_FAILURE;
}
/* delay 20ms */
OsalMSleep(20);
return HDF_SUCCESS;
}
static int32_t SampleInit(void)
{
/* 获取MIPI DSI设备操作句柄 */
g_mipiHandle = MipiDsiOpen(MIPI_DSI0);
if (g_mipiHandle == NULL) {
HDF_LOGE("%s: MipiDsiOpen failure", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t SampleOn(void)
{
int32_t ret;
/* LCD上电序列 */
ret = LcdResetOn();
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: LcdResetOn failure", __func__);
return HDF_FAILURE;
}
if (g_mipiHandle == NULL) {
HDF_LOGE("%s: g_mipiHandle is null", __func__);
return HDF_FAILURE;
}
/* 使用mipi下发初始化序列 */
int32_t count = sizeof(g_OnCmd) / sizeof(g_OnCmd[0]);
int32_t i;
for (i = 0; i < count; i++) {
ret = MipiDsiTx(g_mipiHandle, &(g_OnCmd[i]));
if (ret != HDF_SUCCESS) {
HDF_LOGE("MipiDsiTx failure");
return HDF_FAILURE;
}
}
/* 将mipi切换到HS模式 */
MipiDsiSetHsMode(g_mipiHandle);
return HDF_SUCCESS;
}
/* PanelInfo结构体变量 */
static struct PanelInfo g_panelInfo = {
.width = WIDTH, /* width */
.height = HEIGHT, /* height */
.hbp = HORIZONTAL_BACK_PORCH, /* horizontal back porch */
.hfp = HORIZONTAL_FRONT_PORCH, /* horizontal front porch */
.hsw = HORIZONTAL_SYNC_WIDTH, /* horizontal sync width */
.vbp = VERTIACL_BACK_PORCH, /* vertiacl back porch */
.vfp = VERTIACL_FRONT_PORCH, /* vertiacl front porch */
.vsw = VERTIACL_SYNC_WIDTH, /* vertiacl sync width */
.frameRate = FRAME_RATE, /* frame rate */
.intfType = MIPI_DSI, /* panel interface type */
.intfSync = OUTPUT_USER, /* output timming type */
/* mipi config info */
.mipi = { DSI_2_LANES, DSI_VIDEO_MODE, VIDEO_BURST_MODE, FORMAT_RGB_24_BIT },
/* backlight config info */
.blk = { BLK_PWM, MIN_LEVEL, MAX_LEVEL, DEFAULT_LEVEL },
.pwm = { BLK_PWM1, PWM_MAX_PERIOD },
};
/* 器件驱动需要适配的基础接口 */
static struct PanelData g_panelData = {
.info = &g_panelInfo,
.init = SampleInit,
.on = SampleOn,
.off = SampleOff,
.setBacklight = SampleSetBacklight,
};
/* 器件驱动入口函数 */
int32_t SampleEntryInit(struct HdfDeviceObject *object)
{
HDF_LOGI("%s: enter", __func__);
if (object == NULL) {
HDF_LOGE("%s: param is null!", __func__);
return HDF_FAILURE;
}
/* 器件驱动接口注册,ops提供给平台驱动调用 */
if (PanelDataRegister(&g_panelData) != HDF_SUCCESS) {
HDF_LOGE("%s: PanelDataRegister error!", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
struct HdfDriverEntry g_sampleDevEntry = {
.moduleVersion = 1,
.moduleName = "LCD_SAMPLE",
.Init = SampleEntryInit,
};
HDF_INIT(g_sampleDevEntry);
```
# LCD开发指导<a name="ZH-CN_TOPIC_0000001051616710"></a>
- [开发步骤](#section3904154911218)
Display驱动模型基于HDF驱动框架、Platform接口及OSAL接口开发,可以做到不区分OS(LiteOS、Linux)和芯片平台(Hi35xx、Hi38xx、V3S等),为LCD器件提供统一的驱动模型。
## 开发步骤<a name="section3904154911218"></a>
1. 添加LCD驱动相关的设备描述配置。
2. 在SOC平台驱动适配层中适配对应的芯片平台驱动。
3. 添加器件驱动,并在驱动入口函数Init中注册Panel驱动数据,驱动数据接口主要包括如下接口:
- LCD上下电
根据LCD硬件连接,使用Platform接口层提供的GPIO操作接口操作对应LCD管脚,例如复位管脚、IOVCC管脚,上电时序参考LCD供应商提供的SPEC。
- 发送初始化序列
根据LCD硬件接口,使用Platform接口层提供的I2C、SPI、MIPI等接口,下载LCD初始化序列,初始化参数序列可以参考LCD供应商提供的SPEC。
4. 根据需求实现HDF框架其他接口,比如Release接口。
5. 根据需求使用HDF框架可创建其他设备节点,用于业务逻辑或者调试功能。
# LCD开发概述<a name="ZH-CN_TOPIC_0000001052857284"></a>
- [简介](#section3781515122118)
- [接口说明](#section20280192712120)
## 简介<a name="section3781515122118"></a>
LCD(Liquid Crystal Display)液晶显示驱动,对LCD进行上电,并通过接口初始化LCD内部寄存器,使LCD正常工作。Display驱动模型基于HDF( Hardware Driver Foundation)[驱动框架](HDF开发概述.md)开发,实现跨OS、跨平台,为LCD硬件提供上下电功能、发送初始化序列功能,使LCD进入正常的工作模式,显示芯片平台侧的图像数据,基于HDF驱动框架的Display驱动模型如[图1](#fig69138814229)
**图 1** 基于HDF驱动框架的Display驱动模型<a name="fig69138814229"></a>
![](figures/基于HDF驱动框架的Display驱动模型.png "基于HDF驱动框架的Display驱动模型")
- **Display驱动模型介绍**
Display驱动模型主要由平台驱动层、芯片平台适配层、LCD器件驱动层三部分组成。驱动模型基于HDF驱动框架开发,通过Platform层和OSAL层提供的接口,屏蔽内核形态的差异,使得器件驱动可以便利的迁移到不同OS及芯片平台。模型向上对接Display公共hal层,支撑HDI接口的实现,通过Display-HDI(Hardware Display Interface)对图形服务提供各类驱动能力接口。
(1)Display平台驱动层:通过HDF提供的IOService数据通道,与公共Hal层对接,集中接收并处理各类上层调用指令;
(2)SOC平台驱动适配层:借助此SOC适配层,实现Display驱动和SOC侧驱动解耦,主要完成芯片平台相关的参数配置,并传递平台驱动层的调用到器件驱动层;
(3)LCD器件驱动层:在器件驱动层中,主要实现和器件自身强相关的驱动适配接口,例如发送初始化序列、上下电、背光设置等。
基于Display驱动模型开发LCD驱动,可以借助平台提供的各种能力及接口,较大程度的降低器件驱动的开发周期和难度,提升开发效率。
## 接口说明<a name="section20280192712120"></a>
LCD接口通常可分为MIPI DSI接口、TTL接口和LVDS接口,常用的是MIPI DSI接口和TTL接口,下面对常用的MIPI DSI接口和TTL接口作简要介绍。
- MIPI DSI接口
**图 2** MIPI DSI接口<a name="fig6936451331"></a>
![](figures/MIPI-DSI接口.png "MIPI-DSI接口")
MIPI DSI接口是MIPI(移动行业处理器接口)联盟定义的显示接口,主要用于移动终端显示屏接口,接口数据传输遵循MIPI协议,MIPI DSI接口为数据接口,传输图像数据,通常情况下MIPI DSI接口的控制信息以MIPI包形式通过MIPI DSI接口发送到对端IC,不需要额外的外设接口。
- TTL接口
**图 3** TTL接口<a name="fig141611855635"></a>
![](figures/TTL接口.png "TTL接口")
TTL(Transistor Transistor Logic)即晶体管-晶体管逻辑,TTL电平信号由TTL器件产生,TTL器件是数字集成电路的一大门类,它采用双极型工艺制造,具有高速度、低功耗和品种多等特点。
TTL接口是并行方式传输数据的接口,有数据信号、时钟信号和控制信号(行同步、帧同步、数据有效信号等),在控制信号控制下完成数据传输。通常TTL接口的LCD,内部寄存器读写需要额外的外设接口,比如SPI接口、I2C接口等。
# MIPI DSI<a name="ZH-CN_TOPIC_0000001157479387"></a>
- **[MIPI DSI概述](MIPI-DSI概述.md)**
- **[MIPI DSI使用指导](MIPI-DSI使用指导.md)**
- **[MIPI DSI使用实例](MIPI-DSI使用实例.md)**
# MIPI DSI使用实例<a name="ZH-CN_TOPIC_0000001062724697"></a>
MIPI-DSI完整的使用示例如下所示:
```
#include "hdf.h"
#include "mipi_dsi_if.h"
void PalMipiDsiTestSample(void)
{
uint8_t chnId;
int32_t ret;
DevHandle handle = NULL;
/* 设备通道编号 */
chnId = 0;
/* 获取操作句柄 */
handle = MipiDsiOpen(chnId);
if (handle == NULL) {
HDF_LOGE("MipiDsiOpen: failed!\n");
return;
}
/* 配置相应参数 */
struct MipiCfg cfg = {0};
cfg.lane = DSI_4_LANES;
cfg.mode = DSI_CMD_MODE;
cfg.burstMode = VIDEO_NON_BURST_MODE_SYNC_EVENTS;
cfg.format = FORMAT_RGB_24_BIT;
cfg.pixelClk = 174;
cfg.phyDataRate = 384;
cfg.timingInfo.hsaPixels = 50;
cfg.timingInfo.hbpPixels = 55;
cfg.timingInfo.hlinePixels = 1200;
cfg.timingInfo.yResLines = 1800;
cfg.timingInfo.vbpLines = 33;
cfg.timingInfo.vsaLines = 76;
cfg.timingInfo.vfpLines = 120;
cfg.timingInfo.xResPixels = 1342;
/* 写入配置数据 */
ret = MipiDsiSetCfg(g_handle, &cfg);
if (ret != 0) {
HDF_LOGE("%s: SetMipiCfg fail! ret=%d\n", __func__, ret);
return;
}
/* 发送PANEL初始化指令 */
struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc));
if (cmd == NULL) {
return;
}
cmd->dtype = DTYPE_DCS_WRITE;
cmd->dlen = 1;
cmd->payload = OsalMemCalloc(sizeof(uint8_t));
if (cmd->payload == NULL) {
HdfFree(cmd);
return;
}
*(cmd->payload) = DTYPE_GEN_LWRITE;
MipiDsiSetLpMode(mipiHandle);
ret = MipiDsiTx(mipiHandle, cmd);
MipiDsiSetHsMode(mipiHandle);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: MipiDsiTx fail! ret=%d\n", __func__, ret);
HdfFree(cmd->payload);
HdfFree(cmd);
return;
}
HdfFree(cmd->payload);
HdfFree(cmd);
/* 回读panel状态寄存器 */
uint8_t readVal = 0;
struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc));
if (cmdRead == NULL) {
return;
}
cmdRead->dtype = DTYPE_DCS_READ;
cmdRead->dlen = 1;
cmdRead->payload = OsalMemCalloc(sizeof(uint8_t));
if (cmdRead->payload == NULL) {
HdfFree(cmdRead);
return;
}
*(cmdRead->payload) = DDIC_REG_STATUS;
MipiDsiSetLpMode(g_handle);
ret = MipiDsiRx(g_handle, cmdRead, sizeof(readVal), &readVal);
MipiDsiSetHsMode(g_handle);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: MipiDsiRx fail! ret=%d\n", __func__, ret);
HdfFree(cmdRead->payload);
HdfFree(cmdRead);
return;
}
HdfFree(cmdRead->payload);
HdfFree(cmdRead);
/* 释放MIPI DSI设备句柄 */
MipiDsiClose(handle);
}
```
# MIPI DSI使用指导<a name="ZH-CN_TOPIC_0000001063082539"></a>
- [使用流程](#section8982671284)
- [获取MIPI-DSI操作句柄](#section57982569176)
- [MIPI-DSI相应配置](#section5935410201815)
- [发送/回读控制指令](#section611661316194)
- [释放MIPI-DSI操作句柄](#section217313211199)
## 使用流程<a name="section8982671284"></a>
使用MIPI-DSI的一般流程如[图1](#fig99821771782)所示。
**图 1** MIPI-DSI使用流程图<a name="fig99821771782"></a>
![](figures/zh-cn_image_0000001072553354.png)
## 获取MIPI-DSI操作句柄<a name="section57982569176"></a>
在进行MIPI-DSI进行通信前,首先要调用MipiDsiOpen获取操作句柄,该函数会返回指定通道ID的操作句柄。
DevHandle MipiDsiOpen\(uint8\_t id\);
**表 1** MipiDsiOpen的参数和返回值描述
<a name="table7603619123820"></a>
<table><tbody><tr id="row1060351914386"><td class="cellrowborder" valign="top" width="20.66%"><p id="p14603181917382"><a name="p14603181917382"></a><a name="p14603181917382"></a><strong id="b16510829133012"><a name="b16510829133012"></a><a name="b16510829133012"></a>参数</strong></p>
</td>
<td class="cellrowborder" valign="top" width="79.34%"><p id="p36031519183819"><a name="p36031519183819"></a><a name="p36031519183819"></a><strong id="b65222293309"><a name="b65222293309"></a><a name="b65222293309"></a>参数描述</strong></p>
</td>
</tr>
<tr id="row960361918383"><td class="cellrowborder" valign="top" width="20.66%"><p id="p8603161903818"><a name="p8603161903818"></a><a name="p8603161903818"></a>id</p>
</td>
<td class="cellrowborder" valign="top" width="79.34%"><p id="p19603111916381"><a name="p19603111916381"></a><a name="p19603111916381"></a>MIPI DSI通道ID</p>
</td>
</tr>
<tr id="row11410612183019"><td class="cellrowborder" valign="top" width="20.66%"><p id="p460381915385"><a name="p460381915385"></a><a name="p460381915385"></a><strong id="b4349113243013"><a name="b4349113243013"></a><a name="b4349113243013"></a>返回值</strong></p>
</td>
<td class="cellrowborder" valign="top" width="79.34%"><p id="p96031619153812"><a name="p96031619153812"></a><a name="p96031619153812"></a><strong id="b63502322308"><a name="b63502322308"></a><a name="b63502322308"></a>返回值描述</strong></p>
</td>
</tr>
<tr id="row15410111273017"><td class="cellrowborder" valign="top" width="20.66%"><p id="p1060418195389"><a name="p1060418195389"></a><a name="p1060418195389"></a>NULL</p>
</td>
<td class="cellrowborder" valign="top" width="79.34%"><p id="p760471912388"><a name="p760471912388"></a><a name="p760471912388"></a>获取失败</p>
</td>
</tr>
<tr id="row1241081213303"><td class="cellrowborder" valign="top" width="20.66%"><p id="p5604719133811"><a name="p5604719133811"></a><a name="p5604719133811"></a>设备句柄</p>
</td>
<td class="cellrowborder" valign="top" width="79.34%"><p id="p3604181933818"><a name="p3604181933818"></a><a name="p3604181933818"></a>获取到指令通道的操作句柄, 类型为DevHandle</p>
</td>
</tr>
</tbody>
</table>
假设系统中的MIPI-DSI通道为0,获取该通道操作句柄的示例如下:
```
DevHandle mipiDsiHandle = NULL; /* 设备句柄 */
chnId = 0; /* MIPI-DSI通道ID */
/* 获取操作句柄 */
mipiDsiHandle = MipiDsiOpen(chnId);
if (mipiDsiHandle == NULL) {
HDF_LOGE("MipiDsiOpen: failed\n");
return;
}
```
## MIPI-DSI相应配置<a name="section5935410201815"></a>
- 写入MIPI-DSI配置
int32\_t MipiDsiSetCfg\(DevHandle handle, struct MipiCfg \*cfg\);
**表 2** MipiDsiSetCfg的参数和返回值描述
<a name="table10692555281"></a>
<table><tbody><tr id="row116914559288"><td class="cellrowborder" valign="top" width="50%"><p id="p1169195516288"><a name="p1169195516288"></a><a name="p1169195516288"></a><strong id="b106965519281"><a name="b106965519281"></a><a name="b106965519281"></a>参数</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p769125512286"><a name="p769125512286"></a><a name="p769125512286"></a><strong id="b969105516280"><a name="b969105516280"></a><a name="b969105516280"></a>参数描述</strong></p>
</td>
</tr>
<tr id="row4691155142812"><td class="cellrowborder" valign="top" width="50%"><p id="p66935515288"><a name="p66935515288"></a><a name="p66935515288"></a>handle</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p863714348217"><a name="p863714348217"></a><a name="p863714348217"></a>操作句柄</p>
</td>
</tr>
<tr id="row469145572817"><td class="cellrowborder" valign="top" width="50%"><p id="p46915519287"><a name="p46915519287"></a><a name="p46915519287"></a>cfg</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p76995518289"><a name="p76995518289"></a><a name="p76995518289"></a>MIPI-DSI相应配置buf 指针</p>
</td>
</tr>
<tr id="row16913554284"><td class="cellrowborder" valign="top" width="50%"><p id="p16955512812"><a name="p16955512812"></a><a name="p16955512812"></a><strong id="b17691155152810"><a name="b17691155152810"></a><a name="b17691155152810"></a>返回值</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p206945502813"><a name="p206945502813"></a><a name="p206945502813"></a><strong id="b196955572818"><a name="b196955572818"></a><a name="b196955572818"></a>返回值描述</strong></p>
</td>
</tr>
<tr id="row146914556283"><td class="cellrowborder" valign="top" width="50%"><p id="p669175582818"><a name="p669175582818"></a><a name="p669175582818"></a>0</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p169205511283"><a name="p169205511283"></a><a name="p169205511283"></a>设置成功</p>
</td>
</tr>
<tr id="row5694558283"><td class="cellrowborder" valign="top" width="50%"><p id="p269175516286"><a name="p269175516286"></a><a name="p269175516286"></a>负数</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p11691554280"><a name="p11691554280"></a><a name="p11691554280"></a>设置失败</p>
</td>
</tr>
</tbody>
</table>
```
int32_t ret;
struct MipiCfg cfg = {0};
/* 当前对接的屏幕配置如下 */
cfg.lane = DSI_4_LANES;
cfg.mode = DSI_CMD_MODE;
cfg.burstMode = VIDEO_NON_BURST_MODE_SYNC_EVENTS;
cfg.format = FORMAT_RGB_24_BIT;
cfg.pixelClk = 174;
cfg.phyDataRate = 384;
cfg.timingInfo.hsaPixels = 50;
cfg.timingInfo.hbpPixels = 55;
cfg.timingInfo.hlinePixels = 1200;
cfg.timingInfo.yResLines = 1800;
cfg.timingInfo.vbpLines = 33;
cfg.timingInfo.vsaLines = 76;
cfg.timingInfo.vfpLines = 120;
cfg.timingInfo.xResPixels = 1342;
/* 写入配置数据 */
ret = MipiDsiSetCfg(g_handle, &cfg);
if (ret != 0) {
HDF_LOGE("%s: SetMipiCfg fail! ret=%d\n", __func__, ret);
return -1;
}
```
- 获取当前MIPI-DSI的配置
int32\_t MipiDsiGetCfg\(DevHandle handle, struct MipiCfg \*cfg\);
**表 3** MipiDsiGetCfg的参数和返回值描述
<a name="table7709554280"></a>
<table><tbody><tr id="row670115515282"><td class="cellrowborder" valign="top" width="50%"><p id="p470205515287"><a name="p470205515287"></a><a name="p470205515287"></a><strong id="b1770105522820"><a name="b1770105522820"></a><a name="b1770105522820"></a>参数</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p270755162817"><a name="p270755162817"></a><a name="p270755162817"></a><strong id="b170165512817"><a name="b170165512817"></a><a name="b170165512817"></a>参数描述</strong></p>
</td>
</tr>
<tr id="row57014555286"><td class="cellrowborder" valign="top" width="50%"><p id="p11701155172815"><a name="p11701155172815"></a><a name="p11701155172815"></a>handle</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p57015510283"><a name="p57015510283"></a><a name="p57015510283"></a>操作句柄</p>
</td>
</tr>
<tr id="row1870155192815"><td class="cellrowborder" valign="top" width="50%"><p id="p137115572815"><a name="p137115572815"></a><a name="p137115572815"></a>cfg</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p771195522818"><a name="p771195522818"></a><a name="p771195522818"></a>MIPI-DSI相应配置buf 指针</p>
</td>
</tr>
<tr id="row12718555283"><td class="cellrowborder" valign="top" width="50%"><p id="p1871175515289"><a name="p1871175515289"></a><a name="p1871175515289"></a><strong id="b871185592819"><a name="b871185592819"></a><a name="b871185592819"></a>返回值</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p771955182813"><a name="p771955182813"></a><a name="p771955182813"></a><strong id="b147175532813"><a name="b147175532813"></a><a name="b147175532813"></a>返回值描述</strong></p>
</td>
</tr>
<tr id="row1071155582812"><td class="cellrowborder" valign="top" width="50%"><p id="p6718551282"><a name="p6718551282"></a><a name="p6718551282"></a>0</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p171195516285"><a name="p171195516285"></a><a name="p171195516285"></a>获取成功</p>
</td>
</tr>
<tr id="row97135519282"><td class="cellrowborder" valign="top" width="50%"><p id="p11711355162815"><a name="p11711355162815"></a><a name="p11711355162815"></a>负数</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p77116555286"><a name="p77116555286"></a><a name="p77116555286"></a>获取失败</p>
</td>
</tr>
</tbody>
</table>
```
int32_t ret;
struct MipiCfg cfg;
memset(&cfg, 0, sizeof(struct MipiCfg));
ret = MipiDsiGetCfg(g_handle, &cfg);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: GetMipiCfg fail!\n", __func__);
return HDF_FAILURE;
}
```
## 发送/回读控制指令<a name="section611661316194"></a>
- 发送指令
int32\_t MipiDsiTx\(PalHandle handle, struct DsiCmdDesc \*cmd\);
**表 4** MipiDsiTx的参数和返回值描述
<a name="table1018490043"></a>
<table><tbody><tr id="row31848013417"><td class="cellrowborder" valign="top" width="50%"><p id="p1415816132411"><a name="p1415816132411"></a><a name="p1415816132411"></a><strong id="b129796117337"><a name="b129796117337"></a><a name="b129796117337"></a>参数</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p11158111316410"><a name="p11158111316410"></a><a name="p11158111316410"></a><strong id="b1699118123314"><a name="b1699118123314"></a><a name="b1699118123314"></a>参数描述</strong></p>
</td>
</tr>
<tr id="row10184701945"><td class="cellrowborder" valign="top" width="50%"><p id="p104891871157"><a name="p104891871157"></a><a name="p104891871157"></a>handle</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p204891671156"><a name="p204891671156"></a><a name="p204891671156"></a>操作句柄</p>
</td>
</tr>
<tr id="row928111518418"><td class="cellrowborder" valign="top" width="50%"><p id="p4282955412"><a name="p4282955412"></a><a name="p4282955412"></a>cmd</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p7282752412"><a name="p7282752412"></a><a name="p7282752412"></a>需要发送的指令数据指针</p>
</td>
</tr>
<tr id="row17393154515328"><td class="cellrowborder" valign="top" width="50%"><p id="p8158313248"><a name="p8158313248"></a><a name="p8158313248"></a><strong id="b18542051332"><a name="b18542051332"></a><a name="b18542051332"></a>返回值</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p161591413741"><a name="p161591413741"></a><a name="p161591413741"></a><strong id="b45520523313"><a name="b45520523313"></a><a name="b45520523313"></a>返回值描述</strong></p>
</td>
</tr>
<tr id="row339324593215"><td class="cellrowborder" valign="top" width="50%"><p id="p103191916578"><a name="p103191916578"></a><a name="p103191916578"></a>0</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p1231981611712"><a name="p1231981611712"></a><a name="p1231981611712"></a>发送成功</p>
</td>
</tr>
<tr id="row15393184519323"><td class="cellrowborder" valign="top" width="50%"><p id="p531916166716"><a name="p531916166716"></a><a name="p531916166716"></a>负数</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p93191161174"><a name="p93191161174"></a><a name="p93191161174"></a>发送失败</p>
</td>
</tr>
</tbody>
</table>
```
int32_t ret;
struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc));
if (cmd == NULL) {
return HDF_FAILURE;
}
cmd->dtype = DTYPE_DCS_WRITE;
cmd->dlen = 1;
cmd->payload = OsalMemCalloc(sizeof(uint8_t));
if (cmd->payload == NULL) {
HdfFree(cmd);
return HDF_FAILURE;
}
*(cmd->payload) = DTYPE_GEN_LWRITE;
MipiDsiSetLpMode(mipiHandle);
ret = MipiDsiTx(mipiHandle, cmd);
MipiDsiSetHsMode(mipiHandle);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: PalMipiDsiTx fail! ret=%d\n", __func__, ret);
HdfFree(cmd->payload);
HdfFree(cmd);
return HDF_FAILURE;
}
HdfFree(cmd->payload);
HdfFree(cmd);
```
- 回读指令
int32\_t MipiDsiRx\(DevHandle handle, struct DsiCmdDesc \*cmd, uint32\_t readLen, uint8\_t \*out\);
**表 5** MipiDsiRx的参数和返回值描述
<a name="table223910318361"></a>
<table><tbody><tr id="row924033173613"><td class="cellrowborder" valign="top" width="50%"><p id="p16240143143611"><a name="p16240143143611"></a><a name="p16240143143611"></a><strong id="b1724033112363"><a name="b1724033112363"></a><a name="b1724033112363"></a>参数</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p32401031113610"><a name="p32401031113610"></a><a name="p32401031113610"></a><strong id="b1324013111363"><a name="b1324013111363"></a><a name="b1324013111363"></a>参数描述</strong></p>
</td>
</tr>
<tr id="row024043193619"><td class="cellrowborder" valign="top" width="50%"><p id="p16231153542520"><a name="p16231153542520"></a><a name="p16231153542520"></a>handle</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p122311535122518"><a name="p122311535122518"></a><a name="p122311535122518"></a>操作句柄</p>
</td>
</tr>
<tr id="row192401331163613"><td class="cellrowborder" valign="top" width="50%"><p id="p8706172453614"><a name="p8706172453614"></a><a name="p8706172453614"></a>cmd</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p0706424183610"><a name="p0706424183610"></a><a name="p0706424183610"></a>需要回读的指令数据指针</p>
</td>
</tr>
<tr id="row12646535173616"><td class="cellrowborder" valign="top" width="50%"><p id="p16465359364"><a name="p16465359364"></a><a name="p16465359364"></a>readLen</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p564617356360"><a name="p564617356360"></a><a name="p564617356360"></a>期望回读的数据长度</p>
</td>
</tr>
<tr id="row919916426361"><td class="cellrowborder" valign="top" width="50%"><p id="p11199942153616"><a name="p11199942153616"></a><a name="p11199942153616"></a>out</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p91991042143618"><a name="p91991042143618"></a><a name="p91991042143618"></a>回读的数据buf指针</p>
</td>
</tr>
<tr id="row14240133143619"><td class="cellrowborder" valign="top" width="50%"><p id="p1723253542518"><a name="p1723253542518"></a><a name="p1723253542518"></a><strong id="b4232173517256"><a name="b4232173517256"></a><a name="b4232173517256"></a>返回值</strong></p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p223217356253"><a name="p223217356253"></a><a name="p223217356253"></a><strong id="b7232103510259"><a name="b7232103510259"></a><a name="b7232103510259"></a>返回值描述</strong></p>
</td>
</tr>
<tr id="row424093120369"><td class="cellrowborder" valign="top" width="50%"><p id="p1123203518257"><a name="p1123203518257"></a><a name="p1123203518257"></a>0</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p62324353251"><a name="p62324353251"></a><a name="p62324353251"></a>获取成功</p>
</td>
</tr>
<tr id="row18241531153610"><td class="cellrowborder" valign="top" width="50%"><p id="p42321635122517"><a name="p42321635122517"></a><a name="p42321635122517"></a>负数</p>
</td>
<td class="cellrowborder" valign="top" width="50%"><p id="p323283510252"><a name="p323283510252"></a><a name="p323283510252"></a>获取失败</p>
</td>
</tr>
</tbody>
</table>
```
int32_t ret;
uint8_t readVal = 0;
struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc));
if (cmdRead == NULL) {
return HDF_FAILURE;
}
cmdRead->dtype = DTYPE_DCS_READ;
cmdRead->dlen = 1;
cmdRead->payload = OsalMemCalloc(sizeof(uint8_t));
if (cmdRead->payload == NULL) {
HdfFree(cmdRead);
return HDF_FAILURE;
}
*(cmdRead->payload) = DDIC_REG_STATUS;
MipiDsiSetLpMode(g_handle);
ret = MipiDsiRx(g_handle, cmdRead, sizeof(readVal), &readVal);
MipiDsiSetHsMode(g_handle);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: MipiDsiRx fail! ret=%d\n", __func__, ret);
HdfFree(cmdRead->payload);
HdfFree(cmdRead);
return HDF_FAILURE;
}
HdfFree(cmdRead->payload);
HdfFree(cmdRead);
```
## 释放MIPI-DSI操作句柄<a name="section217313211199"></a>
MIPI-DSI使用完成之后,需要释放操作句柄,释放句柄的函数如下所示:
void MipiDsiClose\(DevHandle handle\);
该函数会释放掉由MipiDsiOpen申请的资源。
**表 6** MipiDsiClose的参数和返回值描述
<a name="table72517953115"></a>
<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>
</th>
<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>
</th>
</tr>
</thead>
<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>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p132442255912"><a name="p132442255912"></a><a name="p132442255912"></a>MIPI-DSI操作句柄</p>
</td>
</tr>
</tbody>
</table>
```
MipiDsiClose(mipiHandle); /* 释放掉MIPI-DSI操作句柄 */
```
# MIPI DSI概述<a name="ZH-CN_TOPIC_0000001062724343"></a>
- [简介](#section1369320102013)
- [接口说明](#section6577545192317)
## 简介<a name="section1369320102013"></a>
- DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface \(MIPI\) Alliance)制定的规范,旨在降低移动设备中显示控制器的成本。它以串行的方式发送像素数据或指令给外设\(通常是LCD或者类似的显示设备\),或从外设中读取状态信息或像素信息;它定义了主机、图像数据源和目标设备之间的串行总线和通信协议。
- MIPI-DSI具备高速模式和低速模式两种工作模式,全部数据通道都可以用于单向的高速传输,但只有第一个数据通道才可用于低速双向传输,从属端的状态信息、像素等是通过该数据通道返回。时钟通道专用于在高速传输数据的过程中传输同步时钟信号。
- 图1显示了简化的DSI接口。从概念上看,符合DSI的接口与基于DBI-2和DPI-2标准的接口具有相同的功能。它向外围设备传输像素或命令数据,并且可以从外围设备读取状态或像素信息。主要区别在于,DSI对所有像素数据、命令和事件进行序列化,而在传统接口中,这些像素数据、命令和事件通常需要附加控制信号才能在并行数据总线上传输。
**图 1** DSI发送、接收接口<a name="fig1122611461203"></a>
![](figures/DSI发送-接收接口.png "DSI发送-接收接口")
## 接口说明<a name="section6577545192317"></a>
**表 1** MIPI-DSI API接口功能介绍
<a name="table4199102313245"></a>
<table><thead align="left"><tr id="row1619910238244"><th class="cellrowborder" valign="top" width="26.619999999999997%" id="mcps1.2.4.1.1"><p id="p141991023182411"><a name="p141991023182411"></a><a name="p141991023182411"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="28.910000000000004%" id="mcps1.2.4.1.2"><p id="p1199102315247"><a name="p1199102315247"></a><a name="p1199102315247"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="44.47%" id="mcps1.2.4.1.3"><p id="p719918232240"><a name="p719918232240"></a><a name="p719918232240"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row15199023172414"><td class="cellrowborder" rowspan="2" valign="top" width="26.619999999999997%" headers="mcps1.2.4.1.1 "><p id="p919902312413"><a name="p919902312413"></a><a name="p919902312413"></a>设置/获取当前MIPI-DSI相关配置</p>
</td>
<td class="cellrowborder" valign="top" width="28.910000000000004%" headers="mcps1.2.4.1.2 "><p id="p21995232243"><a name="p21995232243"></a><a name="p21995232243"></a>MipiDsiSetCfg</p>
</td>
<td class="cellrowborder" valign="top" width="44.47%" headers="mcps1.2.4.1.3 "><p id="p919911233240"><a name="p919911233240"></a><a name="p919911233240"></a>设置MIPI-DSI相关配置</p>
</td>
</tr>
<tr id="row171996232248"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p7199623152412"><a name="p7199623152412"></a><a name="p7199623152412"></a>MipiDsiGetCfg</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1119919235248"><a name="p1119919235248"></a><a name="p1119919235248"></a>获取当前MIPI-DSI相关配置</p>
</td>
</tr>
<tr id="row91994239242"><td class="cellrowborder" rowspan="2" valign="top" width="26.619999999999997%" headers="mcps1.2.4.1.1 "><p id="p101998233245"><a name="p101998233245"></a><a name="p101998233245"></a>获取/释放MIPI-DSI操作句柄</p>
</td>
<td class="cellrowborder" valign="top" width="28.910000000000004%" headers="mcps1.2.4.1.2 "><p id="p51991323112415"><a name="p51991323112415"></a><a name="p51991323112415"></a>MipiDsiOpen</p>
</td>
<td class="cellrowborder" valign="top" width="44.47%" headers="mcps1.2.4.1.3 "><p id="p11991623182415"><a name="p11991623182415"></a><a name="p11991623182415"></a>获取MIPI-DSI操作句柄</p>
</td>
</tr>
<tr id="row12199192352411"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p131991123172412"><a name="p131991123172412"></a><a name="p131991123172412"></a>MipiDsiClose</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p520062313249"><a name="p520062313249"></a><a name="p520062313249"></a>释放MIPI-DSI操作句柄</p>
</td>
</tr>
<tr id="row7200152382417"><td class="cellrowborder" rowspan="2" valign="top" width="26.619999999999997%" headers="mcps1.2.4.1.1 "><p id="p8200202312241"><a name="p8200202312241"></a><a name="p8200202312241"></a>设置MIPI-DSI进入Low power模式/High speed模式</p>
</td>
<td class="cellrowborder" valign="top" width="28.910000000000004%" headers="mcps1.2.4.1.2 "><p id="p6200192318247"><a name="p6200192318247"></a><a name="p6200192318247"></a>MipiDsiSetLpMode</p>
</td>
<td class="cellrowborder" valign="top" width="44.47%" headers="mcps1.2.4.1.3 "><p id="p16200192319240"><a name="p16200192319240"></a><a name="p16200192319240"></a>设置MIPI-DSI进入Low power模式</p>
</td>
</tr>
<tr id="row122001523182417"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p22009236249"><a name="p22009236249"></a><a name="p22009236249"></a>MipiDsiSetHsMode</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p22001423192418"><a name="p22001423192418"></a><a name="p22001423192418"></a>设置MIPI-DSI进入High speed模式</p>
</td>
</tr>
<tr id="row52002237248"><td class="cellrowborder" rowspan="2" valign="top" width="26.619999999999997%" headers="mcps1.2.4.1.1 "><p id="p10200162332412"><a name="p10200162332412"></a><a name="p10200162332412"></a>MIPI-DSI发送/回读指令</p>
</td>
<td class="cellrowborder" valign="top" width="28.910000000000004%" headers="mcps1.2.4.1.2 "><p id="p19200142315249"><a name="p19200142315249"></a><a name="p19200142315249"></a>MipiDsiTx</p>
</td>
<td class="cellrowborder" valign="top" width="44.47%" headers="mcps1.2.4.1.3 "><p id="p1020082319243"><a name="p1020082319243"></a><a name="p1020082319243"></a>MIPI-DSI发送相应指令的接口</p>
</td>
</tr>
<tr id="row6200162372416"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18200112392417"><a name="p18200112392417"></a><a name="p18200112392417"></a>MipiDsiRx</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p9200102312249"><a name="p9200102312249"></a><a name="p9200102312249"></a>MIPI-DSI按期望长度回读的接口</p>
</td>
</tr>
</tbody>
</table>
>![](public_sys-resources/icon-note.gif) **说明:**
>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用
# RTC<a name="ZH-CN_TOPIC_0000001157479385"></a>
- **[RTC概述](RTC概述.md)**
- **[RTC使用指导](RTC使用指导.md)**
- **[RTC使用实例](RTC使用实例.md)**
# RTC使用实例<a name="ZH-CN_TOPIC_0000001052778235"></a>
本实例提供RTC接口的完整使用流程:
1. 系统启动,驱动管理模块会识别系统当前的RTC器件;
2. 驱动管理模块完成RTC设备的初始化和设备创建;
3. 用户通过不同API,对该RTC设备进行对应的操作;
4. 关闭RTC设备,释放设备资源。
示例如下:
```
#include "rtc_if.h"
int32_t RtcAlarmACallback(enum RtcAlarmIndex alarmIndex)
{
if (alarmIndex == RTC_ALARM_INDEX_A) {
/* 报警A的处理 */
printf("RTC Alarm A callback function\n\r");
} else if (alarmIndex == RTC_ALARM_INDEX_B) {
/* 报警B的处理 */
printf("RTC Alarm B callback function\n\r");
} else {
/* 错误处理 */
}
return 0;
}
void RtcTestSample(void)
{
int32_t ret;
struct RtcTime tm;
struct RtcTime alarmTime;
uint32_t freq;
DevHandle handle = NULL;
/* 获取RTC设备句柄 */
handle = RtcOpen();
if (handle == NULL) {
/* 错误处理 */
}
/* 注册报警A的定时回调函数 */
ret = RtcRegisterAlarmCallback(handle, RTC_ALARM_INDEX_A, RtcAlarmACallback);
if (ret != 0) {
/* 错误处理 */
}
/* 设置RTC外接晶体振荡频率,注意按照器件手册要求配置RTC外频 */
freq = 32768; /* 32768 Hz */
ret = RtcSetFreq(handle, freq);
if (ret != 0) {
/* 错误处理 */
}
/* 设置RTC报警中断使能 */
ret = RtcAlarmInterruptEnable(handle, RTC_ALARM_INDEX_A, 1);
if (ret != 0) {
/* 错误处理 */
}
/* 设置RTC时间为2020/01/01 00:00:10 .990 */
tm.year = 2020;
tm.month = 01;
tm.day = 01;
tm.hour= 0;
tm.minute = 0;
tm.second = 10;
tm.millisecond = 990;
/* 写RTC时间信息 */
ret = RtcWriteTime(handle, &tm);
if (ret != 0) {
/* 错误处理 */
}
/* 设置RTC报警时间为2020/01/01 00:00:30 .100 */
alarmTime.year = 2020;
alarmTime.month = 01;
alarmTime.day = 01;
alarmTime.hour = 0;
alarmTime.minute = 0;
alarmTime.second = 30;
alarmTime.millisecond = 100;
/* 设置RTC_ALARM_INDEX_A索引定时报警时间信息, 定时时间到后会打印"RTC Alarm A callback function" */
ret = RtcWriteAlarm(handle, RTC_ALARM_INDEX_A, &alarmTime);
if (ret != 0) {
/* 错误处理 */
}
/* 读取RTC实时时间 */
ret = RtcReadTime(handle, &tm);
if (ret != 0) {
/* 错误处理 */
}
sleep(5)
printf("RTC read time:\n\r");
printf("year-month-date-weekday hour:minute:second .millisecond %04u-%02u-%02u-%u %02u:%02u:%02u .%03u",
tm.year, tm.month, tm.day, tm.weekday, tm.hour, tm.minute, tm.second, tm.millisecond);
/* 销毁RTC设备句柄 */
RtcClose(handle);
}
```
此差异已折叠。
# RTC概述<a name="ZH-CN_TOPIC_0000001051778226"></a>
- [简介](#section104842041574)
- [接口说明](#section16892932155715)
## 简介<a name="section104842041574"></a>
RTC\(real-time clock\)为操作系统中的实时时钟设备,为操作系统提供精准的实时时间和定时报警功能。当设备下电后,通过外置电池供电,RTC继续记录操作系统时间;设备上电后,RTC提供实时时钟给操作系统,确保断电后系统时间的连续性。
## 接口说明<a name="section16892932155715"></a>
**表 1** RTC设备API接口功能介绍
<a name="table1731550155318"></a>
<table><thead align="left"><tr id="row4419501537"><th class="cellrowborder" valign="top" width="21.902190219021904%" id="mcps1.2.4.1.1"><p id="p641050105320"><a name="p641050105320"></a><a name="p641050105320"></a>功能分类</p>
</th>
<th class="cellrowborder" valign="top" width="24.98249824982498%" id="mcps1.2.4.1.2"><p id="p54150165315"><a name="p54150165315"></a><a name="p54150165315"></a>接口名</p>
</th>
<th class="cellrowborder" valign="top" width="53.11531153115312%" id="mcps1.2.4.1.3"><p id="p941150145313"><a name="p941150145313"></a><a name="p941150145313"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row17550163418501"><td class="cellrowborder" rowspan="2" valign="top" width="21.902190219021904%" headers="mcps1.2.4.1.1 "><p id="p11670643205012"><a name="p11670643205012"></a><a name="p11670643205012"></a>RTC句柄操作</p>
</td>
<td class="cellrowborder" valign="top" width="24.98249824982498%" headers="mcps1.2.4.1.2 "><p id="p16550143465015"><a name="p16550143465015"></a><a name="p16550143465015"></a>RtcOpen</p>
</td>
<td class="cellrowborder" valign="top" width="53.11531153115312%" headers="mcps1.2.4.1.3 "><p id="p9550103415015"><a name="p9550103415015"></a><a name="p9550103415015"></a>获取RTC设备驱动句柄</p>
</td>
</tr>
<tr id="row1879052755020"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1479062716506"><a name="p1479062716506"></a><a name="p1479062716506"></a>RtcClose</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1579142745012"><a name="p1579142745012"></a><a name="p1579142745012"></a>释放RTC设备驱动句柄</p>
</td>
</tr>
<tr id="row34145016535"><td class="cellrowborder" rowspan="2" valign="top" width="21.902190219021904%" headers="mcps1.2.4.1.1 "><p id="p229610227124"><a name="p229610227124"></a><a name="p229610227124"></a>RTC时间操作接口</p>
</td>
<td class="cellrowborder" valign="top" width="24.98249824982498%" headers="mcps1.2.4.1.2 "><p id="p19389143041518"><a name="p19389143041518"></a><a name="p19389143041518"></a>RtcReadTime</p>
</td>
<td class="cellrowborder" valign="top" width="53.11531153115312%" headers="mcps1.2.4.1.3 "><p id="p8738101941716"><a name="p8738101941716"></a><a name="p8738101941716"></a>读RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒</p>
</td>
</tr>
<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>RtcWriteTime</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p573815197171"><a name="p573815197171"></a><a name="p573815197171"></a>写RTC时间信息,包括年、月、星期、日、时、分、秒、毫秒</p>
</td>
</tr>
<tr id="row1468016592416"><td class="cellrowborder" rowspan="4" valign="top" width="21.902190219021904%" headers="mcps1.2.4.1.1 "><p id="p36817591648"><a name="p36817591648"></a><a name="p36817591648"></a>RTC报警操作接口</p>
</td>
<td class="cellrowborder" valign="top" width="24.98249824982498%" headers="mcps1.2.4.1.2 "><p id="p968116598418"><a name="p968116598418"></a><a name="p968116598418"></a>RtcReadAlarm</p>
</td>
<td class="cellrowborder" valign="top" width="53.11531153115312%" headers="mcps1.2.4.1.3 "><p id="p768110592416"><a name="p768110592416"></a><a name="p768110592416"></a>读RTC报警时间信息</p>
</td>
</tr>
<tr id="row19313155514"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p73141951155"><a name="p73141951155"></a><a name="p73141951155"></a>RtcWriteAlarm</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p15314656511"><a name="p15314656511"></a><a name="p15314656511"></a>写RTC报警时间信息</p>
</td>
</tr>
<tr id="row138283422555"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2829142165513"><a name="p2829142165513"></a><a name="p2829142165513"></a>RtcRegisterAlarmCallback</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p118291242155518"><a name="p118291242155518"></a><a name="p118291242155518"></a>注册报警超时回调函数</p>
</td>
</tr>
<tr id="row13344113914568"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2344103915616"><a name="p2344103915616"></a><a name="p2344103915616"></a>RtcAlarmInterruptEnable</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p034415397565"><a name="p034415397565"></a><a name="p034415397565"></a>使能/去使能RTC报警中断</p>
</td>
</tr>
<tr id="row11801203517565"><td class="cellrowborder" rowspan="3" valign="top" width="21.902190219021904%" headers="mcps1.2.4.1.1 "><p id="p17261458942"><a name="p17261458942"></a><a name="p17261458942"></a>RTC配置操作</p>
</td>
<td class="cellrowborder" valign="top" width="24.98249824982498%" headers="mcps1.2.4.1.2 "><p id="p15801153515561"><a name="p15801153515561"></a><a name="p15801153515561"></a>RtcGetFreq</p>
</td>
<td class="cellrowborder" valign="top" width="53.11531153115312%" headers="mcps1.2.4.1.3 "><p id="p980133515566"><a name="p980133515566"></a><a name="p980133515566"></a>读RTC外接晶振频率</p>
</td>
</tr>
<tr id="row111502322563"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1615073225618"><a name="p1615073225618"></a><a name="p1615073225618"></a>RtcSetFreq</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p10150832165613"><a name="p10150832165613"></a><a name="p10150832165613"></a>配置RTC外接晶振频率</p>
</td>
</tr>
<tr id="row21771259145618"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1717725916562"><a name="p1717725916562"></a><a name="p1717725916562"></a>RtcReset</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p517712598569"><a name="p517712598569"></a><a name="p517712598569"></a>RTC复位</p>
</td>
</tr>
<tr id="row917116425716"><td class="cellrowborder" rowspan="2" valign="top" width="21.902190219021904%" headers="mcps1.2.4.1.1 "><p id="p144765201754"><a name="p144765201754"></a><a name="p144765201754"></a>读写用户定义寄存器</p>
</td>
<td class="cellrowborder" valign="top" width="24.98249824982498%" headers="mcps1.2.4.1.2 "><p id="p1117110418570"><a name="p1117110418570"></a><a name="p1117110418570"></a>RtcReadReg</p>
</td>
<td class="cellrowborder" valign="top" width="53.11531153115312%" headers="mcps1.2.4.1.3 "><p id="p1517114410578"><a name="p1517114410578"></a><a name="p1517114410578"></a>读用户自定义寄存器</p>
</td>
</tr>
<tr id="row46738190576"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1567331910573"><a name="p1567331910573"></a><a name="p1567331910573"></a>RtcWriteReg</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1967391913576"><a name="p1967391913576"></a><a name="p1967391913576"></a>写用户自定义寄存器</p>
</td>
</tr>
</tbody>
</table>
>![](public_sys-resources/icon-note.gif) **说明:**
>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
# 驱动 # 驱动使用指南
- [HDF驱动框架](HDF驱动框架.md) - [HDF驱动框架](drive.md)
- [HDF开发概述](HDF开发概述.md) - [HDF开发概述](drive-hdf-overview.md)
- [驱动开发](驱动开发.md) - [驱动开发](drive-hdf-development.md)
- [驱动服务管理](驱动服务管理.md) - [驱动服务管理](drive-hdf-servicemanage.md)
- [驱动消息机制管理](驱动消息机制管理.md) - [驱动消息机制管理](drive-hdf-news.md)
- [配置管理](配置管理.md) - [配置管理](drive-hdf-manage.md)
- [HDF开发实例](HDF开发实例.md) - [HDF开发实例](drive-hdf-sample.md)
- [平台驱动](drive-platform.md)
- [驱动平台](驱动平台.md) - [GPIO](drive-platform-gpio-des.md)
- [GPIO](GPIO.md) - [I2C](drive-platform-i2c-des.md)
- [GPIO概述](GPIO概述.md) - [RTC](drive-platform-rtc-des.md)
- [GPIO使用指导](GPIO使用指导.md) - [SDIO](drive-platform-sdio-des.md)
- [GPIO使用实例](GPIO使用实例.md) - [SPI](drive-platform-spi-des.md)
- [UART](drive-platform-uart-des.md)
- [I2C](I2C.md) - [WATCHDOG](drive-platform-watchdog-des.md)
- [I2C概述](I2C概述.md) - [MIPI DSI](drive-platform-mipidsi-des.md)
- [I2C使用指导](I2C使用指导.md) - [外设](drive-peripherals.md)
- [I2C使用实例](I2C使用实例.md) - [LCD](drive-peripherals-lcd-des.md)
- [TOUCHSCREEN](drive-peripherals-touch-des.md)
- [RTC](RTC.md) - [SENSOR](drive-peripherals-sensor-des.md)
- [RTC概述](RTC概述.md) - [WLAN](drive-peripherals-external-des.md)
- [RTC使用指导](RTC使用指导.md)
- [RTC使用实例](RTC使用实例.md)
- [SDIO](SDIO.md)
- [SDIO概述](SDIO概述.md)
- [SDIO使用指导](SDIO使用指导.md)
- [SDIO使用实例](SDIO使用实例.md)
- [SPI](SPI.md)
- [SPI概述](SPI概述.md)
- [SPI使用指导](SPI使用指导.md)
- [SPI使用实例](SPI使用实例.md)
- [UART](UART.md)
- [UART概述](UART概述.md)
- [UART使用指导](UART使用指导.md)
- [UART使用实例](UART使用实例.md)
- [WATCHDOG](WATCHDOG.md)
- [看门狗概述](看门狗概述.md)
- [看门狗使用指导](看门狗使用指导.md)
- [看门狗使用实例](看门狗使用实例.md)
- [MIPI DSI](MIPI-DSI.md)
- [MIPI DSI概述](MIPI-DSI概述.md)
- [MIPI DSI使用指导](MIPI-DSI使用指导.md)
- [MIPI DSI使用实例](MIPI-DSI使用实例.md)
- [外设](外设.md)
- [LCD](LCD.md)
- [LCD开发概述](LCD开发概述.md)
- [LCD开发指导](LCD开发指导.md)
- [LCD开发实例](LCD开发实例.md)
- [TOUCHSCREEN](TOUCHSCREEN.md)
- [Touchscreen开发概述](Touchscreen开发概述.md)
- [Touchscreen开发指导](Touchscreen开发指导.md)
- [Touchscreen开发实例](Touchscreen开发实例.md)
- [SENSOR](SENSOR.md)
- [传感器驱动开发概述](传感器驱动开发概述.md)
- [传感器驱动开发指导](传感器驱动开发指导.md)
- [传感器驱动开发实例](传感器驱动开发实例.md)
- [传感器驱动测试指导](传感器驱动测试指导.md)
- [WLAN](WLAN.md)
- [WLAN开发概述](WLAN开发概述.md)
- [WLAN开发指导](WLAN开发指导.md)
- [WLAN开发实例](WLAN开发实例.md)
# SDIO<a name="ZH-CN_TOPIC_0000001157479379"></a>
- **[SDIO概述](SDIO概述.md)**
- **[SDIO使用指导](SDIO使用指导.md)**
- **[SDIO使用实例](SDIO使用实例.md)**
# SDIO使用实例<a name="ZH-CN_TOPIC_0000001052858034"></a>
SDIO设备完整的使用示例如下所示,首先打开总线号为1的SDIO控制器,然后独占HOST、使能设备、注册中断,接着进行SDIO通信(读写等),通信完成之后,释放中断、去使能设备、释放HOST,最后关闭SDIO控制器。
```
#include "hdf_log.h"
#include "sdio_if.h"
#define TEST_FUNC_NUM 1 /* 本测试用例中,使用编号为1的I/O function */
#define TEST_FBR_BASE_ADDR 0x100 /* 编号为1的I/O function的FBR基地址 */
#define TEST_ADDR_OFFSET 9 /* 本测试用例中,需要读写的寄存器的地址偏移 */
#define TEST_DATA_LEN 3 /* 本测试用例中,读写数据的长度 */
#define TEST_BLOCKSIZE 2 /* 本测试用例中,数据块的大小,单位字节 */
/* 中断服务函数,需要根据各自平台的情况去实现 */
static void SdioIrqFunc(void *data)
{
if (data == NULL) {
HDF_LOGE("SdioIrqFunc: data is NULL.\n");
return;
}
/* 需要开发者自行添加具体的实现 */
}
void SdioTestSample(void)
{
int32_t ret;
DevHandle handle = NULL;
uint8_t data[TEST_DATA_LEN] = {0};
struct SdioFunctionConfig config = {1, 0x123, 0x456};
uint8_t val;
uint32_t addr;
/* 打开总线号为1的SDIO设备 */
handle = SdioOpen(1, &config);
if (handle == NULL) {
HDF_LOGE("SdioOpen: failed!\n");
return;
}
/* 独占HOST */
SdioClaimHost(handle);
/* 使能SDIO设备 */
ret = SdioEnableFunc(handle);
if (ret != 0) {
HDF_LOGE("SdioEnableFunc: failed, ret %d\n", ret);
goto ENABLE_ERR;
}
/* 注册中断 */
ret = SdioClaimIrq(handle, SdioIrqFunc);
if (ret != 0) {
HDF_LOGE("SdioClaimIrq: failed, ret %d\n", ret);
goto CLAIM_IRQ_ERR;
}
/* 设置块大小为2字节 */
ret = SdioSetBlockSize(handle, TEST_BLOCKSIZE);
if (ret != 0) {
HDF_LOGE("SdioSetBlockSize: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 从SDIO设备增量地址读取3字节的数据 */
addr = TEST_FBR_BASE_ADDR * TEST_FUNC_NUM + TEST_ADDR_OFFSET;
ret = SdioReadBytes(handle, data, addr, TEST_DATA_LEN);
if (ret != 0) {
HDF_LOGE("SdioReadBytes: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 向SDIO设备增量地址写入3字节的数据 */
ret = SdioWriteBytes(handle, data, addr, TEST_DATA_LEN);
if (ret != 0) {
HDF_LOGE("SdioWriteBytes: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 从SDIO设备读取1字节的数据 */
ret = SdioReadBytes(handle, &val, addr, 1);
if (ret != 0) {
HDF_LOGE("SdioReadBytes: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 向SDIO设备写入1字节的数据 */
ret = SdioWriteBytes(handle, &val, addr, 1);
if (ret != 0) {
HDF_LOGE("SdioWriteBytes: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 从SDIO设备固定地址读取3字节的数据 */
ret = SdioReadBytesFromFixedAddr(handle, data, addr, TEST_DATA_LEN, 0);
if (ret != 0) {
HDF_LOGE("SdioReadBytesFromFixedAddr: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 向SDIO设备固定地址写入1字节的数据 */
ret = SdioWriteBytesToFixedAddr(handle, data, addr, 1, 0);
if (ret != 0) {
HDF_LOGE("SdioWriteBytesToFixedAddr: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 从SDIO function 0读取1字节的数据 */
addr = 0x02;
ret = SdioReadBytesFromFunc0(handle, &val, addr, 1);
if (ret != 0) {
HDF_LOGE("SdioReadBytesFromFunc0: failed, ret %d\n", ret);
goto COMM_ERR;
}
/* 向SDIO function 0写入1字节的数据 */
ret = SdioWriteBytesToFunc0(handle, &val, addr, 1);
if (ret != 0) {
HDF_LOGE("SdioWriteBytesToFunc0: failed, ret %d\n", ret);
goto COMM_ERR;
}
COMM_ERR:
/* 释放中断 */
ret = SdioReleaseIrq(handle);
if (ret != 0) {
HDF_LOGE("SdioReleaseIrq: failed, ret %d\n", ret);
}
CLAIM_IRQ_ERR:
/* 去使能SDIO设备 */
ret = SdioDisableFunc(handle);
if (ret != 0) {
HDF_LOGE("SdioDisableFunc: failed, ret %d\n", ret);
}
ENABLE_ERR:
/* 释放HOST */
SdioReleaseHost(handle);
/* 关闭SDIO设备 */
SdioClose(handle);
}
```
此差异已折叠。
此差异已折叠。
# SENSOR<a name="ZH-CN_TOPIC_0000001158281695"></a>
- **[传感器驱动开发概述](传感器驱动开发概述.md)**
- **[传感器驱动开发指导](传感器驱动开发指导.md)**
- **[传感器驱动开发实例](传感器驱动开发实例.md)**
- **[传感器驱动测试指导](传感器驱动测试指导.md)**
# SPI<a name="ZH-CN_TOPIC_0000001157319421"></a>
- **[SPI概述](SPI概述.md)**
- **[SPI使用指导](SPI使用指导.md)**
- **[SPI使用实例](SPI使用实例.md)**
# SPI使用实例<a name="ZH-CN_TOPIC_0000001052459271"></a>
SPI设备完整的使用示例如下所示,首先获取SPI设备句柄,然后配置SPI设备属性,接着调用读写接口进行数据传输,最后销毁SPI设备句柄。
```
#include "hdf_log.h"
#include "spi_if.h"
void SpiTestSample(void)
{
int32_t ret;
struct SpiCfg cfg; /* SPI配置信息 */
struct SpiDevInfo spiDevinfo; /* SPI设备描述符 */
DevHandle spiHandle = NULL; /* SPI设备句柄 */
struct SpiMsg msg; /* 自定义传输的消息 */
uint8_t rbuff[4] = { 0 };
uint8_t wbuff[4] = { 0x12, 0x34, 0x56, 0x78 };
uint8_t wbuff2[4] = { 0xa1, 0xb2, 0xc3, 0xd4 };
spiDevinfo.busNum = 0; /* SPI设备总线号 */
spiDevinfo.csNum = 0; /* SPI设备片选号 */
spiHandle = SpiOpen(&spiDevinfo); /* 根据spiDevinfo获取SPI设备句柄 */
if (spiHandle == NULL) {
HDF_LOGE("SpiOpen: failed\n");
return;
}
/* 获取SPI设备属性 */
ret = SpiGetCfg(spiHandle, &cfg);
if (ret != 0) {
HDF_LOGE("SpiGetCfg: failed, ret %d\n", ret);
goto err;
}
cfg.maxSpeedHz = 115200; /* 将最大时钟频率改为115200 */
cfg.bitsPerWord = 8; /* 传输位宽改为8比特 */
/* 配置SPI设备属性 */
ret = SpiSetCfg(spiHandle, &cfg);
if (ret != 0) {
HDF_LOGE("SpiSetCfg: failed, ret %d\n", ret);
goto err;
}
/* 向SPI设备写入指定长度的数据 */
ret = SpiWrite(spiHandle, wbuff, 4);
if (ret != 0) {
HDF_LOGE("SpiWrite: failed, ret %d\n", ret);
goto err;
}
/* 从SPI设备读取指定长度的数据 */
ret = SpiRead(spiHandle, rbuff, 4);
if (ret != 0) {
HDF_LOGE("SpiRead: failed, ret %d\n", ret);
goto err;
}
msg.wbuf = wbuff2; /* 写入的数据 */
msg.rbuf = rbuff; /* 读取的数据 */
msg.len = 4; /* 读取写入数据的长度为4 */
msg.csChange = 1; /* 进行下一次传输前关闭片选 */
msg.delayUs = 0; /* 进行下一次传输前不进行延时 */
msg.speed = 115200; /* 本次传输的速度 */
/* 进行一次自定义传输,传输的msg个数为1 */
ret = SpiTransfer(spiHandle, &msg, 1);
if (ret != 0) {
HDF_LOGE("SpiTransfer: failed, ret %d\n", ret);
goto err;
}
err:
/* 销毁SPI设备句柄 */
SpiClose(spiHandle);
}
```
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册