瑞芯微 RK3568 OpenHarmony-v3.2-Release 控制LED案例

前言

  笔者作为一名Web开发者,最近接手了一个新项目,其中涉及到了硬件开发方面的需求。考虑到我对硬件方面领域一窍不通,这对我来说无疑是一个巨大的挑战。尽管时间紧迫,任务繁重,但我抱着学习的态度,经历了两周的不懈努力,终于实现了一个LED的案例。在这个过程中我踩坑无数遇到了无数次的困难 ,但也因此获得了宝贵的经验和教训。希望通过这篇博客能分享我的学习经历和成果,帮助更多与我有类似经历的开发者,互相勉励。

笔者开发环境情况如下:

DevEco Device Tool 4.0 Release
VMware Workstation Pro 17
OpenHarmony-v3.2-Release
润和 瑞芯微(非标准) RK3568 标准系统
HDC 1.2.0a

目标:通过HDF API调用实现搭载OpenHarmony-v3.2-Release的瑞芯微 RK3568 的LED点亮和熄灭。

一、开发工具及环境搭建

  1. 官方文档已经给出详细搭建教程,将不再过多赘述。
  2. HUAWEI DevEco DeviceTool使用指南
  3. 如果过程中遇到什么问题,建议参考此课程辅助能解决很多问题。
  4. HarmonyOS Connect开发工具系列课

二、知识了解

开发前的基础知识,详情请移步官网

  1. GPIO
  2. HDF
  3. HDC

三、案例编写

3.1 代码结构

  打开项目工程,在代码根目录创建samples子系统文件夹,在子系统目录下创建led部件文件夹, led目录下创建构建文件BUILD.gn及部件配置文件bundle.jsonsrc文件夹,src文件夹下创建led_gpio.c源文件,完整目录如下:

samples/led
│── BUILD.gn
│── src
│ └── led_gpio.c
│── bundle.json
build
└── subsystem_config.json
vendor/hihope
└── rk3568
 └── config.json

3.2 led_gpio.c 代码编写

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>

#include "hdf_log.h"                // 标准日志接口头文件
#include "gpio_if.h"                // GPIO标准接口头文件

// 定义版本号
#define SOFTWARE_VERSION            "V1.0"

// 打印信息,用于打印普通信息
#define PRINT_INFO(fmt, args...)    printf("%s, %s, %d, info: "fmt, __FILE__, __func__, __LINE__, ##args)
// 打印信息,用于打印错误信息
#define PRINT_ERROR(fmt, args...)   printf("%s, %s, %d, error: "fmt, __FILE__, __func__, __LINE__, ##args)

// GPIO引脚序号
static uint16_t m_gpio_id = 0;
// GPIO引脚是否设置为输入,GPIO_DIR_OUT为输出,GPIO_DIR_IN为输入
static uint16_t m_gpio_dir = GPIO_DIR_IN;
// GPIO引脚的高低电平,GPIO_VAL_LOW为低电平,GPIO_VAL_HIGH为高电平
static uint16_t m_gpio_value = GPIO_VAL_LOW;


///


/***************************************************************
* 函数名称: main_help_gpio
* 说    明: 帮助文档
* 参    数: 无
* 返 回 值: 无
***************************************************************/
void main_help_gpio(char *cmd)
{
    printf("%s: platform device gpio\n", cmd);
    printf("Version: %s\n", SOFTWARE_VERSION);
    printf("%s [options]...\n", cmd);
    printf("    -g, --gpio          gpio id\n");
    printf("    -v, --value         the value of gpio, 0 is low, 1 is high\n");
    printf("    -o, --out           gpio dir set to out\n");
    printf("    -i, --in            gpio dir set to in\n");
    printf("    -h, --help          help info\n");
    printf("\n");
}


/***************************************************************
* 函数名称: parse_opt_gpio
* 说    明: 解析参数
* 参    数:
*           @argc:  参数数量
*           @argv:  参数变量数组
* 返 回 值: 无
***************************************************************/
void parse_opt_gpio(int argc, char *argv[])
{
    while (1) {
        struct option long_opts[] = {
            { "gpio",           required_argument,  NULL, 'g' },
            { "value",          required_argument,  NULL, 'v' },
            { "out",            no_argument,        NULL, 'o' },
            { "in",             no_argument,        NULL, 'i' },
            { "help",           no_argument,        NULL, 'h' },
        };
        int option_index = 0;
        int c;

        c = getopt_long(argc, argv, "g:v:oih", long_opts, &option_index);
        if (c == -1) break;

        switch (c) {
        case 'g':
            m_gpio_id = (uint16_t)atoi(optarg);
            break;

        case 'v':
            m_gpio_value = (uint16_t)atoi(optarg);
            break;

        case 'o':
            m_gpio_dir = GPIO_DIR_OUT;
            break;

        case 'i':
            m_gpio_dir = GPIO_DIR_IN;
            break;

        case 'h':
        default:
            main_help_gpio(argv[0]);
            exit(0);
            break;
        }
    }
}


