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/