Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Docs
提交
952ecd1c
D
Docs
项目概览
OpenHarmony
/
Docs
大约 2 年 前同步成功
通知
161
Star
293
Fork
28
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
Docs
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
952ecd1c
编写于
6月 08, 2023
作者:
J
jiaziyangnewer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: platform documents refresh.
Signed-off-by:
N
jiaziyangnewer
<
jiaziyang1@huawei.com
>
上级
8c176ecf
变更
33
展开全部
显示空白变更内容
内联
并排
Showing
33 changed file
with
7210 addition
and
6374 deletion
+7210
-6374
zh-cn/device-dev/driver/driver-platform-adc-des.md
zh-cn/device-dev/driver/driver-platform-adc-des.md
+39
-38
zh-cn/device-dev/driver/driver-platform-adc-develop.md
zh-cn/device-dev/driver/driver-platform-adc-develop.md
+333
-302
zh-cn/device-dev/driver/driver-platform-dac-des.md
zh-cn/device-dev/driver/driver-platform-dac-des.md
+53
-46
zh-cn/device-dev/driver/driver-platform-dac-develop.md
zh-cn/device-dev/driver/driver-platform-dac-develop.md
+286
-264
zh-cn/device-dev/driver/driver-platform-gpio-des.md
zh-cn/device-dev/driver/driver-platform-gpio-des.md
+137
-131
zh-cn/device-dev/driver/driver-platform-gpio-develop.md
zh-cn/device-dev/driver/driver-platform-gpio-develop.md
+412
-374
zh-cn/device-dev/driver/driver-platform-hdmi-des.md
zh-cn/device-dev/driver/driver-platform-hdmi-des.md
+171
-141
zh-cn/device-dev/driver/driver-platform-hdmi-develop.md
zh-cn/device-dev/driver/driver-platform-hdmi-develop.md
+61
-44
zh-cn/device-dev/driver/driver-platform-i2c-des.md
zh-cn/device-dev/driver/driver-platform-i2c-des.md
+34
-36
zh-cn/device-dev/driver/driver-platform-i2c-develop.md
zh-cn/device-dev/driver/driver-platform-i2c-develop.md
+260
-243
zh-cn/device-dev/driver/driver-platform-i3c-des.md
zh-cn/device-dev/driver/driver-platform-i3c-des.md
+147
-136
zh-cn/device-dev/driver/driver-platform-i3c-develop.md
zh-cn/device-dev/driver/driver-platform-i3c-develop.md
+195
-172
zh-cn/device-dev/driver/driver-platform-mipicsi-des.md
zh-cn/device-dev/driver/driver-platform-mipicsi-des.md
+422
-300
zh-cn/device-dev/driver/driver-platform-mipicsi-develop.md
zh-cn/device-dev/driver/driver-platform-mipicsi-develop.md
+317
-293
zh-cn/device-dev/driver/driver-platform-mipidsi-des.md
zh-cn/device-dev/driver/driver-platform-mipidsi-des.md
+226
-223
zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md
zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md
+218
-196
zh-cn/device-dev/driver/driver-platform-mmc-develop.md
zh-cn/device-dev/driver/driver-platform-mmc-develop.md
+354
-335
zh-cn/device-dev/driver/driver-platform-pin-des.md
zh-cn/device-dev/driver/driver-platform-pin-des.md
+94
-81
zh-cn/device-dev/driver/driver-platform-pin-develop.md
zh-cn/device-dev/driver/driver-platform-pin-develop.md
+407
-386
zh-cn/device-dev/driver/driver-platform-pwm-des.md
zh-cn/device-dev/driver/driver-platform-pwm-des.md
+98
-80
zh-cn/device-dev/driver/driver-platform-pwm-develop.md
zh-cn/device-dev/driver/driver-platform-pwm-develop.md
+267
-244
zh-cn/device-dev/driver/driver-platform-regulator-des.md
zh-cn/device-dev/driver/driver-platform-regulator-des.md
+107
-87
zh-cn/device-dev/driver/driver-platform-regulator-develop.md
zh-cn/device-dev/driver/driver-platform-regulator-develop.md
+173
-170
zh-cn/device-dev/driver/driver-platform-rtc-des.md
zh-cn/device-dev/driver/driver-platform-rtc-des.md
+254
-162
zh-cn/device-dev/driver/driver-platform-rtc-develop.md
zh-cn/device-dev/driver/driver-platform-rtc-develop.md
+273
-241
zh-cn/device-dev/driver/driver-platform-sdio-des.md
zh-cn/device-dev/driver/driver-platform-sdio-des.md
+260
-221
zh-cn/device-dev/driver/driver-platform-sdio-develop.md
zh-cn/device-dev/driver/driver-platform-sdio-develop.md
+282
-254
zh-cn/device-dev/driver/driver-platform-spi-des.md
zh-cn/device-dev/driver/driver-platform-spi-des.md
+209
-170
zh-cn/device-dev/driver/driver-platform-spi-develop.md
zh-cn/device-dev/driver/driver-platform-spi-develop.md
+377
-338
zh-cn/device-dev/driver/driver-platform-uart-des.md
zh-cn/device-dev/driver/driver-platform-uart-des.md
+72
-50
zh-cn/device-dev/driver/driver-platform-uart-develop.md
zh-cn/device-dev/driver/driver-platform-uart-develop.md
+381
-358
zh-cn/device-dev/driver/driver-platform-watchdog-des.md
zh-cn/device-dev/driver/driver-platform-watchdog-des.md
+69
-56
zh-cn/device-dev/driver/driver-platform-watchdog-develop.md
zh-cn/device-dev/driver/driver-platform-watchdog-develop.md
+222
-202
未找到文件。
zh-cn/device-dev/driver/driver-platform-adc-des.md
浏览文件 @
952ecd1c
...
...
@@ -4,14 +4,15 @@
### 功能简介<a name="section2"></a>
ADC(Analog to Digital Converter),即模拟-数字转换器,可将模拟信号转换成对应的数字信号,便于存储与计算等操作。除电源线和地线之外,ADC只需要1根线与被测量的设备进行连接,其物理连线如图1:
ADC(Analog to Digital Converter),即模拟-数字转换器,可将模拟信号转换成对应的数字信号,便于存储与计算等操作。除电源线和地线之外,ADC只需要1根线与被测量的设备进行连接,其物理连线如图1
所示
:
**图 1**
ADC物理连线示意图
<a
name=
"fig1"
></a>


ADC接口定义了完成AD转换的通用方法集合,包括:
-
ADC设备管理:打开或关闭ADC设备。
-
ADC读取转换结果:读取AD转换结果。
### 基本概念<a name="section3"></a>
...
...
@@ -60,8 +61,8 @@ ADC模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/
使用ADC设备的一般流程如图2所示。
**图 2**
ADC使用流程图
<a
name=
"fig2"
></a>

**图 2**
ADC使用流程图
<a
name=
"fig2"
></a>

