Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Docs
提交
68396e7c
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看板
未验证
提交
68396e7c
编写于
7月 11, 2022
作者:
O
openharmony_ci
提交者:
Gitee
7月 11, 2022
浏览文件
操作
浏览文件
下载
差异文件
!6144 【OpenHarmony开源贡献者计划2022】update api documents.
Merge pull request !6144 from Mr_YX/master
上级
c74ec1ed
206c9555
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
1028 addition
and
1049 deletion
+1028
-1049
zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md
zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md
+368
-372
zh-cn/device-dev/driver/driver-platform-dac-des.md
zh-cn/device-dev/driver/driver-platform-dac-des.md
+201
-209
zh-cn/device-dev/driver/driver-platform-dac-develop.md
zh-cn/device-dev/driver/driver-platform-dac-develop.md
+459
-468
未找到文件。
zh-cn/device-dev/driver/driver-peripherals-vibrator-des.md
浏览文件 @
68396e7c
# Vibrator
# Vibrator
## 概述
## 概述
### 功能简介
### 功能简介
为了快速开发传感器驱动,基于HDF(Hardware Driver Foundation)驱动框架开发了马达(Vibrator)驱动模型。马达驱动模型,屏蔽设备驱动与系统交互的实现,为硬件服务层提供统一稳定的驱动接口能力,为驱动开发者提供开放的接口和解析接口的能力,用于不同操作系统马达设备部件的部署指导和马达设备部件驱动的开发。马达驱动模型如图1所示:
为了快速开发传感器驱动,基于HDF(Hardware Driver Foundation)驱动框架开发了马达(Vibrator)驱动模型。马达驱动模型,屏蔽设备驱动与系统交互的实现,为硬件服务层提供统一稳定的驱动接口能力,为驱动开发者提供开放的接口和解析接口的能力。用于不同操作系统马达设备部件的部署指导和马达设备部件驱动的开发。马达驱动模型如图1所示:
**图 1**
马达驱动模型图
**图 1**
马达驱动模型图


### 基本概念
### 基本概念
系统通过调用马达实现对设备的振动控制。目前,马达只有两种振动方式:
系统通过调用马达实现对设备的振动控制。目前,马达只有两种振动方式:
-
单次振动
-
单次振动
单次振动是指按照指定的时间控制振动时长。
单次振动是指按照指定的时间控制振动时长。
-
周期振动
-
周期振动
周期振动是指按照预置的效果模式控制振动。例如:预置效果为“haptic.clock.timer” = [600, 600, 200, 600],等待600ms,振动600ms,等待200ms,振动600ms。
周期振动是指按照预置的效果模式控制振动。例如:预置效果为“haptic.clock.timer” = [600, 600, 200, 600],等待600ms,振动600ms,等待200ms,振动600ms。
### 运作机制
### 运作机制
通过介绍马达驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如图2所示:
通过介绍马达驱动模型的加载以及运行流程,对模型内部关键组件以及关联组件之间的关系进行了划分,整体加载流程如图2所示:
**图2**
马达驱动运行图
**图2**
马达驱动运行图


