README.md
1# 关于ADC的HDF实现
2
3## ADC设备简介:
4
5LM35线性模拟温度传感器:
6
7
8
9参考手册知:
10
11link : https://img.dfrobot.com.cn/wiki/5b973267c87e6f19943ab3ad/8b4777fdf3c535371fe8b1fe05150607.pdf
12
131. LM35测温范围是0℃到100℃,灵敏度为10mV/℃,输出电压与温度成正比。
142. 输入输出以及电压和温度的关系如下
15 
16
17又:开发板分辨率为12位,即2^{12}=4096,查看原理图可知ADC的信号基准电压为1.8V。
18
19则得:
20信号电压值计算为:`V = 1.8*val/4096 V=1.8∗val/4096`
21
22每10mv为1°C,则温度值为:`T = V/0.01=val∗0.044`
23
24
25## ADC驱动适配
26对于OpenHarmony标准系统来说,内核使用的是统一的Linux系统内核,这也就是说对于大部分的一些驱动模型,驱动接口,都可以使用统一的一套框架进行适配,也就是在Linux内核部署OpenHarmony的HDF驱动子系统,这样可以提供归一化的驱动平台底座,做到一次开发,多系统部署。
27而UnionPi-Tiger开发板并没有对ADC的HDF进行适配,则要调用ADC的HDF接口前先要进行适配。
28
29### 统一服务模式
30在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式,则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。`ADC模块即采用统一服务模式`。
31
32ADC模块各分层的作用为:
33
341. 接口层(`adc_if_u.c`):提供打开设备,写入数据,关闭设备的能力。
352. 核心层(`adc_core.c`):主要负责服务绑定、初始化以及释放管理器,并提供添加、删除以及获取控制器的能力。
363. 适配层`(adc_iio_adapter.c`):由驱动适配者实现与硬件相关的具体功能,如控制器的初始化等。
37
38统一服务模式图示:
39
40在统一模式下,所有的控制器都被核心层统一管理,并由核心层统一发布一个服务供接口层,因此这种模式下驱动无需再为每个控制器发布服务。
41
42### 适配步骤
43由官方文档可知:
44
45ADC模块适配必选的三个环节是实例化驱动入口,配置属性文件,以及实例化核心层接口函数。
46
471. 实例化驱动入口
48
492. 配置属性文件
50
513. 实例化核心层接口函数
52
53由于,在OpenHarmony源码中已经存放对于驱动子系统适配linux内核的代码和编译脚本,具体路径为`drivers/hdf_core/adapter/khdf/linux`
54则适配过程主要是进行属性文件的配置,以及对接口的调用和对各层的简单分析
55
56#### 配置属性文件
571. 开启HDF_PLATFORM_ADC模块控制宏
58 开启路径`device/board/unionman/unionpi_tiger/kernel/build/unionpi_tiger_standard_defconfi`的`CONFIG_DRIVERS_HDF_PLATFORM_ADC`设置为Y
59
60 
61
62 即把ADC的HDF的驱动能力打开,实质上是使能了`drivers/hdf_core/adapter/khdf/linux/platform/adc`下的Makefile进行编译
63
64 PS:建议编译后来检查下`\\drivers\hdf_core\framework\support\platform\src\adc`
65生成的编译文件的修改日期,以确保其是更改配置后生成的中间文件以及目标文件,否则有可能会出现更改配置而还是没出现或者没用上更改的配置,至此,建议更改配置文件后先使用`hb clean`进行清理旧时的编译文件,再`hb build`进行全量编译以确保更改配置有效编译。
66 
67
682. 在device_info.hcs文件中添加deviceNode描述
69 在路径`vendor/unionman/unionpi_tiger/hdf_config/khdf/device_info/device_info.hcs`
70 添加device Node描述
71 ```
72 device_adc :: device {
73 device0 :: deviceNode {
74 policy = 2;
75 priority = 60;
76 permission = 0644;
77 moduleName = "HDF_PLATFORM_ADC_MANAGER";
78 serviceName = "HDF_PLATFORM_ADC_MANAGER";
79 }
80 device1 :: deviceNode {
81 policy = 0;
82 priority = 65;
83 permission = 0644;
84 moduleName = "linux_adc_adapter";
85 deviceMatchAttr = "linux_adc_adapter";
86 }
87 }
88 ```
89 由于上文提到:ADC模块采用统一服务模式,则此设备描述的节点一为ADC管理器,其参数:policy配置为2,即对外发布服务,priority则为优先级,越小优先级越高;permission为权限等级,moduleName与serviceName统一为HDF_PLATFORM_ADC_MANAGER(因为是统一服务模式);然后从节点二开始配置具体ADC控制器信息。
90
913. 添加a311d_adc_config.hcs器件属性文件
92 在`vendor/unionman/unionpi_tiger/hdf_config/khdf/platform`路径下,添加a311d_adc_config.hcs私有配置
93```
94 root {
95 platform {
96 adc_config {
97 match_attr = "linux_adc_adapter";//与deviceMatchAttr的值一致
98 template adc_device {
99 channelNum = 2; //ADC通道数量
100 driver_channel0_name = ""; //通道0在linux文件系统路径
101 driver_channel1_name = ""; //通道1在linux文件系统路径
102 deviceNum = 0; //设备号标识
103 scanMode = 0; //扫描模式(必要,但实际使用参数无意义)
104 rate = 1000; //转换速率(必要,但实际使用参数无意义)
105 }
106
107 device_adc_0x0000 :: adc_device {
108 channelNum = 2;
109 deviceNum = 0;
110 driver_channel0_name = "/sys/bus/iio/devices/iio:device0/in_voltage2_raw";
111 driver_channel1_name = "/sys/bus/iio/devices/iio:device0/in_voltage3_raw";
112 }
113 }
114 }
115}
116```
117
118以上私有配置配置了设备号,通道数以及实质操作的文件的路径(即将通道2,3分别映射到driver_channel0_name及driver_channel1_name上)以供HDF驱动查找读取
119adc_iio_adapter.c::AdcIioReadDrs:
120
121
1224. 包含在hdf.hcs文件中
123 路径`vendor/unionman/unionpi_tiger/hdf_config/khdf/hdf.hcs`中加上`#include "platform/a311d_adc_config.hcs"`
124
125 
126
127至此,则完成了属性文件的配置
128
129### 编写用户程序:
130
131由官方文档知流程:
132
133
134
135且提供接口:
136
137
138则有程序:
139```C
140#include <stdio.h>
141#include <stdlib.h>
142#include "adc_if.h"
143#include "hdf_log.h"
144#include "osal_time.h"
145
146
147/* 设备号0,通道号1 */
148#define ADC_DEVICE_NUM 0
149#define TEMP_CONST (1.8/(0.01*4096))
150
151int32_t main(int argc, char *argv[])
152{
153 int32_t ret;
154 uint32_t channelNum=0;
155 DevHandle adcHandle = NULL;
156 uint32_t read_val = 0;
157 double temperature = 0;
158 // 默认打开通道0,可以输入参数使用另外的通道
159 if(argc == 2)
160 {
161 channelNum=atoi(argv[1]);
162 }
163
164 /* 打开ADC设备 */
165 adcHandle = AdcOpen(ADC_DEVICE_NUM);
166 if (adcHandle == NULL) {
167 HDF_LOGE("%s: Open ADC%u fail!", __func__, ADC_DEVICE_NUM);
168 printf("%s: Open ADC%u fail!\n", __func__, ADC_DEVICE_NUM);
169 return -1;
170 }
171 /* 读取ADC数据 */
172 ret = AdcRead(adcHandle, channelNum, &read_val);
173 if (ret != HDF_SUCCESS) {
174 HDF_LOGE("%s: ADC read fail!:%d", __func__, ret);
175 printf("%s: ADC read fail!:%d", __func__, ret);
176 AdcClose(adcHandle);
177 return -1;
178 }
179 /* 计算温度 */
180 temperature = ((double)read_val) * TEMP_CONST;
181
182 printf("Temperature is %.1f°C\n", temperature);
183
184 /* 访问完毕关闭ADC设备 */
185 AdcClose(adcHandle);
186 return HDF_SUCCESS;
187}
188
189```
190由上知把设备号信息配置为0,且将通道2,3分别映射到`driver_channel0_name`及`driver_channel1_name`上,则函数`AdcOpen`的参数为0,本实例读取`in_voltage2_raw`的数据则使用`driver_channel0_name`即使用`channelNum`参数0,获取模拟值后根据以上公式进行转换从而获得温度值再打印出来。
191
192编译脚本:BUILD.gn:
193```
194import("//build/ohos.gni")
195import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")
196
197ohos_executable("adc") {
198 sources = [ "adc.c" ]
199
200 include_dirs = [
201 ".",
202 "//drivers/hdf_core/framework/include/platform",
203 "//third_party/node/src",
204 ]
205
206 deps = [ "//drivers/hdf_core/adapter/uhdf2/platform:libhdf_platform" ]
207
208 external_deps = [
209 "hdf_core:libhdf_utils",
210 "hilog:libhilog",
211 ]
212
213 install_enable = true
214 install_images = [ chipset_base_dir ]
215 module_install_dir = "bin"
216 part_name = "product_unionpi_tiger"
217}
218
219
220```
221## 结果展示
222
223进行编译烧录后,把可执行文件移入板中后运行得结果:
224
225
226
227
228## 参考文档:
2291. 标准系统HDF平台驱动(一)——ADC驱动适配:https://ost.51cto.com/posts/21996#LinuxOpenHarmony_48
2302. ADC平台驱动使用:https://docs.openharmony.cn/pages/v3.2/zh-cn/device-dev/driver/driver-platform-adc-des.md/