OpenHarmony:全流程讲解如何编写ADC平台驱动以及应用程序

系统 OpenHarmony
ADC(Analog to Digital Converter),即模拟-数字转换器,可将模拟信号转换成对应的数字信号,便于存储与计算等操作。除电源线和地线之外,ADC只需要1根线与被测量的设备进行连接。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

一、案例简介

该程序是基于OpenHarmony标准系统编写的基础外设类:ADC驱动。

目前该案例已在凌蒙派-RK3568开发板跑通。详细资料请参考官网:https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk3568-openharmony/tree/master/samples/b04_platform_device_adc。

详细资料请参考OpenHarmony官网:

  • ADC平台驱动开发
  • ADC应用程序开发

二、基础知识

1、ADC简介

ADC(Analog to Digital Converter),即模拟-数字转换器,可将模拟信号转换成对应的数字信号,便于存储与计算等操作。除电源线和地线之外,ADC只需要1根线与被测量的设备进行连接。

2、ADC平台驱动

在HDF框架中,同类型设备对象较多时(可能同时存在十几个同类型配置器),若采用独立服务模式,则需要配置更多的设备节点,且相关服务会占据更多的内存资源。相反,采用统一服务模式可以使用一个设备服务作为管理器,统一处理所有同类型对象的外部访问(这会在配置文件中有所体现),实现便捷管理和节约资源的目的。ADC模块即采用统一服务模式。如下图所示:

OpenHarmony:全流程讲解如何编写ADC平台驱动以及应用程序-开源基础软件社区OpenHarmony:全流程讲解如何编写ADC平台驱动以及应用程序-开源基础软件社区

ADC模块各分层的作用为:

  • 接口层:提供打开设备,写入数据,关闭设备的能力。
  • 核心层:主要负责服务绑定、初始化以及释放管理器,并提供添加、删除以及获取控制器的能力。
  • 适配层:由驱动适配者实现与硬件相关的具体功能,如控制器的初始化等。

在统一模式下,所有的控制器都被核心层统一管理,并由核心层统一发布一个服务供接口层,因此这种模式下驱动无需再为每个控制器发布服务。

详细资料请参考官网地址:ADC平台驱动

3、ADC应用程序

ADC模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/adc_if.h。

ADC驱动API接口功能介绍如下所示:

接口名

接口描述

DevHandle AdcOpen(uint32_t number)

打开ADC设备

void AdcClose(DevHandle handle)

关闭ADC设备

int32_t AdcRead(DevHandle handle, uint32_t channel, uint32_t *val)

读取AD转换结果值

使用ADC设备的一般流程如下所示:

OpenHarmony:全流程讲解如何编写ADC平台驱动以及应用程序-开源基础软件社区OpenHarmony:全流程讲解如何编写ADC平台驱动以及应用程序-开源基础软件社区

详细资料请参考官网地址:ADC应用程序

三、程序解析

1、准备工作