马达驱动模型以标准系统Hi3516DV300产品为例,介绍整个驱动加载及运行流程:
马达驱动模型以标准系统Hi3516DV300产品为例,介绍整个驱动加载及运行流程:
1.
从device_info.hcs配置文件中的Vibrator Host读取Vibrator管理配置信息。
1.
从device_info.hcs配置文件中的Vibrator Host读取Vibrator管理配置信息。
2.
解析Vibrator管理配置信息,并关联对应马达抽象驱动。
2.
解析Vibrator管理配置信息,并关联对应马达抽象驱动。
3.
从linear_vibrator_config.hcs配置文件中读取Vibrator数据配置信息。
3.
从linear_vibrator_config.hcs配置文件中读取Vibrator数据配置信息。
4.
解析Vibrator数据配置信息,并关联对应Haptic驱动。
4.
解析Vibrator数据配置信息,并关联对应Haptic驱动。
5.
客户端下发Vibrator Stub控制到服务端。
5.
客户端下发Vibrator Stub控制到服务端。
6.
Vibrator Stub控制调用马达服务。
6.
Vibrator Stub控制调用马达服务。
7.
初始化马达抽象驱动接口。
7.
初始化马达抽象驱动接口。
8.
Haptic中起线程,解析效果模块。
8.
Haptic中起线程,解析效果模块。
9.
Haptic调用马达抽象驱动中的Start接口。
9.
Haptic调用马达抽象驱动中的Start接口。
10.
马达抽象驱动调用马达差异化驱动中的Start接口。
10.
马达抽象驱动调用马达差异化驱动中的Start接口。
## 开发指导
## 开发指导
### 场景介绍
### 场景介绍
当设备需要设置不同的振动效果时,可以调用Vibrator模块,例如,设备的按键可以设置不同强度和时长的振动,闹钟和来电可以设置不同强度和时长的单次或周期性振动。
当设备需要设置不同的振动效果时,可以调用Vibrator模块,例如,设备的按键可以设置不同强度和时长的振动,闹钟和来电可以设置不同强度和时长的单次或周期性振动。
### 接口说明
### 接口说明
马达驱动模型支持静态HCS配置和动态参数两种振动效果配置能力。马达硬件服务调用StartOnce接口动态配置持续振动;调用Start接口启动静态配置的振动效果。马达驱动模型对HDI开放的API接口能力,如下表所示。
马达驱动模型支持静态HCS配置和动态参数两种振动效果配置能力。马达硬件服务调用StartOnce接口动态配置持续振动;调用Start接口启动静态配置的振动效果。马达驱动模型对HDI开放的API接口能力,如下所示。
**表 1**
马达驱动模型对外API接口能力介绍
**表 1**
马达驱动模型对外API接口能力介绍
| 接口名 | 功能描述 |
| 接口名 | 功能描述 |
| -------------------------------------- | ------------------------------------------------ |
| -------------------------------------- | -------------------------------------------------------- |
| int32_t StartOnce(uint32_t duration) | 按照指定持续时间触发振动马达,duration为振动持续时长。 |
| int32_t StartOnce(uint32_t duration) | 按照指定持续时间触发振动马达,duration为振动持续时长。 |
| int32_t Start(const char
*
effectType) | 按照指定预置效果启动马达,effectType表示预置的预置效果。 |
| int32_t Start(const char
*
effectType) | 按照指定预置效果启动马达,effectType表示预置的预置效果。 |
| int32_t Stop(enum VibratorMode mode) | 按照指定的振动模式停止马达振动。 |
| int32_t Stop(enum VibratorMode mode) | 按照指定的振动模式停止马达振动。 |
### 开发步骤
### 开发步骤
Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能力接口,包括马达一次振动、马达效果配置震动、马达停止。基于HDF驱动框架开发的马达驱动模型,实现跨操作系统迁移、器件差异配置等功能。具体的开发步骤如下:
Vibrator驱动模型为上层马达硬件服务层提供稳定的马达控制能力接口,包括马达一次振动、马达效果配置震动、马达停止。基于HDF驱动框架开发的马达驱动模型,实现跨操作系统迁移、器件差异配置等功能。马达具体的开发步骤如下:
1.
基于HDF驱动框架,按照驱动Driver Entry程序,完成马达抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现,配置资源和HCS解析。
1.
基于HDF驱动框架,按照驱动Driver Entry程序,完成马达抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现,配置资源和HCS解析。
-
调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出马达驱动模型,使用HCS作为配置描述源码。HCS配置字段详细介绍参考
[
配置管理
](
https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md
)
。其中Driver Entry入口函数定义如下:
-
调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出马达驱动模型,使用HCS作为配置描述源码。HCS配置字段详细介绍参考
[
配置管理
](
https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md
)
。其中Driver Entry入口函数定义如下:
```c
```
c
/* 注册马达抽象驱动入口数据结构体对象 */
/* 注册马达抽象驱动入口数据结构体对象 */
struct HdfDriverEntry g_vibratorDriverEntry = {
struct
HdfDriverEntry
g_vibratorDriverEntry
=
{
.moduleVersion = 1, // 马达模块版本号
.
moduleVersion
=
1
,
// 马达模块版本号
.moduleName = "HDF_VIBRATOR", // 马达模块名,要与device_info.hcs文件里的马达moduleName字段值一样
.
moduleName
=
"HDF_VIBRATOR"
,
// 马达模块名,要与device_info.hcs文件里的马达moduleName字段值一样
.Bind = BindVibratorDriver, // 马达绑定函数
.
Bind
=
BindVibratorDriver
,
// 马达绑定函数
.Init = InitVibratorDriver, // 马达初始化函数
.
Init
=
InitVibratorDriver
,
// 马达初始化函数
.Release = ReleaseVibratorDriver, // 马达资源释放函数
.
Release
=
ReleaseVibratorDriver
,
// 马达资源释放函数
};
};
HDF_INIT(g_vibratorDriverEntry);
HDF_INIT
(
g_vibratorDriverEntry
);
```
```
-
基于HDF驱动框架,按照驱动Driver Entry程序,完成马达抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。
-
基于HDF驱动框架,按照驱动Driver Entry程序,完成马达抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现。
```c
```
c
/* 马达驱动对外发布的能力 */
/* 马达驱动对外发布的能力 */
static int32_t DispatchVibrator(struct HdfDeviceIoClient *client,
static
int32_t
DispatchVibrator
(
struct
HdfDeviceIoClient
*
client
,
int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
int32_t
cmd
,
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
{
{
int32_t loop;
int32_t
loop
;
for (loop = 0; loop < sizeof(g_vibratorCmdHandle) / sizeof(g_vibratorCmdHandle[0]); ++loop) {
for
(
loop
=
0
;
loop
<
sizeof
(
g_vibratorCmdHandle
)
/
sizeof
(
g_vibratorCmdHandle
[
0
]);
++
loop
)
{
if ((cmd == g_vibratorCmdHandle[loop].cmd) && (g_vibratorCmdHandle[loop].func != NULL)) {
if
((
cmd
==
g_vibratorCmdHandle
[
loop
].
cmd
)
&&
(
g_vibratorCmdHandle
[
loop
].
func
!=
NULL
))
{
return g_vibratorCmdHandle[loop].func(data, reply);
return
g_vibratorCmdHandle
[
loop
].
func
(
data
,
reply
);
}
}
}
}
return HDF_SUCCESS;
return
HDF_SUCCESS
;
}
}
/* 马达驱动对外提供的服务绑定到HDF框架 */
/* 马达驱动对外提供的服务绑定到HDF框架 */
int32_t BindVibratorDriver(struct HdfDeviceObject *device)
int32_t
BindVibratorDriver
(
struct
HdfDeviceObject
*
device
)
{
{
struct VibratorDriverData *drvData = NULL;
struct
VibratorDriverData
*
drvData
=
NULL
;
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE
(
device
,
HDF_FAILURE
);
drvData = (struct VibratorDriverData *)OsalMemCalloc(sizeof(*drvData));
drvData
=
(
struct
VibratorDriverData
*
)
OsalMemCalloc
(
sizeof
(
*
drvData
));
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_MALLOC_FAIL);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE
(
drvData
,
HDF_ERR_MALLOC_FAIL
);
drvData->ioService.Dispatch = DispatchVibrator;
drvData
->
ioService
.
Dispatch
=
DispatchVibrator
;
drvData->device = device;
drvData
->
device
=
device
;
device->service = &drvData->ioService;
device
->
service
=
&
drvData
->
ioService
;
g_vibratorDrvData = drvData;
g_vibratorDrvData
=
drvData
;
return HDF_SUCCESS;
return
HDF_SUCCESS
;
}
}
/* 马达驱动初始化入口函数*/
/* 马达驱动初始化入口函数*/
int32_t InitVibratorDriver(struct HdfDeviceObject *device)
int32_t
InitVibratorDriver
(
struct
HdfDeviceObject
*
device
)
{
{
struct VibratorDriverData *drvData = NULL;
struct
VibratorDriverData
*
drvData
=
NULL
;
drvData->mode = VIBRATOR_MODE_BUTT;
drvData
->
mode
=
VIBRATOR_MODE_BUTT
;
drvData->state = VIBRATOR_STATE_IDLE;
drvData
->
state
=
VIBRATOR_STATE_IDLE
;
......
......
if (CreateVibratorHaptic(device) != HDF_SUCCESS) {
if
(
CreateVibratorHaptic
(
device
)
!=
HDF_SUCCESS
)
{
HDF_LOGE("%s: init workQueue fail!", __func__);
HDF_LOGE
(
"%s: init workQueue fail!"
,
__func__
);
return HDF_FAILURE;
return
HDF_FAILURE
;
}
}
return HDF_SUCCESS;
return
HDF_SUCCESS
;
}
}
/* 释放马达驱动初始化时分配的资源 */
/* 释放马达驱动初始化时分配的资源 */
void ReleaseVibratorDriver(struct HdfDeviceObject *device)
void
ReleaseVibratorDriver
(
struct
HdfDeviceObject
*
device
)
{
{
struct VibratorDriverData *drvData = NULL;
struct
VibratorDriverData
*
drvData
=
NULL
;
......
......
(void)DestroyVibratorHaptic();
(
void
)
DestroyVibratorHaptic
();
(void)OsalMutexDestroy(&drvData->mutex);
(
void
)
OsalMutexDestroy
(
&
drvData
->
mutex
);
(void)OsalMemFree(drvData);
(
void
)
OsalMemFree
(
drvData
);
g_vibratorDrvData = NULL;
g_vibratorDrvData
=
NULL
;
}
}
```
```
-
在系统启动过程中,HDF设备管理模块通过设备HCS配置信息,加载马达抽象驱动,并对外发布马达驱动接口。
-
在系统启动过程中,HDF设备管理模块通过设备HCS配置信息,加载马达抽象驱动,并对外发布马达驱动接口。
```c
```
c
/* 马达设备HCS配置 */
/* 马达设备HCS配置 */
vibrator :: host {
vibrator
::
host
{
hostName = "vibrator_host";
hostName
=
"vibrator_host"
;
device_vibrator :: device {
device_vibrator
::
device
{
device0 :: deviceNode {
device0
::
deviceNode
{
policy = 2; // 驱动服务发布的策略
policy
=
2
;
// 驱动服务发布的策略
priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议配置100,优先级相同则不保证device的加载顺序
priority
=
100
;
// 驱动启动优先级(0-200),值越大优先级越低,建议配置100,优先级相同则不保证device的加载顺序
preload = 0; // 驱动按需加载字段,0表示加载,2表示不加载
preload
=
0
;
// 驱动按需加载字段,0表示加载,2表示不加载
permission = 0664; // 驱动创建设备节点权限
permission
=
0664
;
// 驱动创建设备节点权限
moduleName = "HDF_VIBRATOR"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
moduleName
=
"HDF_VIBRATOR"
;
// 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
serviceName = "hdf_misc_vibrator"; // 驱动对外发布服务的名称,必须唯一
serviceName
=
"hdf_misc_vibrator"
;
// 驱动对外发布服务的名称,必须唯一
deviceMatchAttr = "hdf_vibrator_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
deviceMatchAttr
=
"hdf_vibrator_driver"
;
// 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等
}
}
}
}
```
```
2.
创建马达效果模型,解析马达效果HCS配置。
2.
创建马达效果模型,解析马达效果HCS配置。
-
创建马达效果模型。
-
创建马达效果模型。
```hcs
```
hcs
/* 创建马达效果模型,分配资源,解析马达效果HCS配置 */
/* 创建马达效果模型,分配资源,解析马达效果HCS配置 */
int32_t CreateVibratorHaptic(struct HdfDeviceObject *device)
int32_t CreateVibratorHaptic(struct HdfDeviceObject *device)
{
{
struct VibratorHapticData *hapticData = NULL;
struct VibratorHapticData *hapticData = NULL;
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(device, HDF_FAILURE);
hapticData = (struct VibratorHapticData *)OsalMemCalloc(sizeof(*hapticData));
hapticData = (struct VibratorHapticData *)OsalMemCalloc(sizeof(*hapticData));
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_ERR_MALLOC_FAIL);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(hapticData, HDF_ERR_MALLOC_FAIL);
g_vibratorHapticData = hapticData;
g_vibratorHapticData = hapticData;
hapticData->supportHaptic = false;
hapticData->supportHaptic = false;
if (OsalMutexInit(&hapticData->mutex) != HDF_SUCCESS) {
if (OsalMutexInit(&hapticData->mutex) != HDF_SUCCESS) {
HDF_LOGE("%s: fail to init mutex", __func__);
HDF_LOGE("%s: fail to init mutex", __func__);
goto EXIT;
goto EXIT;
}
}
DListHeadInit(&hapticData->effectSeqHead);
DListHeadInit(&hapticData->effectSeqHead);
/* 解析马达效果HCS配置 */
/* 解析马达效果HCS配置 */
if (ParserVibratorHapticConfig(device->property) != HDF_SUCCESS) {
if (ParserVibratorHapticConfig(device->property) != HDF_SUCCESS) {
HDF_LOGE("%s: parser haptic config fail!", __func__);
HDF_LOGE("%s: parser haptic config fail!", __func__);
goto EXIT;
goto EXIT;
}
}
return HDF_SUCCESS;
return HDF_SUCCESS;
EXIT:
EXIT:
OsalMemFree(hapticData);
OsalMemFree(hapticData);
return HDF_FAILURE;
return HDF_FAILURE;
}
}
```
```
-
马达效果模型使用HCS作为配置描述源码,hcs配置文件字段详细介绍参考
[
配置管理
](
https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md
)
。
-
马达效果模型使用HCS作为配置描述源码,hcs配置文件字段详细介绍参考
[
配置管理
](
https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md
)
。
```hcs
```
/* 马达数据配置模板(vibrator_config.hcs) */
/* 马达数据配置模板(vibrator_config.hcs) */
root {
root {
vibratorConfig {
vibratorConfig {
boardConfig {
boardConfig {
match_attr = "hdf_vibrator_driver"; // 需要和马达设备配置match_attr字段保持一致
match_attr = "hdf_vibrator_driver"; // 需要和马达设备配置match_attr字段保持一致
vibratorAttr {
vibratorAttr {
/* 0:转子;1:线性 */
/* 0:转子;1:线性 */
deviceType = 1; // 设备类型
deviceType = 1; // 设备类型
supportPreset = 1; // 支持的预设类型
supportPreset = 1; // 支持的预设类型
}
}
vibratorHapticConfig {
vibratorHapticConfig {
haptic_clock_timer {
haptic_clock_timer {
effectName = "haptic.clock.timer";
effectName = "haptic.clock.timer";
type = 1; // 0:内置模式;1:时间序列
type = 1; // 0:内置模式;1:时间序列
seq = [600, 600, 200, 600]; // 时间序列
seq = [600, 600, 200, 600]; // 时间序列
}
}
haptic_default_effect {
haptic_default_effect {
effectName = "haptic.default.effect";
effectName = "haptic.default.effect";
type = 0;
type = 0;
seq = [0, 3, 800, 1];
seq = [0, 3, 800, 1];
}
}
}
}
}
}
}
}
}
}
```
```
3.
完成马达振动和停止接口开发,会根据振动效果的模式创建和销毁定时器。
3.
完成马达振动和停止接口开发,会根据振动效果的模式创建和销毁定时器。
马达硬件服务调用StartOnce接口动态配置持续振动时间;调用StartEffect接口启动静态配置的振动效果,为驱动开发者提供抽象的配置接口能力。
马达硬件服务调用StartOnce接口动态配置持续振动时间;调用StartEffect接口启动静态配置的振动效果,为驱动开发者提供抽象的配置接口能力。
```
c
```
c
/* 按照指定持续时间触发振动马达,duration为振动持续时长 */
/* 按照指定持续时间触发振动马达,duration为振动持续时长 */
static
int32_t
StartOnce
(
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
static
int32_t
StartOnce
(
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
{
{
uint32_t
duration
;
uint32_t
duration
;
int32_t
ret
;
int32_t
ret
;
struct
VibratorEffectCfg
config
;
struct
VibratorEffectCfg
config
;
struct
VibratorDriverData
*
drvData
=
GetVibratorDrvData
();
struct
VibratorDriverData
*
drvData
=
GetVibratorDrvData
();
(
void
)
reply
;
(
void
)
reply
;
......
......
config
.
cfgMode
=
VIBRATOR_MODE_ONCE
;
config
.
cfgMode
=
VIBRATOR_MODE_ONCE
;
config
.
duration
=
duration
;
config
.
duration
=
duration
;
config
.
effect
=
NULL
;
config
.
effect
=
NULL
;
/* 根据振动效果的模式创建定时器 */
/* 根据振动效果的模式创建定时器 */
ret
=
StartHaptic
(
&
config
);
ret
=
StartHaptic
(
&
config
);
if
(
ret
!=
HDF_SUCCESS
)
{
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: start haptic fail!"
,
__func__
);
HDF_LOGE
(
"%s: start haptic fail!"
,
__func__
);
return
ret
;
return
ret
;
}
}
return
HDF_SUCCESS
;
return
HDF_SUCCESS
;
}
}
/* 按照预置效果启动马达,effectType表示预置的预置效果 */
/* 按照预置效果启动马达,effectType表示预置的预置效果 */
static
int32_t
StartEffect
(
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
static
int32_t
StartEffect
(
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
{
{
int32_t
ret
;
int32_t
ret
;
const
char
*
effect
=
NULL
;
const
char
*
effect
=
NULL
;
struct
VibratorEffectCfg
config
;
struct
VibratorEffectCfg
config
;
struct
VibratorDriverData
*
drvData
=
GetVibratorDrvData
();
struct
VibratorDriverData
*
drvData
=
GetVibratorDrvData
();
(
void
)
reply
;
(
void
)
reply
;
......
......
config
.
cfgMode
=
VIBRATOR_MODE_PRESET
;
config
.
cfgMode
=
VIBRATOR_MODE_PRESET
;
config
.
duration
=
0
;
config
.
duration
=
0
;
config
.
effect
=
effect
;
config
.
effect
=
effect
;
ret
=
StartHaptic
(
&
config
);
ret
=
StartHaptic
(
&
config
);
if
(
ret
!=
HDF_SUCCESS
)
{
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: start haptic fail!"
,
__func__
);
HDF_LOGE
(
"%s: start haptic fail!"
,
__func__
);
return
ret
;
return
ret
;
}
}
return
HDF_SUCCESS
;
return
HDF_SUCCESS
;
}
}
/* 按照指定的振动模式停止马达振动 */
/* 按照指定的振动模式停止马达振动 */
static
int32_t
Stop
(
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
static
int32_t
Stop
(
struct
HdfSBuf
*
data
,
struct
HdfSBuf
*
reply
)
{
{
int32_t
ret
;
int32_t
ret
;
int32_t
mode
;
int32_t
mode
;
struct
VibratorDriverData
*
drvData
=
GetVibratorDrvData
();
struct
VibratorDriverData
*
drvData
=
GetVibratorDrvData
();
(
void
)
reply
;
(
void
)
reply
;
......
......
/* 停止马达效果振动,销毁马达定时器 */
/* 停止马达效果振动,销毁马达定时器 */
ret
=
StopHaptic
();
ret
=
StopHaptic
();
if
(
ret
!=
HDF_SUCCESS
)
{
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: stop haptic fail!"
,
__func__
);
HDF_LOGE
(
"%s: stop haptic fail!"
,
__func__
);
return
ret
;
return
ret
;
}
}
(
void
)
OsalMutexLock
(
&
drvData
->
mutex
);
(
void
)
OsalMutexLock
(
&
drvData
->
mutex
);
drvData
->
mode
=
VIBRATOR_MODE_BUTT
;
drvData
->
mode
=
VIBRATOR_MODE_BUTT
;
(
void
)
OsalMutexUnlock
(
&
drvData
->
mutex
);
(
void
)
OsalMutexUnlock
(
&
drvData
->
mutex
);
return
HDF_SUCCESS
;
return
HDF_SUCCESS
;
}
}
```
```
4.
马达驱动模型提供给开发者马达驱动差异化接口,开发者实现差异化接口。
4.
马达驱动模型提供给开发者马达驱动差异化接口,开发者实现差异化接口。
-
在差异化器件驱动初始化成功时,注册差异实现接口,方便实现器件差异的驱动接口。
-
在差异化器件驱动初始化成功时,注册差异实现接口,方便实现器件差异的驱动接口。
```c
```
c
/* 注册马达差异化实现接口 */
/* 注册马达差异化实现接口 */
int32_t RegisterVibrator(struct VibratorOps *ops)
int32_t
RegisterVibrator
(
struct
VibratorOps
*
ops
)
{
{
struct VibratorDriverData *drvData = GetVibratorDrvData();
struct
VibratorDriverData
*
drvData
=
GetVibratorDrvData
();
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(ops, HDF_FAILURE);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE
(
ops
,
HDF_FAILURE
);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE
(
drvData
,
HDF_FAILURE
);
(void)OsalMutexLock(&drvData->mutex);
(
void
)
OsalMutexLock
(
&
drvData
->
mutex
);
drvData->ops.Start = ops->Start;
drvData
->
ops
.
Start
=
ops
->
Start
;
drvData->ops.StartEffect = ops->StartEffect;
drvData
->
ops
.
StartEffect
=
ops
->
StartEffect
;
drvData->ops.Stop = ops->Stop;
drvData
->
ops
.
Stop
=
ops
->
Stop
;
(void)OsalMutexUnlock(&drvData->mutex);
(
void
)
OsalMutexUnlock
(
&
drvData
->
mutex
);
return HDF_SUCCESS;
return
HDF_SUCCESS
;
}
}
```
```
-
马达驱动模型提供给开发者马达驱动差异化接口,具体实现如下:
-
马达驱动模型提供给开发者马达驱动差异化接口,具体实现如下:
```c
```
c
/* 按照指定持续时间触发线性马达的振动 */
/* 按照指定持续时间触发线性马达的振动 */
static int32_t StartLinearVibrator()
static
int32_t
StartLinearVibrator
()
{
{
int32_t ret;
int32_t
ret
;
struct VibratorLinearDriverData *drvData = GetLinearVibratorData();
struct
VibratorLinearDriverData
*
drvData
=
GetLinearVibratorData
();
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE
(
drvData
,
HDF_FAILURE
);
......
......
ret = GpioWrite(drvData->gpioNum, GPIO_VAL_LOW);
ret
=
GpioWrite
(
drvData
->
gpioNum
,
GPIO_VAL_LOW
);
if (ret != HDF_SUCCESS) {
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, drvData->gpioNum, GPIO_VAL_LOW);
HDF_LOGE
(
"%s: pull gpio%d to %d level failed"
,
__func__
,
drvData
->
gpioNum
,
GPIO_VAL_LOW
);
return ret;
return
ret
;
}
}
return HDF_SUCCESS;
return
HDF_SUCCESS
;
}
}
/* 按照预置振动效果触发线性马达的振动 */
/* 按照预置振动效果触发线性马达的振动 */
static int32_t StartEffectLinearVibrator(uint32_t effectType)
static
int32_t
StartEffectLinearVibrator
(
uint32_t
effectType
)
{
{
(void)effectType;
(
void
)
effectType
;
HDF_LOGE("%s: vibrator set build-in effect no support!", __func__);
HDF_LOGE
(
"%s: vibrator set build-in effect no support!"
,
__func__
);
return HDF_SUCCESS;
return
HDF_SUCCESS
;
}
}
/* 按照指定的振动模式停止线性马达的振动 */
/* 按照指定的振动模式停止线性马达的振动 */
static int32_t StopLinearVibrator()
static
int32_t
StopLinearVibrator
()
{
{
int32_t ret;
int32_t
ret
;
struct VibratorLinearDriverData *drvData = GetLinearVibratorData();
struct
VibratorLinearDriverData
*
drvData
=
GetLinearVibratorData
();
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE(drvData, HDF_FAILURE);
CHECK_VIBRATOR_NULL_PTR_RETURN_VALUE
(
drvData
,
HDF_FAILURE
);
......
......
ret = GpioWrite(drvData->gpioNum, GPIO_VAL_HIGH);
ret
=
GpioWrite
(
drvData
->
gpioNum
,
GPIO_VAL_HIGH
);
if (ret != HDF_SUCCESS) {
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE("%s: pull gpio%d to %d level failed", __func__, drvData->gpioNum, GPIO_VAL_HIGH);
HDF_LOGE
(
"%s: pull gpio%d to %d level failed"
,
__func__
,
drvData
->
gpioNum
,
GPIO_VAL_HIGH
);
return ret;
return
ret
;
}
}
return HDF_SUCCESS;
return
HDF_SUCCESS
;
}
}
```
```
\ No newline at end of file
zh-cn/device-dev/driver/driver-platform-dac-des.md
浏览文件 @
68396e7c
# DAC
# DAC
## 概述
## 概述
### 功能简介
### 功能简介
DAC(Digital to Analog Converter)是一种通过电流、电压或电荷的形式将数字信号转换为模拟信号的设备。
DAC(Digital to Analog Converter)是一种通过电流、电压或电荷的形式将数字信号转换为模拟信号的设备。
DAC接口定义了完成DAC传输的通用方法集合,包括:
DAC接口定义了完成DAC传输的通用方法集合,包括:
-
DAC设备管理:打开或关闭DAC设备。
-
DAC设备管理:打开或关闭DAC设备。
-
DAC设置目标值:设置DAC设备需要将数字信号转成模拟信号的目标值。
-
DAC设置目标值:设置DAC设备需要将数字信号转成模拟信号的目标值。
### 基本概念
### 基本概念
DAC模块支持数模转换的开发,它主要用于:
DAC模块支持数模转换的开发,它主要用于:
1.
作为过程控制计算机系统的输出通道,与执行器相连,实现对生产过程的自动控制。
2.
在利用反馈技术的模数转换器设计中,作为重要的功能模块呈现。
1.
作为过程控制计算机系统的输出通道,与执行器相连,实现对生产过程的自动控制。
2.
在利用反馈技术的模数转换器设计中,作为重要的功能模块呈现。
-
分辨率
-
分辨率
分辨率指的是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位(即最低位)。
### 运作机制
### 运作机制
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),如果采用独立服务模式,则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。DAC模块接口适配模式采用统一服务模式,如图1所示。
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),如果采用独立服务模式则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。DAC模块接口适配模式采用统一服务模式,如图1所示。
DAC模块各分层的作用为:接口层提供打开设备、写入数据和关闭设备的接口。核心层主要提供绑定设备、初始化设备以及释放设备的能力。适配层实现其它具体的功能。
DAC模块各分层的作用为:接口层提供打开设备,写入数据,关闭设备的接口。核心层主要提供绑定设备、初始化设备以及释放设备的能力。适配层实现其他具体的功能。