/***************************************************************
* 函数名称: main
* 说    明: 主函数,用于GPIO控制
* 参    数:
*           @argc:  参数数量
*           @argv:  参数变量数组
* 返 回 值: 0为成功,反之为错误
***************************************************************/
int main(int argc, char* argv[])
{
    int32_t ret;

    // 解析参数
    parse_opt_gpio(argc, argv);
    printf("gpio id: %d\n", m_gpio_id);
    printf("gpio dir: %s\n", ((m_gpio_dir == GPIO_DIR_OUT) ? ("out") : ("in")));
    printf("gpio value: %d\n", m_gpio_value);

    if (m_gpio_dir == GPIO_DIR_OUT) {
        // GPIO设置为输出
        ret = GpioSetDir(m_gpio_id, GPIO_DIR_OUT);
        if (ret != 0) {
            PRINT_ERROR("GpioSetDir failed and ret = %d\n", ret);
            return -1;
        }

        // GPIO输出电平
        ret = GpioWrite(m_gpio_id, m_gpio_value);
        if (ret != 0) {
            PRINT_ERROR("GpioWrite failed and ret = %d\n", ret);
            return -1;
        }
    } else {
        // GPIO设置为输出
        ret = GpioSetDir(m_gpio_id, GPIO_DIR_IN);
        if (ret != 0) {
            PRINT_ERROR("GpioSetDir failed and ret = %d\n", ret);
            return -1;
        }

        // 读取GPIO引脚的电平
        ret = GpioRead(m_gpio_id, &m_gpio_value);
        if (ret != 0) {
            PRINT_ERROR("GpioRead failed and ret = %d\n", ret);
            return -1;
        }

        printf("GPIO Read Successful and GPIO = %d, value = %d\n", m_gpio_id, m_gpio_value);
    }

    return 0;
}

本案例中的主要程序文件,通过HDF_PLATFORM_GPIO_MANAGER驱动实现对GPIO的控制。

代码借鉴于:https://gitee.com/Lockzhiner-Electronics/lockzhiner-rk3568-openharmony#/Lockzhiner-Electronics/lockzhiner-rk3568-openharmony/blob/master/samples/b03_platform_device_gpio

3.3 添加模块配置规则

samples/led/BUILD.gn内容如下:

import("//build/ohos.gni")  # 导入编译模板
import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")

ohos_executable("led_gpio") {	# 可执行模块
  sources = [ "src/led_gpio.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",
  ]

  cflags_c = []
  cflags_cc = []
  ldflags = []
  configs = []
  part_name = "led"  # 所属部件名称,必选
  install_enable = true # 是否默认安装
}

编译子系统通过模块、部件和产品三层配置来实现编译和打包。模块就是编译子系统的一个目标,包括(动态库、静态库、配置文件、预编译模块等)。模块要定义属于哪个部件,一个模块只能归属于一个部件。OpenHarmony使用定制化的Gn模板来配置模块规则,Gn语法相关的基础知识请参考官网手册
本案例中,项目在进行build命令编译过程中执行的是存在于根目录的build.sh文件,会遍历扫描.gn文件编译对应程序。ohos_executable为配置项目的可执行指令,sources 为led_gpio.c的所在位置。

3.4 添加部件配置规则

samples/led/bundle.json内容如下:

{
    "name": "@ohos/led",	# HPM部件英文名称,格式"@组织/部件名称"
    "description": "leds example.",	# 部件功能一句话描述
    "version": "3.1",	# 版本号,版本号与OpenHarmony版本号一致
    "license": "Apache License 2.0", # 部件License
    "publishAs": "code-segment", # HPM包的发布方式,当前默认都为code-segment
    "segment": {
        "destPath": "samples/led"	
    },	# 发布类型为code-segment时为必填项,定义发布类型code-segment的代码还原路径(源码路径)
    "dirs": {},	# HPM包的目录结构,字段必填内容可以留空
    "scripts": {},	# HPM包定义需要执行的脚本,字段必填,值非必填
    "component": {	# 部件属性
        "name": "led",	# 部件名称
        "subsystem": "samples",	# 部件所属子系统
        "syscap": [],	# 部件为应用提供的系统能力
        "features": [],	# 部件对外的可配置特性列表,一般与build中的sub_component对应,可供产品配置
        "adapted_system_type": [ "mini", "small", "standard" ],	# 轻量(mini)小型(small)和标准(standard),可以是多个
        "rom": "10KB",	# 部件ROM值
        "ram": "10KB",	# 部件RAM估值
        "deps": {
            "components": [],	 # 部件依赖的其他部件
            "third_party": []	# 部件依赖的三方开源软件
        },
        "build": {	# 编译相关配置
            "sub_component": [
                "//samples/led:led_gpio"	# 部件编译入口
            ],	# 部件编译入口,模块在此处配置
            "inner_kits": [],	# 部件间接口
            "test": []	# 部件测试用例编译入口
        }
    }
}

bundle.json文件包含两个部分,第一部分描述该部件所属子系统的信息,第二部分component则定义该部件构建相关配置。添加的时候需要指明该部件包含的模块sub_component,假如有提供给其它部件的接口,需要在inner_kits中说明,假如有测试用例,需要在test中说明,inner_kits与test没有也可以不添加。
本案例中sub_component配置为//samples/led:led_gpio,//代表根目录,samples/led代表路径,led_gpio代表BUILD.gn文件里ohos_executable的名称。

3.5 修改子系统配置文件

build/subsystem_config.json中添加新建的子系统的配置,新增子系统的配置如下所示:

"sample": {
    "path": "samples",	# 路径
    "name": "samples"	# 子系统名
  }

子系统的配置规则主要是在build/subsystem_config.json中指定子系统的路径和子系统名称。
本案例path配置samples文件夹所在路径, name与bundle.json里subsystem名称匹配即可。

3.6 修改产品配置文件

vendor/hihope/rk3568/config.json中添加对应的led部件,直接添加到原有部件后即可

{
  "subsystem": "samples",
  "components": [
    {
      "component": "led",
      "features": []
    }
  ]
}     

本案例中,subsystem配置为bundle.json里subsystem名称,component配置为led部件名称。

3.7 配置HCS

打开vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs,添加GPIO驱动设备描述,具体内容如下:

root {
    device_info {
        platform :: host {
            device_gpio :: device {
                device0 :: deviceNode {                         // GPIO控制器信息描述
                    policy = 2;                                 // 对外发布服务,必须为2,用于定义GPIO管理器的服务
                    priority = 50;
                    permission = 0644;
                    moduleName = "HDF_PLATFORM_GPIO_MANAGER";   // 这与drivers/hdf_core/framework/support/platform/src/gpio/gpio_service.c的g_gpioServiceEntry.moduleName对应,它主要负责GPIO引脚的管理
                    serviceName = "HDF_PLATFORM_GPIO_MANAGER";
                }
                device1 :: deviceNode {
                    policy = 0;                                 // 等于0,不需要发布服务
                    priority = 55;                              // 驱动驱动优先级
                    permission = 0644;                          // 驱动创建设备节点权限
                    moduleName = "linux_gpio_adapter";          // 用于指定驱动名称,必须是linux_adc_adapter,与drivers/hdf_core/adapter/khdf/linux/platform/gpio/gpio_adapter.c对应
                    deviceMatchAttr = "";                       // 用于配置控制器私有数据,不定义
                }
            }
        }
    }
}

vendor/hihope/rk3568/hdf_config/khdf/hdf.hcs在此文件中引入device_info.hcs文件地址,默认已经引入无需修改。
本案例中,通过moduleName配置HDF_PLATFORM_GPIO_MANAGER驱动加载到HDF驱动平台从而实现对GPIO的控制。