#### 打开ADC设备
...
...
@@ -78,7 +79,7 @@ DevHandle AdcOpen(int16_t number);
| 参数 | 参数描述 |
| ---------- | ----------------- |
| number
| ADC设备号
|
| number
| int16_t类型,ADC设备号
|
|
**返回值**
|
**返回值描述**
|
| NULL | 打开ADC设备失败 |
| 设备句柄 | 打开的ADC设备句柄 |
...
...
@@ -86,13 +87,13 @@ DevHandle AdcOpen(int16_t number);
假设系统中存在2个ADC设备,编号从0到1,那么我们现在打开1号设备。
```
c
DevHandle
adcHandle
=
NULL
;
/
* ADC设备句柄 /
DevHandle
adcHandle
=
NULL
;
/
/ ADC设备句柄
/
* 打开ADC设备 */
/
/ 打开ADC设备
adcHandle
=
AdcOpen
(
1
);
if
(
adcHandle
==
NULL
)
{
HDF_LOGE
(
"AdcOpen: fail
\n
"
);
return
;
return
NULL
;
}
```
...
...
@@ -108,11 +109,11 @@ int32_t AdcRead(DevHandle handle, uint32_t channel, uint32_t *val);
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
| ADC设备句柄
|
| channel
| ADC设备通道号
|
| val
| AD转换结果
|
| handle
| DevHandle类型,ADC设备句柄
|
| channel
| uint32_t类型,ADC设备通道号
|
| val
| uint32_t类型指针,AD转换结果
|
|
**返回值**
|
**返回值描述**
|
|
0 | 读取成功
|
|
HDF_SUCCESS | 读取成功
|
| 负数 | 读取失败 |
读取转换结果示例(以通道1为例):
...
...
@@ -122,9 +123,9 @@ uint32_t value;
int32_t
ret
;
ret
=
AdcRead
(
adcHandle
,
1
,
&
value
);
if
(
ret
!=
0
)
{
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"ADC read fail!
\n
"
);
return
;
return
ret
;
}
```
...
...
@@ -140,14 +141,14 @@ void AdcClose(DevHandle handle);
| 参数 | 参数描述 |
| ------ | ----------- |
| handle | ADC设备句柄 |
| handle |
DevHandle类型,
ADC设备句柄 |
| 返回值 | 返回值描述 |
| 无 | 无 |
关闭ADC设备示例:
```
c
AdcClose
(
adcHandle
);
/
* 关闭ADC设备 */
AdcClose
(
adcHandle
);
/
/ 关闭ADC设备
```
### 使用实例<a name="section10"></a>
...
...
@@ -163,15 +164,15 @@ AdcClose(adcHandle); /* 关闭ADC设备 */
示例如下:
```
c
#include "adc_if.h"
/
* ADC标准接口头文件 */
#include "hdf_log.h"
/
* 标准日志打印头文件 */
#include "adc_if.h" /
/ ADC标准接口头文件
#include "hdf_log.h" /
/ 标准日志打印头文件
/
* 设备号0,通道号1 */
/
// 设备号0,通道号1
#define ADC_DEVICE_NUM 0
#define ADC_CHANNEL_NUM 1
#define ADC_TEST_NUM 30
/
* ADC例程总入口 */
/
/ ADC例程总入口
static
int32_t
TestCaseAdc
(
void
)
{
int32_t
i
;
...
...
@@ -179,14 +180,14 @@ static int32_t TestCaseAdc(void)
DevHandle
adcHandle
=
NULL
;
uint32_t
readBuf
[
ADC_TEST_NUM
]
=
{
0
};
/
* 打开ADC设备 */
/
/ 打开ADC设备
adcHandle
=
AdcOpen
(
ADC_DEVICE_NUM
);
if
(
adcHandle
==
NULL
)
{
HDF_LOGE
(
"%s: Open ADC%u fail!"
,
__func__
,
ADC_DEVICE_NUM
);
return
-
1
;
}
/
* 连续进行30次AD转换并读取转换结果 */
/
/ 连续进行30次AD转换并读取转换结果
for
(
i
=
0
;
i
<
ADC_TEST_NUM
;
i
++
)
{
ret
=
AdcRead
(
adcHandle
,
ADC_CHANNEL_NUM
,
&
readBuf
[
i
]);
if
(
ret
!=
HDF_SUCCESS
)
{
...
...
@@ -197,7 +198,7 @@ static int32_t TestCaseAdc(void)
}
HDF_LOGI
(
"%s: ADC read successful!"
,
__func__
);
/
* 访问完毕关闭ADC设备 */
/
/ 访问完毕关闭ADC设备
AdcClose
(
adcHandle
);
return
0
;
...
...
zh-cn/device-dev/driver/driver-platform-adc-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-dac-des.md
浏览文件 @
952ecd1c
...
...
@@ -7,10 +7,13 @@
DAC(Digital to Analog Converter)是一种通过电流、电压或电荷的形式将数字信号转换为模拟信号的设备,主要用于:
-
作为过程控制计算机系统的输出通道,与执行器相连,实现对生产过程的自动控制。
-
在利用反馈技术的模数转换器设计中,作为重要的功能模块呈现。
DAC接口定义了完成DAC传输的通用方法集合,包括:
-
DAC设备管理:打开或关闭DAC设备。
-
DAC设置目标值:设置DAC设备需要将数字信号转成模拟信号的目标值。
### 基本概念
...
...
@@ -61,8 +64,8 @@ DAC模块提供的主要接口如下所示,具体API详见//drivers/hdf_core/f
| 接口名 | 接口描述 |
| ------------------------------------------------------------------ | ------------ |
| DevHandle DacOpen(uint32_t number)
| 打开DAC设备。
|
| void DacClose(DevHandle handle)
| 关闭DAC设备。
|
| DevHandle DacOpen(uint32_t number)
| 打开DAC设备。
|
| void DacClose(DevHandle handle)
| 关闭DAC设备。
|
| int32_t DacWrite(DevHandle handle, uint32_t channel, uint32_t val) | 设置DA目标值。 |
### 开发步骤
...
...
@@ -76,7 +79,7 @@ DAC模块提供的主要接口如下所示,具体API详见//drivers/hdf_core/f
在进行DA转换之前,首先要调用DacOpen打开DAC设备,打开函数如下所示:
```
c
++
```
c
DevHandle
DacOpen
(
uint32_t
number
);
```
...
...
@@ -84,27 +87,27 @@ DevHandle DacOpen(uint32_t number);
| 参数 | 参数描述 |
| --------- | ---------------- |
| number
| DAC设备号。
|
| number
| uint32_t类型,DAC设备号。
|
|
**返回值**
|
**返回值描述**
|
| NULL | 打开DAC设备失败。 |
| 设备句柄 | 打开的DAC设备句柄。 |
假设系统中存在2个DAC设备,编号从0到1,现在打开1号设备。
```
c
++
```
c
DevHandle
dacHandle
=
NULL
;
// DAC设备句柄
/
* 打开DAC设备 */
/
/ 打开DAC设备
dacHandle
=
DacOpen
(
1
);
if
(
dacHandle
==
NULL
)
{
HDF_LOGE
(
"DacOpen:
failed
\n
"
);
return
;
HDF_LOGE
(
"DacOpen:
open dac fail.
\n
"
);
return
NULL
;
}
```
#### 设置DA目标值
```
c
++
```
c
int32_t
DacWrite
(
DevHandle
handle
,
uint32_t
channel
,
uint32_t
val
);
```
...
...
@@ -112,27 +115,29 @@ int32_t DacWrite(DevHandle handle, uint32_t channel, uint32_t val);
| 参数 | 参数描述 |
| --------- | ------------ |
| handle
| DAC设备句柄。
|
| channel
| DAC设备通道号。
|
| val
| 设置DA的值。
|
| handle
| DevHandle类型,DAC设备句柄。
|
| channel
| uint32_t类型,DAC设备通道号。
|
| val
| uint32_t类型,设置DA的值。
|
|
**返回值**
|
**返回值描述**
|
|
0 | 写入成功。
|
| 负数
| 写入失败。
|
|
HDF_SUCCESS | 写入DA目标值成功
|
| 负数
| 写入DA目标值失败
|
```
c++
/* 通过DAC_CHANNEL_NUM设备通道写入目标val值 */
```
c
// 通过DAC_CHANNEL_NUM设备通道写入目标val值
int32_t
ret
;
ret
=
DacWrite
(
dacHandle
,
DAC_CHANNEL_NUM
,
val
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: tp DAC write reg fail!:%d"
,
__func__
,
ret
);
HDF_LOGE
(
"
DacWrite: tp DAC write reg fail!,ret:%d"
,
ret
);
DacClose
(
dacHandle
);
return
-
1
;
return
ret
;
}
```
#### 关闭DAC设备
DAC通信完成之后,需要关闭DAC设备,关闭函数如下所示:
```
c++
```
c
void
DacClose
(
DevHandle
handle
);
```
...
...
@@ -142,12 +147,12 @@ void DacClose(DevHandle handle);
| --------- | ------------ |
| handle | DAC设备句柄。 |
|
**返回值**
|
**返回值描述**
|
|
void | 无
|
|
无 | 无
|
关闭DAC设备示例:
```
c
++
DacClose
(
dacHandle
);
/* 关闭DAC设备 */
```
c
DacClose
(
dacHandle
);
// 关闭DAC设备
```
## 使用实例
...
...
@@ -155,20 +160,22 @@ DacClose(dacHandle); /* 关闭DAC设备 */
DAC设备的具体使用方式可以参考如下示例代码,示例代码步骤主要如下:
1.
根据设备号DAC_DEVICE_NUM打开DAC设备得到设备句柄。
2.
通过DAC的设备号以及设备通道设置val的值,如果写入失败则关闭设备句柄。
3.
访问完毕DAC设备后,则关闭该设备句柄。
运行结果:根据输入的val通过打印日志得到输出的结果。
```
c
++
#include "dac_if.h"
/
* DAC标准接口头文件 */
#include "hdf_log.h"
/
* 标准日志打印头文件 */
```
c
#include "dac_if.h" /
/ DAC标准接口头文件
#include "hdf_log.h" /
/ 标准日志打印头文件
/
* 设备号0,通道号1 */
/
/ 设备号0,通道号1
#define DAC_DEVICE_NUM 0
#define DAC_CHANNEL_NUM 1
/
* DAC例程总入口 */
/
/ DAC例程总入口
static
int32_t
TestCaseDac
(
void
)
{
// 设置要写入的val值
...
...
@@ -176,14 +183,14 @@ static int32_t TestCaseDac(void)
int32_t
ret
;
DevHandle
dacHandle
;
/
* 打开DAC设备 */
/
/ 打开DAC设备
dacHandle
=
DacOpen
(
DAC_DEVICE_NUM
);
if
(
dacHandle
==
NULL
)
{
HDF_LOGE
(
"%s: Open DAC%u fail!"
,
__func__
,
DAC_DEVICE_NUM
);
return
-
1
;
}
/
* 写入数据 */
/
/ 写入数据
ret
=
DacWrite
(
dacHandle
,
DAC_CHANNEL_NUM
,
val
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: tp DAC write reg fail!:%d"
,
__func__
,
ret
);
...
...
@@ -191,9 +198,9 @@ static int32_t TestCaseDac(void)
return
-
1
;
}
/
* 访问完毕关闭DAC设备 */
/
/ 访问完毕关闭DAC设备
DacClose
(
dacHandle
);
HDF_LOGI
(
"%s: function tests end."
,
__func__
);
return
0
;
}
```
zh-cn/device-dev/driver/driver-platform-dac-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-gpio-des.md
浏览文件 @
952ecd1c
...
...
@@ -8,10 +8,13 @@ GPIO(General-purpose input/output)即通用型输入输出。通常,GPIO
GPIO接口定义了操作GPIO管脚的标准方法集合,包括:
-
设置管脚方向:方向可以是输入或者输出(暂不支持高阻态)。
-
读写管脚电平值:电平值可以是低电平或高电平。
-
设置管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式。
-
使能和禁止管脚中断:禁止或使能管脚中断。
-
设置、获取管脚方向:方向可以是输入或者输出(暂不支持高阻态)。
-
读、写管脚电平值:电平值可以是低电平或高电平。
-
设置、取消管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式。取消一个管脚的中断服务函数。
-
使能、禁止管脚中断:禁止或使能管脚中断。
### 基本概念
...
...
@@ -34,7 +37,9 @@ GPIO又俗称为I/O口,I指的是输入(in),O指的是输出(out)。
GPIO模块各分层作用:
-
接口层提供操作GPIO管脚的标准方法。
-
核心层主要提供GPIO管脚资源匹配,GPIO管脚控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互,供芯片厂家快速接入HDF框架。
-
适配层主要是将钩子函数的功能实例化,实现具体的功能。
**图 1**
GPIO统一服务模式结构图
...
...
@@ -45,23 +50,23 @@ GPIO模块各分层作用:
### 场景介绍
GPIO
仅是一个软件层面的概念,主要工作是GPIO管脚资源管理。开发者可以使用提供的GPIO操作接口,实现对管脚
控制。
GPIO
主要是对GPIO管脚资源进行管理。开发者可以使用提供的GPIO操作接口,实现对管脚控制的具体
控制。
### 接口说明
GPIO模块提供的主要接口如表1所示。
GPIO模块提供的主要接口如表1所示。
具体API详见//drivers/hdf_core/framework/include/platform/gpio_if.h。
**表1**
GPIO驱动API接口功能介绍
**表
1**
GPIO驱动API接口功能介绍
| 接口名 | 描述 |
| ------------------------------------------------------------ | ------------------------------ |
| GpioGetByName(const char
*
gpioName) | 获取GPIO管脚ID
|
| int32_t GpioRead(uint16_t gpio, uint16_t
*
val) | 读GPIO管脚电平值
|
| GpioGetByName(const char
\*
gpioName) | 获取GPIO管脚ID
|
| int32_t GpioRead(uint16_t gpio, uint16_t
\*
val) | 读GPIO管脚电平值
|
| int32_t GpioWrite(uint16_t gpio, uint16_t val) | 写GPIO管脚电平值 |
| int32_t GpioGetDir(uint16_t gpio, uint16_t
*
dir) | 获取GPIO管脚方向
|
| int32_t GpioGetDir(uint16_t gpio, uint16_t
\*
dir) | 获取GPIO管脚方向
|
| int32_t GpioSetDir(uint16_t gpio, uint16_t dir) | 设置GPIO管脚方向 |
| int32_t GpioUnsetIrq(uint16_t gpio, void
*
arg);
| 取消GPIO管脚对应的中断服务函数 |
| int32_t GpioSetIrq(uint16_t gpio, uint16_t mode, GpioIrqFunc func, void
*
arg) | 设置GPIO管脚对应的中断服务函数 |
| int32_t GpioUnsetIrq(uint16_t gpio, void
\*
arg)
| 取消GPIO管脚对应的中断服务函数 |
| int32_t GpioSetIrq(uint16_t gpio, uint16_t mode, GpioIrqFunc func, void
\
*
arg) | 设置GPIO管脚对应的中断服务函数 |
| int32_t GpioEnableIrq(uint16_t gpio) | 使能GPIO管脚中断 |
| int32_t GpioDisableIrq(uint16_t gpio) | 禁止GPIO管脚中断 |
...
...
@@ -70,11 +75,11 @@ GPIO模块提供的主要接口如表1所示。
### 开发步骤
GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如
下图
所示。
GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如
图2
所示。
**图
1
**
GPIO使用流程图
**图
2
**
GPIO使用流程图


#### 确定GPIO管脚号
...
...
@@ -116,15 +121,15 @@ GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流
int32_t
GpioSetDir
(
uint16_t
gpio
,
uint16_t
dir
);
```
**表2**
GpioSetDir参数和返回值描述
**表
2**
GpioSetDir参数和返回值描述
|
**参数**
|
**参数描述**
|
| ---------- | ------------------ |
| gpio
|
GPIO管脚号 |
| dir
| 待设置的方向值
|
| gpio
| uint16_t类型,
GPIO管脚号 |
| dir
| uint16_t类型,待设置的方向值
|
|
**返回值**
|
**返回值描述**
|
|
0 | 设置成功
|
| 负数
| 设置失败
|
|
HDF_SUCCESS | 设置GPIO管脚方向成功
|
| 负数
| 设置GPIO管脚方向失败
|
假设需要将GPIO管脚3的方向配置为输出,其使用示例如下:
...
...
@@ -132,8 +137,8 @@ int32_t GpioSetDir(uint16_t gpio, uint16_t dir);
int32_t
ret
;
ret
=
GpioSetDir
(
3
,
GPIO_DIR_OUT
);
// 将3号GPIO管脚配置为输出
if
(
ret
!=
0
)
{
HDF_LOGE
(
"GpioSetDir:
failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"GpioSetDir:
gpio set dir fail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
```
...
...
@@ -146,15 +151,15 @@ if (ret != 0) {
int32_t
GpioGetDir
(
uint16_t
gpio
,
uint16_t
*
dir
);
```
**表3**
GpioGetDir参数和返回值描述
**表
3**
GpioGetDir参数和返回值描述
|
**参数**
|
**参数描述**
|
| ---------- | ------------------ |
| gpio
|
GPIO管脚号 |
| dir
| 获取到的方向值指针
|
| gpio
| uint16_t类型,
GPIO管脚号 |
| dir
| uint16_t类型指针,获取到的方向值
|
|
**返回值**
|
**返回值描述**
|
|
0 | 设置成功
|
| 负数
| 设置失败
|
|
HDF_SUCCESS | 获取GPIO管脚方向成功
|
| 负数
| 获取GPIO管脚方向失败
|
假设需要获取GPIO管脚3的方向,其使用示例如下:
...
...
@@ -163,8 +168,8 @@ int32_t ret;
uin16_t
dir
;
ret
=
GpioGetDir
(
3
,
&
dir
);
// 获取3号GPIO管脚方向
if
(
ret
!=
0
)
{
HDF_LOGE
(
"GpioGetDir:
failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"GpioGetDir:
gpio get dir fail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
```
...
...
@@ -177,15 +182,15 @@ if (ret != 0) {
int32_t
GpioRead
(
uint16_t
gpio
,
uint16_t
*
val
);
```
**表4**
GpioRead参数和返回值描述
**表
4**
GpioRead参数和返回值描述
|
**参数**
|
**参数描述**
|
| ---------- | -------------------- |
| gpio
| GPIO管脚号
|
| val
| 接收读取电平值的指针
|
| gpio
| uint16_t类型,GPIO管脚号
|
| val
| uint16_t类型指针,接收读取电平值
|
|
**返回值**
|
**返回值描述**
|
|
0 | 读取成功
|
| 负数
| 读取失败
|
|
HDF_SUCCESS | 读取GPIO管脚电平值成功
|
| 负数
| 读取GPIO管脚电平值失败
|
假设需要读取GPIO管脚3的电平值,其使用示例如下:
...
...
@@ -194,8 +199,8 @@ int32_t ret;
uint16_t
val
;
ret
=
GpioRead
(
3
,
&
val
);
// 读取3号GPIO管脚电平值
if
(
ret
!=
0
)
{
HDF_LOGE
(
"GpioRead:
failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"GpioRead:
gpio read fail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
```
...
...
@@ -208,15 +213,15 @@ if (ret != 0) {
int32_t
GpioWrite
(
uint16_t
gpio
,
uint16_t
val
);
```
**表5**
GpioWrite参数和返回值描述
**表
5**
GpioWrite参数和返回值描述
|
**参数**
|
**参数描述**
|
| ---------- | ------------------ |
| gpio
|
GPIO管脚号 |
| val
| 待写入的电平值
|
| gpio
| uint16_t类型,
GPIO管脚号 |
| val
| uint16_t类型,待写入的电平值
|
|
**返回值**
|
**返回值描述**
|
|
0 | 写入成功
|
| 负数
| 写入失败
|
|
HDF_SUCCESS | 写入GPIO管脚电平值成功
|
| 负数
| 写入GPIO管脚电平值失败
|
假设需要给GPIO管脚3写入低电平值,其使用示例如下:
...
...
@@ -224,8 +229,8 @@ int32_t GpioWrite(uint16_t gpio, uint16_t val);
int32_t
ret
;
ret
=
GpioWrite
(
3
,
GPIO_VAL_LOW
);
// 给3号GPIO管脚写入低电平值
if
(
ret
!=
0
)
{
HDF_LOGE
(
"Gpio
Read: failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"Gpio
Write: gpio write fail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
```
...
...
@@ -238,17 +243,17 @@ if (ret != 0) {
int32_t
GpioSetIrq
(
uint16_t
gpio
,
uint16_t
mode
,
GpioIrqFunc
func
,
void
*
arg
);
```
**表6**
GpioSetIrq参数和返回值描述
**表
6**
GpioSetIrq参数和返回值描述
|
**参数**
|
**参数描述**
|
| ---------- | ------------------------ |
| gpio
| GPIO管脚号
|
| mode
| 中断触发模式
|
| func
| 中断服务程序
|
| arg
|
传递给中断服务程序的入参 |
| gpio
| uint16_t类型,GPIO管脚号
|
| mode
| uint16_t类型,中断触发模式
|
| func
| 函数指针,中断服务程序
|
| arg
| 无类型指针,
传递给中断服务程序的入参 |
|
**返回值**
|
**返回值描述**
|
|
0 | 设置成功
|
| 负数
| 设置失败
|
|
HDF_SUCCESS | 设置GPIO管脚中断成功
|
| 负数
| 设置GPIO管脚中断失败
|
>  **注意:**<br>
> 同一时间,只能为某个GPIO管脚设置一个中断服务函数,如果重复调用GpioSetIrq函数,则之前设置的中断服务函数会被取代。
...
...
@@ -261,15 +266,15 @@ int32_t GpioSetIrq(uint16_t gpio, uint16_t mode, GpioIrqFunc func, void *arg);
int32_t
GpioUnsetIrq
(
uint16_t
gpio
,
void
*
arg
);
```
**表7**
GpioUnsetIrq参数和返回值描述
**表
7**
GpioUnsetIrq参数和返回值描述
|
**参数**
|
**参数描述**
|
| ---------- | -------------- |
| gpio
| GPIO管脚号
|
| arg
| GPIO中断数据
|
| gpio
| uint16_t类型,GPIO管脚号
|
| arg
| 无类型指针,GPIO中断数据
|
|
**返回值**
|
**返回值描述**
|
|
0 | 取消成功
|
| 负数
| 取消失败
|
|
HDF_SUCCESS | 取消GPIO管脚中断成功
|
| 负数
| 取消GPIO管脚中断失败
|
#### 使能GPIO管脚中断
...
...
@@ -279,14 +284,14 @@ int32_t GpioUnsetIrq(uint16_t gpio, void *arg);
int32_t
GpioEnableIrq
(
uint16_t
gpio
);
```
**表8**
GpioEnableIrq参数和返回值描述
**表
8**
GpioEnableIrq参数和返回值描述
|
**参数**
|
**参数描述**
|
| ---------- | -------------- |
| gpio
| GPIO管脚号
|
| gpio
| uint16_t类型,GPIO管脚号
|
|
**返回值**
|
**返回值描述**
|
|
0 | 使能成功
|
| 负数
| 使能失败
|
|
HDF_SUCCESS | 使能GPIO管脚中断成功
|
| 负数
| 使能GPIO管脚中断失败
|
>  **注意:**<br>
> 必须通过此函数使能管脚中断,之前设置的中断服务函数才能被正确响应。
...
...
@@ -298,51 +303,51 @@ int32_t GpioEnableIrq(uint16_t gpio);
```
c
int32_t
GpioDisableIrq
(
uint16_t
gpio
);
```
**表9**
GpioDisableIrq参数和返回值描述
**表
9**
GpioDisableIrq参数和返回值描述
|
**参数**
|
**参数描述**
|
|
**参数**
|
**参数描述**
|
| ---------- | -------------- |
| gpio
| GPIO管脚号
|
| gpio
| uint16_t类型,GPIO管脚号
|
|
**返回值**
|
**返回值描述**
|
|
0 | 禁止成功
|
| 负数
| 禁止失败
|
|
HDF_SUCCESS | 禁止GPIO管脚中断成功
|
| 负数
| 禁止GPIO管脚中断失败
|
中断相关操作示例:
```
c
/
* 中断服务函数*/
/
/ 中断服务函数
int32_t
MyCallBackFunc
(
uint16_t
gpio
,
void
*
data
)
{
HDF_LOGI
(
"
%s: gpio:%u interrupt service in data
\n
"
,
__func__
,
gpio
);
return
0
;
HDF_LOGI
(
"
MyCallBackFunc: gpio:%u interrupt service in data.
\n
"
,
gpio
);
return
HDF_SUCCESS
;
}
int32_t
ret
;
/
* 设置中断服务程序为MyCallBackFunc,入参为NULL,中断触发模式为上升沿触发 */
/
/ 设置中断服务程序为MyCallBackFunc,入参为NULL,中断触发模式为上升沿触发
ret
=
GpioSetIrq
(
3
,
OSAL_IRQF_TRIGGER_RISING
,
MyCallBackFunc
,
NULL
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"GpioSetIrq:
failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"GpioSetIrq:
gpio set irq fail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
/
* 使能3号GPIO管脚中断 */
/
/ 使能3号GPIO管脚中断
ret
=
GpioEnableIrq
(
3
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"GpioEnableIrq:
failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"GpioEnableIrq:
gpio enable irq fail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
/
* 禁止3号GPIO管脚中断 */
/
/ 禁止3号GPIO管脚中断
ret
=
GpioDisableIrq
(
3
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"GpioDisableIrq:
failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"GpioDisableIrq:
gpio disable irqfail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
/
* 取消3号GPIO管脚中断服务程序 */
/
/ 取消3号GPIO管脚中断服务程序
ret
=
GpioUnsetIrq
(
3
,
NULL
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"GpioUnSetIrq:
failed, ret
%d
\n
"
,
ret
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"GpioUnSetIrq:
gpio unset irq fail, ret:
%d
\n
"
,
ret
);
return
ret
;
}
```
...
...
@@ -363,65 +368,66 @@ if (ret != 0) {
static
uint32_t
g_irqCnt
;
/
* 中断服务函数*/
/
/ 中断服务函数
static
int32_t
TestCaseGpioIrqHandler
(
uint16_t
gpio
,
void
*
data
)
{
HDF_LOGE
(
"
%s: irq triggered! on gpio:%u, in data"
,
__func__
,
gpio
);
g_irqCnt
++
;
/* 如果中断服务函数触发执行,则将全局中断计数加1 */
HDF_LOGE
(
"
TestCaseGpioIrqHandler: irq triggered! on gpio:%u, in data"
,
gpio
);
g_irqCnt
++
;
// 如果中断服务函数触发执行,则将全局中断计数加1
return
GpioDisableIrq
(
gpio
);
}
/
* 测试用例函数 */
/
/ 测试用例函数
static
int32_t
TestCaseGpioIrqEdge
(
void
)
{
int32_t
ret
;
uint16_t
valRead
;
uint16_t
mode
;
uint16_t
gpio
=
8
3
;
/* 待测试的GPIO管脚号 */
uint16_t
gpio
=
8
4
;
// 待测试的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
);
HDF_LOGE
(
"
TestCaseGpioIrqEdge: set dir fail! ret:%d
\n
"
,
ret
);
return
ret
;
}
/
* 先禁止该管脚中断 */
/
/ 先禁止该管脚中断
ret
=
GpioDisableIrq
(
gpio
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: disable irq fail! ret:%d
\n
"
,
__func__
,
ret
);
HDF_LOGE
(
"
TestCaseGpioIrqEdge: disable irq fail! ret:%d
\n
"
,
ret
);
return
ret
;
}
/
* 为管脚设置中断服务函数,触发模式为上升沿和下降沿共同触发 */
/
/ 为管脚设置中断服务函数,触发模式为上升沿和下降沿共同触发
mode
=
OSAL_IRQF_TRIGGER_RISING
|
OSAL_IRQF_TRIGGER_FALLING
;
HDF_LOGE
(
"
%s: mode:%0x
\n
"
,
__func__
,
mode
);
HDF_LOGE
(
"
TestCaseGpioIrqEdge: mode:%0x
\n
"
,
mode
);
ret
=
GpioSetIrq
(
gpio
,
mode
,
TestCaseGpioIrqHandler
,
NULL
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: set irq fail! ret:%d
\n
"
,
__func__
,
ret
);
HDF_LOGE
(
"
TestCaseGpioIrqEdge: set irq fail! ret:%d
\n
"
,
ret
);
return
ret
;
}
/
* 使能此管脚中断 */
/
/ 使能此管脚中断
ret
=
GpioEnableIrq
(
gpio
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: enable irq fail! ret:%d
\n
"
,
__func__
,
ret
);
HDF_LOGE
(
"
TestCaseGpioIrqEdge: enable irq fail! ret:%d
\n
"
,
ret
);
(
void
)
GpioUnsetIrq
(
gpio
,
NULL
);
return
ret
;
}
g_irqCnt
=
0
;
/* 清除全局计数器 */
timeout
=
0
;
/* 等待时间清零 */
/
* 等待此管脚中断服务函数触发,等待超时时间为1000毫秒 */
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 */
HDF_LOGE
(
"
TestCaseGpioIrqEdge: wait irq timeout:%u
\n
"
,
timeout
);
OsalMDelay
(
200
);
/
/ 等待中断触发
timeout
+=
200
;
}
(
void
)
GpioUnsetIrq
(
gpio
,
NULL
);
HDF_LOGI
(
"TestCaseGpioIrqEdge: function tests end, g_irqCnt:%u"
,
g_irqCnt
);
return
(
g_irqCnt
>
0
)
?
HDF_SUCCESS
:
HDF_FAILURE
;
}
```
zh-cn/device-dev/driver/driver-platform-gpio-develop.md
浏览文件 @
952ecd1c
...
...
@@ -20,15 +20,17 @@ GPIO又俗称为I/O口,I指的是输入(in),O指的是输出(out)。
### 运作机制
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式,则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。GPIO模块
接口适配模式
采用统一服务模式(如图1所示)。
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式,则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。GPIO模块采用统一服务模式(如图1所示)。
在统一模式下,所有的控制器都被核心层统一管理,并由核心层统一发布一个服务供接口层,因此这种模式下驱动无需再为每个控制器发布服务。
GPIO模块各分层作用:
-
接口层提供操作GPIO管脚的标准方法。
-
核心层主要提供GPIO管脚资源匹配,GPIO管脚控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互,供芯片厂家快速接入HDF框架。
-
适配层主要是将钩子函数的功能实例化,实现具体的功能。
-
接口层:提供操作GPIO管脚的标准方法。
-
核心层:提供GPIO管脚资源匹配,GPIO管脚控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互,供芯片厂家快速接入HDF框架。
-
适配层:由驱动适配者将钩子函数的功能实例化,实现与硬件相关的具体功能。
**图 1**
GPIO统一服务模式结构图
...
...
@@ -38,7 +40,7 @@ GPIO模块各分层作用:
### 场景介绍
GPIO
仅是一个软件层面的概念,主要工作是GPIO管脚资源管理。驱动开发者可以使用GPIO模块提供的操作接口,实现对管脚的
控制。当驱动开发者需要将GPIO适配到OpenHarmony时,需要进行GPIO驱动适配。下文将介绍如何进行GPIO驱动适配。
GPIO
主要是对GPIO管脚资源进行管理。驱动开发者可以使用GPIO模块提供的操作接口,实现对管脚的具体
控制。当驱动开发者需要将GPIO适配到OpenHarmony时,需要进行GPIO驱动适配。下文将介绍如何进行GPIO驱动适配。
### 接口说明
...
...
@@ -55,22 +57,22 @@ struct GpioMethod {
int32_t
(
*
setDir
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
,
uint16_t
dir
);
int32_t
(
*
getDir
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
,
uint16_t
*
dir
);
int32_t
(
*
toIrq
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
,
uint16_t
*
irq
);
// 【预留】
int32_t
(
*
setIrq
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
,
uint16_t
mode
,
GpioIrqFunc
func
,
void
*
arg
);
int32_t
(
*
setIrq
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
,
uint16_t
mode
);
int32_t
(
*
unsetIrq
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
);
int32_t
(
*
enableIrq
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
);
int32_t
(
*
disableIrq
)(
struct
GpioCntlr
*
cntlr
,
uint16_t
local
);
}
```
**表1**
GpioMethod结构体成员的钩子函数功能说明
**表
1**
GpioMethod结构体成员的钩子函数功能说明
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| -------- | -------- | -------- | -------- | -------- |
| write | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号
<br/>
val:uint16_t类型,电平传入值 | 无 | HDF_STATUS相关状态 | GPIO引脚写入电平值 |
| read | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识
| val:uint16_t类型指针,用于传出电平值。 | HDF_STATUS相关状态 | GPIO引脚读取电平值 |
| read | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识
号 | val:uint16_t类型指针,用于传出电平值。 | HDF_STATUS相关状态 | GPIO引脚读取电平值 |
| setDir | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号
<br/>
dir:uint16_t类型,管脚方向传入值 | 无 | HDF_STATUS相关状态 | 设置GPIO引脚输入/输出方向 |
| getDir | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号 | dir:uint16_t类型指针,用于传出管脚方向值 | HDF_STATUS相关状态 | 读GPIO引脚输入/输出方向 |
| setIrq | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号
<br/>
mode:uint16_t类型,表示触发模式(边沿或电平)
<br/>
func:函数指针,中断服务程序;
<br/>
arg:void指针,中断服务程序入参 | 无 | HDF_STATUS相关状态 | 将GPIO引脚设置为中断模式 |
| setIrq | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号
<br/>
mode:uint16_t类型,表示触发模式(边沿或电平)
| 无 | HDF_STATUS相关状态 | 将GPIO引脚设置为中断模式 |
| unsetIrq | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号 | 无 | HDF_STATUS相关状态 | 取消GPIO中断设置 |
| enableIrq | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号 | 无 | HDF_STATUS相关状态 | 使能GPIO管脚中断 |
| disableIrq | cntlr:结构体指针,核心层GPIO控制器
<br/>
local:uint16_t类型,GPIO端口标识号 | 无 | HDF_STATUS相关状态 | 禁止GPIO管脚中断 |
...
...
@@ -79,18 +81,22 @@ struct GpioMethod {
GPIO模块适配包含以下四个步骤:
-
实例化驱动入口。
-
配置属性文件。
-
实例化GPIO控制器对象。
-
驱动调试。
-
实例化驱动入口
-
配置属性文件
-
实例化GPIO控制器对象
-
驱动调试
### 开发实例
下方将基于Hi3516DV300开发板以//device_soc_hisilicon/common/platform/gpio/gpio_hi35xx.c驱动为示例,展示需要驱动适配者提供哪些内容来完整实现设备功能。
1.
实例化驱动入口
。
1.
实例化驱动入口
驱动入口必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
GPIO驱动入口开发参考:
...
...
@@ -99,16 +105,29 @@ GPIO模块适配包含以下四个步骤:
struct HdfDriverEntry g_gpioDriverEntry = {
.moduleVersion = 1,
.Bind = Pl061GpioBind, // GPIO不需要实现Bind,本例是一个空实现,驱动适配者可根据自身需要添加相关操作
.
Init
=
Pl061GpioInit
,
// 见Init参考
.
Release
=
Pl061GpioRelease
,
// 见Release参考
.Init = Pl061GpioInit, // 挂接Gpio模块Init实例化
.Release = Pl061GpioRelease, // 挂接Gpio模块Release实例化
.moduleName = "hisi_pl061_driver", // 【必要且需要与HCS文件中里面的moduleName匹配】
};
HDF_INIT(g_gpioDriverEntry); // 调用HDF_INIT将驱动入口注册到HDF框架中
```
2.
配置属性文件。
2.
配置属性文件
完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,deviceNode信息与驱动入口注册相关。本例以一个GPIO控制器为例,如有多个器件信息,则需要在device_info.hcs文件增加deviceNode信息,以及在gpio_config.hcs文件中增加对应的器件属性。器件属性值与核心层GpioCntlr成员的默认值或限制范围有密切关系,需要在gpio_config.hcs中配置器件属性。
完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,deviceNode信息与驱动入口注册相关。本例以一个GPIO控制器为例,如有多个器件信息,则需要在device_info.hcs文件增加deviceNode信息。器件属性值与核心层GpioCntlr成员的默认值或限制范围有密切关系,需要在gpio_config.hcs中配置器件属性。
统一服务模式的特点是device_info.hcs文件中第一个设备节点必须为GPIO管理器,其各项参数如表2所示:
**表 2** device_info.hcs节点参数说明
| 成员名 | 值 |
| -------- | -------- |
| policy | 驱动服务发布的策略,GPIO管理器具体配置为2,表示驱动对内核态和用户态都发布服务 |
| priority | 驱动启动优先级(0-200),值越大优先级越低。GPIO管理器具体配置为10 |
| permission | 驱动创建设备节点权限,GPIO管理器具体配置为0664 |
| moduleName | 驱动名称,GPIO管理器固定为HDF_PLATFORM_GPIO_MANAGER |
| serviceName | 驱动对外发布服务的名称,GPIO管理器服务名设置为HDF_PLATFORM_GPIO_MANAGER |
| deviceMatchAttr | 驱动私有数据匹配的关键字,GPIO管理器没有使用,可忽略 |
- device_info.hcs 配置参考:
...
...
@@ -122,12 +141,18 @@ GPIO模块适配包含以下四个步骤:
priority = 50;
device_gpio :: device {
device0 :: deviceNode {
policy = 2;
priority = 10;
permission = 0644;
moduleName = "HDF_PLATFORM_GPIO_MANAGER";
serviceName = "HDF_PLATFORM_GPIO_MANAGER";
}
device1 :: deviceNode {
policy = 0; // 等于0,不需要发布服务
priority = 10; // 驱动启动优先级
permission = 0644; // 驱动创建设备节点权限
moduleName = "hisi_pl061_driver"; // 【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致
deviceMatchAttr = "hisilicon_hi35xx_pl061"; // 【必要】用于配置控制器私有数据,要与gpio_config.hcs中
// 对应控制器保持一致,其他控制器信息也在文件中
deviceMatchAttr = "hisilicon_hi35xx_pl061"; // 【必要】用于配置控制器私有数据,要与gpio_config.hcs中对应控制器保持一致,其他控制器信息也在文件中
}
}
}
...
...
@@ -137,7 +162,7 @@ GPIO模块适配包含以下四个步骤:
- gpio_config.hcs配置参考:
在//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/gpio/gpio_config.hcs文件配置器件属性,其中配置参数如下:
此处以Hi3516DV300为例,给出HCS配置参考。其中部分字段为Hi3516DV300特有功能,驱动适配者可根据需要进行删除或添加字段。
```c
root {
...
...
@@ -152,7 +177,13 @@ GPIO模块适配包含以下四个步骤:
irqStart = 48; // 【必要】开启中断
irqShare = 0; // 【必要】共享中断
}
...
template gpio_info { // gpio_info模板
gpioCustomName = ""; // gpio管脚默认名称
}
GPIO0 :: gpio_info {
gpioCustomName = "GPIO0_0";
}
......
}
}
}
...
...
@@ -164,7 +195,9 @@ GPIO模块适配包含以下四个步骤:
#include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/gpio/gpio_config.hcs" // 配置文件相对路径
```
3.
实例化GPIO控制器对象。
本例基于Hi3516DV300开发板的小型系统LiteOS内核运行,对应的hdf.hcs文件路径为vendor/hisilicon/hispark_taurus/hdf_config/hdf.hcs以及//device/hisilicon/hispark_taurus/sdk_liteos/hdf_config/hdf.hcs。驱动适配者需根据实际情况选择对应路径下的文件进行修改。
3.
实例化GPIO控制器对象
完成驱动入口注册之后,下一步就是以核心层GpioCntlr对象的初始化为核心,包括驱动适配者自定义结构体(传递参数和数据),实例化GpioCntlr成员GpioMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
...
...
@@ -219,7 +252,7 @@ GPIO模块适配包含以下四个步骤:
};
```
-
GpioCntlr成员钩子函数结构体GpioMethod的实例化,其他成员在Init函数中初始
化。
- GpioCntlr成员钩子函数结构体GpioMethod的实例
化。
```c
//GpioMethod结构体成员都是钩子函数,驱动适配者需要根据表1完成相应的函数功能。
...
...
@@ -246,9 +279,9 @@ GPIO模块适配包含以下四个步骤:
返回值:
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见
//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS定义)。
HDF_STATUS相关状态(表3为部分展示,如需使用其他状态,可参考
//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS定义)。
**表2** Init函数
说明
**表 3** HDF_STATUS相关状态
说明
| 状态(值) | 问题描述 |
| -------- | -------- |
...
...
@@ -308,6 +341,11 @@ GPIO模块适配包含以下四个步骤:
(void)OsalSpinDestroy(&groups[i].lock);
goto ERR_EXIT;
}
ret = GpioDumperCreate(&pl061->groups[i]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: create dumper failed:%d", __func__, ret);
return ret;
}
}
return HDF_SUCCESS;
...
...
@@ -345,17 +383,17 @@ GPIO模块适配包含以下四个步骤:
if (pl061->groupNum > PL061_GROUP_MAX || pl061->groupNum <= 0 ||
pl061->bitNum > PL061_BIT_MAX || pl061->bitNum <= 0) {
HDF_LOGE("%s: err groupNum:%hu, bitNum:%hu", __func__, pl061->groupNum, pl0
61->bitNum);
HDF_LOGE("%s: err groupNum:%hu, bitNum:%hu", __func__, pl061->groupNum, pl0
61->bitNum);
return HDF_ERR_INVALID_PARAM;
}
pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep); //
地址映射
pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep); //
地址映射
if (pl061->regBase == NULL) {
HDF_LOGE("%s: err remap phy:0x%x", __func__, pl061->phyBase);
return HDF_ERR_IO;
}
ret = Pl061GpioInitGroups(pl061); //
group信息初始化,并添加到HDF核心层
ret = Pl061GpioInitGroups(pl061); //
group信息初始化,并添加到HDF核心层
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: err init groups:%d", __func__, ret);
OsalIoUnmap((void *)pl061->regBase);
...
...
@@ -437,6 +475,6 @@ GPIO模块适配包含以下四个步骤:
}
```
4.
驱动调试
。
4.
驱动调试
【可选】针对新增驱动程序,建议验证驱动基本功能,例如GPIO控制状态,中断响应情况等。
zh-cn/device-dev/driver/driver-platform-hdmi-des.md
浏览文件 @
952ecd1c
# HDMI
## 概述
### 功能简介
HDMI(High Definition Multimedia Interface),即高清多媒体接口,主要用于DVD、机顶盒等音视频Source到TV、显示器等Sink设备的传输。
HDMI以主从方式工作,通常有一个Source端和一个Sink端。
HDMI接口定义了完成HDMI传输的通用方法集合,包括:
-
HDMI控制器管理:打开或关闭HDMI控制器
-
HDMI启动/停止传输:启动或停止HDMI传输
-
HDMI控制器设置:设置音频、视频及HDR属性,设置色彩深度、声音图像消隐等
-
HDMI读取EDID:读取Sink端原始的EDID数据
-
HDMI热插拔:注册/注销热插拔回调函数
### 基本概念
...
...
@@ -20,25 +25,50 @@ HDMI接口定义了完成HDMI传输的通用方法集合,包括:
HDMI是Hitachi、Panasonic、Philips、Silicon Image、Sony、Thomson、Toshiba共同发布的一款音视频传输协议。传输过程遵循TMDS(Transition Minimized Differential Signaling)协议。
-
TMDS(Transition Minimized Differential signal):过渡调制差分信号,也被称为最小化传输差分信号,用于发送音频、视频及各种辅助数据。
-
DDC(Display Data Channel):显示数据通道,发送端与接收端可利用DDC通道得知彼此的发送与接收能力,但HDMI仅需单向获知接收端(显示器)的能力。
-
CEC(Consumer Electronics Control):消费电子控制,该功能应该能够在连接HDMI的发送设备与接收设备之间实现交互操作。
-
FRL(Fixed Rate Link):TMDS 的架构进行讯号传输时,最高带宽可达 18Gbps,而FRL模式的带宽则提升到48 Gbps。
-
HDCP(High-bandwidth Digital Content Protection):即高带宽数字内容保护技术,当用户对高清晰信号进行非法复制时,该技术会进行干扰,降低复制出来的影像的质量,从而对内容进行保护。
-
EDID(Extended Display Identification Data):扩展显示标识数据,通常存储在显示器的固件中,标识供应商信息、EDID版本信息、最大图像大小、颜色设置、厂商预设置、频率范围的限制以及显示器名和序列号的字符串。
### 运作机制
在HDF框架中,HDMI模块接口适配模式拟采用独立服务模式,如图1所示。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDF设备管理器的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
独立服务模式下,核心层不会统一发布一个服务供上层使用,因此这种模式下驱动要为每个控制器发布一个服务,具体表现为:
-
驱动适配者需要实现HdfDriverEntry的Bind钩子函数以绑定服务。
-
device_info.hcs文件中deviceNode的policy字段为1或2,不能为0。
**图 1**
HDMI独立服务模式结构图

HDMI模块各分层作用:
-
接口层提供打开HDMI设备、启动HDMI传输、停止HDMI传输、声音图像消隐设置、设置色彩深度、获取色彩深度、设置视频属性、获取视频属性、设置HDR属性、读取Sink端原始EDID数据、注册HDMI热插拔检测回调函数、注销HDMI热插拔检测回调函数、关闭HDMI设备的接口。
-
核心层主要提供HDMI控制器的打开、关闭及管理的能力,通过钩子函数与适配层交互。
-
适配层主要是将钩子函数的功能实例化,实现具体的功能。
HDMI的Source端提供+5V和GND,用于DDC和CEC通信。通过DDC通道,Source端可以读取Sink端的各项参数,如接受能力等;CEC为可选通道,用于同步Source端与Sink端的控制信号,改善用户体验。TMDS通道有四组差分信号,TMDS Clock Channel为TMDS提供时钟信号,其余三组传输音视频数据及各种辅助数据;HDP为热插拔检测端口,当有Sink端接入时,Source端会通过中断服务程序进行响应。
HDMI物理连接如图
1
所示:
HDMI物理连接如图
2
所示:
**图
1**
HDMI物理连线示意图
**图
2**
HDMI物理连线示意图


### 约束与限制
HDMI模块当前仅支持轻量和小型系统内核(LiteOS)。
HDMI模块当前仅支持轻量和小型系统内核(LiteOS)
,暂无实际适配驱动
。
## 使用指导
...
...
@@ -48,8 +78,9 @@ HDMI具有体积小,传输速率高,传输带宽宽,兼容性好,能同
### 接口说明
**表 1**
HDMI驱动API接口功能介绍
HDMI模块提供的主要接口如下所示,具体API详见//drivers/hdf_core/framework/include/platform/hdmi_if.h。
**表 1**
HDMI驱动API接口功能介绍
| 接口名 | 描述 |
| ----------------------------- | -------------------------- |
...
...
@@ -69,11 +100,11 @@ HDMI具有体积小,传输速率高,传输带宽宽,兼容性好,能同
### 开发步骤
使用HDMI设备的一般流程如图
2
所示。
使用HDMI设备的一般流程如图
3
所示。
**图
2**
HDMI设备使用流程图
**图
3**
HDMI设备使用流程图


#### 打开HDMI控制器
...
...
@@ -87,7 +118,7 @@ DevHandle HdmiOpen(int16_t number);
| 参数 | 参数描述 |
| ---------- | -------------------- |
| number
| HDMI控制器号
|
| number
| int16_t类型,HDMI控制器号
|
|
**返回值**
|
**返回值描述**
|
| NULL | 打开HDMI控制器失败 |
| 控制器句柄 | 打开的HDMI控制器句柄 |
...
...
@@ -95,13 +126,13 @@ DevHandle HdmiOpen(int16_t number);
假设系统中存在2个HDMI控制器,编号从0到1,以下代码示例为获取0号控制器:
```
c
DevHandle
hdmiHandle
=
NULL
;
/
* HDMI控制器句柄 /
DevHandle
hdmiHandle
=
NULL
;
/
/ HDMI控制器句柄
/
* 打开HDMI控制器 */
/
/ 打开HDMI控制器
hdmiHandle
=
HdmiOpen
(
0
);
if
(
hdmiHandle
==
NULL
)
{
HDF_LOGE
(
"HdmiOpen:
failed
\n
"
);
return
;
HDF_LOGE
(
"HdmiOpen:
hdmi open fail!
\n
"
);
return
NULL
;
}
```
...
...
@@ -115,16 +146,16 @@ int32_t HdmiRegisterHpdCallbackFunc(DevHandle handle, struct HdmiHpdCallbackInfo
| 参数 | 参数描述 |
| ---------- | ------------------ |
| handle
| HDMI控制器句柄
|
| callback
|
热插拔回调函数信息 |
| handle
| DevHandle类型,HDMI控制器句柄
|
| callback
| 结构体指针,
热插拔回调函数信息 |
|
**返回值**
|
**返回值描述**
|
|
0 | 注册成功
|
|
HDF_SUCCESS | 注册成功
|
| 负数 | 注册失败 |
注册热插拔检测回调函数示例:
```
c
/
* 热插拔检测回调函数定义 */
/
/ 热插拔检测回调函数定义
static
void
HdmiHpdHandle
(
void
*
data
,
bool
hpd
)
{
if
(
data
==
NULL
)
{
...
...
@@ -133,23 +164,22 @@ static void HdmiHpdHandle(void *data, bool hpd)
}
if
(
hpd
==
true
)
{
HDF_LOGD
(
"HdmiHpdHandle: hot plug"
);
/
* 调用者添加相关处理 */
/
/ 调用者添加相关处理
}
else
{
HDF_LOGD
(
"HdmiHpdHandle: hot unplug"
);
/
* 调用者添加相关处理 */
/
/ 调用者添加相关处理
}
}
/* 热插拔检测回调函数注册示例 */
···
// 热插拔检测回调函数注册示例
struct
HdmiHpdCallbackInfo
info
=
{
0
};
info
.
data
=
handle
;
info
.
callbackFunc
=
HdmiHpdHandle
;
ret
=
HdmiRegisterHpdCallbackFunc
(
hdmiHandle
,
info
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"HdmiRegisterHpdCallbackFunc: Register failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiRegisterHpdCallbackFunc: Register hpd callback func fail, ret:%d"
,
ret
);
return
ret
;
}
···
```
#### 读取EDID
...
...
@@ -162,9 +192,9 @@ int32_t HdmiReadSinkEdid(DevHandle handle, uint8_t *buffer, uint32_t len);
| 参数 | 参数描述 |
| ---------- | ---------------------- |
| handle
| HDMI控制器句柄
|
| buffer
| 数据缓冲区
|
| len
| 数据长度
|
| handle
| DevHandle类型,HDMI控制器句柄
|
| buffer
| uint8_t类型指针,数据缓冲区
|
| len
| uint32_t类型,数据长度
|
|
**返回值**
|
**返回值描述**
|
| 正整数 | 成功读取的原始EDID数据 |
| 负数或0 | 读取失败 |
...
...
@@ -177,7 +207,8 @@ uint8_t edid[HDMI_EDID_MAX_LEN] = {0};
len
=
HdmiReadSinkEdid
(
hdmiHandle
,
edid
,
HDMI_EDID_MAX_LEN
);
if
(
len
<=
0
)
{
HDF_LOGE
(
"%s: HdmiReadSinkEdid failed len = %d."
,
__func__
,
len
);
HDF_LOGE
(
"HdmiReadSinkEdid: hdmi read sink edid fail, len = %d."
,
len
);
return
HDF_FAILURE
;
}
```
...
...
@@ -189,13 +220,12 @@ int32_t HdmiSetAudioAttribute(DevHandle handle, struct HdmiAudioAttr *attr);
**表 5**
HdmiSetAudioAttribute参数和返回值描述
| 参数 | 参数描述 |
| ------ | -------------- |
| handle | HDMI控制器句柄 |
| attr
| 音频属性
|
| handle |
DevHandle类型,
HDMI控制器句柄 |
| attr
| 结构体指针,音频属性
|
| 返回值 | 返回值描述 |
|
0 | 设置成功
|
|
HDF_SUCCESS | 设置成功
|
| 负数 | 设置失败 |
设置音频属性示例:
...
...
@@ -210,8 +240,9 @@ audioAttr.bitDepth = HDMI_ADIO_BIT_DEPTH_16;
audioAttr
.
sampleRate
=
HDMI_SAMPLE_RATE_8K
;
audioAttr
.
channels
=
HDMI_AUDIO_FORMAT_CHANNEL_3
;
ret
=
HdmiSetAudioAttribute
(
handle
,
&
audioAttr
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"HdmiSetAudioAttribute failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiSetAudioAttribute: hdmi set audio attribute fail!, ret:%d"
,
ret
);
return
ret
;
}
```
...
...
@@ -223,13 +254,12 @@ int32_t HdmiSetVideoAttribute(DevHandle handle, struct HdmiVideoAttr *attr);
**表 6**
HdmiSetVideoAttribute参数和返回值描述
| 参数 | 参数描述 |
| 参数| 参数描述|
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| attr
| 视频属性
|
| handle
| DevHandle类型,
HDMI控制器句柄 |
| attr
| 结构体指针,视频属性
|
|
**返回值**
|
**返回值描述**
|
|
0 | 设置成功
|
|
HDF_SUCCESS | 设置成功
|
| 负数 | 设置失败 |
设置视频属性示例:
...
...
@@ -243,8 +273,9 @@ videoAttr.colorimetry = HDMI_COLORIMETRY_EXTENDED;
videoAttr
.
extColorimetry
=
HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM
;
videoAttr
.
quantization
=
HDMI_QUANTIZATION_RANGE_FULL
;
ret
=
HdmiSetVideoAttribute
(
handle
,
&
videoAttr
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"HdmiSetVideoAttribute failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiSetVideoAttribute: hdmi set video attribute fail, ret:%d."
,
ret
);
return
ret
;
}
```
...
...
@@ -256,13 +287,12 @@ int32_t HdmiSetHdrAttribute(DevHandle handle, struct HdmiHdrAttr *attr);
**表 7**
HdmiSetHdrAttribute参数和返回值描述
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| attr
| HDR属性
|
| handle
| DevHandle类型,
HDMI控制器句柄 |
| attr
| 结构体指针,HDR属性
|
|
**返回值**
|
**返回值描述**
|
|
0 | 设置成功
|
|
HDF_SUCCESS | 设置成功
|
| 负数 | 设置失败 |
设置HDR属性示例:
...
...
@@ -277,8 +307,9 @@ hdrAttr.eotfType = HDMI_EOTF_SMPTE_ST_2048;
hdrAttr
.
metadataType
=
HDMI_DRM_STATIC_METADATA_TYPE_1
;
hdrAttr
.
colorimetry
=
HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_709
;
ret
=
HdmiSetHdrAttribute
(
handle
,
&
hdrAttr
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"HdmiSetHdrAttribute failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiSetHdrAttribute: hdmi set hdr attribute fail, ret:%d"
,
ret
);
return
ret
;
}
```
...
...
@@ -290,13 +321,12 @@ int32_t HdmiAvmuteSet(DevHandle handle, bool enable);
**表 8**
HdmiAvmuteSet参数和返回值描述
| 参数 | 参数描述 |
| ---------- | ----------------- |
| handle
| HDMI控制器句柄
|
| enable
|
使能/去使能avmute |
| handle
| DevHandle类型,HDMI控制器句柄
|
| enable
| 布尔值,
使能/去使能avmute |
|
**返回值**
|
**返回值描述**
|
|
0 | 设置成功
|
|
HDF_SUCCESS | 设置成功
|
| 负数 | 设置失败 |
设置声音图像消隐示例:
...
...
@@ -305,8 +335,9 @@ int32_t HdmiAvmuteSet(DevHandle handle, bool enable);
int32_t
ret
;
ret
=
HdmiAvmuteSet
(
hdmiHandle
,
true
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"HdmiAvmuteSet failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiAvmuteSet: hdmi avmute set fail, ret:%d"
,
ret
);
return
ret
;
}
```
...
...
@@ -318,13 +349,12 @@ int32_t HdmiDeepColorSet(DevHandle handle, enum HdmiDeepColor color);
**表 9**
HdmiDeepColorSet参数和返回值描述
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| color
| 色彩深度
|
| handle
| DevHandle类型,
HDMI控制器句柄 |
| color
| 枚举类型,色彩深度
|
|
**返回值**
|
**返回值描述**
|
|
0 | 设置成功
|
|
HDF_SUCCESS | 设置成功
|
| 负数 | 设置失败 |
设置色彩深度示例:
...
...
@@ -333,8 +363,9 @@ int32_t HdmiDeepColorSet(DevHandle handle, enum HdmiDeepColor color);
int32_t
ret
;
ret
=
HdmiDeepColorSet
(
handle
,
HDMI_DEEP_COLOR_48BITS
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"HdmiDeepColorSet failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiDeepColorSet: hdmi deep color set fail, ret:%d."
,
ret
);
return
ret
;
}
```
...
...
@@ -346,13 +377,12 @@ int32_t HdmiDeepColorGet(DevHandle handle, enum HdmiDeepColor *color);
**表 10**
HdmiDeepColorGet参数和返回值描述
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| color
| 色彩深度
|
| handle
| DevHandle类型,
HDMI控制器句柄 |
| color
| 枚举类型指针,色彩深度
|
|
**返回值**
|
**返回值描述**
|
|
0 | 获取成功
|
|
HDF_SUCCESS | 获取成功
|
| 负数 | 获取失败 |
获取色彩深度示例:
...
...
@@ -362,8 +392,9 @@ enum HdmiDeepColor color;
int32_t
ret
;
ret
=
HdmiDeepColorGet
(
handle
,
&
color
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"HdmiDeepColorGet failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiDeepColorGet: hdmi deep color get fail, ret:%d"
,
ret
);
return
ret
;
}
```
...
...
@@ -375,12 +406,11 @@ int32_t HdmiStart(DevHandle handle);
**表 11**
HdmiStart参数和返回值描述
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| handle
| DevHandle类型,
HDMI控制器句柄 |
|
**返回值**
|
**返回值描述**
|
|
0 | 启动成功
|
|
HDF_SUCCESS | 启动成功
|
| 负数 | 启动失败 |
启动HDMI传输示例:
...
...
@@ -389,8 +419,9 @@ int32_t HdmiStart(DevHandle handle);
int32_t
ret
;
ret
=
HdmiStart
(
hdmiHandle
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"start transmission failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiStart: start transmission fail, ret:%d"
,
ret
);
return
ret
;
}
```
...
...
@@ -402,12 +433,11 @@ int32_t HdmiStop(DevHandle handle);
**表 12**
HdmiStop参数和返回值描述
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| handle
| DevHandle类型,
HDMI控制器句柄 |
|
**返回值**
|
**返回值描述**
|
|
0 | 停止成功
|
|
HDF_SUCCESS | 停止成功
|
| 负数 | 停止失败 |
停止HDMI传输示例:
...
...
@@ -416,8 +446,9 @@ int32_t HdmiStop(DevHandle handle);
int32_t
ret
;
ret
=
HdmiStop
(
hdmiHandle
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"stop transmission failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiStop: stop transmission fail, ret:%d."
,
ret
);
return
ret
;
}
```
...
...
@@ -429,12 +460,11 @@ int32_t HdmiUnregisterHpdCallbackFunc(DevHandle handle);
**表 13**
HdmiUnregisterHpdCallbackFunc参数和返回值描述
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| handle
| DevHandle类型,
HDMI控制器句柄 |
|
**返回值**
|
**返回值描述**
|
|
0 | 注销成功
|
|
HDF_SUCCESS | 注销成功
|
| 负数 | 注销失败 |
注销热插拔检测回调函数示例:
...
...
@@ -443,8 +473,9 @@ int32_t HdmiUnregisterHpdCallbackFunc(DevHandle handle);
int32_t
ret
;
ret
=
HdmiUnregisterHpdCallbackFunc
(
hdmiHandle
);
if
(
ret
!=
0
)
{
HDF_LOGE
(
"unregister failed."
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"HdmiUnregisterHpdCallbackFunc:unregister fail, ret:%d."
,
ret
);
return
ret
;
}
```
...
...
@@ -456,10 +487,9 @@ void HdmiClose(DevHandle handle);
**表 14**
HdmiClose参数和返回值描述
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
HDMI控制器句柄 |
| handle
| DevHandle类型,
HDMI控制器句柄 |
关闭HDMI控制器示例:
...
...
zh-cn/device-dev/driver/driver-platform-hdmi-develop.md
浏览文件 @
952ecd1c
# HDMI
## 概述
### 功能简介
...
...
@@ -19,18 +18,25 @@ HDMI(High Definition Multimedia Interface),即高清多媒体接口,是H
-
HDCP(High-bandwidth Digital Content Protection):即高带宽数字内容保护技术,当用户对高清晰信号进行非法复制时,该技术会进行干扰,降低复制出来的影像的质量,从而对内容进行保护。
### 运作机制
在HDF框架中,HDMI的接口适配模式采用独立服务模式(如图1)。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用率。
在HDF框架中,HDMI的接口适配模式拟采用独立服务模式(如图1)。在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用率。
HDMI模块各分层作用:
-
接口层提供打开HDMI设备、启动HDMI传输、停止HDMI传输、声音图像消隐设置、设置色彩深度、获取色彩深度、设置视频属性、获取视频属性、设置HDR属性、读取Sink端原始EDID数据、注册HDMI热插拔检测回调函数、注销HDMI热插拔检测回调函数、关闭HDMI设备的接口。
-
核心层主要提供HDMI控制器的打开、关闭及管理的能力,通过钩子函数与适配层交互。
**图 1**
HDMI独立服务模式
-
适配层主要是将钩子函数的功能实例化,实现具体的功能。