查看《凌蒙派-RK3568开发板_排针说明表_》(即Git仓库的//docs/board/凌蒙派-RK3568开发板_排针说明表_v1.0.xlsx),选中ADC5(即ADC5)。

2、配置文件

(1)device_info.hcs

创建config/device_info.hcs,用于驱动设备描述,具体内容如下:

#include "adc_config.hcs"

root {
    device_info {
        platform :: host {
            device_adc :: device {
                device0 :: deviceNode {                         // ADC控制器信息描述
                    policy = 2;                                 // 对外发布服务,必须为2,用于定义ADC管理器的服务
                    priority = 50;
                    permission = 0644;
                    moduleName = "HDF_PLATFORM_ADC_MANAGER";    // 这与drivers/hdf_core/framework/support/platform/src/adc/adc_core.c的g_adcManagerEntry.moduleName对应,它主要负责ADC的管理
                    serviceName = "HDF_PLATFORM_ADC_MANAGER";
                }
                device1 :: deviceNode {
                    policy = 0;                                 // 等于0,不需要发布服务
                    priority = 55;                              // 驱动驱动优先级
                    permission = 0644;                          // 驱动创建设备节点权限
                    moduleName = "linux_adc_adapter";           // 用于指定驱动名称,必须是linux_adc_adapter
                    deviceMatchAttr = "linux_adc_adapter";      // 用于配置控制器私有数据,必须与adc_config.hcs中对应控制器保持一致
                }
            }
        }
    }
}

注意:

  • device0:ADC控制器,为了引入HDF_PLATFORM_ADC_MANAGER驱动,必须要。
  • device1:ADC实际操作接口。
  • moduleName:该驱动名称,必须是linux_adc_adapter,//drivers/hdf_core/adapter/khdf/linux/platform/adc/adc_iio_adapter.c已编写好。
  • deviceMatchAttr:关键字必须与config.hcs的match_attr匹配。

(2)adc_config.hcs

创建config/adc_config.hcs,用于定义私有变量,具体内容如下:

root {
    platform {
        adc_config {
            match_attr = "linux_adc_adapter";       // 与device_info.hcs的deviceMatchAttr的值一致
            template adc_device {                   // 必须与//drivers/hdf_core/adapter/khdf/linux/platform/adc/adc_iio_adapter.c的配置树定义保持一致
                deviceNum = 0;                      // 设备号标识
                channelNum = 8;                     // ADC通道数量
                driver_channel0_name = "";          // 通道0在linux文件系统路径
                driver_channel1_name = "";          // 通道1在linux文件系统路径
                driver_channel2_name = "";          // 通道2在linux文件系统路径
                driver_channel3_name = "";          // 通道3在linux文件系统路径
                driver_channel4_name = "";          // 通道4在linux文件系统路径
                driver_channel5_name = "";          // 通道5在linux文件系统路径
                driver_channel6_name = "";          // 通道6在linux文件系统路径
                driver_channel7_name = "";          // 通道7在linux文件系统路径
                scanMode = 0;                       // 扫描模式(必要,但无意义)
                rate = 1000;                        // 转换速率(必要,但无意义)
            }
            device_0 :: adc_device {
                deviceNum = 0;
                channelNum = 8;
                driver_channel0_name = "/sys/bus/iio/devices/iio:device0/in_voltage0_raw";
                driver_channel1_name = "/sys/bus/iio/devices/iio:device0/in_voltage1_raw";
                driver_channel2_name = "/sys/bus/iio/devices/iio:device0/in_voltage2_raw";
                driver_channel3_name = "/sys/bus/iio/devices/iio:device0/in_voltage3_raw";
                driver_channel4_name = "/sys/bus/iio/devices/iio:device0/in_voltage4_raw";
                driver_channel5_name = "/sys/bus/iio/devices/iio:device0/in_voltage5_raw";
                driver_channel6_name = "/sys/bus/iio/devices/iio:device0/in_voltage6_raw";
                driver_channel7_name = "/sys/bus/iio/devices/iio:device0/in_voltage7_raw";
            }
        }
    }
}

ADC实际驱动是//drivers/hdf_core/adapter/khdf/linux/platform/adc/adc_iio_adapter.c,template adc_device定义的各项关键变量是由adc_iio_adapter.c决定,不可修改。

adc_iio_adapter.c实际是对Linux IIO子系统进行操作来控制ADC。

注意:

  • channelNum:表示通道数量。
  • driver_channelX_name:必须是从0开始。

(3)参与配置树编译

编辑//vendor/lockzhiner/rk3568/hdf_config/khdf/hdf.hcs,将device_info.hcs添加配置树中。具体内容如下所示:

#include "../../samples/b04_platform_device_adc/config/device_info.hcs"

3、HDF驱动

ADC平台驱动是//drivers/hdf_core/adapter/khdf/linux/platform/adc/adc_iio_adapter.c,用户不必编写HDF驱动。

4、参与Linux内核编译

编辑//kernel/linux/config/linux-5.10/arch/arm64/configs/rk3568_standard_defconfig,启用CONFIG_DRIVERS_HDF_PLATFORM_ADC,具体内容如下:

CONFIG_DRIVERS_HDF_PLATFORM_ADC=y

5、应用程序

(1)adc_test.c

添加平台驱动ADC的头文件,具体内容如下:

#include "adc_if.h"                 // ADC标准接口头文件

程序可通过,具体内容如下:

int main(int argc, char* argv[])
{
    DevHandle handle = NULL;
    int32_t ret;
    uint32_t value;

    // 解析参数
    parse_opt(argc, argv);
    printf("adc_device: %d\n", m_adc_device);
    printf("adc_channel: %d\n", m_adc_channel);

    // 打开ADC设备
    handle = AdcOpen(m_adc_device);
    if (handle == NULL) {
        PRINT_ERROR("AdcOpen failed\n");
        return -1;
    }

    // 进行AD转换并读取转换结果
    ret = AdcRead(handle, m_adc_channel, &value);
    if (ret != 0) {
        PRINT_ERROR("AdcRead failed and ret = %d\n", ret);
        AdcClose(handle);
        return -1;
    }

    printf("Adc Device(%d), Channel(%d) read successful and value = %d\n", m_adc_device, m_adc_channel, value);

    // 关闭ADC设备
    AdcClose(handle);

    return 0;
}

(2)BUILD.gn

import("//build/ohos.gni")
import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")

print("samples: compile rk3568_adc_test")
ohos_executable("rk3568_adc_test") {
  sources = [ "adc_test.c" ]
  include_dirs = [
    "$hdf_framework_path/include",
    "$hdf_framework_path/include/core",
    "$hdf_framework_path/include/osal",
    "$hdf_framework_path/include/platform",
    "$hdf_framework_path/include/utils",
    "$hdf_uhdf_path/osal/include",
    "$hdf_uhdf_path/ipc/include",
    "//base/hiviewdfx/hilog/interfaces/native/kits/include",
    "//third_party/bounds_checking_function/include",
  ]

  deps = [
    "$hdf_uhdf_path/platform:libhdf_platform",
    "$hdf_uhdf_path/utils:libhdf_utils",
    "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog",
  ]

  cflags = [
    "-Wall",
    "-Wextra",
    "-Werror",
    "-Wno-format",
    "-Wno-format-extra-args",
  ]

  subsystem_name = "applications"
  part_name = "product_rk3568"
  install_enable = true
}

(3)参与应用程序编译

编辑//vendor/lockzhiner/rk3568/samples/BUILD.gn,开启编译选项。具体如下:

"b04_platform_device_adc/app:rk3568_adc_test",

四、程序编译

建议使用docker编译方法,运行如下:

hb set -root .
hb set
# 选择lockzhiner下的rk3568编译分支。
hb build -f

五、运行结果

该程序运行结果如下所示:

# rk3568_adc_test -d 0 -c 5
../../vendor/lockzhiner/rk3568/samples/b21_platform_device_adc/app/adc_test.c, main, 103, info: adc_device: 0
../../vendor/lockzhiner/rk3568/samples/b21_platform_device_adc/app/adc_test.c, main, 104, info: adc_channel: 5
Adc Device(0), Channel(5) read successful and value = 955
#

可以将ADC引脚通过引线接入排针线中的GNU或3V3中,可以查看ADC的变化。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

责任编辑:jianghua 来源: 51CTO 开源基础软件社区
相关推荐

2023-09-19 15:21:33

RTC鸿蒙

2023-09-19 15:14:59

鸿蒙Watchdog

2023-09-06 15:31:19

GPIO鸿蒙

2022-08-29 17:34:05

鸿蒙操作系统

2011-01-28 09:12:53

jQuery Mobi

2009-09-27 17:23:16

Hibernate应用

2021-12-06 07:47:36

Linux 驱动程序Linux 系统

2018-06-22 09:00:00

Java框架Pronghorn

2009-07-03 06:57:32

2021-01-16 11:40:28

ARM嵌入式开发ADC应用

2011-04-01 11:01:02

应用程序BlackBerryJava

2023-03-24 14:47:24

NAPI框架HDF框架

2011-03-22 14:12:17

LAMP

2023-03-21 18:06:49

ADC数字转换器

2010-02-24 13:25:22

Python线程应用程

2009-10-10 13:56:44

IIS应用程序VB开发

2011-07-20 15:58:58

iPhone 应用程序 生命周期

2009-12-25 10:39:49

WPF应用程序关闭

2010-02-07 10:21:27

Android应用程序

2010-02-06 15:26:11

Android应用程序
点赞
收藏

51CTO技术栈公众号