OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3566移植案例(上)

往期知识点记录:

  • 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
  • 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
  • OpenHarmony(鸿蒙南向开发)——轻量系统STM32F407芯片移植案例
  • OpenHarmony(鸿蒙南向开发)——Combo解决方案之W800芯片移植案例
  • OpenHarmony(鸿蒙南向开发)——小型系统STM32MP1芯片移植案例
  • OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3568移植案例(上)
  • OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3568移植案例(下)
  • OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3566移植案例(上)
  • 持续更新中……

本文章是基于瑞芯微RK3566芯片的khdvk_3566b开发板,进行标准系统相关功能的移植,主要包括产品配置添加,内核启动、升级,音频ADM化,Camera,TP,LCD,WIFI,BT,vibrator、sensor、图形显示模块的适配案例总结,以及相关功能的适配。

产品配置和目录规划

产品配置

在产品//vendor/目录下创建以kaihong名字命名的文件夹,并在kaihong文件夹下面新建产品命的文件夹khdvk_3566b。

//vendor/kaihong/khdvk_3566b目录下创建config.json文件。该文件用于描述产品所使用的SOC以及所需的子系统。配置如下

{"product_name": "khdvk_3566b","device_company": "kaihong","device_build_path": "device/board/kaihong/build","target_cpu": "arm","type": "standard","version": "3.0","board": "khdvk_3566b","enable_ramdisk": true,//是否支持ramdisk二级启动"build_selinux": true,// 是否支持selinux权限管理"subsystems": [{"subsystem": "arkui","components": [{"component": "ace_engine_standard","features": []},{"component": "napi","features": []}]},...{"subsystem": "thirdparty","components": [{"component": "musl","features": []}]}]
}

主要的配置内容包括:

  1. product_device:配置所使用的SOC。
  2. type:配置系统的级别,这里直接standard即可。
  3. subsystems:系统需要启用的子系统。子系统可以简单理解为一块独立构建的功能块。

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

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

目录规划

参考https://gitee.com/openharmony-sig/sig-content/blob/master/devboard/docs/board-soc-arch-design.md,并把芯片适配目录规划为:

device
├── board                                --- 单板厂商目录
│   └── kaihong                          --- 单板厂商名字:
│       └── khdvk_3566b                  --- 单板名:khdvk_3566b,主要放置开发板相关的驱动业务代码
└── soc                                  --- SoC厂商目录└── rockchip                         --- SoC厂商名字:rockchip└── rk3566                       --- SoC Series名:rk3566,主要为芯片原厂提供的一些方案,以及闭源库等vendor
└── kaihong                              --- 开发产品样例厂商目录└── khdvk_3566b                      --- 产品名字:产品、hcs以及demo相关

内核启动

二级启动

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

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

1.使能二级启动

在//vendor/kaihong/khdvk_3566b/config.json中使能enable_ramdisk。