**图 1**
HDMI独立服务模式

### 约束与限制
HDMI模块当前仅支持轻量和小型系统内核(LiteOS)
。
HDMI模块当前仅支持轻量和小型系统内核(LiteOS)
,暂无实际适配驱动
。
## 开发指导
...
...
@@ -41,6 +47,7 @@ HDMI具有体积小、传输速率高、传输带宽宽、兼容性好、能同
### 接口说明
HdmiCntlrOps定义:
```
c
struct
HdmiCntlrOps
{
void
(
*
hardWareInit
)(
struct
HdmiCntlr
*
cntlr
);
...
...
@@ -80,7 +87,7 @@ struct HdmiCntlrOps {
};
```
**表1**
HdmiCntlrOps结构体成员的回调函数功能说明
**表
1**
HdmiCntlrOps结构体成员的回调函数功能说明
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| ------------------------ | ------------------------------------------------------------ | -------------------------------------- | ------------------ | -------------------------------------------------- |
...
...
@@ -120,20 +127,30 @@ struct HdmiCntlrOps {
### 开发步骤
HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以及实例化HDMI控制器对象。
HDMI模块适配包含以下四个步骤:
-
实例化驱动入口
-
实例化驱动入口:
-
实例化HdfDriverEntry结构体成员。
-
调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
配置属性文件:
-
配置属性文件
-
在device_info.hcs文件中添加deviceNode描述。
-
【可选】添加hdmi_config.hcs器件属性文件。
-
实例化HDMI控制器对象:
-
实例化HDMI控制器对象
-
初始化HdmiCntlr成员。
-
实例化HdmiCntlr成员HdmiCntlrOps方法集合。
-
驱动调试
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,HDMI传输等。
1.
实例化驱动入口
驱动入口必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
...
...
@@ -148,16 +165,14 @@ HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以
.
Bind
=
HdmiAdapterBind
,
.
Init
=
HdmiAdapterInit
,
.
Release
=
HdmiAdapterRelease
,
.
moduleName
=
"adapter_hdmi_driver"
,
//【必要】与HCS里面的名字匹配
.
moduleName
=
"adapter_hdmi_driver"
,
// 【必要且与HCS文件中里面的moduleName匹配】
};
HDF_INIT
(
g_hdmiDriverEntry
);
// 调用HDF_INIT将驱动入口注册到HDF框架中
```
2.
配置属性文件
完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在hdmi_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层HdmiCntlr相关成员的默认值或限制范围有密切关系。
从第一个节点开始配置具体HDMI控制器信息,此节点并不表示某一路HDMI控制器,而是代表一个资源性质设备,用于描述一类HDMI控制器的信息。本例只有一个HDMI控制器,如有多个控制器,则需要在device_info文件增加deviceNode信息,以及在hdmi_config文件中增加对应的器件属性。
完成驱动入口注册之后,下一步请在device_info.hcs文件中添加deviceNode信息,并在hdmi_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于厂商驱动的实现以及核心层HdmiCntlr相关成员的默认值或限制范围有密切关系。从第一个节点开始配置具体HDMI控制器信息,此节点并不表示某一路HDMI控制器,而是代表一个资源性质设备,用于描述一类HDMI控制器的信息。本例只有一个HDMI控制器,如有多个控制器,则需要在device_info文件增加deviceNode信息,以及在hdmi_config文件中增加对应的器件属性。
-
device_info.hcs配置参考
...
...
@@ -227,7 +242,7 @@ HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以
}
```
3.
实例化控制器对象
3.
实例化
HDMI
控制器对象
最后一步,完成驱动入口注册之后,要以核心层HdmiCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化HdmiCntlr成员HdmiCntlrOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
...
...
@@ -245,7 +260,6 @@ HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以
uint32_t
irqNum
;
//【必要】中断号
};
/* HdmiCntlr是核心层控制器结构体,其中的成员在Init函数中被赋值。 */
struct
HdmiCntlr
{
struct
IDeviceIoService
service
;
struct
HdfDeviceObject
*
hdfDevObj
;
...
...
@@ -320,16 +334,17 @@ HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以
**返回值:**
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)
HDF_STATUS相关状态 (表2为部分展示,如需使用其他状态,可参考//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS的定义)。
**表 2**
HDF_STATUS相关状态说明
|状态(值)|状态描述|
|:-|:-|
|HDF_ERR_INVALID_OBJECT|控制器对象非法|
|HDF_ERR_INVALID_PARAM |参数非法|
|HDF_ERR_MALLOC_FAIL |内存分配失败|
|HDF_ERR_IO |I/O错误|
|HDF_SUCCESS |传输成功|
|HDF_FAILURE |传输失败|
| 状态(值) | 问题描述 |
| -------- | -------- |
| HDF_ERR_INVALID_OBJECT | 控制器对象非法 |
| HDF_ERR_MALLOC_FAIL | 内存分配失败 |
| HDF_ERR_IO | I/O
错误 |
| HDF_SUCCESS | 初始化成功 |
| HDF_FAILURE | 初始化失败 |
**函数说明:**
...
...
@@ -358,13 +373,13 @@ HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以
cntlr
->
hdfDevObj
=
obj
;
//【必要】使HdfDeviceObject与HdmiCntlr可以相互转化的前提
obj
->
service
=
&
cntlr
->
service
;
//【必要】使HdfDeviceObject与HdmiCntlr可以相互转化的前提
ret
=
HdmiAdapterCntlrParse
(
cntlr
,
obj
);
//【必要】初始化cntlr,失败则goto __ERR。
...
...
...
ret
=
HdmiAdapterHostParse
(
host
,
obj
);
//【必要】初始化host对象的相关属性,失败则goto __ERR。
...
...
...
ret
=
HdmiAdapterHostInit
(
host
,
cntlr
);
// 厂商自定义的初始化,失败则goto __ERR。
...
...
...
ret
=
HdmiCntlrAdd
(
cntlr
);
// 调用核心层函数,失败则goto __ERR。
...
...
...
HDF_LOGD
(
"HdmiAdapterBind: success."
);
return
HDF_SUCCESS
;
__ERR:
...
...
@@ -416,11 +431,13 @@ HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以
static
void
HdmiAdapterRelease
(
struct
HdfDeviceObject
*
obj
)
{
struct
HdmiCntlr
*
cntlr
=
NULL
;
...
...
...
cntlr
=
(
struct
HdmiCntlr
*
)
obj
->
service
;
// 这里有HdfDeviceObject到HdmiCntlr的强制转化,通过service成员,赋值见Bind函数。
...
...
...
HimciDeleteHost
((
struct
HimciAdapterHost
*
)
cntlr
->
priv
);
// 厂商自定义的内存释放函数,这里有HdmiCntlr到HimciAdapterHost的强制转化。
}
```
4.
驱动调试
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,HDMI传输等。
zh-cn/device-dev/driver/driver-platform-i2c-des.md
浏览文件 @
952ecd1c
# I2C
## 概述
### 功能简介
...
...
@@ -16,12 +15,14 @@ I2C数据的传输必须以一个起始信号作为开始条件,以一个结
I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。
I2C接口定义了完成I2C传输的通用方法集合,包括:
-
I2C控制器管理:打开或关闭I2C控制器
-
I2C消息传输:通过消息传输结构体数组进行自定义传输
**图
1** I2C物理连线示意图
**图
1**
I2C物理连线示意图


## 使用指导
...
...
@@ -33,7 +34,7 @@ I2C通常用于与各类支持I2C协议的传感器、执行器或输入输出
I2C模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/i2c_if.h。
**表1**
I2C驱动API接口功能介绍
**表
1**
I2C驱动API接口功能介绍
| 接口名 | 接口描述 |
| -------- | -------- |
...
...
@@ -45,9 +46,9 @@ I2C模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/
使用I2C设备的一般流程如下图所示。
**图2**
I2C设备使用流程图
**图
2**
I2C设备使用流程图


#### 打开I2C控制器
...
...
@@ -58,11 +59,11 @@ I2C模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/
DevHandle
I2cOpen
(
int16_t
number
);
```
**表
2**
I2cOpen参数和返回值描述
**表
2**
I2cOpen参数和返回值描述
|
**参数**
|
**参数描述**
|
| -------- | -------- |
| number | I2C控制器号 |
| number |
int16_t类型,
I2C控制器号 |
|
**返回值**
|
**返回值描述**
|
| NULL | 打开I2C控制器失败 |
| 设备句柄 | 打开的I2C控制器设备句柄 |
...
...
@@ -70,57 +71,55 @@ DevHandle I2cOpen(int16_t number);
假设系统中存在8个I2C控制器,编号从0到7,以下代码示例为获取3号控制器:
```
c
DevHandle
i2cHandle
=
NULL
;
/
* I2C控制器句柄 /
DevHandle
i2cHandle
=
NULL
;
/
/ I2C控制器句柄
/
* 打开I2C控制器 */
/
/ 打开I2C控制器
i2cHandle
=
I2cOpen
(
3
);
if
(
i2cHandle
==
NULL
)
{
HDF_LOGE
(
"I2cOpen:
failed
\n
"
);
return
;
HDF_LOGE
(
"I2cOpen:
i2c open fail.
\n
"
);
return
NULL
;
}
```
#### 进行I2C通信
消息传输
```
c
int32_t
I2cTransfer
(
DevHandle
handle
,
struct
I2cMsg
\
*
msgs
,
int16_t
count
);
int32_t
I2cTransfer
(
DevHandle
handle
,
struct
I2cMsg
*
msgs
,
int16_t
count
);
```
**表
3**
I2cTransfer参数和返回值描述
**表
3**
I2cTransfer参数和返回值描述
|
**参数**
|
**参数描述**
|
| -------- | -------- |
| handle | I2C控制器设备句柄 |
| msgs | 待传输数据的消息结构体数组 |
| count | 消息数组长度 |
| handle |
DevHandle类型,
I2C控制器设备句柄 |
| msgs |
结构体指针,
待传输数据的消息结构体数组 |
| count |
int16_t类型,
消息数组长度 |
|
**返回值**
|
**返回值描述**
|
| 正整数 | 成功传输的消息结构体数目 |
| 负数 | 执行失败 |
I2C传输消息类型为I2cMsg,每个传输消息结构体表示一次读或写,通过一个消息数组,可以执行若干次的读写组合操作。组合读写示例:
```
c
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 */
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
;
HDF_LOGE
(
"I2cTransfer:
i2c transfer fail, ret:
%d
\n
"
,
ret
);
return
HDF_FAILURE
;
}
```
...
...
@@ -142,19 +141,18 @@ I2C通信完成之后,需要关闭I2C控制器,关闭函数如下所述:
void
I2cClose
(
DevHandle
handle
);
```
**表
4**
I2cClose参数和返回值描述
**表
4**
I2cClose参数和返回值描述
| 参数 | 参数描述 |
| -------- | -------- |
| handle | I2C控制器设备句柄 |
| handle |
DevHandle类型,
I2C控制器设备句柄 |
关闭I2C控制器示例:
```
c
I2cClose
(
i2cHandle
);
/
* 关闭I2C控制器 */
I2cClose
(
i2cHandle
);
/
/ 关闭I2C控制器
```
### 使用示例
本例程以操作开发板上的I2C设备为例,详细展示I2C接口的完整使用流程。
...
...
zh-cn/device-dev/driver/driver-platform-i2c-develop.md
浏览文件 @
952ecd1c
...
...
@@ -15,11 +15,14 @@ I2C(Inter Integrated Circuit)总线是由Philips公司开发的一种简单
I2C模块各分层的作用为:
-
接口层:提供打开设备,数据传输以及关闭设备的能力。
-
核心层:主要负责服务绑定、初始化以及释放管理器,并提供添加、删除以及获取控制器的能力。
-
适配层:由驱动适配者实现与硬件相关的具体功能,如控制器的初始化等。
**图1**
I2C统一服务模式结构图
<a
name=
"fig1"
></a>

**图 1**
I2C统一服务模式结构图
<a
name=
"fig1"
></a>

## 使用指导
...
...
@@ -71,13 +74,13 @@ static const struct I2cLockMethod g_i2cLockOpsDefault = {
若实际情况不允许使用mutex(例如使用者可能在中断上下文调用I2C接口,mutex可能导致休眠,而中断上下文不允许休眠)时,驱动适配者可以考虑使用其他类型的锁来实现一个自定义的I2cLockMethod。一旦实现了自定义的I2cLockMethod,默认的I2cLockMethod将被覆盖。
**表
1**
I2cMethod结构体成员函数功能说明
**表
1**
I2cMethod结构体成员函数功能说明
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| -------- | -------- | -------- | -------- | -------- |
| transfer | cntlr:结构体指针,核心层I2C控制器。
<br>
msgs:结构体指针,用户消息。
<br>
count:uint16_t,消息数量。 | 无 | HDF_STATUS相关状态 | 传递用户消息 |
| transfer | cntlr:结构体指针,核心层I2C控制器。
<br>
msgs:结构体指针,用户消息。
<br>
count:uint16_t
类型
,消息数量。 | 无 | HDF_STATUS相关状态 | 传递用户消息 |
**表
2**
I2cLockMethod结构体成员函数功能说明
**表
2**
I2cLockMethod结构体成员函数功能说明
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| -------- | -------- | -------- | -------- | -------- |
...
...
@@ -86,22 +89,26 @@ static const struct I2cLockMethod g_i2cLockOpsDefault = {
### 开发步骤
I2C模块适配
的三个必选环节是实例化驱动入口,配置属性文件,以及实例化核心层接口函数。
I2C模块适配
包含以下四个步骤:
1.
实例化驱动入口
- 实例化HdfDriverEntry结构体成员。
- 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
2.
配置属性文件
- 在device_info.hcs文件中添加deviceNode描述。
- 【可选】添加i2c_config.hcs器件属性文件。
3.
实例化I2C控制器对象
- 初始化I2cCntlr成员。
- 实例化I2cCntlr成员I2cMethod和I2cLockMethod。
>  **说明:**<br>
> 实例化I2cCntlr成员I2cMethod和I2cLockMethod,详见[接口说明](#接口说明)。
...
...
@@ -113,7 +120,7 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
下方将以Hi3516DV300的驱动//device/soc/hisilicon/common/platform/i2c/i2c_hi35xx.c为示例,展示需要驱动适配者提供哪些内容来完整实现设备功能。
1.
驱动开发首先需要实例化驱动入口。
1.
实例化驱动入口
驱动入口必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
...
...
@@ -134,7 +141,7 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
};
HDF_INIT(g_i2cDriverEntry); // 调用HDF_INIT将驱动入口注册到HDF框架中
/
* 核心层i2c_core.c管理器服务的驱动入口 */
/
/ 核心层i2c_core.c管理器服务的驱动入口
struct HdfDriverEntry g_i2cManagerEntry = {
.moduleVersion = 1,
.Bind = I2cManagerBind,
...
...
@@ -145,20 +152,24 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
HDF_INIT(g_i2cManagerEntry);
```
2.
完成驱动入口注册之后,下一步请在//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode信息,并在i2c_config.hcs中配置器件属性。
2.
配置属性文件
完成驱动入口注册之后,下一步请在//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode信息,并在i2c_config.hcs中配置器件属性。
deviceNode信息与驱动入口注册相关,器件属性值对于驱动适配者的驱动实现以及核心层I2cCntlr相关成员的默认值或限制范围有密切关系。
统一服务模式的特点是device_info.hcs文件中第一个设备节点必须为I2C管理器,其各项参数必须如表2
设置:
统一服务模式的特点是device_info.hcs文件中第一个设备节点必须为I2C管理器,其各项参数必须如表3
设置:
**表3** 统一服务模式的特点
**表 3** device_info.hcs节点参数说明
| 成员名 | 值 |
| -------- | -------- |
| moduleName | 固定为HDF_PLATFORM_I2C_MANAGER |
| serviceName | 固定为HDF_PLATFORM_I2C_MANAGER |
| policy | 具体配置为1或2取决于是否对用户态可见 |
| deviceMatchAttr | 没有使用,可忽略 |
| policy | 驱动服务发布的策略,I2C管理器具体配置为2,表示驱动对内核态和用户态都发布服务 |
| priority | 驱动启动优先级(0-200),值越大优先级越低。I2C管理器具体配置为50 |
| permission | 驱动创建设备节点权限,I2C管理器具体配置为0664 |
| moduleName | 驱动名称,I2C管理器固定为HDF_PLATFORM_I2C_MANAGER |
| serviceName | 驱动对外发布服务的名称,I2C管理器服务名设置为HDF_PLATFORM_I2C_MANAGER |
| deviceMatchAttr | 驱动私有数据匹配的关键字,I2C管理器设置为hdf_platform_i2c_manager |
从第二个节点开始配置具体I2C控制器信息,此节点并不表示某一路I2C控制器,而是代表一个资源性质设备,用于描述一类I2C控制器的信息。多个控制器之间相互区分的参数是busId和reg_pbase,这在i2c_config.hcs文件中有所体现。
...
...
@@ -197,14 +208,14 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
root {
platform {
i2c_config {
match_attr = "hisilicon_hi35xx_i2c"; //
【必要】需要和device_info.hcs中的deviceMatchAttr值一致
match_attr = "hisilicon_hi35xx_i2c"; //
【必要】需要和device_info.hcs中的deviceMatchAttr值一致
template i2c_controller { // 模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省。
bus = 0; //
【必要】i2c识别号
reg_pbase = 0x120b0000; //
【必要】物理基地址
reg_size = 0xd1; //
【必要】寄存器位宽
irq = 0; //
【可选】中断号,由控制器的中断特性决定是否需要
freq = 400000; //
【可选】频率,初始化硬件控制器的可选参数
clk = 50000000; //
【可选】控制器时钟,由控制器时钟的初始化流程决定是否需要
bus = 0; //
【必要】i2c识别号
reg_pbase = 0x120b0000; //
【必要】物理基地址
reg_size = 0xd1; //
【必要】寄存器位宽
irq = 0; //
【可选】中断号,由控制器的中断特性决定是否需要
freq = 400000; //
【可选】频率,初始化硬件控制器的可选参数
clk = 50000000; //
【可选】控制器时钟,由控制器时钟的初始化流程决定是否需要
}
controller_0x120b0000 :: i2c_controller {
bus = 0;
...
...
@@ -227,14 +238,16 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
#include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/i2c/i2c_config.hcs" // 配置文件相对路径
```
3.
完成驱动入口注册之后,下一步就是以核心层I2cCntlr对象的初始化为核心,包括驱动适配者自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
3.
实例化I2C控制器对象
完成驱动入口注册之后,下一步就是以核心层I2cCntlr对象的初始化为核心,包括驱动适配者自定义结构体(传递参数和数据),实例化I2cCntlr成员I2cMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
- 自定义结构体参考
从驱动的角度看,自定义结构体是参数和数据的载体,而且i2c_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层I2cCntlr对象,例如设备号、总线号等。
```c
/* 驱动适配者自定义结构体 */
// 驱动适配者自定义结构体
struct Hi35xxI2cCntlr {
struct I2cCntlr cntlr; // 【必要】是核心层控制对象,具体描述见下面。
OsalSpinlock spin; // 【必要】驱动适配者需要基于此锁变量对各个i2c操作函数实现对应的加锁解锁。
...
...
@@ -247,7 +260,7 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
uint32_t regBasePhy; // 【必要】寄存器物理基地址
};
/* I2cCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值。*/
// I2cCntlr是核心层控制器结构体,其中的成员在Init函数中会被赋值。
struct I2cCntlr {
struct OsalMutex lock;
void *owner;
...
...
@@ -261,7 +274,7 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
- I2cCntlr成员钩子函数结构体I2cMethod的实例化,和锁机制钩子函数结构体I2cLockMethod实例化,其他成员在Init函数中初始化。
```c
/* i2c_hi35xx.c中的示例 */
// i2c_hi35xx.c中的示例
static const struct I2cMethod g_method = {
.transfer = Hi35xxI2cTransfer,
};
...
...
@@ -280,16 +293,16 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
返回值:
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见
//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS定义)。
HDF_STATUS相关状态(表4为部分展示,如需使用其他状态,可参考
//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS定义)。
**表
4** Init函数入参及返回值参考
**表
4** HDF_STATUS相关状态说明
| 状态(值) | 问题描述 |
| -------- | -------- |
| HDF_ERR_INVALID_OBJECT | 控制器对象非法 |
| HDF_ERR_INVALID_PARAM | 参数非法 |
| HDF_ERR_MALLOC_FAIL | 内存分配失败 |
| HDF_ERR_IO | I/O 错误 |
| HDF_ERR_IO | I/O错误 |
| HDF_SUCCESS | 传输成功 |
| HDF_FAILURE | 传输失败 |
...
...
@@ -300,23 +313,23 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
```c
static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device)
{
...
/* 遍历、解析i2c_config.hcs中的所有配置节点,并分别进行初始化,需要调用Hi35xxI2cParseAndInit函数。*/
...
...
// 遍历、解析i2c_config.hcs中的所有配置节点,并分别进行初始化,需要调用Hi35xxI2cParseAndInit函数。
DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
ret = Hi35xxI2cParseAndInit(device, childNode);//函数定义见下
...
...
...
}
...
...
...
}
static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
{
struct Hi35xxI2cCntlr *hi35xx = NULL;
...
// 入参判空
......
// 入参判空
hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx)); // 内存分配
...
// 返回值校验
......
// 返回值校验
hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize); // 地址映射
...
// 返回值校验
......
// 返回值校验
Hi35xxI2cCntlrInit(hi35xx); // 【必要】i2c设备的初始化
hi35xx->cntlr.priv = (void *)node; // 【必要】存储设备属性
...
...
@@ -325,7 +338,7 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
hi35xx->cntlr.lockOps = &g_lockOps; // 【必要】I2cLockMethod的实例化对象的挂载
(void)OsalSpinInit(&hi35xx->spin); // 【必要】锁的初始化
ret = I2cCntlrAdd(&hi35xx->cntlr); // 【必要】调用此函数将控制器对象添加至平台核心层,返回成功信号后驱动才完全接入平台核心层。
...
......
#ifdef USER_VFS_SUPPORT
(void)I2cAddVfsById(hi35xx->cntlr.busId); // 【可选】若支持用户级的虚拟文件系统,则接入。
#endif
...
...
@@ -360,8 +373,8 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
```c
static void Hi35xxI2cRelease(struct HdfDeviceObject *device)
{
...
/* 与Hi35xxI2cInit一样,需要将每个节点分别进行释放。*/
......
// 与Hi35xxI2cInit一样,需要将每个节点分别进行释放。
DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
Hi35xxI2cRemoveByNode(childNode); // 函数定义如下
}
...
...
@@ -369,13 +382,13 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
static void Hi35xxI2cRemoveByNode(const struct DeviceResourceNode *node)
{
...
/
* 【必要】可以调用I2cCntlrGet函数通过设备的bus号获取I2cCntlr对象的指针,以及调用I2cCntlrRemove函数将I2cCntlr对象从平台核心层移除。*/
...
...
/
/ 【必要】可以调用I2cCntlrGet函数通过设备的bus号获取I2cCntlr对象的指针,以及调用I2cCntlrRemove函数将I2cCntlr对象从平台核心层移除。
cntlr = I2cCntlrGet(bus);
if (cntlr != NULL && cntlr->priv == node) {
...
...
...
I2cCntlrRemove(cntlr);
/
* 【必要】解除地址映射,释放锁和内存。*/
/
/ 【必要】解除地址映射,释放锁和内存。
hi35xx = (struct Hi35xxI2cCntlr *)cntlr;
OsalIoUnmap((void *)hi35xx->regBase);
(void)OsalSpinDestroy(&hi35xx->spin);
...
...
@@ -384,3 +397,7 @@ I2C模块适配的三个必选环节是实例化驱动入口,配置属性文
return;
}
```
4.
驱动调试
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,消息传输的成功与否等。
zh-cn/device-dev/driver/driver-platform-i3c-des.md
浏览文件 @
952ecd1c
...
...
@@ -9,38 +9,49 @@ I3C(Improved Inter Integrated Circuit)总线是由MIPI Alliance开发的一
I3C是两线双向串行总线,针对多个传感器从设备进行了优化,并且一次只能由一个I3C主设备控制。相比于I2C,I3C总线拥有更高的速度、更低的功耗,支持带内中断、从设备热接入以及切换当前主设备,同时向后兼容I2C从设备。I3C增加了带内中断(In-Bind Interrupt)功能,支持I3C设备进行热接入操作,弥补了I2C总线需要额外增加中断线来完成中断的不足。I3C总线上允许同时存在I2C设备、I3C从设备和I3C次级主设备。
I3C接口定义了完成I3C传输的通用方法集合,包括:
-
I3C控制器管理:打开或关闭I3C控制器。
-
I3C控制器配置:获取或配置I3C控制器参数。
-
I3C消息传输:通过消息传输结构体数组进行自定义传输。
-
I3C带内中断:请求或释放带内中断。
### 基本概念<a name="section3"></a>
-
IBI(In-Band Interrupt)
<br>
带内中断。在SCL线没有启动信号时,I3C从设备可以通过拉低SDA线使主设备发出SCL启动信号,从而发出带内中断请求。若有多个从机同时发出中断请求,I3C主机则通过从机地址进行仲裁,低地址优先相应。
-
DAA(Dynamic Address Assignment)
<br>
动态地址分配。I3C支持对从设备地址进行动态分配从而避免地址冲突。在分配动态地址之前,连接到I3C总线上的每个I3C设备都应以两种方式之一来唯一标识:
1)设备可能有一个符合I2C规范的静态地址,主机可以使用此静态地址;
2)在任何情况下,设备均应具有48位的临时ID。 除非设备具有静态地址且主机使用静态地址,否则主机应使用此48位临时ID。
-
CCC(Common Command Code)
<br>
通用命令代码,所有I3C设备均支持CCC,可以直接将其传输到特定的I3C从设备,也可以同时传输到所有I3C从设备。
-
BCR(Bus Characteristic Register)
<br>
总线特性寄存器,每个连接到 I3C 总线的 I3C 设备都应具有相关的只读总线特性寄存器 (BCR),该寄存器描述了I3C兼容设备在动态地址分配和通用命令代码中的作用和功能。
-
DCR(Device Characteristic Register)
<br>
设备特性寄存器,连接到 I3C 总线的每个 I3C 设备都应具有相关的只读设备特性寄存器 (DCR)。 该寄存器描述了用于动态地址分配和通用命令代码的 I3C 兼容设备类型(例如,加速度计、陀螺仪等)。
### 运作机制<a name="section4"></a>
在HDF框架中,I3C模块接口适配模式采用统一服务模式,这需要一个设备服务来作为I3C模块的管理器,统一处理外部访问,这会在配置文件中有所体现。统一服务模式适合于同类型设备对象较多的情况,如I3C可能同时具备十几个控制器,采用独立服务模式需要配置更多的设备节点,且服务会占据内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。
相比于I2C,I3C总线拥有更高的速度、更低的功耗,支持带内中断、从设备热接入以及切换当前主设备,同时向后兼容I2C从设备。一路I3C总线上,可以连接多个设备,这些设备可以是I2C从设备、I3C从设备和I3C次级主设备,但只能同时存在一个主设备,一般为控制器本身。
相比于I2C,I3C总线拥有更高的速度、更低的功耗,支持带内中断、从设备热接入以及切换当前主设备,同时向后兼容I2C从设备。一路I3C总线上,可以连接多个设备,这些设备可以是I2C从设备、I3C从设备和I3C次级主设备,但只能同时存在一个主设备,一般为控制器本身。
**图 1**
I3C物理连线示意图
<a
name=
"fig1"
></a>