四、代码编译、烧录

  • 编译之前,删除以下文件:vendor/hihope/rk3568/hdf_config/khdf/hdf_test/hdf_hcs.hcbout/kernel/vendor/hihope/rk3568/hdf_config/khdf/hdf_test/hdf_hcs_hex.oout/kernel/OBJ/linux-5.10/arch/arm64/boot/Imageout/kernel/OBJ/linux-5.10/arch/arm64/boot/Image.lz4out/rk3568/packages/phone/images/boot_linux.imgout/kernel/src_tmp
  • 笔者在编译这步吃过很大的亏,很多时候只是因为编译后没有重新生成并覆盖旧生成的文件,导致卡了很久进度,如果发现编译后新文件未生效还是旧文件,大概率是编译问题建议直接删除out重新编译
  • 编译完成直接进行烧录即可

五、测试运行

烧录完成之后重启开发板,通过hdc工具调试,进入shell命令模式,执行以下命令:

# led_gpio -g 495 -v 1 -o
gpio id: 495
gpio dir: out
gpio value: 1
GPIO Read Successful and GPIO = 13, value = 1
#
# 
# led_gpio -g 495 -v 0 -o
gpio id: 495
gpio dir: out
gpio value: 0
#

命令解析:

led_gpio 可执行模块
-g 495   led的gpio号,我这里的led的gpio号为495,请根据实际情况填写
-v 0    设置低电平 -v 1:设置高电平
-o     设置GPIO为输出 -i:设置GPIO为输入

六、结果

  • 操作过程中如看到led点亮和熄灭,则案例实验成功
  • 如遇报错,需通过串口日志进一步排查问题所在

排查思路:

  1. led设备是否挂载在i2c下,设备树dtsdtsi对应i2c是否配置并开启
  2. 修改设备树是否成功,编译之后查看out/kernel/src_tmp/linux-5.10/arch/arm64/boot/dts/rockchip下的dtsdtsi文件是否成功生效,如果未生效表明修改方式不对,需要自己打patch并替换原patch
  3. HCS是否配置成功,通过hdc工具调试连接开发板,进入shell命令模式,cd /sys/devices/virtual/hdf查看文件列表是否存在HDF_PLATFORM_GPIO_MANAGER
  4. gpio号是否正确
  • 29
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: openharmony-rk3568是一个基于RK3568芯片的开源操作系统,它支持多种设备,包括智能家居、智能电视、智能音箱等。它的设计目标是提供一个安全、稳定、高效的操作系统,同时支持多种应用程序和开发工具。它的开源性质使得开发者可以自由地修改和定制系统,以满足不同的需求。 ### 回答2: OpenHarmony是一个开源的分布式操作系统,可以支持多种硬件平台,而RK3568是一款较新的高性能芯片,两者的结合可以为用户带来更好的操作体验。 首先,OpenHarmony可以将不同的硬件设备以及网络连接在一起,形成一种分布式的系统架构,将数据、计算和存储等资源分散处理,从而提高系统的效率和安全性。而RK3568作为一款高性能芯片,拥有强大的处理能力和图形处理能力,可以为OpenHarmony提供更快速、更稳定的运行环境,同时还可以实现更丰富的用户体验。 同时,OpenHarmony的分布式架构使得它可以支持多种应用场景,例如智能家居、智慧城市、智慧交通等领域,而RK3568的高性能和强大的图形处理能力,则可以为这些应用场景提供更好的支持和优化,从而实现更好的用户体验和效果。 总之,OpenHarmonyRK3568的结合,可以为用户提供更快速、更稳定、更安全、更丰富的操作体验,为智能化的未来应用场景提供更好的支持和优化。 ### 回答3: OpenHarmony-RK3568是一款基于鲲鹏架构的开源操作系统,针对高性能应用而设计。其核心使用了华为自主研发的鸿蒙内核,结合了物联网、人工智能、云计算等多种技术,可快速实现设备快速开发和低成本生产。 该操作系统基于RK3568芯片,是一款高性能的处理器,其支持多种语言和多媒体压缩编解码功能,可实现流畅的视频播放和游戏体验。OpenHarmony-RK3568不仅适用于家庭娱乐设备,还可用于工业控制、智能家居等行业。 相比于其他操作系统,OpenHarmony-RK3568是一个开放的平台,可充分利用华为丰富的资源和技术优势,灵活应用于各种不同的场景。此外,华为还为开发者提供了详细的开发文档、SDK和开发工具,帮助他们快速开发应用程序和系统服务,打造自己的智能设备生态系统。 总的来说,OpenHarmony-RK3568是一款高性能、灵活开放的操作系统,为设备制造商和开发者提供了不同的可能性。它将带来更好的用户体验和更低的开发成本,是未来智能设备行业的重要一环。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值