OpenHarmony(鸿蒙南向开发)——标准系统方案之扬帆移植案例

本文为博客 VIP 文章,开通 VIP 后可阅读全文

开通 VIP

本文章是基于瑞芯微RK3399芯片的yangfan开发板,进行标准系统相关功能的移植,主要包括产品配置添加,内核启动、升级,音频ADM化,Camera,TP,LCD,WIFI,BT,vibrator、sensor、图形显示模块的适配案例总结,以及相关功能的适配。 开发板系统移植采用Board仓和SoC代码分离方案,Board仓保存板载驱动的模块,例如音频,Camera,TP,WIFI等驱动模块的适配代码。在SoC仓保存与SoC驱动相关模块,例如I2C,ISP,RGA等驱动模块的适配代码。

产品配置和目录规划

产品配置

在产品//vendor/yangfan目录下创建config.json文件,并指定CPU的架构。//vendor/yangfan/rk3399.json配置如下:

{
    "product_name": "yangfan",---产品名:yangfan
    "device_company": "rockchip",---单板厂商:rockchip
    "device_build_path": "device/board/isoftstone/yangfan",---设备构建路径:device/board/isoftstone/yangfan
    "target_cpu": "arm",---目标cpu:arm
    "type": "standard",---配置系统的级别:standard
    "version": "3.0",---版本:3.0
    "board": "yangfan",---单板名:yangfan
    "enable_ramdisk": true,---启用内存虚拟盘:true
    "build_selinux": true,---构建selinux:true
    "inherit": [ "productdefine/common/inherit/rich.json", "productdefine/common/inherit/chipset_common.json" ],
    "subsystems": [
    {
      "subsystem": "security",
      "components": [
        {
          "component": "selinux",
          "features": []
        }
      ]
    },
    {
      "subsystem": "communication",
      "components": [
        {
          "component": "netmanager_ext",
          "features": []
        }
      ]
    },
    ...
}

主要的配置内容包括:

  1. “product_name”: “yangfan”,—产品名:yangfan
  2. “device_company”: “rockchip”,—单板厂商:rockchip
  3. “device_build_path”: “device/board/isoftstone/yangfan”,—设备构建路径:device/board/isoftstone/yangfan
  4. “target_cpu”: “arm”,—目标cpu:arm
  5. “type”: “standard”,—配置系统的级别:standard
  6. “version”: “3.0”,—版本:3.0
  7. “board”: “yangfan”,—单板名:yangfan
  8. “enable_ramdisk”: true,—启用内存虚拟盘:true

已定义的子系统可以在//build/subsystem_config.json中找到。当然也可以定制子系统。

建议先拷贝Hi3516DV300开发板的配置文件,删除掉hisilicon_products子系统。该子系统为Hi3516DV300 SOC编译内核,不适合RK3568。

目录规划

参考 Board和SoC解耦的设计思路 ,并把芯片适配目录规划为:

device
├── board                                --- 单板厂商目录
│   └── isoftstone                       --- 单板厂商名字:
│       └── yangfan                      --- 单板名:扬帆,主要放置开发板相关的驱动业务代码
└── soc									 --- SoC厂商目录
    └── rockchip                         --- SoC厂商名字:rockchip
        └── rk3399						 --- SoC Series名:rk3399,主要为芯片原厂提供的一些方案,以及闭源库等

产品样例目录规划为:

vendor
└── isoftstone					
    └── yangfan         			         --- 产品名字:产品、hcs以及demo相关

内核启动

二级启动

二级启动简单来说就是将之前直接挂载system,从system下的init启动,改成先挂载ramdsik,从ramdsik中的init 启动,做些必要的初始化动作,如挂载system,vendor等分区,然后切到system下的init 。

RK3399适配主要是将主线编译出来的ramdisk 打包到boot_linux.img中,主要有以下工作:

  1. 使能二级启动

在//vendor/yangfan/rk3399.json中使能enable_ramdisk。

{
    "product_name": "yangfan",
    "device_company": "rockchip",
    "device_build_path": "device/board/isoftstone/yangfan",
    "target_cpu": "arm",
    "type": "standard",
    "version": "3.0",
    "board": "yangfan",
    "enable_ramdisk": true,
    "build_selinux": true,
    ...
}
  1. 将主线编译出来的ramdsik.img 打包到boot_linux.img

配置:

由于rk 启动uboot 支持从ramdisk 启动,只需要在打包boot_linux.img 的配置文件中增加ramdisk.img ,因此没有使用主线的its格式,具体配置就是在内核编译脚本make-ohos.sh 中增加:

function make_extlinux_conf()
{
	dtb_path=$1
	uart=$2
	image=$3

	echo "label rockchip-kernel-5.10" > ${EXTLINUX_CONF}
	echo "	kernel /extlinux/${image}" >> ${EXTLINUX_CONF}
	echo "	fdt /extlinux/${TOYBRICK_DTB}" >> ${EXTLINUX_CONF}
	if [ "enable_ramdisk" == "${ramdisk_flag}" ]; then
		echo "	initrd /extlinux/ramdisk.img" >> ${EXTLINUX_CONF}
	fi
	cmdline="append earlycon=uart8250,mmio32,${uart} root=PARTUUID=614e0000-0000-4b53-8000-1d28000054a9 rw rootwait rootfstype=ext4"
	echo "  ${cmdline}" >> ${EXTLINUX_CONF}
}

打包

增加了打包boot镜像的脚本make-boot.sh,供编译完ramdisk,打包boot 镜像时调用,主要内容:

genext2fs -B ${blocks} -b ${block_size} -d boot_linux -i 8192 -U boot_linux.img

调用make-boot.sh的修改请参考 RK3568 适配二级启动。

INIT配置

init相关配置请参考 启动恢复子系统即可

音频

简介

本文以OpenHarmony 3.0为基础,讲解基于HDF(Hardware Driver Foundation)驱动框架开发的Audio驱动框架,包括Audio驱动的架构组成、功能部件的实现和服务节点详细介绍。

  1. ADM(Audio Driver Model)

    音频驱动框架模型,向上服务于多媒体音频子系统,便于系统开发者能够更便捷的根据场景来开发应用。向下服务于具体的设备厂商,对于Codec和DSP设备厂商来说,可根据ADM模块提供的向下统一接口适配各自的驱动代码,就可以实现快速开发和适配HOS系统。

  2. Audio Control Dispatch

    接收lib层的控制指令并将控制指令分发到驱动层。

  3. Audio Stream Dispatch

    向上通过lib层完成数据流的接收,向下完成数据流对驱动层的分发。

  4. Card Manager

    多声卡管理模块。每个声卡含有Dai、Platform、Codec、Accessory、Dsp、Sapm模块。

  5. Platform Driver

    驱动适配层。

  6. SAPM(Smart Audio Power Manager)

    电源管理模块,对整个ADM电源进行功耗策略优化。

Audio驱动介绍

代码目录
drivers
	├── framework
	│	└── model
	│	│	└── audio					#框架代码
	│	│		├─── common				#公共实现
	│	│		├─── core				#核心
	│	│		├─── dispatch			#控制流和数据流实现
	│	│		└── sapm				#电源管理
	│	└── include
	│		└── audio					#对外接口
	├── adapter
    │	└──khdf
	│		└── linux
	│			└── model
	│				└── audio			#编译文件
	└── peripheral
		└── audio
			└── chipsets		
				└── rk3399				#驱动实现
					├── accessory		#SmartPA驱动
					├── dai				#I2S驱动
					└── soc				#Dma驱动

Audio流程说明
启动流程

  1. 系统启动时audio模块的Platform、Codec、Accessory、Dsp、Dai各个驱动首先被加载,各驱动从各自私有配置文件中获取配置信息,并将获取的配置信息保存到各驱动的Data数据结构中。
  2. 各驱动模块调用ADM注册接口将自己添加到各驱动模块的链表中。
  3. ADM模块读取hdf_audio_driver_0(音频card_0)和hdf_audio_driver_1(音频card_1)配置信息,加载各模块的具体设备。
  4. ADM模块调用各模块的初始化函数对各模块设备进行初始化。
  5. 将初始化成功的音频设备添加到cardManager链表。
播放流程

  1. 播放音频,首先Interface Lib层通过播放流服务下发Render Open指令,Render Stream Dispatch服务收到指令后分别调用各模块的函数接口对指令进行下发。
  2. Interface Lib层通过控制服务下发通路选择指令,Control Dispatch控制服务收到指令后调用Dai模块接口设置通路。
  3. Interface Lib层通过播放流服务下发硬件参数,Render Stream Dispatch服务收到参数后分别调用各模块参数设置接口,对硬件参数进行设置。
  4. Interface Lib层通过播放流服务下发播放启动指令,Render Stream Dispatch服务收到指令后分别调用各模块启动接口,对各模块进行启动设置。
  5. Interface Lib层通过播放流服务下发音频数据,Render Stream Dispatch服务收到数据后调用Platform AudioPcmWrite接口将音频数据传给Dma。
  6. Interface Lib层通过播放流服务下发播放停止指令,Render Stream Dispatch服务收到指令后分别调用各模块停止接口,对各模块进行停止设置。
  7. Interface Lib层通过播放流服务下发Render Close指令,Render Stream Dispatch服务收到指令后调用Platform AudioRenderClose接口对已申请资源进行释放。
控制流程

  1. 设置音量,首先Interface Lib层通过控制服务下发获取音量范围指令,Control Dispatch控制服务收到指令后进行解析并调用Codec模块Get函数接口获取可设置音量范围。
  2. Interface Lib层通过控制服务下发设置音量指令,Control Dispatch控制服务收到指令后进行解析并调用Codec模块Set函数接口设置音量。
实现说明
  1. 驱动注册

以codec的注册函数为例,当codec驱动初始化时调用如下codec注册函数,将codec注册到codecController链表中。

    int32_t AudioRegisterCodec(struct HdfDeviceObject *device, struct CodecData *codecData, struct DaiData *daiData)
    {
    ...

        codec = (struct CodecDevice *)OsalMemCalloc(sizeof(*codec));
    ...

        OsalMutexInit(&codec->mutex);
        codec->devCodecName = codecData->drvCodecName;
        codec->devData = codecData;
        codec->device = device;

        ret = AudioSocRegisterDai(device, daiData);
    ...
        DListInsertHead(&codec->list, &codecController); 
    ...
    }
    c
  1. 数据流数据分发

当录音或者播放时,上层lib层通过dispatch将数据下发或读取数据,此接口接收到lib层的请求后,将数据进行分发或将数据返回。

    static int32_t StreamDispatch(struct HdfDeviceIoClient *client, int cmdId,
        struct HdfSBuf *data, struct HdfSBuf *reply)
    {
        unsigned int count = sizeof(g_streamDispCmdHandle) / sizeof(g_streamDispCmdHandle[0]);
        for (unsigned int i = 0; i < count; ++i) {
            if ((cmdId == (int)(g_streamDispCmdHandle[i].cmd)) && (g_streamDispCmdHandle[i].func != NULL)) {
                return g_streamDispCmdHandle[i].func(client, data, reply);
            }
        }
        ADM_LOG_ERR("invalid [cmdId=%d]", cmdId);
        return HDF_FAILURE;
    }
    c
  1. 控制功能注册接口

音量控制、增益控制、通路控制等控制功能都是通过此接口添加到声卡控制列表。

    int32_t AudioAddControls(struct AudioCard *audioCard, const struct AudioKcontrol *controls, int32_t controlMaxNum)
    {
    ...

        for (i = 0; i < controlMaxNum; i++) {
            control = AudioAddControl(audioCard, &controls[i]);
            if (control == NULL) {
                ADM_LOG_ERR("Add control fail!");
                return HDF_FAILURE;
            }
            DListInsertHead(&control->list, &audioCard->controls);
        }
        ADM_LOG_DEBUG("Success.");
        return HDF_SUCCESS;
    }
    c
  1. 电源管理接口

添加组件实现:

    int32_t AudioSapmNewComponents(struct AudioCard *audioCard,
        const struct AudioSapmComponent *component, int32_t cptMaxNum)
    {
    ...

        for (i = 0; i < cptMaxNum; i++) {
            ret = AudioSapmNewComponent(audioCard, component);
            if (ret != HDF_SUCCESS) {
                ADM_LOG_ERR("AudioSapmNewComponent fail!");
                return HDF_FAILURE;
            }
            component++;
        }

        return HDF_SUCCESS;
    }

    c

添加通路实现:


    int32_t AudioSapmAddRoutes(struct AudioCard *audioCard, const struct AudioSapmRoute *route, int32_t routeMaxNum)
    {
    ...

        for (i = 0; i < routeMaxNum; i++) {
            ret = AudioSapmAddRoute(audioCard, route);
            if (ret != HDF_SUCCESS) {
                ADM_LOG_ERR("AudioSapmAddRoute failed!");
                return HDF_FAILURE;
            }
            route++;
        }
        return HDF_SUCCESS;
    }

    c

添加控制功能实现:


    int32_t AudioSapmNewControls(struct AudioCard *audioCard)
    {
    ...

        DLIST_FOR_EACH_ENTRY(sapmComponent, &audioCard->components, struct AudioSapmComponent, list) {
            if (sapmComponent->newCpt) {
                continue;
            }
            if (sapmComponent->kcontrolsNum > 0) {
                sapmComponent->kcontrols = OsalMemCalloc(sizeof(struct AudioKcontrol*) * sapmComponent->kcontrolsNum);
                if (sapmComponent->kcontrols == NULL) {
                    ADM_LOG_ERR("malloc kcontrols fail!");
                    return HDF_FAILURE;
                }
            }

            switch (sapmComponent->sapmType) {
                case AUDIO_SAPM_ANALOG_SWITCH:
                case AUDIO_SAPM_MIXER:
                case AUDIO_SAPM_MIXER_NAMED_CTRL:
                case AUDIO_SAPM_SPK:
                case AUDIO_SAPM_PGA:
                    ret = AudioSapmNewMixerControls(sapmComponent, audioCard);
                    break;
                case AUDIO_SAPM_MUX:
                case AUDIO_SAPM_VIRT_MUX:
                case AUDIO_SAPM_VALUE_MUX:
                    ret = AudioSapmNewMuxControls(sapmComponent, audioCard);
                    break;
                default:
                    ret = HDF_SUCCESS;
                    break;
            }
    ...

            ReadInitComponentPowerStatus(sapmComponent);
            sapmComponent->newCpt = 1;
            DListInsertTail(&sapmComponent->dirty, &audioCard->sapmDirty);
        }

        ret = AudioSapmPowerComponents(audioCard);
    ...

        return HDF_SUCCESS;
    }

    c
  1. 控制流数据分发

当录音或者播放时,上层lib层通过dispatch将控制指令下发,此接口接收到lib层的控制指令后,将控制指令分发到各驱动模块。

    static int32_t ControlDispatch(struct HdfDeviceIoClient *client, int cmdId,
        struct HdfSBuf *data, struct HdfSBuf *reply)
    {
    ...

        if (cmdId >= AUDIODRV_CTRL_IOCTRL_ELEM_BUTT || cmdId < 0) {
            ADM_LOG_ERR("Invalid [cmdId=%d].", cmdId);
            return HDF_FAILURE;
        }

        for (i = 0; i < HDF_ARRAY_SIZE(g_controlDispCmdHandle); ++i) {
            if ((cmdId == (int)(g_controlDispCmdHandle[i].cmd)) && (g_controlDispCmdHandle[i].func != NULL)) {
                return g_controlDispCmdHandle[i].func(client, data, reply);
            }
        }
        return HDF_FAILURE;
    }
    c

Audio服务介绍

服务节点

基于ADM框架的audio驱动对HDI层提供三个服务hdf_audio_render、hdf_audio_capture、hdf_audio_control。 开发板audio驱动服务节点如下:

console:/dev # ls -al hdf_audio_*                                              
crw------- 1 system system 249,   5 1970-01-01 00:21 hdf_audio_capture  //录音数据流服务。
crw------- 1 system system 249,   3 1970-01-01 00:21 hdf_audio_codec_dev0  //音频设备名称。
crw------- 1 system system 249,   4 1970-01-01 00:21 hdf_audio_control  //音频控制流服务。
crw------- 1 system system 249,   6 1970-01-01 00:21 hdf_audio_render  //播放数据流务。
  1. 音频控制流服务

用来接收上层lib层下发的控制指令,包括音量控制、增益控制、通路控制,这些控制指令都是通过控制流服务下发到驱动。

  1. 音频数据播放流服务

用来接收上层lib层下发的音频数据和播放相关的参数,还有播放的启动

OpenHarmony鸿蒙实战】在RK3399开发板实现智能门禁人脸识别 本样例是基于RK3399开发板,使用OpenHarmony3.0-LTS开发的应用。通过定时获取摄像头数据,实现人脸识别比对等功能。 阅读详情

相关推荐

OpenHarmony富设备开发板RK3399适配解析与实战指南

嵌入式系统开发中,硬件适配与驱动集成是连接芯片与操作系统的核心技术环节。其原理在于通过引导程序、内核移植及硬件抽象层,将操作系统与特定芯片的硬件资源进行高效对接,从而实现系统稳定启动与硬件功能调用。这一过程的技术价值在于大幅降低开发门槛,提升产品研发效率,并为上层应用提供统一的硬件访问接口。在物联网和智能硬件领域,尤其是智能零售终端、工业HMI、服务机器人等富设备应用场景中,成熟的硬件参考设计至关重要。近期,基于RK3399芯片的“扬帆开发板成功合入OpenHarmony社区主干,为开发者提供了经过社区验

weixin_30402231的博客 260

RK3568 OpenHarmony V3.2 Beta5 开发之板级驱动适配()

Openharmony驱动适配实战

liucan633的博客 4020

OpenHarmony实战:帆移植案例(上)

本文章是基于瑞芯微RK3399芯片的yangfan开发

m0_64420071的博客 1861

rk3568 OpenHarmony 内核单独编译

TB-RK3568X0是根据自己的板卡选择的,make-ohos.sh文件里的model_list可以查看支持的板卡。需要对rk3568 openharmony的Linux内核进行调试,内核源码在。boot_linux.img即是修改后的内核镜像,烧录到板卡里。编译成功后返回,openharmony的源码根目录。目录下生成新的boot_linux.img。目录下,这是没打鸿蒙补丁前的源码。真正编译及打了补丁的内核源码在。

damifeng的专栏 4888

鸿蒙南向开发】—— OpenHarmony 标准系统方案扬帆移植案例

本文以 OpenHarmony 3.0 为基础,讲解基于 HDF(Hardware Driver Foundation)驱动框架开发的 Audio 驱动框架,包括 Audio 驱动的架构组成、功能部件的实现和服务节点详细介绍。音频驱动框架模型,向上服务于多媒体音频子系统,便于系统开发者能够更便捷的根据场景来开发应用。向下服务于具体的设备厂商,对于 Codec 和 DSP 设备厂商来说,可根据 ADM 模块提供的向下统一接口适配各自的驱动代码,就可以实现快速开发和适配 HOS 系统

pengjiadashaoye的博客 1074

鸿蒙OpenHarmony南向开发保姆级知识点汇总~

OpenHarmony的技术架构和设计使得它能够适应不同的设备和场景,无论是,OpenHarmony都能提供一致的用户体验和开发体验。这使得开发者能够更加高效地开发适用于多种设备的软件,同时也为用户提供了更加统一和流畅的使用体验。于是小编下面针对了不同阶段的一些知识点做了一个简单的整理,希望能够帮助到大家!

鸿蒙开发知识记录 4419

OpenHarmony鸿蒙南向开发保姆级知识点汇总~

OpenHarmony的技术架构和设计使得它能够适应不同的设备和场景,无论是,OpenHarmony都能提供一致的用户体验和开发体验。这使得开发者能够更加高效地开发适用于多种设备的软件,同时也为用户提供了更加统一和流畅的使用体验。于是小编下面针对了不同阶段的一些知识点做了一个简单的整理,希望能够帮助到大家!

MNxiaona666的博客 3540

鸿蒙OH 5.0】OpenHarmony 标准系统方案扬帆移植案例

讲解基于 HDF(Hardware Driver Foundation)驱动框架开发的 Audio 驱动框架,包括 Audio 驱动的架构组成、功能部件的实现和服务节点详细介绍。音频驱动框架模型,向上服务于多媒体音频子系统,便于系统开发者能够更便捷的根据场景来开发应用。向下服务于具体的设备厂商,对于 Codec 和 DSP 设备厂商来说,可根据 ADM 模块提供的向下统一接口适配各自的驱动代码,就可以实现快速开发和适配 HOS 系统

xiaolizibie的博客 849

鸿蒙开发进阶(OpenHarmony标准系统方案扬帆移植方案

​本文章是基于瑞芯微RK3399芯片的yangfan开发板,进行标准系统相关功能的移植,主要包括产品配置添加,内核启动、升级,音频ADM化,Camera,TP,LCD,WIFI,BT,vibrator、sensor、图形显示模块的适配案例总结,以及相关功能的适配。 开发系统移植采用Board仓和SoC代码分离方案,Board仓保存板载驱动的模块,例如音频,Camera,TP,WIFI等驱动模块的适配代码。在SoC仓保存与SoC驱动相关模块,例如I2C,ISP,RGA等驱动模块的适配代码。

WEZC156465的博客 969

开发板如何适配OpenHarmony 3.2

编译脚本会先把kernel/linux/linux-5.10拷贝到out/kernel/src_tmp/linux-5.10/,然后打上3568的内核补丁patch -p1 < kernel/linux/patches/linux-5.10/rk3568_patch/kernel.patch后编译生成自己的镜像,不利于我们开发,我们自己开发过程中做如下修改,这样方便我们开发过程中的修改。

OpenHarmony_dev的博客 3746

3.8 RK3399项目开发实录-板载OpenHarmony系统的使用(wulianjishu666)

瑞芯微RK3399开发笔记,欢迎点赞收藏。

vx349014857的博客 1792

鸿蒙内核态代码

Kernel代码组成:OH内核态层 = 标准LTS Linux 内核 + 三方SoC芯片平台代码 + OH内核态基础代码 + OH内核态特性(如HDF)标准LTS Linux 内核三方SoC芯片平台代码OH内核态基础代码编译生成最终版本kernel代码主要脚本参考文档。

weixin_43913586的博客 862

Openharmony之GPU Mesa3D移植一(weston 老框架)

目录 1、获取openharmony rk分支版本代码 2、编译5.10内核 1)修改DTS 2)修改config配置 3)修改drivers/gpu/drm/drm_ioctl.c 4)编译 5)刷机 3、编译Buildroot 1)下载代码 2)修改配置 3)编译 4)刷机测试 4、重新编译rk分支 1)找到编译好的二进制文件 2)修改rk分支代码对应的编译配置项 3)重新编译 4)刷机 注意: 5、问题 1)内核编译报错: 2)内核刷机后进不了系统 ...

u013131156的专栏 6600
上一篇: OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3566移植案例(下)
下一篇: OpenHarmony(鸿蒙南向开发)——子系统开发内核
OpenHarmony_小贾
博客等级 码龄3年 1万+粉丝 · 1181原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值