未验证 提交 d31322d7 编写于 作者: O openharmony_ci 提交者: Gitee

!19440 Platform文档刷新

Merge pull request !19440 from 贾子扬/master
......@@ -4,29 +4,30 @@
### 功能简介<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>
![](figures/ADC物理连线示意图.png "ADC物理连线示意图")
![ADC物理连线示意图](figures/ADC物理连线示意图.png)
ADC接口定义了完成AD转换的通用方法集合,包括:
- ADC设备管理:打开或关闭ADC设备。
- ADC读取转换结果:读取AD转换结果。
### 基本概念<a name="section3"></a>
- 分辨率
分辨率指的是ADC模块能够转换的二进制位数,位数越多分辨率越高。
分辨率指的是ADC模块能够转换的二进制位数,位数越多分辨率越高。
- 转换误差
转换误差通常是以输出误差的最大值形式给出。它表示A/D转换器实际输出的数字量和理论上的输出数字量之间的差别。常用最低有效位的倍数表示。
转换误差通常是以输出误差的最大值形式给出。它表示A/D转换器实际输出的数字量和理论上的输出数字量之间的差别。常用最低有效位的倍数表示。
- 转换时间
转换时间是指A/D转换器从转换控制信号到来开始,到输出端得到稳定的数字信号所经过的时间。
转换时间是指A/D转换器从转换控制信号到来开始,到输出端得到稳定的数字信号所经过的时间。
### 运作机制<a name="section4"></a>
......@@ -50,18 +51,18 @@ ADC模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/
<a name="table1"></a>
| 接口名 | 接口描述 |
| 接口名 | 接口描述 |
| -------- | ---------------- |
| DevHandle AdcOpen(uint32_t number) | 打开ADC设备 |
| void AdcClose(DevHandle handle) | 关闭ADC设备 |
| int32_t AdcRead(DevHandle handle, uint32_t channel, uint32_t \*val) | 读取AD转换结果值 |
| DevHandle AdcOpen(uint32_t number) | 打开ADC设备 |
| void AdcClose(DevHandle handle) | 关闭ADC设备 |
| int32_t AdcRead(DevHandle handle, uint32_t channel, uint32_t \*val) | 读取AD转换结果值 |
### 开发步骤<a name="section9"></a>
使用ADC设备的一般流程如图2所示。
**图 2** ADC使用流程图<a name="fig2"></a>
![](figures/ADC使用流程图.png "ADC使用流程图")
**图 2** ADC使用流程图<a name="fig2"></a>
![ADC使用流程图](figures/ADC使用流程图.png)
#### 打开ADC设备
......@@ -76,23 +77,23 @@ DevHandle AdcOpen(int16_t number);
<a name="table2"></a>
| 参数 | 参数描述 |
| 参数 | 参数描述 |
| ---------- | ----------------- |
| number | ADC设备号 |
| **返回值** | **返回值描述** |
| NULL | 打开ADC设备失败 |
| 设备句柄 | 打开的ADC设备句柄 |
| number | int16_t类型,ADC设备号 |
| **返回值** | **返回值描述** |
| NULL | 打开ADC设备失败 |
| 设备句柄 | 打开的ADC设备句柄 |
假设系统中存在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;
}
```
......@@ -106,14 +107,14 @@ int32_t AdcRead(DevHandle handle, uint32_t channel, uint32_t *val);
<a name="table3"></a>
| 参数 | 参数描述 |
| 参数 | 参数描述 |
| ---------- | -------------- |
| 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;
}
```
......@@ -138,16 +139,16 @@ void AdcClose(DevHandle handle);
<a name="table4"></a>
| 参数 | 参数描述 |
| 参数 | 参数描述 |
| ------ | ----------- |
| 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;
......
......@@ -7,29 +7,32 @@
DAC(Digital to Analog Converter)是一种通过电流、电压或电荷的形式将数字信号转换为模拟信号的设备,主要用于:
- 作为过程控制计算机系统的输出通道,与执行器相连,实现对生产过程的自动控制。
- 在利用反馈技术的模数转换器设计中,作为重要的功能模块呈现。
DAC接口定义了完成DAC传输的通用方法集合,包括:
- DAC设备管理:打开或关闭DAC设备。
- DAC设置目标值:设置DAC设备需要将数字信号转成模拟信号的目标值。
### 基本概念
- 分辨率
分辨率指的是DAC模块能够转换的二进制位数,位数越多分辨率越高。
分辨率指的是DAC模块能够转换的二进制位数,位数越多分辨率越高。
- 转换精度
精度是指输入端加有最大数值时,DAC的实际输出值和理论计算值之差,DAC转换器的转换精度与DAC转换器的集成芯片结构和接口电路配置有关。理想情况下,DAC的转换精度越小越好,因此为了获得更高精度的DAC转换结果,首先要保证选择的DAC转换器具备足够高的分辨率。其次,接口电路的器件或电源存在误差时,会造成DAC转换的误差,若这些误差超过一定程度,就会导致DAC转换错误。
精度是指输入端加有最大数值时,DAC的实际输出值和理论计算值之差,DAC转换器的转换精度与DAC转换器的集成芯片结构和接口电路配置有关。理想情况下,DAC的转换精度越小越好,因此为了获得更高精度的DAC转换结果,首先要保证选择的DAC转换器具备足够高的分辨率。其次,接口电路的器件或电源存在误差时,会造成DAC转换的误差,若这些误差超过一定程度,就会导致DAC转换错误。
- 转换速度
转换速度一般由建立时间决定。从输入由全0突变为全1时开始,到输出电压稳定在FSR±½LSB范围(或以FSR±x%FSR指明范围)内为止,这段时间称为建立时间,它是DAC的最大响应时间,所以用它衡量转换速度的快慢。
转换速度一般由建立时间决定。从输入由全0突变为全1时开始,到输出电压稳定在FSR±½LSB范围(或以FSR±x%FSR指明范围)内为止,这段时间称为建立时间,它是DAC的最大响应时间,所以用它衡量转换速度的快慢。
满量程范围FSR(Full Scale Range),是指DAC输出信号幅度的最大范围,不同的DAC有不同的满量程范围,该范围可以用正、负电流或者正、负电压来限制。
满量程范围FSR(Full Scale Range),是指DAC输出信号幅度的最大范围,不同的DAC有不同的满量程范围,该范围可以用正、负电流或者正、负电压来限制。
最低有效位LSB(Least Significant Byte),指的是一个二进制数字中的第0位(即最低位)。
最低有效位LSB(Least Significant Byte),指的是一个二进制数字中的第0位(即最低位)。
### 运作机制
......@@ -59,10 +62,10 @@ DAC模块提供的主要接口如下所示,具体API详见//drivers/hdf_core/f
**表 1** DAC驱动API接口功能介绍
| 接口名 | 接口描述 |
| 接口名 | 接口描述 |
| ------------------------------------------------------------------ | ------------ |
| 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,78 +79,80 @@ DAC模块提供的主要接口如下所示,具体API详见//drivers/hdf_core/f
在进行DA转换之前,首先要调用DacOpen打开DAC设备,打开函数如下所示:
```c++
```c
DevHandle DacOpen(uint32_t number);
```
**表 2** DacOpen参数和返回值描述
| 参数 | 参数描述 |
| 参数 | 参数描述 |
| --------- | ---------------- |
| number | DAC设备号。 |
| **返回值** | **返回值描述** |
| NULL | 打开DAC设备失败。 |
| 设备句柄 | 打开的DAC设备句柄。 |
| number | uint32_t类型,DAC设备号。 |
| **返回值** | **返回值描述** |
| NULL | 打开DAC设备失败。 |
| 设备句柄 | 打开的DAC设备句柄。 |
假设系统中存在2个DAC设备,编号从0到1,现在打开1号设备。
```c++
DevHandle dacHandle = NULL; // DAC设备句柄
```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);
```
**表 3** DacWrite参数和返回值描述
| 参数 | 参数描述 |
| 参数 | 参数描述 |
| --------- | ------------ |
| 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);
```
**表 4** DacClose参数和返回值描述
| 参数 | 参数描述 |
| 参数 | 参数描述 |
| --------- | ------------ |
| handle | DAC设备句柄。 |
| 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;
}
```
\ No newline at end of file
```
......@@ -8,10 +8,13 @@ GPIO(General-purpose input/output)即通用型输入输出。通常,GPIO
GPIO接口定义了操作GPIO管脚的标准方法集合,包括:
- 设置管脚方向:方向可以是输入或者输出(暂不支持高阻态)。
- 读写管脚电平值:电平值可以是低电平或高电平。
- 设置管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式。
- 使能和禁止管脚中断:禁止或使能管脚中断。
- 设置、获取管脚方向:方向可以是输入或者输出(暂不支持高阻态)。
- 读、写管脚电平值:电平值可以是低电平或高电平。
- 设置、取消管脚中断服务函数:设置一个管脚的中断响应函数,以及中断触发方式。取消一个管脚的中断服务函数。
- 使能、禁止管脚中断:禁止或使能管脚中断。
### 基本概念
......@@ -19,11 +22,11 @@ GPIO又俗称为I/O口,I指的是输入(in),O指的是输出(out)。
- GPIO输入
输入是检测各个引脚上的电平状态,高电平或者低电平状态。常见的输入模式有:模拟输入、浮空输入、上拉输入、下拉输入。
输入是检测各个引脚上的电平状态,高电平或者低电平状态。常见的输入模式有:模拟输入、浮空输入、上拉输入、下拉输入。
- GPIO输出
输出是当需要控制引脚电平的高低时需要用到输出功能。常见的输出模式有:开漏输出、推挽输出、复用开漏输出、复用推挽输出。
输出是当需要控制引脚电平的高低时需要用到输出功能。常见的输出模式有:开漏输出、推挽输出、复用开漏输出、复用推挽输出。
### 运作机制
......@@ -34,7 +37,9 @@ GPIO又俗称为I/O口,I指的是输入(in),O指的是输出(out)。
GPIO模块各分层作用:
- 接口层提供操作GPIO管脚的标准方法。
- 核心层主要提供GPIO管脚资源匹配,GPIO管脚控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互,供芯片厂家快速接入HDF框架。
- 适配层主要是将钩子函数的功能实例化,实现具体的功能。
**图 1** GPIO统一服务模式结构图
......@@ -45,36 +50,36 @@ 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管脚电平值 |
| int32_t GpioWrite(uint16_t gpio, uint16_t val) | 写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 GpioEnableIrq(uint16_t gpio) | 使能GPIO管脚中断 |
| int32_t GpioDisableIrq(uint16_t gpio) | 禁止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 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 GpioEnableIrq(uint16_t gpio) | 使能GPIO管脚中断 |
| int32_t GpioDisableIrq(uint16_t gpio) | 禁止GPIO管脚中断 |
>![](../public_sys-resources/icon-note.gif) **说明:**<br>
>本文涉及GPIO的所有接口,支持内核态及用户态使用。
### 开发步骤
GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如下图所示。
GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流程如图2所示。
**图1** GPIO使用流程图
**图 2** GPIO使用流程图
![image](figures/GPIO使用流程图.png "GPIO使用流程图")
![GPIO使用流程图](figures/GPIO使用流程图.png)
#### 确定GPIO管脚号
......@@ -82,31 +87,31 @@ GPIO标准API通过GPIO管脚号来操作指定管脚,使用GPIO的一般流
- 根据SOC芯片规则进行计算
不同SOC芯片由于其GPIO控制器型号、参数、以及控制器驱动的不同,GPIO管脚号的换算方式不一样。
不同SOC芯片由于其GPIO控制器型号、参数、以及控制器驱动的不同,GPIO管脚号的换算方式不一样。
- Hi3516DV300
- Hi3516DV300
控制器管理12组GPIO管脚,每组8个。
控制器管理12组GPIO管脚,每组8个。
GPIO号 = GPIO组索引 (0~11) \* 每组GPIO管脚数(8) + 组内偏移
GPIO号 = GPIO组索引 (0~11) \* 每组GPIO管脚数(8) + 组内偏移
举例:GPIO10_3的GPIO号 = 10 \* 8 + 3 = 83
举例:GPIO10_3的GPIO号 = 10 \* 8 + 3 = 83
- Hi3518EV300
- Hi3518EV300
控制器管理10组GPIO管脚,每组10个。
控制器管理10组GPIO管脚,每组10个。
GPIO号 = GPIO组索引 (0~9) \* 每组GPIO管脚数(10) + 组内偏移
GPIO号 = GPIO组索引 (0~9) \* 每组GPIO管脚数(10) + 组内偏移
举例:GPIO7_3的GPIO管脚号 = 7 \* 10 + 3 = 73
举例:GPIO7_3的GPIO管脚号 = 7 \* 10 + 3 = 73
- 通过管脚别名获取
调用接口GpioGetByName进行获取,入参是该管脚的别名,接口返回值是管脚的全局ID。
调用接口GpioGetByName进行获取,入参是该管脚的别名,接口返回值是管脚的全局ID。
```c
GpioGetByName(const char *gpioName);
```
```c
GpioGetByName(const char *gpioName);
```
#### 设置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 | 待设置的方向值 |
| **返回值** | **返回值描述** |
| 0 | 设置成功 |
| 负数 | 设置失败 |
| gpio | uint16_t类型,GPIO管脚号 |
| dir | uint16_t类型,待设置的方向值 |
| **返回值** | **返回值描述** |
| 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 | 获取到的方向值指针 |
| **返回值** | **返回值描述** |
| 0 | 设置成功 |
| 负数 | 设置失败 |
| gpio | uint16_t类型,GPIO管脚号 |
| dir | uint16_t类型指针,获取到的方向值 |
| **返回值** | **返回值描述** |
| 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 | 接收读取电平值的指针 |
| **返回值** | **返回值描述** |
| 0 | 读取成功 |
| 负数 | 读取失败 |
| gpio | uint16_t类型,GPIO管脚号 |
| val | uint16_t类型指针,接收读取电平值 |
| **返回值** | **返回值描述** |
| 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 | 待写入的电平值 |
| **返回值** | **返回值描述** |
| 0 | 写入成功 |
| 负数 | 写入失败 |
| gpio | uint16_t类型,GPIO管脚号 |
| val | uint16_t类型,待写入的电平值 |
| **返回值** | **返回值描述** |
| 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("GpioRead: failed, ret %d\n", ret);
if (ret != HDF_SUCCESS) {
HDF_LOGE("GpioWrite: 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 | 传递给中断服务程序的入参 |
| **返回值** | **返回值描述** |
| 0 | 设置成功 |
| 负数 | 设置失败 |
| gpio | uint16_t类型,GPIO管脚号 |
| mode | uint16_t类型,中断触发模式 |
| func | 函数指针,中断服务程序 |
| arg | 无类型指针,传递给中断服务程序的入参 |
| **返回值** | **返回值描述** |
| HDF_SUCCESS | 设置GPIO管脚中断成功 |
| 负数 | 设置GPIO管脚中断失败 |
> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:**<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管脚中断失败 |
> ![icon-caution.gif](public_sys-resources/icon-caution.gif) **注意:**<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 = 83; /* 待测试的GPIO管脚号 */
uint16_t gpio = 84; // 待测试的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;
}
```
\ No newline at end of file
```
# HDMI
# 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独立服务模式
- 适配层主要是将钩子函数的功能实例化,实现具体的功能。
![image1](figures/独立服务模式结构图.png)
**图 1** HDMI独立服务模式
![HDMI独立服务模式](figures/独立服务模式结构图.png)
### 约束与限制
HDMI模块当前仅支持轻量和小型系统内核(LiteOS)
HDMI模块当前仅支持轻量和小型系统内核(LiteOS),暂无实际适配驱动
## 开发指导
......@@ -41,6 +47,7 @@ HDMI具有体积小、传输速率高、传输带宽宽、兼容性好、能同
### 接口说明
HdmiCntlrOps定义:
```c
struct HdmiCntlrOps {
void (*hardWareInit)(struct HdmiCntlr *cntlr);
......@@ -80,17 +87,17 @@ struct HdmiCntlrOps {
};
```
**表1** HdmiCntlrOps结构体成员的回调函数功能说明
**表 1** HdmiCntlrOps结构体成员的回调函数功能说明
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| ------------------------ | ------------------------------------------------------------ | -------------------------------------- | ------------------ | -------------------------------------------------- |
| hardWareInit | **cntlr**:结构体指针,核心层HDMI控制器 | 无 | 无 | 初始化HDMI硬件 |
| hardWareStatusGet | **cntlr**:结构体指针,核心层HDMI控制器<br /> | **status**:HDMI硬件状态 ; | 无 | 获取HDMI当前硬件状态 |
| controllerReset | **cntlr**:结构体指针,核心层HDMI控制器 | 无 | 无 | 复位HDMI控制器 |
| hotPlugStateGet | **cntlr**:结构体指针,核心层HDMI控制器 | 无 | bool:HDMI热插拔状态 | 获取HDMI热插拔状态 |
| hardWareInit | **cntlr**:结构体指针,核心层HDMI控制器 | 无 | 无 | 初始化HDMI硬件 |
| hardWareStatusGet | **cntlr**:结构体指针,核心层HDMI控制器<br /> | **status**:HDMI硬件状态 ; | 无 | 获取HDMI当前硬件状态 |
| controllerReset | **cntlr**:结构体指针,核心层HDMI控制器 | 无 | 无 | 复位HDMI控制器 |
| hotPlugStateGet | **cntlr**:结构体指针,核心层HDMI控制器 | 无 | bool:HDMI热插拔状态 | 获取HDMI热插拔状态 |
| hotPlugInterruptStateGet | **cntlr**:结构体指针,核心层HDMI控制器 | 无 | bool:HDMI热插拔中断状态 | 获取HDMI热插拔中断状态 |
| lowPowerSet | **cntlr**:结构体指针,核心层HDMI控制器<br />**enable**:bool,使能/去使能 | 无 | 无 | 使能/去使能低功耗 |
| tmdsModeSet | **cntlr**:结构体指针,核心层HDMI控制器<br />**mode**:TMDS模式 | 无 | 无 | 设置TMDS模式 |
| lowPowerSet | **cntlr**:结构体指针,核心层HDMI控制器<br />**enable**:bool,使能/去使能 | 无 | 无 | 使能/去使能低功耗 |
| tmdsModeSet | **cntlr**:结构体指针,核心层HDMI控制器<br />**mode**:TMDS模式 | 无 | 无 | 设置TMDS模式 |
| tmdsConfigSet | **cntlr**:结构体指针,核心层HDMI控制器<br />**mode**:TMDS参数 | 无 | HDF_STATUS相关状态 | 配置TMDS参数 |
| infoFrameEnable | **cntlr**:结构体指针,核心层HDMI控制器<br />**infoFrameType**:packet类型<br />**enable**:bool,使能/去使能 | 无 | 无 | 使能/去使能infoFrame |
| infoFrameSend | **cntlr**:结构体指针,核心层HDMI控制器<br />**infoFrameType**:packet类型<br />**data**:infoFrame数据<br />**len**:数据长度 | 无 | HDF_STATUS相关状态 | 发送infoFrame |
......@@ -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框架中
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配置参考
......@@ -181,8 +196,8 @@ HDMI模块适配的三个环节是实例化驱动入口、配置属性文件以
- hdmi_config.hcs 配置参考
```c
root {
platform {
root {
platform {
hdmi_config {
template hdmi_controller { // 模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省。
match_attr = ""; //【必要】需要和device_info.hcs中的deviceMatchAttr值一致。
......@@ -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&nbsp;错误 |
| 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传输等。
# I2C
## 概述
### 功能简介
......@@ -16,12 +15,14 @@ I2C数据的传输必须以一个起始信号作为开始条件,以一个结
I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址,当主设备需要和某一个从设备通信时,通过广播的方式,将从设备地址写到总线上,如果某个从设备符合此地址,将会发出应答信号,建立传输。
I2C接口定义了完成I2C传输的通用方法集合,包括:
- I2C控制器管理:打开或关闭I2C控制器
- I2C消息传输:通过消息传输结构体数组进行自定义传输
**图1** I2C物理连线示意图
**图 1** I2C物理连线示意图
![image](figures/I2C物理连线示意图.png "I2C物理连线示意图")
![I2C物理连线示意图](figures/I2C物理连线示意图.png)
## 使用指导
......@@ -33,9 +34,9 @@ I2C通常用于与各类支持I2C协议的传感器、执行器或输入输出
I2C模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/i2c_if.h。
**表1** I2C驱动API接口功能介绍
**表 1** I2C驱动API接口功能介绍
| 接口名 | 接口描述 |
| 接口名 | 接口描述 |
| -------- | -------- |
| DevHandle I2cOpen(int16_t number) | 打开I2C控制器 |
| void I2cClose(DevHandle handle) | 关闭I2C控制器 |
......@@ -45,9 +46,9 @@ I2C模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/
使用I2C设备的一般流程如下图所示。
**图2** I2C设备使用流程图
**图 2** I2C设备使用流程图
![image](figures/I2C设备使用流程图.png "I2C设备使用流程图")
![I2C设备使用流程图](figures/I2C设备使用流程图.png)
#### 打开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接口的完整使用流程。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册