### 约束与限制<a name="section5"></a>
...
...
@@ -53,6 +64,7 @@ I3C模块当前仅支持轻量和小型系统内核(LiteOS-A),不支持在
I3C可连接单个或多个I3C、I2C从器件,它主要用于:
-
与传感器通信,如陀螺仪、气压计或支持I3C协议的图像传感器等;
-
通过软件或硬件协议转换,与其他接口(如 UART 串口等)的设备进行通信。
### 接口说明<a name="section8"></a>
...
...
@@ -81,7 +93,7 @@ I3C模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/
I3C的使用流程如图2所示。
**图 2**
I3C使用流程图
<a
name=
"fig2"
></a>


#### 打开I3C控制器<a name="section5"></a>
...
...
@@ -96,7 +108,7 @@ DevHandle I3cOpen(int16_t number);
| 参数 | 参数描述 |
| ---------- | ------------------- |
| number
| I3C控制器号
|
| number
| int16_t类型,I3C控制器号
|
|
**返回值**
|
**返回值描述**
|
| NULL | 打开I3C控制器失败 |
| 控制器句柄 | 打开的I3C控制器句柄 |
...
...
@@ -104,13 +116,13 @@ DevHandle I3cOpen(int16_t number);
假设系统中存在8个I3C控制器,编号从0到7,以下示例代码为打开1号控制器:
```
c
DevHandle
i3cHandle
=
NULL
;
/
* I3C控制器句柄 /
DevHandle
i3cHandle
=
NULL
;
/
/ I3C控制器句柄
/
* 打开I3C控制器 */
/
/ 打开I3C控制器
i3cHandle
=
I3cOpen
(
1
);
if
(
i3cHandle
==
NULL
)
{
HDF_LOGE
(
"I3cOpen:
failed
\n
"
);
return
;
HDF_LOGE
(
"I3cOpen:
i3c open fail.
\n
"
);
return
NULL
;
}
```
...
...
@@ -126,10 +138,10 @@ int32_t I3cGetConfig(DevHandle handle, struct I3cConfig *config);
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
I3C控制器句柄 |
| config
|
I3C控制器配置 |
| handle
| DevHandle类型,
I3C控制器句柄 |
| config
| 结构体指针,
I3C控制器配置 |
|
**返回值**
|
**返回值描述**
|
|
0 | 获取成功
|
|
HDF_SUCCESS | 获取成功
|
| 负数 | 获取失败 |
获取I3C控制器配置示例:
...
...
@@ -137,10 +149,10 @@ int32_t I3cGetConfig(DevHandle handle, struct I3cConfig *config);
```
c
struct
I3cConfig
config
;
ret
=
I3cGetConfig
(
i3cHandle
,
&
config
);
int32_t
ret
=
I3cGetConfig
(
i3cHandle
,
&
config
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: Get config fail!"
,
__func__
);
return
HDF_FAILURE
;
HDF_LOGE
(
"
I3cGetConfig: get config fail, ret:%d"
,
ret
);
return
ret
;
}
```
...
...
@@ -156,10 +168,10 @@ int32_t I3cSetConfig(DevHandle handle, struct I3cConfig *config);
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
| I3C控制器句柄
|
| config
| I3C控制器配置
|
| handle
| DevHandle类型,I3C控制器句柄
|
| config
| 结构体指针,I3C控制器配置
|
|
**返回值**
|
**返回值描述**
|
|
0 | 配置成功
|
|
HDF_SUCCESS | 配置成功
|
| 负数 | 配置失败 |
配置I3C控制器示例:
...
...
@@ -169,10 +181,10 @@ struct I3cConfig config;
config
->
busMode
=
I3C_BUS_HDR_MODE
;
config
->
curMaster
=
NULL
;
ret
=
I3cSetConfig
(
i3cHandle
,
&
config
);
int32_t
ret
=
I3cSetConfig
(
i3cHandle
,
&
config
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: Set config fail!"
,
__func__
);
return
HDF_FAILURE
;
HDF_LOGE
(
"
I3cSetConfig: set config fail, ret:%d"
,
ret
);
return
ret
;
}
```
...
...
@@ -189,10 +201,10 @@ int32_t I3cTransfer(DevHandle handle, struct I3cMsg *msgs, int16_t count, enum T
| 参数 | 参数描述 |
| ---------- | -------------------------------------------- |
| handle
| I3C控制器句柄
|
| msgs
| 待传输数据的消息结构体数组
|
| count
| 消息数组长度
|
| mode
|
传输模式,0:I2C模式;1:I3C模式;2:发送CCC |
| handle
| DevHandle类型,I3C控制器句柄
|
| msgs
| 结构体指针,待传输数据的消息结构体数组
|
| count
| int16_t类型,消息数组长度
|
| mode
| 枚举类型,
传输模式,0:I2C模式;1:I3C模式;2:发送CCC |
|
**返回值**
|
**返回值描述**
|
| 正整数 | 成功传输的消息结构体数目 |
| 负数 | 执行失败 |
...
...
@@ -203,20 +215,20 @@ I3C传输消息类型为I3cMsg,每个传输消息结构体表示一次读或
int32_t
ret
;
uint8_t
wbuff
[
2
]
=
{
0x12
,
0x13
};
uint8_t
rbuff
[
2
]
=
{
0
};
struct
I3cMsg
msgs
[
2
];
/* 自定义传输的消息结构体数组 */
msgs
[
0
].
buf
=
wbuff
;
/* 写入的数据 */
msgs
[
0
].
len
=
2
;
/* 写入数据长度为2 */
msgs
[
0
].
addr
=
0x3F
;
/* 写入设备地址为0x3F */
msgs
[
0
].
flags
=
0
;
/* 传输标记为0,默认为写 */
msgs
[
1
].
buf
=
rbuff
;
/* 要读取的数据 */
msgs
[
1
].
len
=
2
;
/* 读取数据长度为2 */
msgs
[
1
].
addr
=
0x3F
;
/* 读取设备地址为0x3F */
msgs
[
1
].
flags
=
I3C_FLAG_READ
/
* I3C_FLAG_READ置位 */
/
* 进行一次I2C模式自定义传输,传输的消息个数为2 */
struct
I3cMsg
msgs
[
2
];
// 自定义传输的消息结构体数组
msgs
[
0
].
buf
=
wbuff
;
// 写入的数据
msgs
[
0
].
len
=
2
;
// 写入数据长度为2
msgs
[
0
].
addr
=
0x3F
;
// 写入设备地址为0x3F
msgs
[
0
].
flags
=
0
;
// 传输标记为0,默认为写
msgs
[
1
].
buf
=
rbuff
;
// 要读取的数据
msgs
[
1
].
len
=
2
;
// 读取数据长度为2
msgs
[
1
].
addr
=
0x3F
;
// 读取设备地址为0x3F
msgs
[
1
].
flags
=
I3C_FLAG_READ
/
/ I3C_FLAG_READ置位
/
/ 进行一次I2C模式自定义传输,传输的消息个数为2
ret
=
I3cTransfer
(
i3cHandle
,
msgs
,
2
,
I2C_MODE
);
if
(
ret
!=
2
)
{
HDF_LOGE
(
"I3cTransfer:
failed, ret
%d
\n
"
,
ret
);
return
;
HDF_LOGE
(
"I3cTransfer:
transfer fail, ret:
%d
\n
"
,
ret
);
return
HDF_FAILURE
;
}
```
...
...
@@ -238,12 +250,12 @@ int32_t I3cRequestIbi(DevHandle handle, uint16_t addr, I3cIbiFunc func, uint32_t
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
I3C控制器句柄 |
| addr
| I3C设备地址
|
| func
| IBI回调函数
|
| handle
| DevHandle类型,
I3C控制器句柄 |
| addr
| uint16_t类型,I3C设备地址
|
| func
| 函数指针,IBI回调函数
|
| payload | IBI有效载荷 |
|
**返回值**
|
**返回值描述**
|
|
0 | 请求成功
|
|
HDF_SUCCESS | 请求成功
|
| 负数 | 请求失败 |
请求带内中断示例:
...
...
@@ -253,9 +265,9 @@ static int32_t TestI3cIbiFunc(DevHandle handle, uint16_t addr, struct I3cIbiData
{
(
void
)
handle
;
(
void
)
addr
;
HDF_LOGD
(
"
%s: %.16s"
,
__func__
,
(
char
*
)
data
.
buf
);
HDF_LOGD
(
"
TestI3cIbiFunc: %.16s"
,
(
char
*
)
data
.
buf
);
return
0
;
return
HDF_SUCCESS
;
}
int32_t
I3cTestRequestIbi
(
void
)
...
...
@@ -263,22 +275,22 @@ int32_t I3cTestRequestIbi(void)
DevHandle
i3cHandle
=
NULL
;
int32_t
ret
;
/
* 打开I3C控制器 */
/
/ 打开I3C控制器
i3cHandle
=
I3cOpen
(
1
);
if
(
i3cHandle
==
NULL
)
{
HDF_LOGE
(
"I3cOpen:
failed
\n
"
);
HDF_LOGE
(
"I3cOpen:
i3c open fail.
\n
"
);
return
;
}
}
ret
=
I3cRequestIbi
(
i3cHandle
,
0x3F
,
TestI3cIbiFunc
,
16
);
if
(
ret
!=
0
)
{
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Request IBI failed!"
,
__func__
);
return
-
1
;
return
ret
;
}
I3cClose
(
i3cHandle
);
HDF_LOGD
(
"
%s: Done"
,
__func__
);
HDF_LOGD
(
"
I3cTestRequestIbi: done"
);
return
0
;
return
HDF_SUCCESS
;
}
```
...
...
@@ -294,16 +306,16 @@ int32_t I3cFreeIbi(DevHandle handle, uint16_t addr);
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
|
I3C控制器句柄 |
| addr
| I3C设备地址
|
| handle
| DevHandle类型,
I3C控制器句柄 |
| addr
| uint16_t类型,I3C设备地址
|
|
**返回值**
|
**返回值描述**
|
|
0 | 释放成功
|
|
HDF_SUCCESS | 释放成功
|
| 负数 | 释放失败 |
释放带内中断示例:
```
c
I3cFreeIbi
(
i3cHandle
,
0x3F
);
/
* 释放带内中断 */
I3cFreeIbi
(
i3cHandle
,
0x3F
);
/
/ 释放带内中断
```
#### 关闭I3C控制器<a name="section11"></a>
...
...
@@ -319,12 +331,12 @@ void I3cClose(DevHandle handle);
| 参数 | 参数描述 |
| ---------- | -------------- |
| handle
| I3C控制器句柄
|
| handle
| DevHandle类型,I3C控制器句柄
|
关闭I3C控制器实例:
```
c
I3cClose
(
i3cHandle
);
/
* 关闭I3C控制器 */
I3cClose
(
i3cHandle
);
/
/ 关闭I3C控制器
```
## 使用实例<a name="section10"></a>
...
...
@@ -342,28 +354,28 @@ I3cClose(i3cHandle); /* 关闭I3C控制器 */
示例如下:
```
c
#include "i3c_if.h"
/* I3C标准接口头文件 */
#include "hdf_log.h"
/* 标准日志打印头文件 */
#include "osal_io.h"
/* 标准IO读写接口头文件 */
#include "osal_time.h"
/* 标准延迟&睡眠接口头文件 */
#include "i3c_if.h"
// I3C标准接口头文件
#include "hdf_log.h"
// 标准日志打印头文件
#include "osal_io.h"
// 标准IO读写接口头文件
#include "osal_time.h"
// 标准延迟&睡眠接口头文件
/
* 定义一个表示设备的结构体,存储信息 */
/
/ 定义一个表示设备的结构体,存储信息
struct
TestI3cDevice
{
uint16_t
busNum
;
/
* I3C总线号 */
uint16_t
addr
;
/
* I3C设备地址 */
uint16_t
regLen
;
/
* 寄存器字节宽度 */
DevHandle
i3cHandle
;
/
* I3C控制器句柄 */
uint16_t
busNum
;
/
/ I3C总线号
uint16_t
addr
;
/
/ I3C设备地址
uint16_t
regLen
;
/
/ 寄存器字节宽度
DevHandle
i3cHandle
;
/
/ I3C控制器句柄
};
/
* 基于I3cTransfer方法封装一个寄存器读写的辅助函数, 通过flag表示读或写 */
static
int
TestI3cReadWrite
(
struct
TestI3cDevice
*
testDevice
,
unsigned
int
regAddr
,
/
/ 基于I3cTransfer方法封装一个寄存器读写的辅助函数,通过flag表示读或写
static
int
32_t
TestI3cReadWrite
(
struct
TestI3cDevice
*
testDevice
,
unsigned
int
regAddr
,
unsigned
char
*
regData
,
unsigned
int
dataLen
,
uint8_t
flag
)
{
int
index
=
0
;
unsigned
char
regBuf
[
4
]
=
{
0
};
struct
I3cMsg
msgs
[
2
]
=
{
0
};
/
* 单双字节寄存器长度适配 */
/
/ 单双字节寄存器长度适配
if
(
testDevice
->
regLen
==
1
)
{
regBuf
[
index
++
]
=
regAddr
&
0xFF
;
}
else
{
...
...
@@ -371,81 +383,80 @@ static int TestI3cReadWrite(struct TestI3cDevice *testDevice, unsigned int regAd
regBuf
[
index
++
]
=
regAddr
&
0xFF
;
}
/
* 填充I3cMsg消息结构 */
/
/ 填充I3cMsg消息结构
msgs
[
0
].
addr
=
testDevice
->
addr
;
msgs
[
0
].
flags
=
0
;
/* 标记为0,表示写入 */
msgs
[
0
].
flags
=
0
;
// 标记为0,表示写入
msgs
[
0
].
len
=
testDevice
->
regLen
;
msgs
[
0
].
buf
=
regBuf
;
msgs
[
1
].
addr
=
testDevice
->
addr
;
msgs
[
1
].
flags
=
(
flag
==
1
)
?
I3C_FLAG_READ
:
0
;
/
* 添加读标记位,表示读取 */
msgs
[
1
].
flags
=
(
flag
==
1
)
?
I3C_FLAG_READ
:
0
;
/
/ 添加读标记位,表示读取
msgs
[
1
].
len
=
dataLen
;
msgs
[
1
].
buf
=
regData
;
if
(
I3cTransfer
(
testDevice
->
i3cHandle
,
msgs
,
2
,
I2C_MODE
)
!=
2
)
{
HDF_LOGE
(
"
%s: i3c read err"
,
__func__
);
HDF_LOGE
(
"
TestI3cReadWrite: i3c transfer err."
);
return
HDF_FAILURE
;
}
return
HDF_SUCCESS
;
}
/
* 寄存器读函数 */
static
inline
int
TestI3cReadReg
(
struct
TestI3cDevice
*
testDevice
,
unsigned
int
regAddr
,
/
/ 寄存器读函数
static
inline
int
32_t
TestI3cReadReg
(
struct
TestI3cDevice
*
testDevice
,
unsigned
int
regAddr
,
unsigned
char
*
regData
,
unsigned
int
dataLen
)
{
return
TestI3cReadWrite
(
testDevice
,
regAddr
,
regData
,
dataLen
,
1
);
}
/
* 寄存器写函数 */
static
inline
int
TestI3cWriteReg
(
struct
TestI3cDevice
*
testDevice
,
unsigned
int
regAddr
,
/
/ 寄存器写函数
static
inline
int
32_t
TestI3cWriteReg
(
struct
TestI3cDevice
*
testDevice
,
unsigned
int
regAddr
,
unsigned
char
*
regData
,
unsigned
int
dataLen
)
{
return
TestI3cReadWrite
(
testDevice
,
regAddr
,
regData
,
dataLen
,
0
);
}
/
* I3C例程总入口 */
/
/ I3C例程总入口
static
int32_t
TestCaseI3c
(
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
TestI3cDevice
testDevice
;
/
* 设备信息初始化 */
/
/ 设备信息初始化
testDevice
.
busNum
=
18
;
testDevice
.
addr
=
0x3F
;
testDevice
.
regLen
=
1
;
testDevice
.
regLen
=
2
;
testDevice
.
i3cHandle
=
NULL
;
/
* 打开I3C控制器 */
/
/ 打开I3C控制器
testDevice
.
i3cHandle
=
I3cOpen
(
testDevice
.
busNum
);
if
(
testDevice
.
i3cHandle
==
NULL
)
{
HDF_LOGE
(
"
%s: Open I3c:%u fail!"
,
__func__
,
testDevice
.
busNum
);
return
-
1
;
HDF_LOGE
(
"
TestCaseI3c: open I3c:%u fail!"
,
testDevice
.
busNum
);
return
HDF_FAILURE
;
}
/
* 向地址为0x3F的设备连续写7字节数据 */
/
/ 向地址为0x3F的设备连续写7字节数据
ret
=
TestI3cWriteReg
(
&
testDevice
,
0x3F
,
bufWrite
,
7
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: test i3c write reg fail!:%d"
,
__func__
,
ret
);
HDF_LOGE
(
"
TestCaseI3c: test i3c write reg fail, ret:%d"
,
ret
);
I3cClose
(
testDevice
.
i3cHandle
);
return
-
1
;
return
ret
;
}
OsalMSleep
(
10
);
/
* 从地址为0x3F的设备连续读7字节数据 */
/
/ 从地址为0x3F的设备连续读7字节数据
ret
=
TestI3cReadReg
(
&
testDevice
,
0x3F
,
bufRead
,
7
);
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"
%s: test i3c read reg fail!:%d"
,
__func__
,
ret
);
HDF_LOGE
(
"
TestCaseI3c: test i3c read reg fail, ret:%d"
,
ret
);
I3cClose
(
testDevice
.
i3cHandle
);
return
-
1
;
return
ret
;
}
HDF_LOG
I
(
"%s: test i3c write&read reg success!"
,
__func__
);
/
* 访问完毕关闭I3C控制器 */
HDF_LOG
D
(
"TestCaseI3c: test i3c write&read reg success!"
);
HDF_LOGD
(
"TestCaseI3c: function tests end."
);
/
/ 访问完毕关闭I3C控制器
I3cClose
(
testDevice
.
i3cHandle
);
return
0
;
return
HDF_SUCCESS
;
}
```
zh-cn/device-dev/driver/driver-platform-i3c-develop.md
浏览文件 @
952ecd1c
...
...
@@ -42,14 +42,16 @@ I3C是两线双向串行总线,针对多个传感器从设备进行了优化
I3C模块各分层的作用为:
-
接口层:提供打开设备,写入数据,关闭设备的能力。
-
核心层:主要负责服务绑定、初始化以及释放管理器,并提供添加、删除以及获取控制器的能力。由于框架需要统一管理I3C总线上挂载的所有设备,因此还提供了添加、删除以及获取设备的能力,以及中断回调函数。
-
适配层:由驱动适配者实现与硬件相关的具体功能,如控制器的初始化等。
在统一模式下,所有的控制器都被核心层统一管理,并由核心层统一发布一个服务供接口层,因此这种模式下驱动无需再为每个控制器发布服务。
**图 1**
I3C统一服务模式结构图
<a
name=
"fig1"
></a>
**图 1**
I3C统一服务模式结构图
<a
name=
"fig1"
></a>


### 约束与限制<a name="5"></a>
...
...
@@ -62,6 +64,7 @@ I3C模块当前仅支持轻量和小型系统内核(LiteOS-A) 。
I3C可连接单个或多个I3C、I2C从器件,它主要用于:
-
与传感器通信,如陀螺仪、气压计或支持I3C协议的图像传感器等。
-
通过软件或硬件协议转换,与其他通信接口(如UART串口等)的设备进行通信。
当驱动开发者需要将I3C设备适配到OpenHarmony时,需要进行I3C驱动适配,下文将介绍如何进行I3C驱动适配。
...
...
@@ -71,6 +74,7 @@ I3C可连接单个或多个I3C、I2C从器件,它主要用于:
为了保证上层在调用I3C接口时能够正确的操作硬件,核心层在//drivers/hdf_core/framework/support/platform/include/i3c/i3c_core.h中定义了以下钩子函数。驱动适配者需要在适配层实现这些函数的具体功能,并与这些钩子函数挂接,从而完成接口层与核心层的交互。
I3cMethod定义:
```
c
struct
I3cMethod
{
int32_t
(
*
sendCccCmd
)(
struct
I3cCntlr
*
cntlr
,
struct
I3cCccCmd
*
ccc
);
...
...
@@ -83,39 +87,52 @@ struct I3cMethod {
};
```
**表1**
I3cMethod结构体成员的钩子函数功能说明
|
函数成员|入参|出参|返回值|功能
|
|
-|-|-|-|-
|
|
sendCccCmd
|
**cntlr**
:结构体指针,核心层I3C控制器
<br
/>
**ccc**
:传入的通用命令代码结构体指针 |
**ccc**
:传出的通用命令代码结构体指针 | HDF_STATUS相关状态|发送CCC(Common command Code,即通用命令代码)|
|
Transfer |
**cntlr**
:结构体指针,核心层I3C控制器
<br
/>
**msgs**
:结构体指针,用户消息
<br
/>
**count**
:int16_t,消息数量 |
**msgs**
:结构体指针,用户消息
| HDF_STATUS相关状态 | 使用I3C模式传递用户消息 |
**表
1**
I3cMethod结构体成员的钩子函数功能说明
|
函数成员 | 入参 | 出参 | 返回值 | 功能
|
|
- | - | - | - | -
|
|
sendCccCmd
|
**cntlr**
:结构体指针,核心层I3C控制器
<br
/>
**ccc**
:传入的通用命令代码结构体指针 |
**ccc**
:传出的通用命令代码结构体指针 | HDF_STATUS相关状态|发送CCC(Common command Code,即通用命令代码)|
|
Transfer |
**cntlr**
:结构体指针,核心层I3C控制器
<br
/>
**msgs**
:结构体指针,用户消息
<br
/>
**count**
:int16_t,消息数量 |
**msgs**
:结构体指针,用户消息
| HDF_STATUS相关状态 | 使用I3C模式传递用户消息 |
|i2cTransfer |
**cntlr**
:结构体指针,核心层I3C控制器
<br
/>
**msgs**
:结构体指针,用户消息
<br
/>
**count**
:int16_t,消息数量 |
**msgs**
:结构体指针,用户消息 | HDF_STATUS相关状态 | 使用I2C模式传递用户消息 |
|
setConfig
|
**cntlr**
:结构体指针,核心层I3C控制器
<br
/>
**config**
:控制器配置参数| 无 | HDF_STATUS相关状态 | 设置I3C控制器配置参数 |
|
getConfig|
**cntlr**
:结构体指针,核心层I3C控制器
|
**config**
:控制器配置参数 | HDF_STATUS相关状态 | 获取I3C控制器配置参数 |
|
requestIbi|
**device**
:结构体指针,核心层I3C设备
| 无 | HDF_STATUS相关状态 | 为I3C设备请求IBI(In-Bind Interrupt,即带内中断) |
|
freeIbi|
**device**
:结构体指针,核心层I3C设备
| 无 | HDF_STATUS相关状态 | 释放IBI |
|
setConfig
|
**cntlr**
:结构体指针,核心层I3C控制器
<br
/>
**config**
:控制器配置参数| 无 | HDF_STATUS相关状态 | 设置I3C控制器配置参数 |
|
getConfig |
**cntlr**
:结构体指针,核心层I3C控制器
|
**config**
:控制器配置参数 | HDF_STATUS相关状态 | 获取I3C控制器配置参数 |
|
requestIbi |
**device**
:结构体指针,核心层I3C设备
| 无 | HDF_STATUS相关状态 | 为I3C设备请求IBI(In-Bind Interrupt,即带内中断) |
|
freeIbi |
**device**
:结构体指针,核心层I3C设备
| 无 | HDF_STATUS相关状态 | 释放IBI |
### 开发步骤 <a name="9"></a>
I3C模块适配的四个环节是实例化驱动入口、配置属性文件、实例化I3C控制器对象以及注册中断处理子程序。
I3C模块适配包含以下五个步骤:
-
实例化驱动入口
-
实例化驱动入口:
-
实例化HdfDriverEntry结构体成员。
-
调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
-
配置属性文件
:
-
配置属性文件
-
在device_info.hcs文件中添加deviceNode描述。
-
【可选】添加i3c_config.hcs器件属性文件。
-
实例化I3C控制器对象:
-
实例化I3C控制器对象
-
初始化I3cCntlr成员。
-
实例化I3cCntlr成员I3cMethod方法集合,其定义和成员函数说明见下文。
-
注册中断处理子程序:
-
注册中断处理子程序
为控制器注册中断处理程序,实现设备热接入和IBI(带内中断)功能。
1.
实例化驱动入口
-
驱动调试
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的测试用例是否成功,数据能否传输等。
### 开发实例
下方将以Hi3516DV300的虚拟驱动//drivers/hdf_core/framework/test/unittest/platform/virtual/i3c_virtual.c为示例,展示需要驱动适配者提供哪些内容来完整实现设备功能。
1.
实例化驱动入口
驱动入口必须为HdfDriverEntry(在//drivers/hdf_core/framework/include/core/hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
...
...
@@ -136,7 +153,7 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
};
HDF_INIT
(
g_virtualI3cDriverEntry
);
// 调用HDF_INIT将驱动入口注册到HDF框架中
/
* 核心层i3c_core.c管理器服务的驱动入口 */
/
/ 核心层i3c_core.c管理器服务的驱动入口
struct
HdfDriverEntry
g_i3cManagerEntry
=
{
.
moduleVersion
=
1
,
.
Init
=
I3cManagerInit
,
...
...
@@ -147,19 +164,20 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
```
2.
配置属性文件
完成驱动入口注册之后,下一步请在//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode信息,并在i3c_config.hcs中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值对于驱动适配者的驱动实现以及核心层I3cCntlr相关成员的默认值或限制范围有密切关系。
完成驱动入口注册之后,下一步请在//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode信息,并在i3c_config.hcs中配置器件属性。
deviceNode信息与驱动入口注册相关,器件属性值对于驱动适配者的驱动实现以及核心层I3cCntlr相关成员的默认值或限制范围有密切关系。
统一服务模式的特点是device_info.hcs文件中第一个设备节点必须为I3C管理器,其各项参数必须如表2设置:
统一服务模式的特点是device_info.hcs文件中第一个设备节点必须为I3C管理器,其各项参数必须如下设置:
**表 2**
device_info.hcs节点参数说明
|成员名|值|
|-|-|
|moduleName |HDF_PLATFORM_I3C_MANAGER|
|serviceName|无(预留)|
|policy|0|
|cntlrMatchAttr| 无(预留)|
| 成员名 | 值 |
| -------- | -------- |
| policy | 驱动服务发布的策略,I3C管理器具体配置为0,表示驱动不需要发布服务 |
| priority | 驱动启动优先级(0-200),值越大优先级越低。I3C管理器具体配置为52 |
| permission | 驱动创建设备节点权限,I3C管理器具体配置为0664 |
| moduleName | 驱动名称,I3C管理器固定为HDF_PLATFORM_I3C_MANAGER |
| serviceName | 驱动对外发布服务的名称,I3C管理器服务名设置为HDF_PLATFORM_I3C_MANAGER |
| deviceMatchAttr | 驱动私有数据匹配的关键字,I3C管理器没有使用,可忽略 |
从第二个节点开始配置具体I3C控制器信息,此节点并不表示某一路I3C控制器,而是代表一个资源性质设备,用于描述一类I3C控制器的信息。本例只有一个I3C控制器,如有多个控制器,则需要在device_info.hcs文件增加deviceNode信息,以及在i3c_config文件中增加对应的器件属性。
...
...
@@ -228,7 +246,7 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
此步骤需要通过实现HdfDriverEntry成员函数(Bind,Init,Release)来完成。
I3cCntlr成员钩子函数结构体I3cMethod的实例化,I3cLockMethod钩子函数结构体本例未实现,若要实例化,可参考I2C驱动开发
,其他成员在Init函数中初始化
。
I3cCntlr成员钩子函数结构体I3cMethod的实例化,I3cLockMethod钩子函数结构体本例未实现,若要实例化,可参考I2C驱动开发。
-
自定义结构体参考
...
...
@@ -250,7 +268,7 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
uint32_t
i2cFmPlusRate
;
};
/
* I3cCntlr是核心层控制器结构体,其中的成员在Init函数中被赋值。 */
/
/ I3cCntlr是核心层控制器结构体,其中的成员在Init函数中被赋值。
struct
I3cCntlr
{
OsalSpinlock
lock
;
void
*
owner
;
...
...
@@ -272,17 +290,18 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
**返回值:**
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS
定义)。
HDF_STATUS相关状态(表3为部分展示,如需使用其他状态,可参考//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS
定义)。
**表 3**
HDF_STATUS相关状态说明
|状态(值)|问题描述
|
|:-|:-:
|
|HDF_ERR_INVALID_OBJECT|控制器对象非法
|
|HDF_ERR_INVALID_PARAM |参数非法
|
|HDF_ERR_MALLOC_FAIL |内存分配失败
|
|HDF_ERR_IO |I/O 错误
|
|HDF_SUCCESS |传输成功
|
|HDF_FAILURE |传输失败
|
| 状态(值) | 问题描述
|
| -------- | --------
|
| HDF_ERR_INVALID_OBJECT | 控制器对象非法
|
| HDF_ERR_INVALID_PARAM | 参数非法
|
| HDF_ERR_MALLOC_FAIL | 内存分配失败
|
| HDF_ERR_IO | I/O错误
|
| HDF_SUCCESS | 传输成功
|
| HDF_FAILURE | 传输失败
|
**函数说明:**
...
...
@@ -306,14 +325,14 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
HDF_LOGE
(
"%s: Read drs fail! ret:%d"
,
__func__
,
ret
);
goto
__ERR__
;
}
...
...
...
virtual
->
regBase
=
OsalIoRemap
(
virtual
->
regBasePhy
,
virtual
->
regSize
);
// 【必要】地址映射
ret
=
OsalRegisterIrq
(
hi35xx
->
softIrqNum
,
OSAL_IRQF_TRIGGER_NONE
,
I3cIbiHandle
,
"I3C"
,
virtual
);
//【必要】注册中断程序
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: register irq failed!"
,
__func__
);
return
ret
;
}
...
...
...
VirtualI3cCntlrInit
(
virtual
);
// 【必要】I3C设备的初始化
virtual
->
cntlr
.
priv
=
(
void
*
)
node
;
// 【必要】存储设备属性
virtual
->
cntlr
.
busId
=
virtual
->
busId
;
// 【必要】初始化I3cCntlr成员
...
...
@@ -360,13 +379,13 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
{
struct
DeviceResourceIface
*
drsOps
=
NULL
;
/* 获取drsOps方法 */
// 获取drsOps方法
drsOps
=
DeviceResourceGetIfaceInstance
(
HDF_CONFIG_SOURCE
);
if
(
drsOps
==
NULL
||
drsOps
->
GetUint32
==
NULL
||
drsOps
->
GetUint16
==
NULL
)
{
HDF_LOGE
(
"%s: Invalid drs ops fail!"
,
__func__
);
return
HDF_FAILURE
;
}
/* 将配置参数依次读出,并填充至结构体中 */
// 将配置参数依次读出,并填充至结构体中
if
(
drsOps
->
GetUint16
(
node
,
"busId"
,
&
virtual
->
busId
,
0
)
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: Read busId fail!"
,
__func__
);
return
HDF_ERR_IO
;
...
...
@@ -379,7 +398,7 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
HDF_LOGE
(
"%s: Read IrqNum fail!"
,
__func__
);
return
HDF_ERR_IO
;
}
···
......
return
HDF_SUCCESS
;
}
```
...
...
@@ -421,8 +440,8 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
HDF_LOGE
(
"%s: read busId fail!"
,
__func__
);
return
;
}
...
/* 可以调用I3cCntlrGet函数通过设备的cntlrNum获取I3cCntlr对象,以及调用I3cCntlrRemove函数来释放I3cCntlr对象的内容。 */
...
...
// 可以调用I3cCntlrGet函数通过设备的cntlrNum获取I3cCntlr对象,以及调用I3cCntlrRemove函数来释放I3cCntlr对象的内容。
cntlr
=
I3cCntlrGet
(
busId
);
if
(
cntlr
!=
NULL
&&
cntlr
->
priv
==
node
)
{
I3cCntlrPut
(
cntlr
);
...
...
@@ -444,8 +463,8 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
HDF_LOGE
(
"%s: device or property is NULL"
,
__func__
);
return
;
}
...
/* 遍历、解析i3c_config.hcs中的所有配置节点,并分别进行release操作 */
...
...
// 遍历、解析i3c_config.hcs中的所有配置节点,并分别进行release操作
DEV_RES_NODE_FOR_EACH_CHILD_NODE
(
device
->
property
,
childNode
)
{
VirtualI3cRemoveByNode
(
childNode
);
//函数定义如上
}
...
...
@@ -471,7 +490,7 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
case
I3C_RESERVED_ADDR_7H7A
:
case
I3C_RESERVED_ADDR_7H7C
:
case
I3C_RESERVED_ADDR_7H7F
:
/
* 广播地址单比特错误的所有情形 */
/
/ 广播地址单比特错误的所有情形
HDF_LOGW
(
"%s: broadcast Address single bit error!"
,
__func__
);
break
;
default:
...
...
@@ -495,7 +514,7 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
return
HDF_ERR_INVALID_PARAM
;
}
virtual
=
(
struct
VirtualI3cCntlr
*
)
data
;
/
* 【必要】获取产生中断的地址,使用CHECK_RESERVED_ADDR宏判断该地址是否为I3C保留地址。 */
/
/ 【必要】获取产生中断的地址,使用CHECK_RESERVED_ADDR宏判断该地址是否为I3C保留地址。
ibiAddr
=
VirtualI3cGetIbiAddr
();
if
(
CHECK_RESERVED_ADDR
(
ibiAddr
)
==
I3C_ADDR_RESERVED
)
{
HDF_LOGD
(
"%s: Calling VirtualI3cResAddrWorker..."
,
__func__
);
...
...
@@ -508,13 +527,17 @@ I3C模块适配的四个环节是实例化驱动入口、配置属性文件、
return
HDF_ERR_MALLOC_FAIL
;
}
if
(
device
->
ibi
->
payload
>
VIRTUAL_I3C_TEST_STR_LEN
)
{
/
* 将字符串"Hello I3C!"放入IBI缓冲区内 */
/
/ 将字符串"Hello I3C!"放入IBI缓冲区内
*
device
->
ibi
->
data
=
*
testStr
;
}
/
* 根据产生IBI的I3C设备调用IBI回调函数 */
/
/ 根据产生IBI的I3C设备调用IBI回调函数
return
I3cCntlrIbiCallback
(
device
);
}
return
HDF_SUCCESS
;
}
```
5.
驱动调试
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的测试用例是否成功,数据能否传输等。
zh-cn/device-dev/driver/driver-platform-mipicsi-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-mipicsi-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-mipidsi-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-mipidsi-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-mmc-develop.md
浏览文件 @
952ecd1c
...
...
@@ -27,17 +27,20 @@ MMC、SD、SDIO总线,其总线规范类似,都是从MMC总线规范演化
独立服务模式下,核心层不会统一发布一个服务供上层使用,因此这种模式下驱动要为每个控制器发布一个服务,具体表现为:
-
驱动适配者需要实现HdfDriverEntry的Bind钩子函数以绑定服务。
-
device_info.hcs文件中deviceNode的policy字段为1或2,不能为0。
MMC模块各分层作用:
-
接口层提供打开MMC设备、检查MMC控制器是否存在设备、关闭MMC设备的接口。
-
核心层主要提供MMC控制器、移除和管理的能力,还有公共控制器业务。通过钩子函数与适配层交互。
-
适配层主要是将钩子函数的功能实例化,实现具体的功能。
**图1**
MMC独立服务模式结构图
**图
1**
MMC独立服务模式结构图