{"product_name": "khdvk_3566b","device_company": "kaihong","device_build_path": "device/board/kaihong/build","target_cpu": "arm","type": "standard","version": "3.0","board": "khdvk_3566b","enable_ramdisk": true,//是否支持ramdisk二级启动"build_selinux": true,// 是否支持selinux权限管理

2.把主线编译出来的ramdsik.img 打包到boot.img

配置:

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

function make_extlinux_conf()
{dtb_path=$1uart=$2image=$3echo "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}" ]; thenecho "    initrd /extlinux/ramdisk.img" >> ${EXTLINUX_CONF}ficmdline="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的修改可以参考如下pr:

https://gitee.com/openharmony/build/pulls/569/files

INIT配置

init相关配置请参考 启动子系统的规范要求 即可

音频

khdvk_3566b Audio硬件结构图

khdvk_3566b平台Audio驱动框架图

  1. HDI adapter

实现Audio HAL层驱动(HDI接口适配),给Audio服务(frameworks)提供所需的音频硬件驱动能力接口。包含 Audio Manager、Audio Adapter、Audio Control、Audio Capture、Audio Render等接口对象。

  1. Audio Interface Lib

配合内核中的Audio Driver Model使用,实现音频硬件的控制、录音数据的读取、播放数据的写入。它里面包括Stream_ctrl_common 通用层,主要是为了和上层的audio HDI adapter层进行对接。

  1. ADM(Audio Driver Model)

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

  1. Audio Control Dispatch

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

  1. Audio Stream Dispatch

接收lib层的数据并将数据分发到驱动层

  1. Card Manager

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

  1. Platform Drivers

驱动适配层。

  1. SAPM(Smart Audio Power Manager)

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

Audio 驱动开发

这里以khdvk_3566b为例,讲述Audio驱动开发,其涉及到的模块驱动主要有:Codec驱动、platform驱动、Dai驱动。
相关代码路径如下:

device/board/kaihong/khdvk_3566b/audio_drivers/codec/rk809_codec/
device/board/kaihong/khdvk_3566b/audio_drivers/codec/dai/
device/board/kaihong/khdvk_3566b/audio_drivers/codec/soc/

HDF HCS配置路径如下:

vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/
vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/ 

Audio 驱动开发流程:

step1:配置各个模块的HCS
step2:修改各个模块的编译文件
step3:配置各个模块的函数操作集
step4:进行功能调试
Audio驱动开发实例
codec驱动开发实例

代码路径:
device/board/kaihong/khdvk_3566b/audio_drivers/codec/rk809_codec/

  1. 将codec注册绑定到HDF框架中,moduleName与device_info.hcs中的moduleName匹配

    struct HdfDriverEntry g_Rk809DriverEntry = {

 .moduleVersion = 1,.moduleName = "CODEC_RK809",.Bind = Rk809DriverBind,.Init = Rk809DriverInit,.Release = RK809DriverRelease,
};HDF_INIT(g_Rk809DriverEntry);
  1. Codec模块需要填充下面三个结构体:

g_codecData:codec设备的操作函数集和私有数据集。

g_codecDaiDeviceOps:codecDai的操作函数集,包括启动传输和参数配置等函数接口。

g_codecDaiData:codec的数字音频接口的操作函数集和私有数据集。

struct CodecData g_rk809Data = {.Init = Rk809DeviceInit,.Read = RK809CodecReadReg,.Write = Rk809CodecWriteReg,
};struct AudioDaiOps g_rk809DaiDeviceOps = {.Startup = Rk809DaiStartup,.HwParams = Rk809DaiHwParams,.Trigger = Rk809NormalTrigger,
};struct DaiData g_rk809DaiData = {.DaiInit = Rk809DaiDeviceInit,.ops = &g_rk809DaiDeviceOps,
};

1> CodecData结构体操作函数的实现

int32_t Rk809DeviceInit(struct AudioCard *audioCard, const struct CodecDevice *device)
{......  //get和set功能注册 if (CodecSetCtlFunc(device->devData, RK809GetCtrlOps, RK809SetCtrlOps) != HDF_SUCCESS) {AUDIO_DRIVER_LOG_ERR("AudioCodecSetCtlFunc failed.");return HDF_FAILURE;}//codec默认寄存器的初始化ret = RK809RegDefaultInit(device->devData->regCfgGroup);......if (AudioAddControls(audioCard, device->devData->controls, device->devData->numControls) != HDF_SUCCESS) {AUDIO_DRIVER_LOG_ERR("add controls failed.");return HDF_FAILURE;}......
}
/*读寄存器接口*/
int32_t RK809CodecReadReg(const struct CodecDevice *codec, uint32_t reg, uint32_t *val)
{......if (Rk809DeviceRegRead(reg, val)) {AUDIO_DRIVER_LOG_ERR("read register fail: [%04x]", reg);return HDF_FAILURE;}return HDF_SUCCESS;
}/*写寄存器接口*/
int32_t Rk809CodecWriteReg(const struct CodecDevice *codec, uint32_t reg, uint32_t value)
{if (Rk809DeviceRegWrite(reg, value)) {AUDIO_DRIVER_LOG_ERR("write register fail: [%04x] = %04x", reg, value);return HDF_FAILURE;}return HDF_SUCCESS;
}

2> g_rk809DaiDeviceOps结构体的具体实现

/*Rk809DaiStartup为启动时的一些设置*/
int32_t Rk809DaiStartup(const struct AudioCard *card, const struct DaiDevice *device)
{......ret = RK809WorkStatusEnable(device->devData->regCfgGroup);......
}
/*Rk809DaiHwParams为参数配置,包括采样率、位宽等。*/
int32_t Rk809DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
{......ret = AudioFormatToBitWidth(param->format, &bitWidth); codecDaiParamsVal.frequencyVal = param->rate;codecDaiParamsVal.DataWidthVal = bitWidth;ret =  RK809DaiParamsUpdate(card->rtd->codecDai->devData->regCfgGroup, codecDaiParamsVal);......
}
/*PCM流控制寄存器相关配置*/
int32_t Rk809NormalTrigger(const struct AudioCard *card, int cmd, const struct DaiDevice *device)
{g_cuurentcmd = cmd;switch (cmd) {case AUDIO_DRV_PCM_IOCTL_RENDER_START:case AUDIO_DRV_PCM_IOCTL_RENDER_RESUME:RK809DeviceRegConfig(rk817_render_start_regmap_config);break;case AUDIO_DRV_PCM_IOCTL_RENDER_STOP:case AUDIO_DRV_PCM_IOCTL_RENDER_PAUSE:RK809DeviceRegConfig(rk817_render_stop_regmap_config);break;case AUDIO_DRV_PCM_IOCTL_CAPTURE_START:case AUDIO_DRV_PCM_IOCTL_CAPTURE_RESUME:RK809DeviceRegConfig(rk817_capture_start_regmap_config);break;case AUDIO_DRV_PCM_IOCTL_CAPTURE_STOP:case AUDIO_DRV_PCM_IOCTL_CAPTURE_PAUSE:RK809DeviceRegConfig(rk817_capture_stop_regmap_config);break;default:break;}return HDF_SUCCESS;
}
  1. 完成 bind、init和release函数的实现

HdfDriverEntry结构体的具体填充:

/*获取codec service,以及注册codec*/
static int32_t Rk809DriverInit(struct HdfDeviceObject *device)
{......CodecGetConfigInfo(device, &(g_chip->codec)) CodecSetConfigInfo(&(g_chip->codec),  &(g_chip->dai)GetServiceName(device)CodecGetDaiName(device,  &(g_chip->dai.drvDaiName)OsalMutexInit(&g_rk809Data.mutex);AudioRegisterCodec(device, &(g_chip->codec), &(g_chip->dai)......
}   
/*将codec service绑定到HDF*/
static int32_t Rk809DriverBind(struct HdfDeviceObject *device)
{struct CodecHost *codecHost;......codecHost = (struct CodecHost *)OsalMemCalloc(sizeof(*codecHost));......codecHost->device = device;device->service = &codecHost->service;return HDF_SUCCESS;
}
/*释放资源*/
static void RK809DriverRelease(struct HdfDeviceObject *device)
{struct CodecHost *codecHost;......codecHost = (struct CodecHost *)device->service;if (codecHost == NULL) {HDF_LOGE("CodecDriverRelease: codecHost is NULL");return;}OsalMemFree(codecHost);
}
  1. 配置codec hcs文件

    1> vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/device_info.hcs

相关配置如下:

device_codec :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "CODEC_RK809";serviceName = "codec_service_0";deviceMatchAttr = "hdf_codec_driver";}
}

2> vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/codec_config.hcs

该文件涉及音量、静音模式、mic、通道模式等相关寄存器配置

DAI驱动开发实例

代码路径:

device/board/kaihong/khdvk_3566b/audio_drivers/codec/dai/
  1. 将I2S驱动注册绑定到HDF框架中,代码片段如下,启动moduleName与HCS文件的中moduleName一致

    struct HdfDriverEntry g_daiDriverEntry = {

 .moduleVersion = 1,.moduleName = "DAI_RK3568",.Bind = DaiDriverBind,.Init = DaiDriverInit,.Release = DaiDriverRelease,
  1. DAI模块需要填充下面两个结构体

g_daiData:dai设备私有配置,其中包含dai设备的初始化、读写寄存器、操作函数。

g_daiDeviceOps:dai设备操作函数集,包含了dai的参数设置、触发、启动。

struct AudioDaiOps g_daiDeviceOps = {.Startup = Rk3568DaiStartup,.HwParams = Rk3568DaiHwParams,.Trigger = Rk3568NormalTrigger,
};struct DaiData g_daiData = {.Read = Rk3568DeviceReadReg,.Write = Rk3568DeviceWriteReg,.DaiInit = Rk3568DaiDeviceInit,.ops = &g_daiDeviceOps,
};

1> AudioDaiOps结构体的具体填充

/*Rk3568DaiHwParams中主要完成一些pcm流信息的设置*/
int32_t Rk3568DaiHwParams(const struct AudioCard *card, const struct AudioPcmHwParams *param)
{......  data->pcmInfo.channels = param->channels;if (AudioFormatToBitWidth(param->format, &bitWidth) != HDF_SUCCESS) {AUDIO_DEVICE_LOG_ERR("AudioFormatToBitWidth error");return HDF_FAILURE;}data->pcmInfo.bitWidth = bitWidth;data->pcmInfo.rate = param->rate;data->pcmInfo.streamType = param->streamType;i2sTdm = dev_get_drvdata(&platformdev->dev);ret = RK3568I2sTdmSetSysClk(i2sTdm, param);if (ret != HDF_SUCCESS) {AUDIO_DEVICE_LOG_ERR("RK3568I2sTdmSetSysClk error");return HDF_FAILURE;}ret = RK3568I2sTdmSetMclk(i2sTdm, &mclk, param);if (ret != HDF_SUCCESS) {AUDIO_DEVICE_LOG_ERR("RK3568I2sTdmSetMclk error");return HDF_FAILURE;}AUDIO_DEVICE_LOG_DEBUG("success");return HDF_SUCCESS;
}
int32_t Rk3568NormalTrigger(const struct AudioCard *card, int cmd, const struct DaiDevice *device)
{......Rk3568TxAndRxSetReg(i2sTdm, streamType, triggerFlag);......
}

2> DaiData结构体的具体填充

/*封装linux内核的读寄存器接口*/
int32_t Rk3568DeviceReadReg(const struct DaiDevice *dai, uint32_t reg, uint32_t *val)
{......if (regmap_read(i2sTdm->regmap, reg, val)) {......
}
/*封装linux内核的写寄存器接口*/  
int32_t Rk3568DeviceWriteReg(const struct DaiDevice *dai, uint32_t reg, uint32_t value)
{......if (regmap_write(i2sTdm->regmap, reg, value)) {......
}
/*dai 设备的初始化*/
int32_t Rk3568DaiDeviceInit(struct AudioCard *card, const struct DaiDevice *dai)
  1. 完成 bind、init和release函数的实现

HdfDriverEntry结构体中的bind、init、release具体填充:

static int32_t DaiDriverInit(struct HdfDeviceObject *device)
{......DaiGetConfigInfo(device, &g_daiData)DaiGetServiceName(device)AudioSocRegisterDai(device, (void *)&g_daiData);......
}
static int32_t DaiDriverBind(struct HdfDeviceObject *device)
{......daiHost->device = device;device->service = &daiHost->service;g_daiData.daiInitFlag = false;......
}
static void DaiDriverRelease(struct HdfDeviceObject *device)
{......OsalMutexDestroy(&g_daiData.mutex);daiHost = (struct DaiHost *)device->service;OsalMemFree(daiHost);......
}

4.配置dai hcs文件

1> vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/device_info.hcs

device_dai0 :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "DAI_RK3568";serviceName = "dai_service";deviceMatchAttr = "hdf_dai_driver";}
}

2> vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/dai_config.hcs

该文件涉及I2S时序、配置参数以及rk809使能等相关寄存器配置

Platform驱动开发实例
  1. 将DMA驱动注册到HDF框架中,代码片段如下,启动moduleName与HCS文件的中moduleName一致
struct HdfDriverEntry g_platformDriverEntry = {.moduleVersion = 1,.moduleName = "DMA_RK3568",.Bind = PlatformDriverBind,.Init = PlatformDriverInit,.Release = PlatformDriverRelease,
}; HDF_INIT(g_platformDriverEntry);
  1. DMA模块需要填充下面两个结构体
struct AudioDmaOps g_dmaDeviceOps = {.DmaBufAlloc = Rk3568DmaBufAlloc, //dma内存申请函数接口.DmaBufFree = Rk3568DmaBufFree,   // dma内存释放函数接口.DmaRequestChannel = Rk3568DmaRequestChannel,  // dma申请通道函数接口.DmaConfigChannel = Rk3568DmaConfigChannel,    // dma通道配置函数接口.DmaPrep = Rk3568DmaPrep,             // dma准备函数接口.DmaSubmit = Rk3568DmaSubmit,         // dma submit函数接口.DmaPending = Rk3568DmaPending,       // dma pending函数接口.DmaPause = Rk3568DmaPause,           // dma暂停、停止函数接口.DmaResume = Rk3568DmaResume,         // dma恢复函数接口.DmaPointer = Rk3568PcmPointer,       // dma获取当前播放或录音位置函数接口
};

struct PlatformData g_platformData = {.PlatformInit = AudioDmaDeviceInit,   // dma设备初始化接口.ops = &g_dmaDeviceOps,
};
  1. 完成 bind、init和release函数的实现

HdfDriverEntry结构体中的bind、init、release具体填充:

static int32_t PlatformDriverInit(struct HdfDeviceObject *device)
{......PlatformGetServiceName(device);AudioSocRegisterPlatform(device, &g_platformData)......
}
static int32_t PlatformDriverBind(struct HdfDeviceObject *device)
{......platformHost->device = device;device->service = &platformHost->service;......
}
static void PlatformDriverRelease(struct HdfDeviceObject *device)
{......platformHost = (struct PlatformHost *)device->service;OsalMemFree(platformHost);......
}
  1. 配置dma hcs文件

1> vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/device_info.hcs

相关配置如下:

 device_dma :: device {device0 :: deviceNode {policy = 1;priority = 50;preload = 0;permission = 0666;moduleName = "DMA_RK3568";serviceName = "dma_service_0";deviceMatchAttr = "hdf_dma_driver";}}

2> vendor/kaihong/khdvk_3566b/hdf_config/khdf/audio/dma_config.hcs

没有特殊参数需要配置,一般情况下不需改动。

Makefile和Kconfig配置文件

文件路径:

drivers/adapter/khdf/linux/model/audio

Makefile文件相关内容:

obj-$(CONFIG_DRIVERS_HDF_AUDIO_RK3566) += \$(KHDF_AUDIO_RK3566_DIR)/codec/rk809_codec/src/rk809_codec_adapter.o \$(KHDF_AUDIO_RK3566_DIR)/codec/rk809_codec/src/rk809_codec_impl.o \$(KHDF_AUDIO_RK3566_DIR)/codec/rk809_codec/src/rk809_codec_linux_driver.o \$(KHDF_AUDIO_RK3566_DIR)/dsp/src/rk3568_dsp_adapter.o \$(KHDF_AUDIO_RK3566_DIR)/dsp/src/rk3568_dsp_ops.o \$(KHDF_AUDIO_RK3566_DIR)/dai/src/rk3568_dai_adapter.o \$(KHDF_AUDIO_RK3566_DIR)/dai/src/rk3568_dai_ops.o \$(KHDF_AUDIO_RK3566_DIR)/dai/src/rk3568_dai_linux_driver.o \$(KHDF_AUDIO_RK3566_DIR)/soc/src/rk3568_dma_adapter.o \$(KHDF_AUDIO_RK3566_DIR)/soc/src/rk3568_dma_ops.o

Kconfig相关内容:

config DRIVERS_HDF_AUDIO_RK3566bool "Enable HDF Audio Codec driver"default ndepends on DRIVERS_HDF_AUDIOhelpAnswer Y to choice HDF Audio Codec driver.

LCD

khdvk_3566b平台默认支持一个mipi接口的lcd屏幕

LCD的适配主要依赖于HDF显示模型,显示驱动模型基于 HDF 驱动框架、Platform 接口及 OSAL 接口开发,可以屏蔽不同内核形态(LiteOS、Linux)差异,适用于不同芯片平台,为显示屏器件提供统一的驱动平台。

如图为 HDF Display驱动模型层次关系

当前驱动模型主要部署在内核态中,向上对接到 Display 公共 hal 层,辅助 HDI 的实现。显示驱动通过 Display-HDI 层对图形服务暴露显示屏驱动能力;向下对接显示屏 panel 器件,驱动屏幕正常工作,自上而下打通显示全流程通路。

所以LCD的适配主要在于LCD panel器件驱动的适配

器件驱动的适配分为2部分:panel驱动和hcs配置

涉及的文件有:

drivers/framework/model/display/driver/panel
vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info
vendor/kaihong/khdvk_3566b/hdf_config/khdf/input

panel驱动

器件驱动主要围绕如下接口展开:

struct PanelData {struct HdfDeviceObject *object;int32_t (*init)(struct PanelData *panel);int32_t (*on)(struct PanelData *panel);int32_t (*off)(struct PanelData *panel);int32_t (*prepare)(struct PanelData *panel);int32_t (*unprepare)(struct PanelData *panel);struct PanelInfo *info;enum PowerStatus powerStatus;struct PanelEsd *esd;struct BacklightDev *blDev;void *priv;
};

驱动中在初始化接口中实例化该结构体:

panelSimpleDev->panel.init = PanelSimpleInit;
panelSimpleDev->panel.on = PanelSimpleOn;
panelSimpleDev->panel.off = PanelSimpleOff;
panelSimpleDev->panel.prepare = PanelSimplePrepare;
panelSimpleDev->panel.unprepare = PanelSimpleUnprepare;static void PanelResInit(struct panel_jdi_gt911_dev *panel_dev)
{......   panel_dev->panel.info = &g_panelInfo;panel_dev->panel.init = PanelInit;panel_dev->panel.on = PanelOn;panel_dev->panel.off = PanelOff;panel_dev->panel.prepare = PanelPrepare;panel_dev->panel.unprepare = PanelUnprepare;...... 
}

g_panelInfo配置panel基础参数

PanelInit负责panel的软件初始化

PanelOn负责亮屏

PanelOff负责灭屏

PanelPrepare负责亮屏的硬件时序初始化

PanelUnprepare负责灭屏的硬件时序初始化

实例化后使用RegisterPanel接口向display模型注册该panel驱动即可

需要说明的是,khdvk_3566b上的这款lcd使用的时候DRM显示框架

hcs配置

device3 :: deviceNode {policy = 0;priority = 100;preload = 0;moduleName = "LCD_MIPI_JDI_GT911";
}

背光

背光控制分为原生linux内核框架下背光驱动以及基于HDF框架开发的背光驱动模型。

rk3566背光是通过pwm控制占空比实现的,具体使用的是pwm4

linux背光驱动代码路径:

linux-5.10/drivers/video/backlight/pwm_bl.c
linux-5.10/drivers/video/backlight/backlight.c
linux-5.10/drivers/pwm/pwm-rockchip.c

使用HDF框架下的背光驱动,需要关闭原生驱动

    # CONFIG_BACKLIGHT_PWM is not set

HDF实现

基于HDF框架开发的背光驱动模型,如下图:

代码路径:

drivers/framework/model/display/driver/backlight/hdf_bl.c

HDF BL入口函数:

    static int32_t BacklightInit(struct HdfDeviceObject *object){if (object == NULL) {HDF_LOGE("%s: object is null!", __func__);return HDF_FAILURE;}HDF_LOGI("%s success", __func__);return HDF_SUCCESS;}struct HdfDriverEntry g_blDevEntry = {.moduleVersion = 1,.moduleName = "HDF_BL",.Init = BacklightInit,.Bind = BacklightBind,};HDF_INIT(g_blDevEntry);

代码路径:

drivers/framework/model/display/driver/backlight/pwm_bl.c

HDF PWM入口函数:

    struct HdfDriverEntry g_pwmBlDevEntry = {.moduleVersion = 1,.moduleName = "PWM_BL",.Init = BlPwmEntryInit,};HDF_INIT(g_pwmBlDevEntry);

具体控制背光的接口:

    static int32_t BlPwmUpdateBrightness(struct BacklightDev *blDev, uint32_t brightness){int32_t ret;uint32_t duty;struct BlPwmDev *blPwmDev = NULL;blPwmDev = ToBlDevPriv(blDev);if (blPwmDev == NULL) {HDF_LOGE("%s blPwmDev is null", __func__);return HDF_FAILURE;}if (blPwmDev->props.maxBrightness == 0) {HDF_LOGE("%s maxBrightness is 0", __func__);return HDF_FAILURE;}if (brightness == 0) {return PwmDisable(blPwmDev->pwmHandle);}duty = (brightness * blPwmDev->config.period) / blPwmDev->props.maxBrightness;ret = PwmSetDuty(blPwmDev->pwmHandle, duty);if (ret != HDF_SUCCESS) {HDF_LOGE("%s: PwmSetDuty failed, ret %d", __func__, ret);return HDF_FAILURE;}return PwmEnable(blPwmDev->pwmHandle);}static struct BacklightOps g_blDevOps = {.updateBrightness = BlPwmUpdateBrightness,};

HDF PWM实现的调用的就是内核pwm的接口。

代码路径:

drivers/framework/model/display/driver/panel/mipi_jdi_gt911.c

在LCD HDF器件驱动注册背光:

    panel_dev->panel.blDev = GetBacklightDev("hdf_pwm");if (panel_dev->panel.blDev == NULL) {HDF_LOGE("%s GetBacklightDev fail", __func__);goto FAIL;}

HCS配置

驱动hcs配置:

    device_pwm_bl :: device {device0 :: deviceNode {policy = 0;priority = 95;preload = 0;moduleName = "PWM_BL";deviceMatchAttr = "pwm_bl_dev";}}device_backlight :: device {device0 :: deviceNode {policy = 2;priority = 90;preload = 0;permission = 0660;moduleName = "HDF_BL";serviceName = "hdf_bl";}}

pwm背光的hcs配置:

    root {backlightConfig {pwmBacklightConfig {match_attr = "pwm_bl_dev";pwmDevNum = 1;pwmMaxPeroid = 25000;backlightDevName = "hdf_pwm";minBrightness = 0;defBrightness = 127;maxBrightness = 255;}}}

测试

cat /sys/kernel/debug/pwm 来查看hdf pwm是否申请到pwm4

申请成功有如下结果:

requested 代表申请成功

enabled 代表pwm4使能成功

    # cat /sys/kernel/debug/pwmplatform/fe6e0000.pwm, 1 PWM devicepwm-0   (backlight           ): requested period: 25000 ns duty: 0 ns polarity: normal

显示适配

显示适配需要完成的工作:图形服务HDI接口适配、GPU适配、mipi dsi驱动适配

显示HDI

显示HDI 对图形服务提供显示驱动能力,包括显示图层的管理、显示内存的管理及硬件加速等。 显示HDI需要适配两部分:gralloc 和 display_device。

OpenHarmony提供了使用与Hi3516DV300参考实现,厂商可根据实际情况参考适配,khdvk_3566b display适配是在//device/soc/rockchip/hardware/display目录下,仓名为 device_soc_rockchip 。

display gralloc适配

gralloc模块提供显示内存管理功能,该实现基于drm开发。

drm设备节点定义在//device/soc/rockchip/hardware/display/src/display_gralloc/display_gralloc_gbm.c文件中,根据khdvk_3566b实际情况修改了drm文件节点。

const char *g_drmFileNode = "/dev/dri/renderD128";
display device适配

display device模块提供显示设备管理、layer管理、硬件加速等功能。

  1. display drm设备节点初始化,根据khdvk_3566b实际情况修改了drm设备名称。
//device/soc/rockchip/hardware/display/src/display_device/drm/drm_device.cpp
std::shared_ptr<HdiDeviceInterface> DrmDevice::Create()
{DISPLAY_DEBUGLOG();if (mDrmFd == nullptr) {const std::string name("rockchip");    // 将drm驱动设备名称修改为“rockchip”int drmFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);  // 将drm驱动设备文件句柄修改为"/dev/dri/card0"if (drmFd < 0) {DISPLAY_LOGE("drm file:%{public}s open failed %{public}s", name.c_str(), strerror(errno));return nullptr;}DISPLAY_DEBUGLOG("the drm fd is %{public}d", drmFd);mDrmFd = std::make_shared<HdiFd>(drmFd);}if (mInstance == nullptr) {mInstance = std::make_shared<DrmDevice>();}return mInstance;
}
  1. display硬件合成的修改
//device/soc/rockchip/hardware/display/src/display_gfx/display_gfx.c

硬件合成文件添加了颜色空间的支持模式

RgaSURF_FORMAT colorSpaceModeChange(PixelFormat color, uint8_t *isYuv)
{RgaSURF_FORMAT rkFormat;switch (color) {case PIXEL_FMT_RGB_565:          /**< RGB565 format */rkFormat = RK_FORMAT_RGB_565;*isYuv = 0;break;case PIXEL_FMT_RGBA_4444:        /**< RGBA4444 format */rkFormat = RK_FORMAT_RGBA_4444;*isYuv = 0;break;case PIXEL_FMT_RGBA_5551:        /**< RGBA5551 format */rkFormat = RK_FORMAT_RGBA_5551;*isYuv = 0;break;case PIXEL_FMT_RGBX_8888:        /**< RGBX8888 format */rkFormat = RK_FORMAT_RGBX_8888;*isYuv = 0;break;case PIXEL_FMT_RGBA_8888:        /**< RGBA8888 format */rkFormat = RK_FORMAT_RGBA_8888;*isYuv = 0;break;case PIXEL_FMT_RGB_888:          /**< RGB888 format */rkFormat = RK_FORMAT_RGB_888;*isYuv = 0;break;case PIXEL_FMT_BGR_565:          /**< BGR565 format */rkFormat = RK_FORMAT_BGR_565;*isYuv = 0;break;case PIXEL_FMT_BGRA_4444:        /**< BGRA4444 format */rkFormat = RK_FORMAT_BGRA_4444;*isYuv = 0;break;case PIXEL_FMT_BGRA_5551:        /**< BGRA5551 format */rkFormat = RK_FORMAT_BGRA_5551;*isYuv = 0;break;case PIXEL_FMT_BGRX_8888:        /**< BGRX8888 format */rkFormat = RK_FORMAT_BGRX_8888;*isYuv = 0;break;case PIXEL_FMT_BGRA_8888:        /**< BGRA8888 format */rkFormat = RK_FORMAT_BGRA_8888;*isYuv = 0;break;case PIXEL_FMT_YCBCR_422_SP:     /**< YCBCR422 semi-planar format */rkFormat = RK_FORMAT_YCbCr_420_SP;*isYuv = 1;break;case PIXEL_FMT_YCRCB_422_SP:     /**< YCRCB422 semi-planar format */rkFormat = RK_FORMAT_YCrCb_422_SP;*isYuv = 1;break;case PIXEL_FMT_YCBCR_420_SP:     /**< YCBCR420 semi-planar format */rkFormat = RK_FORMAT_YCbCr_420_SP;*isYuv = 1;break;case PIXEL_FMT_YCRCB_420_SP:     /**< YCRCB420 semi-planar format */rkFormat = RK_FORMAT_YCrCb_420_SP;*isYuv = 1;break;case PIXEL_FMT_YCBCR_422_P:      /**< YCBCR422 planar format */rkFormat = RK_FORMAT_YCbCr_422_P;*isYuv = 1;break;case PIXEL_FMT_YCRCB_422_P:      /**< YCRCB422 planar format */rkFormat = RK_FORMAT_YCrCb_422_P;*isYuv = 1;break;case PIXEL_FMT_YCBCR_420_P:      /**< YCBCR420 planar format */rkFormat = RK_FORMAT_YCbCr_420_P;*isYuv = 1;break;case PIXEL_FMT_YCRCB_420_P:      /**< YCRCB420 planar format */rkFormat = RK_FORMAT_YCrCb_420_P;*isYuv = 1;break;case PIXEL_FMT_YUYV_422_PKG:     /**< YUYV422 packed format */rkFormat = RK_FORMAT_YUYV_422;*isYuv = 1;break;case PIXEL_FMT_UYVY_422_PKG:     /**< UYVY422 packed format */rkFormat = RK_FORMAT_UYVY_422;*isYuv = 1;break;case PIXEL_FMT_YVYU_422_PKG:     /**< YVYU422 packed format */rkFormat = RK_FORMAT_YUYV_422;*isYuv = 1;break;case PIXEL_FMT_VYUY_422_PKG:     /**< VYUY422 packed format */rkFormat = RK_FORMAT_VYUY_422;*isYuv = 1;break;default:rkFormat = RK_FORMAT_UNKNOWN;break;}return rkFormat;
}

在合成时增加了旋转90、180、270度

int32_t TransformTypeChange(TransformType type)
{int32_t rkRotateType;switch (type) {case ROTATE_90:            /**< Rotation by 90 degrees */rkRotateType = IM_HAL_TRANSFORM_ROT_90;break;case ROTATE_180:             /**< Rotation by 180 degrees */rkRotateType = IM_HAL_TRANSFORM_ROT_180;break;case ROTATE_270:             /**< Rotation by 270 degrees */rkRotateType = IM_HAL_TRANSFORM_ROT_270;break;default:rkRotateType = 0;        /**< No rotation */break;}return rkRotateType;
}
测试验证

hello_composer 测试模块:Rosen图形框架提供的测试程序,主要显示流程,HDI接口等功能是否正常,默认随系统编译。

代码路径:

foundation/graphic/graphic_2d/rosen/samples/composer/
├── BUILD.gn
├── hello_composer.cpp
├── hello_composer.h
├── layer_context.cpp
├── layer_context.h
└── main.cpp

具体验证如下:

  1. 关闭render service
   service_control stop render_service
  1. 关闭 fondation进程
   service_control stop fondation
  1. 运行hello_composer测试相关接口
    切换到/system/bin目录下,运行hello_composer测试命令
   #cd /system/bin#./hello_composerrga_api version 1.3.0_[1] (df26244 build: 2021-09-01 11:23:31 base: )

查看mipi显示屏幕上的变化

https://gitee.com/openharmony/drivers_peripheral/tree/master/display/test/unittest/standard单元测试:HDI显示模块提供的测试模块,主要测试HDI接口、显示buffer、驱动等能力,测试时也需要关闭render service和fondation进程。

代码路径:/drivers/peripheral/display/test/unittest/standard

├── BUILD.gn
├── common
│   ├── display_test.h
│   ├── display_test_utils.cpp
│   └── display_test_utils.h
├── display_device
│   ├── hdi_composition_check.cpp
│   ├── hdi_composition_check.h
│   ├── hdi_device_test.cpp
│   ├── hdi_device_test.h
│   ├── hdi_test_device_common.h
│   ├── hdi_test_device.cpp
│   ├── hdi_test_device.h
│   ├── hdi_test_display.cpp
│   ├── hdi_test_display.h
│   ├── hdi_test_layer.cpp
│   ├── hdi_test_layer.h
│   ├── hdi_test_render_utils.cpp
│   └── hdi_test_render_utils.h
│── display_gfx
│   │── display_gfx_test.cpp
│   │── display_gfx_test.h
│   │── soft_blit.cpp
│   │── soft_blit.h
└── display_gralloc├── display_gralloc_test.cpp└── display_gralloc_test.h

具体验证如下:

  1. 添加编译模块
    修改drivers/peripheral/display/test/BUILD.gn
  group("hdf_test_display") {testonly = truedeps = [ "fuzztest:hdf_display_fuzztest","unittest/standard:hdf_unittest_display",        //添加display单元测试]}
  1. 添加缺失的文件包含
    修改drivers/peripheral/display/test/unittest/standard/BUILD.gn
    在第63行处,添加包含目录//device/soc/rockchip/hardware/display/src/display_gralloc,如果不修改此处有可能编译报错。
ohos_unittest("gralloctest") {module_out_path = module_output_pathsources = [ "display_gralloc/display_gralloc_test.cpp" ]deps = ["//drivers/peripheral/display/hal:hdi_display_gralloc","//third_party/googletest:gtest_main",]include_dirs = ["common","//drivers/peripheral/display/hal/default_standard/include","//drivers/peripheral/display/hal/default_standard/src/display_gralloc","//device/soc/rockchip/hardware/display/src/display_gralloc",        //添加这行,将display_gralloc包含进编译"//drivers/peripheral/display/interfaces/include","//drivers/peripheral/base","//drivers/peripheral/display/interfaces/include","//foundation/graphic/standard/utils/include",]external_deps = ["device_driver_framework:libhdf_utils","utils_base:utils",]
}
  1. 编译命令
    编译hdf_test_display的命令如下:
   ./build.sh --product-name khdvk_3566b --build-target hdf_test_display
  1. 编译结果
    编译结果路径在out/khdvk_3566b/tests/unittest/hdf/display目录下,该目录下有三个可执行文件devicetest、gfxtest、gralloctest,可将这三文件通过hdc发送到khdvk_3566b开发板上运行测试。

  2. 运行测试
    通过hdc下载到开发板/system/bin/目录下,并修改测试程序的可执行属性,在终端下输入如下命令

hdc_std.exe file send D:\hdc\devicetest /system/bin/
hdc_std.exe file send D:\hdc\gfxtest /system/bin/
hdc_std.exe file send D:\hdc\gralloctest /system/bin/

进入hdc命令hdc_std.exe shell后

先关闭render service和foundation:

service_control stop render_service
service_control stop fondation

再分别执行命令,查看mipi屏显示结果:

cd /system/bin/

执行devicetest

chmod -R 777 devicetest
devicetest

执行gfxtest

chmod -R 777 gfxtest
gfxtest

执行gralloctest

chmod -R 777 gralloctest
gralloctest

GPU

GPU图形处理器, khdvk_3566b GPU适配是在//device/soc/rockchip/hardware/gpu目录下,目前采用的是rockchip提供闭源的bifrost gpu方案。

目录结构:

├── BUILD.gn
├── lib64
│   └── libmali-bifrost-g52-g2p0-ohos.so
├── lib
│   └── libmali-bifrost-g52-g2p0-ohos.so
└── include└── gbm.h

gpu编译的内容,我们来看下BUILD.gn的内容,其中我们预编译了libmali-bifrost-g52-g2p0-ohos.so动态库,khdvk_3566b是arm64位的,所以编译了lib64目录下的libmali-bifrost-g52-g2p0-ohos.so动态库。其中gup模块符号链接libEGL.so、libGLESv1.so、libGLESv2.so、libGLESv3.so、libmali.so.0、libmali.so.1动态库的符号。

import("//build/ohos.gni")
import("//build/ohos/ndk/ndk.gni")config("libmali-bifrost-g52-g2p0-ohos") {include_dirs = [ "include" ]cflags = ["-Wno-incompatible-pointer-types","-Werror","-Wimplicit-function-declaration","-Wno-error=unused-variable",]cflags = []
}ohos_prebuilt_shared_library("mali-bifrost-g52-g2p0-ohos") {if (target_cpu == "arm") {source = "lib/libmali-bifrost-g52-g2p0-ohos.so"} else if (target_cpu == "arm64") {source = "lib64/libmali-bifrost-g52-g2p0-ohos.so"}# decoupling system.img and vendor.imginstall_images = [ chipset_base_dir ]relative_install_dir = "chipsetsdk"subsystem_name = "rockchip_products"part_name = "rockchip_products"install_enable = truesymlink_target_name = ["libEGL.so","libGLESv1.so","libGLESv2.so","libGLESv3.so","libmali.so.0","libmali.so.1",]
}

TOUCH PANEL

常见的INPUT设备有键盘、鼠标、游戏杆、Touch Screen等。Touch 设备与主机通讯采用标准 I2C 总线,触屏 IC 提供中断支持,提高了触屏数据的实时性。本项目的触摸屏器件IC 为 GT911。

驱动框架模型

INPUT驱动模型

INPUT 驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。

(1)设备管理层:为各类输入设备驱动提供input设备的注册、注销接口,同时统一管理 input 设备列表;

(2)平台驱动层:指各类input设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向manager注册input设备等;

(3)器件驱动层:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化。

HDI接口层框架图

INPUT驱动提供给系统服务Input Service可直接调用的驱动能力接口,按照属性分类三类:input设备管理模块、input数据上报模块、input业务控制模块,HDI接口主要包括如下三大类:

  • input设备管理模块:管理输入设备,包括输入设备的打开、关闭、设备列表信息获取等;
  • input数据上报模块:负责输入事件的上报,包括注册、注销数据上报回调函数等;
  • input业务控制模块:提供input设备的业务控制接口,包括获取器件信息及设备类型、设置电源状态等。

HDF驱动适配

HCS配置

配置设备描述信息,在device_info.hcs中添加device_touch_chip:

 input :: host {hostName = "input_host";priority = 100;device_input_manager :: device {   // Input管理层设备描述信息device0 :: deviceNode {policy = 2;priority = 100;preload = 0;permission = 0660;moduleName = "HDF_INPUT_MANAGER";serviceName = "hdf_input_host";deviceMatchAttr = "";}}device_hdf_touch :: device {      // Input公共驱动层设备描述信息device0 :: deviceNode {policy = 2;priority = 120;preload = 0;permission = 0660;moduleName = "HDF_TOUCH";serviceName = "hdf_input_event1";deviceMatchAttr = "touch_device1";}}device_touch_chip :: device {     // Input器件驱动层信息device0 :: deviceNode {policy = 0;priority = 130;preload = 0;permission = 0660;moduleName = "HDF_TOUCH_GT911";serviceName = "hdf_touch_gt911_service";deviceMatchAttr = "zsj_gt911_5p5";}}device_hdf_hid :: device {device0 :: deviceNode {policy = 2;priority = 200;preload = 0;permission = 0660;moduleName = "HDF_HID";}}}

配置Touch器件信息,在input_config.hcs中添加器件的特性:

 chipConfig {template touchChip {match_attr = "";chipName = "gt911";vendorName = "zsj";chipInfo = "AAAA11222";  busType = 0;deviceAddr = 0x5D;                       irqFlag = 2;maxSpeed = 400;chipVersion = 0; //parse Coord TypeApowerSequence {/* [type, status, dir , delay]<type> 0:none 1:vcc-1.8v 2:vci-3.3v 3:reset 4:int<status> 0:off or low  1:on or high  2:no ops<dir> 0:input  1:output  2:no ops<delay> meanings delay xms, 20: delay 20ms*/powerOnSeq = [4, 0, 1, 5,3, 0, 1, 10,3, 1, 1, 60,4, 2, 0, 50];suspendSeq = [3, 0, 2, 10];resumeSeq = [3, 1, 2, 10];powerOffSeq = [3, 0, 2, 10,1, 0, 2, 20];}}chip0 :: touchChip {match_attr = "zsj_gt911_5p5";chipInfo = "ZIDN45100";  chipVersion = 0; }     }
适配文件

Touch驱动适配涉及的文件及目录:

1、 编辑 Makefile 文件:./drivers/adapter/khdf/linux/model/input/Makefile

2、 公共配置文件:./vendor/kaihong/khdvk_3566b/hdf_config/khdf/device_info/device_info.hcs

3、 私有配置文件:./vendor/kaihong/khdvk_3566b/hdf_config/khdf/input/input_config.hcs

4、 驱动:drivers\framework\model\input\driver\touchscreen

HDF驱动模型高度抽象集成,TP驱动的适配主要是器件驱动层的适配,首先需要明确TP所需要的软硬件资源。

TP模组需要主机上的如下硬件资源:

1.中断引脚

2.Reset引脚

3.使用的哪一组i2c,从设备的地址是什么

4.TP的初始化固件(通常由IC厂商提供)

5.触摸屏的分辨率

TP模组需要依赖主机上的如下软件资源:

1.Hdf gpio子系统 用于设置gpio pin脚以及一些中断资源

2.Hdf i2c 子系统 用于进行i2c通信

3.Input模型

器件差异化接口适配,示例代码路径:

./drivers/framework/model/input/driver/touchscreen/Touch_gdi_gt911.cstatic struct TouchChipOps g_gt911ChipOps = {     // 器件IC接口.Init = ChipInit,                             // 初始化.Detect = ChipDetect,                         // 器件检测.Resume = ChipResume,                         // 唤醒.Suspend = ChipSuspend,                       // 休眠.DataHandle = ChipDataHandle,                 // 器件数据读取.UpdateFirmware = UpdateFirmware,             // 固件升级.SetAbility = SetAbility,                     // 配置
};

器件驱动初始化及HDF注册,示例代码路径:

./drivers/framework/model/input/driver/touchscreen/touch_jdi_gt911.cstatic int32_t HdfGoodixChipInit(struct HdfDeviceObject *device)
{.../* 器件配置结构体内存申请、配置信息解析及挂载 */chipCfg = ChipConfigInstance(device);.../* 器件实例化 */chipDev = ChipDeviceInstance();.../* 器件信息挂载及器件私有操作挂载 */chipDev->chipCfg = chipCfg;chipDev->ops = &g_gt911ChipOps;.../* 注册器件驱动至平台驱动 */RegisterChipDevice(chipDev);...
}struct HdfDriverEntry g_touchGoodixChipEntry = {.moduleVersion = 1,.moduleName = "HDF_TOUCH_GT911",.Init = HdfGoodixChipInit,          // 器件驱动初始化函数.Release = HdfGoodixChipRelease,
};
HDF_INIT(g_touchGoodixChipEntry);       // 注册器件驱动至HDF框架
代码分布
/drivers/peripheral/input
/drivers/framework/model/input

经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?

为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

在这里插入图片描述

《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

在这里插入图片描述

基于ArkTS 开发

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

在这里插入图片描述

鸿蒙开发面试真题(含参考答案):https://gitcode.com/HarmonyOS_MN/733GH/overview

在这里插入图片描述

OpenHarmony 开发环境搭建

图片

《OpenHarmony源码解析》:https://gitcode.com/HarmonyOS_MN/733GH/overview

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……
  • 系统架构分析
  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

图片

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

图片
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1538516.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

如何配置 Apache 反向代理服务器 ?

将 Apache 配置为反向代理意味着将 Apache 设置为侦听和引导 web 流量到后端服务器或服务。这有助于管理和平衡服务器上的负载&#xff0c;提高安全性&#xff0c;并使您的 web 服务更高效。您还可以将其设置为监听标准 HTTP 和 HTTPS 端口上的请求&#xff0c;并将其重定向到运…

无人机维修保养一对一教学技术详解

随着无人机技术的日益普及和应用的广泛深入&#xff0c;无人机的维修保养成为确保飞行安全、延长使用寿命的关键环节。为了培养专业的无人机维护人才&#xff0c;一对一教学成为了一种高效、针对性的培训方式。以下将详细解析无人机维修保养一对一教学的技术要点&#xff0c;涵…

深入 mysql,掌握一对一、一对多、多对多表设计、查询及级联操作

数据库表的基本概念与关系 数据库通常包含多个表&#xff0c;每个表存储特定类型的信息。例如&#xff1a; 学生表&#xff1a;存储学生信息。老师表&#xff1a;存储老师信息。班级表&#xff1a;存储班级信息。 这些表通过各种关系连接&#xff0c;形成一个结构化的数据管…

基于WOA-SVM的乳腺癌数据分类识别算法matlab仿真,对比BP神经网络和SVM

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 支持向量机&#xff08;SVM&#xff09; 4.2 WOA 4.3 WOA优化SVM参数 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a 3.部分核…

零工市场小程序:保障灵活就业

截止2024年高校毕业生达到1179万&#xff0c;在今年的经济情况下&#xff0c;就业市场就面临着比较大的压力&#xff0c;许多毕业生面临一时之间难以找到合适的工作的问题&#xff0c;那么求职者就会需要一份临时的工作来得到报酬&#xff0c;面对传统的找零工方式&#xff0c;…

用ASR PRO离线语音芯片和月饼盒做一个会跑会跳会说话的机器狗

中秋节刚过&#xff0c;大家月饼盒应该还有&#xff0c;不要扔&#xff0c;可以做点小玩意。 机器狗的创意来自B站石桥北的视频&#xff0c;他使用了一块ESP32芯片和打印件加四个舵机实现&#xff0c;应该说是比较复杂的&#xff0c;需要有3D打印机打印外壳&#xff0c;还得会…

Qt串口助手开发:基于多线程moveToThread方法串口通信工具

介绍了一个基于Qt框架开发的简易串口助手&#xff0c;满足粉丝的需求。该项目展示了如何利用Qt的moveToThread方法实现多线程串口通信&#xff0c;确保数据接收和发送功能的流畅性。项目中的核心类包括SerialWorker类和MainWindow类&#xff0c;分别负责串口操作和用户界面交互…

【数据可视化】Arcgis api4.x 热力图、时间动态热力图、timeSlider时间滑块控件应用 (超详细、附免费教学数据、收藏!)

1.效果 目录 1.效果 2.安装配置 3.热力图 4.TimeSlider滑块应用 4.1 时间滑块控件 4.2 添加控件 5.时间动态热力图 2.安装配置 这里不教大家如何在前端框架使用arcgis api。不过npm安装、css如何引入、教学数据存放与图层加载的教程&#xff0c;可以浏览我之前发的一篇文…

高效财税自动化软件的特点与优势

随着企业管理信息系统和互联网的不断发展&#xff0c;企业对财务管理提出了更高的要求。为有效助力企业规范财务工作&#xff0c;提高工作效率和准确性&#xff0c;实现信息化管理&#xff0c;越来越多的企业选择引入RPA等高效财税自动化软件。本文金智维将围绕RPA高效财税自动…

LeetCode 2332.坐上公交的最晚时间 (双指针 + 贪心)

给你一个下标从 0 开始长度为 n 的整数数组 buses &#xff0c;其中 buses[i] 表示第 i 辆公交车的出发时间。同时给你一个下标从 0 开始长度为 m 的整数数组 passengers &#xff0c;其中 passengers[j] 表示第 j 位乘客的到达时间。所有公交车出发的时间互不相同&#xff0c;…

基于SpringCloud的能源管理系统-能源管理平台源码-双碳平台源码-能管管理系统源码

一、介绍 基于SpringCloud的能管管理系统-能源管理平台源码-能源在线监测平台-双碳平台源码-SpringCloud全家桶-能管管理系统源码 二、软件架构 二、功能介绍 三、数字大屏展示 四、数据采集原理 五、软件截图

Mycat搭建读写分离

启动Mycat 进入 /mycat/conf/datasources目录下&#xff0c;修改prototypeDs.datasource.json文件 去mycat/bin目录用启动mycat ./mycat start (关闭mycat ./mycat stop)连接mycat 默认端口8066 用户名root 密码123456 注意&#xff1a;这里ip设为null表示任何ip都可以访问…

【设计模式-组合】

**Composite Pattern&#xff08;组合模式&#xff09;**是一种结构型设计模式&#xff0c;旨在将对象组合成树形结构&#xff0c;以表示“部分-整体”的层次结构。这种模式允许客户端以统一的方式处理单个对象和对象集合&#xff0c;从而简化了树形结构的处理。 核心思想 组…

LLM应用实战: 文档问答系统Kotaemon-1. 简介及部署实践

1.背景 本qiang~这两周关注到一个很火的开源文档问答系统Kotaemon&#xff0c;从8月28日至今短短两周时间&#xff0c;github星标迅猛增长10K&#xff0c;因此计划深挖一下其中的原理及奥秘。 本篇主要是Kotaemon的简介信息&#xff0c;涉及到主要特点&#xff0c;与传统文档…

MindShare PCIE 3.0 笔记-第一二章

MindShare 官网&#xff0c;地址如下: MindShare Chapter 1&#xff1a;PCIE 背景介绍 - PCI 总线模型 1. 以 PCI 总线作为外设总线的 SOC 芯片架构 下图展示了一个以 PCI 总线作为外设总线的 SOC 芯片架构(PCI 总线类似 AXI 下的 AHB&#xff1f;)&#xff1a; 由上图可知…

虚拟机与物理机的文件共享

之前往虚拟机里传文件都是直接拖拽或者借助工具上传&#xff0c;都不太方便&#xff0c;倘若物理机的文件直接能在虚拟机里读取使用&#xff0c;那多好啊~ 1 虚拟机设置 注意文件夹名称不要中文/空格 2 验证Kali下分享文件夹功能是否启用 vmware-hgfsclient 3 创建挂载目录…

数据库基础知识---------------------------(2)

MYSQL的存储过程 就是数据库 SQL 语言层面的代码封装与重用 语法格式 delimiter 自定义结束符号 create procedure 存储名({in,out,inout} 参数名,数据类型...) begin sql 语句 end 自定义结束符 delimiter; 变量定义 局部变量 用户自定义 仅在begin / end 块中有效 当将查询…

apach httpd多后缀解析漏洞

漏洞详情&#xff1a; httpd支持一个文件拥有多个后缀&#xff0c;并为不同后缀执行不同的指令。 那么&#xff0c;在有多个后缀的情况下&#xff0c;只要一个文件含有.php后缀的文件即将被识别成PHP文件&#xff0c;没必要是最后一个后缀。 利用这个特性&#xff0c;可以绕过…

Linux硬连接、软连接和复制的区别

‌硬连接、软连接和复制在Linux系统中的主要区别体现在以下三点&#xff1a; 文件链接的方式文件独立性文件系统的操作上。‌ 一、硬连接 1. 硬连接是通过ln命令创建的&#xff0c;它为文件创建别名&#xff0c;与源文件共享同一inode号码&#xff0c;因此硬连接和源文件实际…

Mint Expedition Season 3 拉开帷幕:登顶高峰的时刻到了

自 7 月 15 日 Mint Expedition 启动以来&#xff0c;Mint&#xff0c;一条专注于 NFT 行业的以太坊 Layer 2&#xff0c;日常交易量和交易额都出现了爆发式增长。这一成功离不开 Mint 社区的合作&#xff0c;包括 Minters、Web3 去中心化应用程序的开发者&#xff0c;以及大量…