说明:
<br>
核心层可以调用接口层的函数,核心层通过钩子函数调用适配层函数,从而适配层可以间接的调用接口层函数,但是不可逆转接口层调用适配层函数。

说明:
<br>
核心层可以调用接口层的函数,核心层通过钩子函数调用适配层函数,从而适配层间接的可以调用接口层函数,但是不可逆转接口层调用适配层函数。
**图 1**
DAC统一服务模式
**图 1**
DAC统一服务模式


### 约束与限制
### 约束与限制
DAC模块当前仅支持轻量和小型系统内核(LiteOS)。
DAC模块当前仅支持轻量和小型系统内核(LiteOS)。
## 使用指导
## 使用指导
### 场景介绍
### 场景介绍
DAC模块的主要工作是以电流、电压或电荷的形式将数字信号转换为模拟信号,主要应用于音频设备中。日常所见的音响、耳机等,均使用DAC模块作为数模转换的通道。
DAC模块的主要工作是以电流、电压或电荷的形式将数字信号转换为模拟信号,主要应用于音频设备中。日常所见的音响、耳机等,均使用DAC模块作为数模转换的通道。
### 接口说明
### 接口说明
DAC模块提供的主要接口如下所示,更多关于接口的介绍请参考对应的API接口文档。
DAC模块提供的主要接口如下所示,更多关于接口的介绍请参考对应的API接口文档。
**表 1**
DAC驱动API接口功能介绍
**表 1**
DAC驱动API接口功能介绍
| 接口名 | 描述 |
| ------------------------------------------------------------------ | ------------ |
| 接口名 | 描述 |
| DevHandle DacOpen(uint32_t number) | 打开DAC设备。 |
| :------------------------------------------------------------| :------------ |
| void DacClose(DevHandle handle) | 关闭DAC设备。 |
| DevHandle DacOpen(uint32_t number) | 打开DAC设备 |
| int32_t DacWrite(DevHandle handle, uint32_t channel, uint32_t val) | 设置DA目标值。 |
| void DacClose(DevHandle handle) | 关闭DAC设备 |
| int32_t DacWrite(DevHandle handle, uint32_t channel, uint32_t val) | 设置DA目标值 |
### 开发步骤
### 开发步骤
使用DAC设备的一般流程如图2所示。
使用DAC设备的一般流程如图2所示。
**图 2**
DAC使用流程图