## 开发指导
...
...
@@ -71,15 +74,15 @@ struct MmcCntlrOps {
};
```
**表1**
MmcCntlrOps结构体成员的钩子函数功能说明
**表
1**
MmcCntlrOps结构体成员的钩子函数功能说明
| 成员函数 | 入参 | 返回值 | 功能 |
| -------- | -------- | -------- | -------- |
| doRequest | cntlr:结构体指针,核心层MMC控制器
<br>
cmd:结构体指针,传入命令值 | HDF_STATUS相关状态 | request相应处理 |
| setClock | cntlr:结构体指针,核心层MMC控制器
<br>
clock:时钟传入值 | HDF_STATUS相关状态 | 设置时钟频率 |
| setClock | cntlr:结构体指针,核心层MMC控制器
<br>
clock:
uint32_t类型,
时钟传入值 | HDF_STATUS相关状态 | 设置时钟频率 |
| setPowerMode | cntlr:结构体指针,核心层MMC控制器
<br>
mode:枚举值(见MmcPowerMode定义),功耗模式 | HDF_STATUS相关状态 | 设置功耗模式 |
| setBusWidth | cntlr:核心层结构体指针,核心层MMMC控制器
<br>
width:枚举
值
(见MmcBusWidth定义),总线带宽 | HDF_STATUS相关状态 | 设置总线带宽 |
| setBusTiming | cntlr:结构体指针,核心层MMC控制器
<br>
timing:枚举
值
(见MmcBusTiming定义),总线时序 | HDF_STATUS相关状态 | 设置总线时序 |
| setBusWidth | cntlr:核心层结构体指针,核心层MMMC控制器
<br>
width:枚举
类型
(见MmcBusWidth定义),总线带宽 | HDF_STATUS相关状态 | 设置总线带宽 |
| setBusTiming | cntlr:结构体指针,核心层MMC控制器
<br>
timing:枚举
类型
(见MmcBusTiming定义),总线时序 | HDF_STATUS相关状态 | 设置总线时序 |
| setSdioIrq | cntlr:结构体指针,核心层MMC控制器
<br>
enable:布尔值,控制中断 | HDF_STATUS相关状态 | 使能/去使能SDIO中断 |
| hardwareReset | cntlr:结构体指针,核心层MMC控制器 | HDF_STATUS相关状态 | 复位硬件 |
| systemInit | cntlr:结构体指针,核心层MMC控制器 | HDF_STATUS相关状态 | 系统初始化 |
...
...
@@ -95,18 +98,22 @@ struct MmcCntlrOps {
MMC模块适配包含以下四个步骤:
-
实例化驱动入口。
-
配置属性文件。
-
实例化MMC控制器对象。
-
驱动调试。
-
实例化驱动入口
-
配置属性文件
-
实例化MMC控制器对象
-
驱动调试
### 开发实例
下方将基于Hi3516DV300开发板以//device_soc_hisilicon/common/platform/mmc/himci_v200/himci.c驱动为示例,展示需要驱动适配者提供哪些内容来完整实现设备功能。
1.
实例化驱动入口
。
1.
实例化驱动入口
驱动入口必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
MMC驱动入口开发参考:
...
...
@@ -122,9 +129,22 @@ MMC模块适配包含以下四个步骤:
HDF_INIT(g_mmcDriverEntry); // 调用HDF_INIT将驱动入口注册到HDF框架中
```
2.
配置属性文件。
2.
配置属性文件
完成驱动入口注册之后,需要在device_info.hcs文件中添加deviceNode信息,deviceNode信息与驱动入口注册相关。本例以三个MMC控制器为例,如有多个器件信息,则需要在device_info.hcs文件增加对应的deviceNode信息,以及在mmc_config.hcs文件中增加对应的器件属性。器件属性值与核心层MmcCntlr成员的默认值或限制范围有密切关系,需要在mmc_config.hcs中配置器件属性。
独立服务模式的特点是device_info.hcs文件中设备节点代表着一个设备对象,如果存在多个设备对象,则按需添加,注意服务名与驱动私有数据匹配的关键字名称必须唯一。其中各项参数如表2所示:
完成驱动入口注册之后,需要在device_info.hcs文件中添加deviceNode信息,deviceNode信息与驱动入口注册相关。本例以三个MMC控制器为例,如有多个器件信息,则需要在device_info.hcs文件增加对应的deviceNode信息。器件属性值与核心层MmcCntlr成员的默认值或限制范围有密切关系,需要在mmc_config.hcs中配置器件属性。
**表 2** device_info.hcs节点参数说明
| 成员名 | 值 |
| -------- | -------- |
| policy | 驱动服务发布的策略,MMC控制器具体配置为2,表示驱动对内核态和用户态都发布服务 |
| priority | 驱动启动优先级(0-200),值越大优先级越低。MMC控制器控制器具体配置为10 |
| permission | 驱动创建设备节点权限,MMC控制器控制器具体配置为0664 |
| moduleName | 驱动名称,MMC控制器控制器固定为hi3516_mmc_driver |
| serviceName | 驱动对外发布服务的名称,MMC控制器控制器服务名设置为HDF_PLATFORM_MMC_X,X代表MMC控制器号|
| deviceMatchAttr | 驱动私有数据匹配的关键字,MMC控制器控制器设置为hi3516_mmc_X,X代表控制器类型名 |
- device_info.hcs 配置参考:
...
...
@@ -144,7 +164,7 @@ MMC模块适配包含以下四个步骤:
permission = 0644; // 驱动创建设备节点权限
moduleName = "hi3516_mmc_driver"; // 【必要】用于指定驱动名称,需要与驱动Entry中的moduleName一致。
serviceName = "HDF_PLATFORM_MMC_0"; // 【必要】驱动对外发布服务的名称,必须唯一。
deviceMatchAttr = "hi3516_mmc_emmc"; // 【必要】用于配置控制器私有数据,要与mmc_config.hcs中对应控制器保持一致
。
deviceMatchAttr = "hi3516_mmc_emmc"; // 【必要】用于配置控制器私有数据,要与mmc_config.hcs中对应控制器保持一致。emmc类型
。
}
device1 :: deviceNode {
policy = 1;
...
...
@@ -162,7 +182,7 @@ MMC模块适配包含以下四个步骤:
serviceName = "HDF_PLATFORM_MMC_2";
deviceMatchAttr = "hi3516_mmc_sdio"; // SDIO类型
}
...
......
}
}
}
...
...
@@ -184,7 +204,7 @@ MMC模块适配包含以下四个步骤:
freqMax = 100000000; // 【必要】最大频率值
freqDef = 400000; // 【必要】默认频率值
maxBlkNum = 2048; // 【必要】最大的block号
maxBlkSize = 512; // 【必要】最大的block个数
maxBlkSize = 512; // 【必要】最大block大小
ocrDef = 0x300000; // 【必要】工作电压设置相关
caps2 = 0; // 【必要】属性寄存器相关,见mmc_caps.h中MmcCaps2定义。
regSize = 0x118; // 【必要】寄存器位宽
...
...
@@ -230,7 +250,7 @@ MMC模块适配包含以下四个步骤:
#include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/mmc/mmc_config.hcs" // 配置文件相对路径
```
3.
实例化MMC控制器对象
。
3.
实例化MMC控制器对象
完成配置属性文件之后,下一步就是以核心层MmcCntlr对象的初始化为核心,包括驱动适配自定义结构体(传递参数和数据),实例化MmcCntlr成员MmcCntlrOps(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind、Init、Release)。
...
...
@@ -287,7 +307,7 @@ MMC模块适配包含以下四个步骤:
};
```
-
MmcCntlr成员钩子函数结构体MmcCntlrOps的实例化,其他成员在Bind函数中初始
化。
- MmcCntlr成员钩子函数结构体MmcCntlrOps的实例
化。
```c
static struct MmcCntlrOps g_himciHostOps = {
...
...
@@ -317,9 +337,9 @@ MMC模块适配包含以下四个步骤:
返回值:
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS
定义)。
HDF_STATUS相关状态(表3为部分展示,如需使用其他状态,可参考//drivers/hdf_core/framework/include/utils/hdf_base.h中HDF_STATUS的
定义)。
**表2** Bind函数
说明
**表 3** HDF_STATUS相关状态
说明
| 状态(值) | 问题描述 |
| -------- | -------- |
...
...
@@ -331,7 +351,6 @@ MMC模块适配包含以下四个步骤:
| HDF_FAILURE | 初始化失败 |
函数说明:
MmcCntlr、HimciHost、HdfDeviceObject之间互相赋值,方便其他函数可以相互转化,初始化自定义结构体HimciHost对象,初始化MmcCntlr成员,调用核心层MmcCntlrAdd函数,完成MMC控制器的添加。
```c
...
...
@@ -349,13 +368,13 @@ MMC模块适配包含以下四个步骤:
cntlr->hdfDevObj = obj; // 【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
obj->service = &cntlr->service; // 【必要】使HdfDeviceObject与MmcCntlr可以相互转化的前提
ret = MmcCntlrParse(cntlr, obj); // 【必要】 初始化cntlr,失败就goto _ERR。
...
...
...
ret = HimciHostParse(host, obj); // 【必要】 初始化host对象的相关属性,失败就goto _ERR。
...
...
...
ret = HimciHostInit(host, cntlr); // 驱动适配者自定义的初始化,失败就goto _ERR。
...
...
...
ret = MmcCntlrAdd(cntlr); // 调用核心层函数,失败就goto _ERR。
...
...
...
(void)MmcCntlrAddDetectMsgToQueue(cntlr); // 将卡检测消息添加到队列中。
HDF_LOGD("HimciMmcBind: success.");
return HDF_SUCCESS;
...
...
@@ -417,13 +436,13 @@ MMC模块适配包含以下四个步骤:
static void HimciMmcRelease(struct HdfDeviceObject *obj)
{
struct MmcCntlr *cntlr = NULL;
...
...
...
cntlr = (struct MmcCntlr *)obj->service; // 这里有HdfDeviceObject到MmcCntlr的强制转化,通过service成员,赋值见Bind函数。
...
...
...
HimciDeleteHost((struct HimciHost *)cntlr->priv); // 驱动适配者自定义的内存释放函数,这里有MmcCntlr到HimciHost的强制转化。
}
```
4.
驱动调试
。
4.
驱动调试
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。
\ No newline at end of file
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据读写成功与否等。
zh-cn/device-dev/driver/driver-platform-pin-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-pin-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-pwm-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-pwm-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-regulator-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-regulator-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-rtc-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-rtc-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-sdio-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-sdio-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-spi-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-spi-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-uart-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-uart-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-watchdog-des.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
zh-cn/device-dev/driver/driver-platform-watchdog-develop.md
浏览文件 @
952ecd1c
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录