**图 2**
DAC使用流程图

#### 打开DAC设备
#### 打开DAC设备
在进行DA转换之前,首先要调用DacOpen打开DAC设备,打开函数如下所示:
在进行DA转换之前,首先要调用DacOpen打开DAC设备,打开函数如下所示:
```
c++
DevHandle
DacOpen
(
uint32_t
number
);
```
```
DevHandle DacOpen(uint32_t number);
```
**表 2**
DacOpen参数和返回值描述
**表 2**
DacOpen参数和返回值描述
| 参数 | 参数描述 |
| --------- | ---------------- |
| 参数 | 参数描述 |
| number | DAC设备号。 |
| ---------- | ----------------- |
|
**返回值**
|
**返回值描述**
|
| number | DAC设备号 |
| NULL | 打开DAC设备失败。 |
|
**返回值**
|
**返回值描述**
|
| 设备句柄 | 打开的DAC设备句柄。 |
| NULL | 打开DAC设备失败 |
| 设备句柄 | 打开的DAC设备句柄 |
假设系统中存在2个DAC设备,编号从0到1,现在打开1号设备。
```
c++
DevHandle
dacHandle
=
NULL
;
/* DAC设备句柄 /
假设系统中存在2个DAC设备,编号从0到1,现在打开1号设备。
/* 打开DAC设备 */
```
dacHandle
=
DacOpen
(
1
);
DevHandle dacHandle = NULL; /* DAC设备句柄 /
if
(
dacHandle
==
NULL
)
{
HDF_LOGE
(
"DacOpen: failed
\n
"
);
/* 打开DAC设备 */
return
;
dacHandle = DacOpen(1);
}
if (dacHandle == NULL) {
```
HDF_LOGE("DacOpen: failed\n");
return;
#### 设置DA目标值
}
```
```
c++
int32_t
DacWrite
(
DevHandle
handle
,
uint32_t
channel
,
uint32_t
val
);
#### 设置DA目标值
```
```
**表 3**
DacWrite参数和返回值描述
int32_t DacWrite(DevHandle handle, uint32_t channel, uint32_t val);
```
| 参数 | 参数描述 |
| --------- | ------------ |
**表 3**
DacWrite参数和返回值描述
| handle | DAC设备句柄。 |
| channel | DAC设备通道号。|
| val | 设置DA的值。 |
| 参数 | 参数描述 |
|
**返回值**
|
**返回值描述**
|
| ---------- | -------------- |
| 0 | 写入成功。 |
| handle | DAC设备句柄 |
| 负数 | 写入失败。 |
| channel | DAC设备通道号 |
| val | 设置DA的值 |
```
c++
|
**返回值**
|
**返回值描述**
|
/* 通过DAC_CHANNEL_NUM设备通道写入目标val值 */
| 0 | 写入成功 |
ret
=
DacWrite
(
dacHandle
,
DAC_CHANNEL_NUM
,
val
);
| 负数 | 写入失败 |
if
(
ret
!=
HDF_SUCCESS
)
{
HDF_LOGE
(
"%s: tp DAC write reg fail!:%d"
,
__func__
,
ret
);
```
DacClose
(
dacHandle
);
/* 通过DAC_CHANNEL_NUM设备通道写入目标val值 */
return
-
1
;
ret = DacWrite(dacHandle, DAC_CHANNEL_NUM, val);
}
if (ret != HDF_SUCCESS) {
```
HDF_LOGE("%s: tp DAC write reg fail!:%d", __func__, ret);
DacClose(dacHandle);
#### 关闭DAC设备
return -1;
}
DAC通信完成之后,需要关闭DAC设备,关闭函数如下所示:
```
```
c++
void
DacClose
(
DevHandle
handle
);
#### 关闭DAC设备
```
DAC通信完成之后,需要关闭DAC设备,关闭函数如下所示:
**表 4**
DacClose参数和返回值描述
```
void DacClose(DevHandle handle);
| 参数 | 参数描述 |
```
| --------- | ------------ |
| handle | DAC设备句柄。 |
**表 4**
DacClose参数和返回值描述
|
**返回值**
|
**返回值描述**
|
| void | 无 |
| 参数 | 参数描述 |
关闭DAC设备示例:
| ---------- | -------------- |
| handle | DAC设备句柄 |
```
c++
|
**返回值**
|
**返回值描述**
|
DacClose
(
dacHandle
);
/* 关闭DAC设备 */
| void | 无 |
```
## 使用实例
关闭DAC设备示例:
DAC设备的具体使用方式可以参考如下示例代码,示例代码步骤主要如下:
```
1.
根据设备号DAC_DEVICE_NUM打开DAC设备得到设备句柄。
DacClose(dacHandle); /* 关闭DAC设备 */
2.
通过DAC的设备号以及设备通道设置val的值,如果写入失败则关闭设备句柄。
```
3.
访问完毕DAC设备后,则关闭该设备句柄。
## 使用实例
运行结果:根据输入的val通过打印日志得到输出的结果。
DAC设备的具体使用方式可以参考如下示例代码,示例代码步骤主要如下:
```
c++
#include "dac_if.h"
/* DAC标准接口头文件 */
1.
根据设备号DAC_DEVICE_NUM打开DAC设备得到设备句柄。
#include "hdf_log.h"
/* 标准日志打印头文件 */
2.
通过DAC的设备号以及设备通道设置val的值,如果写入失败则关闭设备句柄。
3.
访问完毕DAC设备后,则关闭该设备句柄。
/* 设备号0,通道号1 */
#define DAC_DEVICE_NUM 0
运行结果:根据输入的val通过打印日志得到输出的结果。
#define DAC_CHANNEL_NUM 1
```
/* DAC例程总入口 */
#include "dac_if.h" /* DAC标准接口头文件 */
static
int32_t
TestCaseDac
(
void
)
#include "hdf_log.h" /* 标准日志打印头文件 */
{
// 设置要写入的val值
/* 设备号0,通道号1 */
uint32_t
val
=
2
;
#define DAC_DEVICE_NUM 0
int32_t
ret
;
#define DAC_CHANNEL_NUM 1
DevHandle
dacHandle
;
/* DAC例程总入口 */
/* 打开DAC设备 */
static int32_t TestCaseDac(void)
dacHandle
=
DacOpen
(
DAC_DEVICE_NUM
);
{
if
(
dacHandle
==
NULL
)
{
// 设置要写入的val值
HDF_LOGE
(
"%s: Open DAC%u fail!"
,
__func__
,
DAC_DEVICE_NUM
);
uint32_t val = 2;
return
-
1
;
int32_t ret;
}
DevHandle dacHandle;
/* 写入数据 */
/* 打开DAC设备 */
ret
=
DacWrite
(
dacHandle
,
DAC_CHANNEL_NUM
,
val
);
dacHandle = DacOpen(DAC_DEVICE_NUM);
if
(
ret
!=
HDF_SUCCESS
)
{
if (dacHandle == NULL) {
HDF_LOGE
(
"%s: tp DAC write reg fail!:%d"
,
__func__
,
ret
);
HDF_LOGE("%s: Open DAC%u fail!", __func__, DAC_DEVICE_NUM);
DacClose
(
dacHandle
);
return -1;
return
-
1
;
}
}
/* 写入数据 */
/* 访问完毕关闭DAC设备 */
ret = DacWrite(dacHandle, DAC_CHANNEL_NUM, val);
DacClose
(
dacHandle
);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: tp DAC write reg fail!:%d", __func__, ret);
return
0
;
DacClose(dacHandle);
}
return -1;
```
}
\ No newline at end of file
/* 访问完毕关闭DAC设备 */
DacClose(dacHandle);
return 0;
}
```
zh-cn/device-dev/driver/driver-platform-dac-develop.md
浏览文件 @
68396e7c
# DAC
# DAC
## 概述
## 概述
### 功能简介
### 功能简介
DAC(Digital to Analog Converter)是一种通过电流、电压或电荷的形式将数字信号转换为模拟信号的设备。
DAC(Digital to Analog Converter)是一种通过电流、电压或电荷的形式将数字信号转换为模拟信号的设备。
DAC模块支持数模转换的开发。它主要用于:
DAC模块支持数模转换的开发。它主要用于:
1.
作为过程控制计算机系统的输出通道,与执行器相连,实现对生产过程的自动控制。
1.
作为过程控制计算机系统的输出通道,与执行器相连,实现对生产过程的自动控制。
2.
在利用反馈技术的魔术转换器设计中,作为重要的功能模块呈现。
2.
在利用反馈技术的魔术转换器设计中,作为重要的功能模块呈现。
### 基本概念
### 基本概念
-
分辨率
-
分辨率
分辨率指的是D/A转换器能够转换的二进制位数,位数越多分辨率越高。
分辨率指的是D/A转换器能够转换的二进制位数,位数越多分辨率越高。
-
转换精度
-
转换精度
精度是指输入端加有最大数值时,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位(即最低位)。
### 运作机制
### 运作机制
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。DAC模块接口适配模式采用统一服务模式(如图1所示)。
在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式,则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。DAC模块接口适配模式采用统一服务模式(如图1所示)。
DAC模块各分层的作用为:接口层提供打开设备,写入数据,关闭设备接口的能力。核心层主要提供绑定设备、初始化设备以及释放设备的能力。适配层实现其他具体的功能。
DAC模块各分层的作用为:接口层提供打开设备、写入数据和关闭设备接口的能力。核心层主要提供绑定设备、初始化设备以及释放设备的能力。适配层实现其他具体的功能。

说明:
<br>
核心层可以调用接口层的函数,也可以通过钩子函数调用适配层函数,从而使得适配层间接的可以调用接口层函数,但是不可逆转接口层调用适配层函数。

说明:
<br>
核心层可以调用接口层的函数,也可以通过钩子函数调用适配层函数,从而使得适配层间接的可以调用接口层函数,但是不可逆转接口层调用适配层函数。
**图 1**
统一服务模式
**图 1**
统一服务模式


### 约束与限制
DAC模块当前仅支持轻量和小型系统内核(LiteOS)。
### 约束与限制
## 开发指导
DAC模块当前仅支持轻量和小型系统内核(LiteOS)。
### 场景介绍
## 开发指导
DAC模块主要在设备中数模转换、音频输出和电机控制等设备使用,设置将DAC模块传入的数字信号转换为输出模拟信号时需要用到DAC数模转换驱动。
### 场景介绍
### 接口说明
DAC模块主要在设备中数模转换,音频输出,电机控制等设备使用,设置将DAC模块传入的数字信号转换为输出模拟信号时需要用到DAC数模转换驱动。
通过以下DacMethod中的函数调用DAC驱动对应的函数。
### 接口说明
DacMethod定义:
通过以下DacMethod中的函数调用DAC驱动对应的函数。
```
c++
DacMethod定义:
struct
DacMethod
{
// 写入数据的钩子函数
```
int32_t
(
*
write
)(
struct
DacDevice
*
device
,
uint32_t
channel
,
uint32_t
val
);
struct DacMethod {
// 启动DAC设备的钩子函数
// 写入数据的钩子函数
int32_t
(
*
start
)(
struct
DacDevice
*
device
);
int32_t (*write)(struct DacDevice *device, uint32_t channel, uint32_t val);
// 停止DAC设备的钩子函数
// 启动DAC设备的钩子函数
int32_t
(
*
stop
)(
struct
DacDevice
*
device
);
int32_t (*start)(struct DacDevice *device);
};
// 停止DAC设备的钩子函数
```
int32_t (*stop)(struct DacDevice *device);
};
**表 1**
DacMethod结构体成员的回调函数功能说明
```
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
**表 1**
DacMethod结构体成员的回调函数功能说明
| -------- | ------------------------------------------------------------ | ---- | ------------------ | -------------- |
| write | device:结构体指针,核心层DAC控制器
<br>
channel:uint32_t,传入的通道号
<br>
val:uint32_t,要传入的数据 | 无 | HDF_STATUS相关状态 | 写入DA的目标值 |
| start | device:结构体指针,核心层DAC控制器 | 无 | HDF_STATUS相关状态 | 开启DAC设备 |
| stop | device:结构体指针,核心层DAC控制器 | 无 | HDF_STATUS相关状态 | 关闭DAC设备 |
| 函数成员 | 入参 | 出参 | 返回值 | 功能 |
| -------- | ------------------------------------------------------------ | ---- | ------------------ | -------------- |
### 开发步骤
| write | device:结构体指针,核心层DAC控制器
<br>
channel:uint32_t,传入的通道号
<br>
val:uint32_t,要传入的数据 | 无 | HDF_STATUS相关状态 | 写入DA的目标值 |
| start | device:结构体指针,核心层DAC控制器 | 无 | HDF_STATUS相关状态 | 开启DAC设备 |
DAC模块适配包含以下四个步骤:
| stop | device:结构体指针,核心层DAC控制器 | 无 | HDF_STATUS相关状态 | 关闭DAC设备 |
1.
实例化驱动入口。
2.
配置属性文件。
3.
实例化核心层接口函数。
### 开发步骤
4.
驱动调试。
DAC模块适配包含以下四个步骤:
### 开发实例
-
实例化驱动入口。
下方将展示厂商需要提供哪些内容来完整实现设备功能。
-
配置属性文件。
-
实例化核心层接口函数。
1.
实例化驱动入口:
-
驱动调试。
驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。HDF框架会汇总所有加载的驱动的HdfDriverEntry对象入口,形成一个类似数组的段地址空间,方便上层调用。
1.
实例化驱动入口:
一般在加载驱动时HDF会先调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。 HDF框架会汇总所有加载的驱动的HdfDriverEntry对象入口 ,形成一个类似数组的段地址空间,方便上层调用。
```c++
一般在加载驱动时HDF会先调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
static struct HdfDriverEntry g_dacDriverEntry = {
.moduleVersion = 1,
```
.Init = VirtualDacInit,
static struct HdfDriverEntry g_dacDriverEntry = {
.Release = VirtualDacRelease,
.moduleVersion = 1,
.moduleName = "virtual_dac_driver", //【必要且与 HCS 里面的名字匹配】
.Init = VirtualDacInit,
};
.Release = VirtualDacRelease,
HDF_INIT(g_dacDriverEntry); // 调用HDF_INIT将驱动入口注册到HDF框架中
.moduleName = "virtual_dac_driver", //【必要且与 HCS 里面的名字匹配】
```
};
HDF_INIT(g_dacDriverEntry); // 调用HDF_INIT将驱动入口注册到HDF框架中
2.
配置属性文件:
```
-
在vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode描述。
2.
配置属性文件:
器件属性值对于厂商驱动的实现以及核心层DacDevice相关成员的默认值或限制范围有密切关系,比如设备通道的个数以及传输速率的最大值,会影响DacDevice相关成员的默认值。
-
在vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode描述。
由于采用了统一服务模式,device_info.hcs文件中第一个设备节点必须为DAC管理器,其各项参数必须如下设置:
器件属性值对于厂商驱动的实现以及核心层DacDevice相关成员的默认值或限制范围有密切关系,比如设备通道的个数以及传输速率的最大值,会影响DacDevice相关成员的默认值。
| 成员名 | 值 |
由于采用了统一服务模式,device_info.hcs文件中第一个设备节点必须为DAC管理器,其各项参数必须如下设置:
| --------------- | ------------------------------------------------------------------- |
| policy | 具体配置为0,不发布服务 |
| 成员名 | 值 |
| priority | 驱动启动优先级(0-200),值越大优先级越低,优先级相同则不保证device的加载顺序。|
| --------------- | ------------------------------------------------------------ |
| permission | 驱动权限 |
| policy | 具体配置为0,不发布服务|
| moduleName | 固定为HDF_PLATFORM_DAC_MANAGER |
| priority | 驱动启动优先级(0-200),值越大优先级越低,优先级相同则不保证device的加载顺序。|
| serviceName | 固定为HDF_PLATFORM_DAC_MANAGER |
| permission | 驱动权限|
| deviceMatchAttr | 没有使用,可忽略 |
| moduleName | 固定为HDF_PLATFORM_DAC_MANAGER|
| serviceName | 固定为HDF_PLATFORM_DAC_MANAGER|
从第二个节点开始配置具体DAC控制器信息,此节点并不表示某一路DAC控制器,而是代表一个资源性质设备,用于描述一类DAC控制器的信息。本例只有一个DAC设备,如有多个设备,则需要在device_info文件增加deviceNode信息,以及在dac_config文件中增加对应的器件属性。
| deviceMatchAttr | 没有使用,可忽略|
device_info.hcs配置参考。
从第二个节点开始配置具体DAC控制器信息,此节点并不表示某一路DAC控制器,而是代表一个资源性质设备,用于描述一类DAC控制器的信息。本例只有一个DAC设备,如有多个设备,则需要在device_info文件增加deviceNode信息,以及在dac_config文件中增加对应的器件属性。
```hcs
device_info.hcs配置参考。
root {
device_dac :: device {
```
// device0是DAC管理器
root {
device0 :: deviceNode {
device_dac :: device {
policy = 0;
// device0是DAC管理器
priority = 52;
device0 :: deviceNode {
permission = 0644;
policy = 0;
serviceName = "HDF_PLATFORM_DAC_MANAGER";
priority = 52;
moduleName = "HDF_PLATFORM_DAC_MANAGER";
permission = 0644;
}
serviceName = "HDF_PLATFORM_DAC_MANAGER";
}
moduleName = "HDF_PLATFORM_DAC_MANAGER";
// dac_virtual是DAC控制器
}
dac_virtual :: deviceNode {
}
policy = 0;
// dac_virtual是DAC控制器
priority = 56;
dac_virtual :: deviceNode {
permission = 0644;
policy = 0;
moduleName = "virtual_dac_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致
priority = 56;
serviceName = "VIRTUAL_DAC_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一
permission = 0644;
deviceMatchAttr = "virtual_dac"; //【必要】用于配置控制器私有数据,要与dac_config.hcs中对应控制器保持一致
moduleName = "virtual_dac_driver"; //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致
}
serviceName = "VIRTUAL_DAC_DRIVER"; //【必要】驱动对外发布服务的名称,必须唯一
}
deviceMatchAttr = "virtual_dac"; //【必要】用于配置控制器私有数据,要与dac_config.hcs中对应控制器保持一致
```
}
}
- 添加dac_test_config.hcs器件属性文件
```
在vendor/vendor_hisilicon/hispark_taurus/hdf_config/hdf_test/xxx_test_config.hcs目录下新增文件用于驱动配置参数,(例如:vendor/vendor_hisilicon/hispark_taurus/hdf_config/hdf_test/dac_test_config.hcs)其中配置参数如下:
-
添加dac_test_config.hcs器件属性文件
```hcs
在vendor/vendor_hisilicon/hispark_taurus/hdf_config/hdf_test/xxx_test_config.hcs目录下新增文件用于驱动配置参数,(例如:vendor/vendor_hisilicon/hispark_taurus/hdf_config/hdf_test/dac_test_config.hcs)其中配置参数如下:
root {
platform {
```
dac_config {
root {
match_attr = "virtual_dac"; //【必要】需要和device_info.hcs中的deviceMatchAttr值一致
platform {
template dac_device {
dac_config {
deviceNum = 0; // 设备号
match_attr = "virtual_dac"; //【必要】需要和device_info.hcs中的deviceMatchAttr值一致
validChannel = 0x1; // 有效通道1
template dac_device {
rate = 20000; // 速率
deviceNum = 0; // 设备号
}
validChannel = 0x1; // 有效通道1
device_0 :: dac_device {
rate = 20000; // 速率
deviceNum = 0; // 设备号
}
validChannel = 0x2; // 有效通道2
device_0 :: dac_device {
}
deviceNum = 0; // 设备号
}
validChannel = 0x2; // 有效通道2
}
}
}
}
```
}
}
3.
实例化核心层接口函数:
```
-
初始化DacDevice成员。
3.
实例化核心层接口函数:
在VirtualDacParseAndInit函数中对DacDevice成员进行初始化操作。
-
初始化DacDevice成员。
```c++
在VirtualDacParseAndInit函数中对DacDevice成员进行初始化操作。
// 虚拟驱动自定义结构体
struct VirtualDacDevice {
```
// DAC设备结构体
// 虚拟驱动自定义结构体
struct DacDevice device;
struct VirtualDacDevice {
// DAC设备号
// DAC设备结构体
uint32_t deviceNum;
struct DacDevice device;
// 有效通道
// DAC设备号
uint32_t validChannel;
uint32_t deviceNum;
// DAC速率
// 有效通道
uint32_t rate;
uint32_t validChannel;
};
// DAC速率
// 解析并且初始化核心层DacDevice对象
uint32_t rate;
static int32_t VirtualDacParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
};
{
// 解析并且初始化核心层DacDevice对象
// 定义返回值
static int32_t VirtualDacParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
int32_t ret;
{
// DAC设备虚拟指针
// 定义返回值
struct VirtualDacDevice *virtual = NULL;
int32_t ret;
(void)device;
// DAC设备虚拟指针
// 给virtual指针开辟空间
struct VirtualDacDevice *virtual = NULL;
virtual = (struct VirtualDacDevice *)OsalMemCalloc(sizeof(*virtual));
(void)device;
if (virtual == NULL) {
// 给virtual指针开辟空间
// 为空则返回错误参数
virtual = (struct VirtualDacDevice *)OsalMemCalloc(sizeof(*virtual));
HDF_LOGE("%s: Malloc virtual fail!", __func__);
if (virtual == NULL) {
return HDF_ERR_MALLOC_FAIL;
// 为空则返回错误参数
}
HDF_LOGE("%s: Malloc virtual fail!", __func__);
// 读取属性文件配置参数
return HDF_ERR_MALLOC_FAIL;
ret = VirtualDacReadDrs(virtual, node);
}
if (ret != HDF_SUCCESS) {
// 读取属性文件配置参数
// 读取失败
ret = VirtualDacReadDrs(virtual, node);
HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
if (ret != HDF_SUCCESS) {
// 释放virtual空间
// 读取失败
OsalMemFree(virtual);
HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
// 指针置为0
// 释放virtual空间
virtual = NULL;
OsalMemFree(virtual);
return ret;
// 指针置为0
}
virtual = NULL;
// 初始化虚拟指针
return ret;
VirtualDacDeviceInit(virtual);
}
// 对DacDevice中priv对象初始化
// 初始化虚拟指针
virtual->device.priv = (void *)node;
VirtualDacDeviceInit(virtual);
// 对DacDevice中devNum对象初始化
// 对DacDevice中priv对象初始化
virtual->device.devNum = virtual->deviceNum;
virtual->device.priv = (void *)node;
// 对DacDevice中ops对象初始化
// 对DacDevice中devNum对象初始化
virtual->device.ops = &g_method;
virtual->device.devNum = virtual->deviceNum;
// 添加DAC设备
// 对DacDevice中ops对象初始化
ret = DacDeviceAdd(&virtual->device);
virtual->device.ops = &g_method;
if (ret != HDF_SUCCESS) {
// 添加DAC设备
// 添加设备失败
ret = DacDeviceAdd(&virtual->device);
HDF_LOGE("%s: add Dac controller failed! ret = %d", __func__, ret);
if (ret != HDF_SUCCESS) {
// 释放virtual空间
// 添加设备失败
OsalMemFree(virtual);
HDF_LOGE("%s: add Dac controller failed! ret = %d", __func__, ret);
// 虚拟指针置空
// 释放virtual空间
virtual = NULL;
OsalMemFree(virtual);
return ret;
// 虚拟指针置空
}
virtual = NULL;
return ret;
return HDF_SUCCESS;
}
}
```
return HDF_SUCCESS;
}
- 自定义结构体参考。
```
通过自定义结构体定义DAC数模转换必要的参数,在定义结构体时需要根据设备的功能参数来实现自定义结构体,从驱动的角度看,自定义结构体是参数和数据的载体,dac_config.hcs文件中传递的参数和数据会被HDF驱动模块的DacTestReadConfig函数读入,通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层DacDevice对象,例如设备号、总线号等。
```c++
- 自定义结构体参考。
struct VirtualDacDevice {
struct DacDevice device; //【必要】是核心层控制对象,具体描述见下面
通过自定义结构体定义DAC数模转换必要的参数,在定义结构体时需要根据设备的功能参数来实现自定义结构体,从驱动的角度看,自定义结构体是参数和数据的载体,dac_config.hcs文件中传递的参数和数据会被HDF驱动模块的DacTestReadConfig函数读入,通过DeviceResourceIface来初始化结构体成员,其中一些重要数值也会传递给核心层DacDevice对象,例如设备号、总线号等。
uint32_t deviceNum; //【必要】设备号
uint32_t validChannel; //【必要】有效通道
```
uint32_t rate; //【必要】采样率
struct VirtualDacDevice {
};
struct DacDevice device; //【必要】是核心层控制对象,具体描述见下面
uint32_t deviceNum; //【必要】设备号
// DacDevice是核心层控制器结构体,其中的成员在Init函数中会被赋值
uint32_t validChannel; //【必要】有效通道
struct DacDevice {
uint32_t rate; //【必要】采样率
const struct DacMethod *ops;
};
OsalSpinlock spin; // 自旋锁
uint32_t devNum; // 设备号
// DacDevice是核心层控制器结构体,其中的成员在Init函数中会被赋值
uint32_t chanNum; // 设备通道号
struct DacDevice {
const struct DacLockMethod *lockOps;
const struct DacMethod *ops;
void *priv;
OsalSpinlock spin; // 自旋锁
};
uint32_t devNum; // 设备号
```
uint32_t chanNum; // 设备通道号
const struct DacLockMethod *lockOps;
- 实例化DacDevice成员DacMethod。
void *priv;
};
VirtualDacWrite、VirtualDacStop、VirtualDacStart函数会在dac_virtual.c文件中进行模块功能的实例化。
```
```c++
- 实例化DacDevice成员DacMethod。
static const struct DacMethod g_method = {
.write = VirtualDacWrite, // DAC设备写入值
.stop = VirtualDacStop, // 停止DAC设备
VirtualDacWrite、VirtualDacStop、VirtualDacStart函数会在dac_virtual.c文件中进行模块功能的实例化。
.start = VirtualDacStart, // 开始启动DAC设备
};
```
```
static const struct DacMethod g_method = {
.write = VirtualDacWrite, // DAC设备写入值
 **说明:**<br>
.stop = VirtualDacStop, // 停止DAC设备
DacDevice成员DacMethod的定义和成员说明见[接口说明](#接口说明)。
.start = VirtualDacStart, // 开始启动DAC设备
};
- Init函数参考
```
入参:
 **说明:**<br>
DacDevice成员DacMethod的定义和成员说明见[接口说明](#接口说明)。
HdfDeviceObject这个是整个驱动对外暴露的接口参数,具备hcs配置文件的信息。
返回值:
- Init函数参考
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS定义)。
入参:
| 状态(值) | 问题描述 |
HdfDeviceObject这个是整个驱动对外暴露的接口参数,具备hcs配置文件的信息。
| ---------------------- | ------------- |
| HDF_ERR_INVALID_OBJECT | 控制器对象非法。 |
返回值:
| HDF_ERR_INVALID_PARAM | 参数非法。 |
| HDF_ERR_MALLOC_FAIL | 内存分配失败。 |
HDF_STATUS相关状态(下表为部分展示,如需使用其他状态,可见//drivers/framework/include/utils/hdf_base.h中HDF_STATUS 定义)。
| HDF_ERR_IO | I/O 错误。 |
| HDF_SUCCESS | 传输成功。 |
| 状态(值) | 问题描述 |
| HDF_FAILURE | 传输失败。 |
| ---------------------- | -------------- |
| HDF_ERR_INVALID_OBJECT | 控制器对象非法 |
函数说明:
| HDF_ERR_INVALID_PARAM | 参数非法 |
| HDF_ERR_MALLOC_FAIL | 内存分配失败 |
初始化自定义结构体对象,初始化DacDevice成员,并调用核心层DacDeviceAdd函数。
| HDF_ERR_IO | I/O 错误 |
| HDF_SUCCESS | 传输成功 |
```c++
| HDF_FAILURE | 传输失败 |
static int32_t VirtualDacParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
{
函数说明:
// 定义返回值参数
int32_t ret;
初始化自定义结构体对象,初始化DacDevice成员,并调用核心层DacDeviceAdd函数。
// DAC设备的结构体指针
struct VirtualDacDevice *virtual = NULL;
```
(void)device;
static int32_t VirtualDacParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
// 分配指定大小的内存
{
virtual = (struct VirtualDacDevice *)OsalMemCalloc(sizeof(*virtual));
// 定义返回值参数
if (virtual == NULL) {
int32_t ret;
// 分配内存失败
// DAC设备的结构体指针
HDF_LOGE("%s: Malloc virtual fail!", __func__);
struct VirtualDacDevice *virtual = NULL;
return HDF_ERR_MALLOC_FAIL;
(void)device;
}
// 分配指定大小的内存
// 读取hcs中的node节点参数
virtual = (struct VirtualDacDevice *)OsalMemCalloc(sizeof(*virtual));
ret = VirtualDacReadDrs(virtual, node);
if (virtual == NULL) {
if (ret != HDF_SUCCESS) {
// 分配内存失败
// 读取节点失败
HDF_LOGE("%s: Malloc virtual fail!", __func__);
HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
return HDF_ERR_MALLOC_FAIL;
goto __ERR__;
}
}
// 读取hcs中的node节点参数
// 初始化DAC设备指针
ret = VirtualDacReadDrs(virtual, node);
VirtualDacDeviceInit(virtual);
if (ret != HDF_SUCCESS) {
// 节点数据传入私有数据
// 读取节点失败
virtual->device.priv = (void *)node;
HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
// 传入设备号
goto __ERR__;
virtual->device.devNum = virtual->deviceNum;
}
// 传入方法
// 初始化DAC设备指针
virtual->device.ops = &g_method;
VirtualDacDeviceInit(virtual);
// 添加DAC设备
// 节点数据传入私有数据
ret = DacDeviceAdd(&virtual->device);
virtual->device.priv = (void *)node;
if (ret != HDF_SUCCESS) {
// 传入设备号
// 添加DAC设备失败
virtual->device.devNum = virtual->deviceNum;
HDF_LOGE("%s: add Dac controller failed! ret = %d", __func__, ret);
// 传入方法
goto __ERR__;
virtual->device.ops = &g_method;
}
// 添加DAC设备
// 成功添加DAC设备
ret = DacDeviceAdd(&virtual->device);
return HDF_SUCCESS;
if (ret != HDF_SUCCESS) {
__ERR__:
// 添加DAC设备失败
// 如果指针为空
HDF_LOGE("%s: add Dac controller failed! ret = %d", __func__, ret);
if (virtual != NULL) {
goto __ERR__;
// 释放内存
}
OsalMemFree(virtual);
// 成功添加DAC设备
// 指针置空
return HDF_SUCCESS;
virtual = NULL;
__ERR__:
}
// 如果指针为空
if (virtual != NULL) {
return ret;
// 释放内存
}
OsalMemFree(virtual);
// 指针置空
static int32_t VirtualDacInit(struct HdfDeviceObject *device)
virtual = NULL;
{
}
// 定义返回值参数
int32_t ret;
return ret;
// 设备结构体子节点
}
const struct DeviceResourceNode *childNode = NULL;
// 入参指针进行判断
static int32_t VirtualDacInit(struct HdfDeviceObject *device)
if (device == NULL || device->property == NULL) {
{
// 入参指针为空
// 定义返回值参数
HDF_LOGE("%s: device or property is NULL", __func__);
int32_t ret;
return HDF_ERR_INVALID_OBJECT;
// 设备结构体子节点
}
const struct DeviceResourceNode *childNode = NULL;
// 入参指针不为空
// 入参指针进行判断
ret = HDF_SUCCESS;
if (device == NULL || device->property == NULL) {
DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
// 入参指针为空
// 解析子节点
HDF_LOGE("%s: device or property is NULL", __func__);
ret = VirtualDacParseAndInit(device, childNode);
return HDF_ERR_INVALID_OBJECT;
if (ret != HDF_SUCCESS) {
}
// 解析失败
// 入参指针不为空
break;
ret = HDF_SUCCESS;
}
DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
}
// 解析子节点
// 解析成功
ret = VirtualDacParseAndInit(device, childNode);
return ret;
if (ret != HDF_SUCCESS) {
}
// 解析失败
```
break;
}
- Release函数参考
}
// 解析成功
入参:
return ret;
}
HdfDeviceObject是整个驱动对外暴露的接口参数,具备hcs配置文件的信息。
```
返回值:
- Release函数参考
无。
入参:
函数说明:
HdfDeviceObject是整个驱动对外暴露的接口参数,具备hcs配置文件的信息。
释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。
返回值:
```c++
无。
static void VirtualDacRemoveByNode(const struct DeviceResourceNode *node)
{
函数说明:
// 定义返回值参数
int32_t ret;
释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给Release接口,当HDF框架调用Init函数初始化驱动失败时,可以调用Release释放驱动资源。所有强制转换获取相应对象的操作前提是在Init函数中具备对应赋值的操作。
// 定义DAC设备号
int16_t devNum;
```
// DAC设备结构体指针
static void VirtualDacRemoveByNode(const struct DeviceResourceNode
*
node)
struct DacDevice *device = NULL;
{
// DAC虚拟结构体指针
// 定义返回值参数
struct VirtualDacDevice *virtual = NULL;
int32_t ret;
// 设备资源接口结构体指针
// 定义DAC设备号
struct DeviceResourceIface *drsOps = NULL;
int16_t devNum;
// 通过实例入口获取设备资源
// DAC设备结构体指针
drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
struct DacDevice
*
device = NULL;
// 入参指判空
// DAC虚拟结构体指针
if (drsOps == NULL || drsOps->GetUint32 == NULL) {
struct VirtualDacDevice
*
virtual = NULL;
// 指针为空
// 设备资源接口结构体指针
HDF_LOGE("%s: invalid drs ops fail!", __func__);
struct DeviceResourceIface
*
drsOps = NULL;
return;
// 通过实例入口获取设备资源
}
drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
// 获取devNum节点的数据
// 入参指判空
ret = drsOps->GetUint16(node, "devNum", (uint16_t *)&devNum, 0);
if (drsOps == NULL || drsOps->GetUint32 == NULL) {
if (ret != HDF_SUCCESS) {
// 指针为空
//获取失败
HDF_LOGE("%s: invalid drs ops fail!", __func__);
HDF_LOGE("%s: read devNum fail!", __func__);
return;
return;
}
}
// 获取devNum节点的数据
// 获取DAC设备号
ret = drsOps->GetUint16(node, "devNum", (uint16_t
*
)&devNum, 0);
device = DacDeviceGet(devNum);
if (ret != HDF_SUCCESS) {
// 判断DAC设备号以及数据是否为空
//获取失败
if (device != NULL && device->priv == node) {
HDF_LOGE("%s: read devNum fail!", __func__);
// 为空释放DAC设备号
return;
DacDevicePut(device);
}
// 移除DAC设备号
// 获取DAC设备号
DacDeviceRemove(device);
device = DacDeviceGet(devNum);
virtual = (struct VirtualDacDevice *)device;
// 判断DAC设备号以及数据是否为空
// 释放虚拟指针
if (device != NULL && device->priv == node) {
OsalMemFree(virtual);
// 为空释放DAC设备号
}
DacDevicePut(device);
return;
// 移除DAC设备号
}
DacDeviceRemove(device);
virtual = (struct VirtualDacDevice
*
)device;
static void VirtualDacRelease(struct HdfDeviceObject *device)
// 释放虚拟指针
{
OsalMemFree(virtual);
// 定义设备资源子节点结构体指针
}
const struct DeviceResourceNode *childNode = NULL;
return;
// 入参指针判空
}
if (device == NULL || device->property == NULL) {
// 入参指针为空
static void VirtualDacRelease(struct HdfDeviceObject
*
device)
HDF_LOGE("%s: device or property is NULL", __func__);
{
return;
// 定义设备资源子节点结构体指针
}
const struct DeviceResourceNode
*
childNode = NULL;
// 入参指针判空
DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
if (device == NULL || device->property == NULL) {
// 通过节点移除DAC
// 入参指针为空
VirtualDacRemoveByNode(childNode);
HDF_LOGE("%s: device or property is NULL", __func__);
}
return;
}
}
```
DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
4.
驱动调试:
// 通过节点移除DAC
VirtualDacRemoveByNode(childNode);
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的测试用例是否成功等。
}
\ No newline at end of file
}
```
4. 驱动调试:
【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的测试用例是否成功等。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录