CH585集成OpenHarmony轻量系统最小集
CH585芯片信息简介
概述
52832是一款通用多协议SoC。它可以满足各种应用的要求,对于需要高阶低功耗蓝牙功能、协议并发以及丰富外设和功能的应用,它能够轻松应对这些应用带来的挑战。此外,它带来了更大的Flash和RAM。这使它成为专业照明、高端可穿戴设备和其他复杂的物联网应用的理想选择。
主要特性
-
RISC-V3C 处理器
- 青稞 32 位 RISC-V3C 内核
- 支持 RV32IMBC 指令集和自扩展指令
- 低功耗三级流水线
- 多档系统主频,最低 32KHz,最高 78MHz
- 特有高速的中断响应机制
-
512K 字节非易失存储 FlashROM:
- 448KB 用户应用程序存储区 CodeFlash
- 32KB 用户非易失数据存储区 DataFlash
- 24KB 系统引导程序存储区 BootLoader
- 8KB 系统非易失配置信息存储区 InfoFlash
- 支持 ICP、ISP 和 IAP,支持 OTA 无线升级
-
128K 字节易失数据存储 SRAM:
- 96KB 双电源供电的睡眠保持存储区 RAM96K
- 32KB 双电源供电的睡眠保持存储区 RAM32K
-
低功耗蓝牙 BLE:
- 集成 2.4GHz RF 收发器和基带及链路控制
- 接收灵敏度-95dBm,可编程+4.5dBm 发送功率
- BLE 符合 Bluetooth Low Energy 5.4 规范
- 支持 2Mbps 和 1Mbps
- 支持 2.4G 模式下最高 8KHz 上报率
- 提供优化的协议栈和应用层 API,支持组网
厂商工具
编译liteos_m轻量系统时需要使用到沁恒提供的编译工具链,进入官网:https://mounriver.com/download,选择 "Linux" -> "工具链和调试器",点击 MRS_Toolchain_Linux_X64_V240.tar.xz 下载。

下载完成后解压到编译的Liunx设备目录中,以用户目录~为例,将工具链添加到 .bashrc 环境中。
# .bashrc
# CH585 编译工具链
export PATH=~/MRS_Toolchain_Linux_X64_V240/Toolchain/RISC-V-Embedded-GCC/bin:$PATH
# 配置完成后执行 source ~/.bashrc
注意:如果不添加到环境中,在配置 device/qemu/ch585/liteos_m/config.gni 文件时,就需要修改 board_toolchain_path = "" ,将工具链路径配置到 board_toolchain_path 中。
编译OH静态库
OH编译环境准备
OH的编译环境可以参考官方文档,进行轻量系统编译环境搭建:https://gitcode.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/Readme-CN.md
下载 OpenHarmony-v6.1-Release 代码和预编译工具链后,参考 vendor/ohemu/qemu_riscv32_mini_system_demo 产品,创建一个 ch585 的产品,另外其对应的 device 仓为 device/qemu/riscv32_virt ,可以直接复制然后修改相关产品名称,目录规划如下:
device
└── qemu
└── ch585
产品样例目录规划为:
vendor
└── qemu
└── ch585
具体的预编译适配步骤如下:
-
修改
vendor/qemu/ch585/config.json文件,内容如下:{ "product_name": "ch585", --- 用于hb set进行选择时,显示的产品名称 "ohos_version": "OpenHarmony 6.1Release", --- 使用的OS版本 "device_company": "qemu", --- 单板厂商名,用于编译时找到/device/qemu目录 "type":"mini", --- 构建系统的类型mini/small/standard "version": "3.0", --- 构建系统的版本 "board": "ch585", --- 单板名,用于编译时找到/device/qemu/ch585目录 "kernel_type": "liteos_m", --- 内核类型,指定某个内核进行编译 "kernel_version": "3.1.0", --- 内核版本,指定某个具体的内核版本进行编译 "target_cpu": "riscv32", --- 指定系统组件的指令集 "force_link_libs": [], --- 强制链接库 "subsystems": [ --- 选择所需要编译构建的子系统,下面会补充 { "subsystem": "startup", "components": [ { "component": "bootstrap_lite" }, { "component": "init", "features": [ "init_feature_begetctl_liteos = true" ] } ] }, { "subsystem": "hiviewdfx", "components": [ { "component": "hilog_lite" }, { "component": "hievent_lite" }, { "component": "hiview_lite" } ] }, { "subsystem": "systemabilitymgr", "components": [ { "component": "samgr_lite" } ] }, { "subsystem": "commonlibrary", "components": [ { "component": "utils_lite", "features":[ "utils_lite_feature_file = true" ] } ] } ], "third_party_dir": "//third_party", --- 三方库目录 "product_adapter_dir": "//vendor/ohemu/ch585/hals" --- 产品驱动适配目录 } -
修改
vendor/qemu/ch585/ohos.build文件,内容如下:{ "parts": { "product_ch585": { "module_list": [ "//vendor/ohemu/ch585:ch585" ] } }, "subsystem": "product_ch585" } -
修改
vendor/qemu/ch585/BUILD.gn文件,内容如下:group("ch585") { deps = [] } -
修改
device/qemu/ch585/liteos_m/config.gni文件,内容如下:kernel_type = "liteos_m" kernel_version = "3.1.0" board_cpu = "" board_arch = "rv32imac" board_toolchain = "riscv-none-embed-gcc" board_toolchain_path = "" board_toolchain_prefix = "riscv-none-embed-" board_toolchain_type = "gcc" # config.json parse if (product_path != "") { product_conf = read_file("${product_path}/config.json", "json") force_link_libs = product_conf.force_link_libs } board_opt_flags = [] board_cflags = [ "-mabi=ilp32", "-mstrict-align", "-falign-functions=2", "-msave-restore", "-fno-optimize-strlen", "-freorder-blocks-algorithm=simple", "-fno-schedule-insns", "-mtune=size", "-mno-small-data-limit=0", "-fno-aggressive-loop-optimizations", "-Wpointer-arith", "-ffunction-sections", "-fdata-sections", "-static", "-fno-common", "-fno-stack-protector", "-Wno-format-truncation", "-D__RISC_V__", "-D__LITEOS_M__", "-DLWIP_SUPPORT_CUSTOM_PBUF=1", "-D_BSD_SOURCE", "-Wformat=0", "-DLOSCFG_BASE_CORE_HILOG", "-fno-unwind-tables", "-ffreestanding", "-Os", "-g0", "-fno-asynchronous-unwind-tables", "-fno-strict-aliasing", "-fno-tree-scev-cprop", "-fno-ipa-ra", "--short-enums", "-msmall-data-limit=0", ] board_cflags += board_opt_flags board_asmflags = [ "-march=rv32imac", "-mabi=ilp32", "-static", "-Os", ] board_asmflags += board_opt_flags board_cxx_flags = board_cflags board_ld_flags = [] board_ld_flags += [ "-Wl,--wrap=_malloc_r", "-Wl,--wrap=_realloc_r", "-Wl,--wrap=_free_r", "-Wl,--wrap=_memalign_r", "-Wl,--wrap=_malloc_usable_size_r", "-Wl,--wrap,_calloc_r", "-Wl,--wrap=printf", "-Wl,--gc-sections", ] board_include_dirs = [ "//commonlibrary/utils_lite/include" ] board_adapter_dir = "//device/qemu/ch585/driver" board_configed_sysroot = "" storage_type = "" -
修改
device/qemu/ch585/ohos.build文件,内容如下:{ "parts": { "device_ch585": { "module_list": [ "//device/qemu/ch585:ch585" ] } }, "subsystem": "device_ch585" } -
修改
vendor/qemu/ch585/BUILD.gn文件,内容如下:group("ch585") { } -
验证
hb set配置是否正确,输入hb set能够显示如下图片表示配置正确。执行
hb set输入项目根目录,并且回车,hb命令会遍历所有//vendor/<product_company>/<product_name>目录下的config.json,给出可选产品编译选项,config.json的product_name用于显示产品名,device_company和board用于关联出//device/board/<device_company>/<board>目录,并且匹配<any_dir_name>/config.gni文件,如果能够匹配多个文件,表示该单板适配了多个内核,那么可以根据config.json的kernel_type和kernel_version来唯一匹配config.gni的kernel_type和kernel_version,即可确定了需要编译适配了哪个内核的单板。
通过
hb env可以查看选择出来的预编译环境变量。
现在执行 hb build 即可编译出相关静态库:

CH585集成OpenHarmony子系统
下载IDE和代码
打开沁恒官网,查看ch585详情文档

找到下面的资料部分,下载IDE1和CH585EVT.ZIP:

LiteOS_M内核适配层
ch585已经完成了liteos_m的内核适配,在EVT\EXAM\HarmonyOS\kernel_liteos_m目录中可看到以下目录:
kernel_liteos_m
|-- arch // Arch 适配
|-- kernel // liteos_m 内核适配
|-- third_party // oh 三方库适配
|-- utils // 辅助工具
└── target_config.h // 系统关键参数的定义
Arch适配主要是集成了Qinke_V3C的gcc,使liteos_m内核能在ch585处理器架构的硬件上正确运行。
liteos_m 内核适配代码在kernel_liteos_m\kernel\src目录下,主要有以下部分的基础适配:
- 内存池与内存分配适配:在kernel_liteos_m\kernel\src\mm\los_membox.c中提供了内存池初始化、释放、检查等功能
- 内存申请适配:kernel_liteos_m\kernel\src\mm\los_memory.c中则提供了内存的申请和释放等功能,像线程栈的申请,消息队列内存申请,以及普通的malloc内存申请都会在这里分配内存
- task适配:kernel_liteos_m\kernel\src\los_task.c系统中调度的基本单位,本质上是一个无限循环的函数,拥有独立的栈空间和上下文(寄存器状态)。有就绪(Ready)、运行(Running)、阻塞(Blocked)、挂起(Suspended)这几种状态
- 消息队列适配:kernel_liteos_m\kernel\src\los_queue.c用于任务间通信(IPC)的数据结构,遵循先进先出(FIFO)原则,允许一个任务将数据块发送到队列中,另一个任务从队列中接收数据。它实现了生产者-消费者模型,解耦了数据的发送方和接收方,并提供了缓冲机制。
- 互斥锁适配:kernel_liteos_m\kernel\src\los_mux.c一种特殊的二值信号量,用于保护共享资源,确保同一时刻只有一个任务能访问临界区,止多个任务同时读写共享变量、外设寄存器等导致数据竞争。
- 调度器适配:kernel_liteos_m\kernel\src\los_sched.c负责决定哪个就绪任务获得 CPU 使用权。管理所有任务的状态(就绪、运行、阻塞、挂起),根据调度算法(如优先级抢占式 + 同优先级时间片轮转)进行任务切换。
- 信号量适配:kernel_liteos_m\kernel\src\los_sem.c一个计数器,用于控制对有限数量资源的并发访问,或用于任务间的同步。
- 排序链表适配:kernel_liteos_m\kernel\src\los_sortlink.c 内核中的一种高效数据结构,本质上是一个按关键字(通常是超时时间/唤醒时刻)升序排列的双向链表。用于统一管理所有需要延时或超时等待的任务/定时器节点。新节点插入时按时间顺序找到正确位置,这样链表头始终是最近要到期的节点
- 软件定时器适配:kernel_liteos_m\kernel\src\los_swtmr.c 基于硬件 Tick 实现的虚拟定时器,不占用硬件定时器资源。提供单次或周期性的定时回调功能。用户创建 Swtmr 后,内核在后台通过 Tick 驱动其倒计时,到期后执行注册的回调函数或发送事件。
- 事件轮询适配:kernel_liteos_m\kernel\src\los_event.c一种 I/O 事件通知机制,允许一个任务同时监控多个文件描述符(FD)、Socket 或设备句柄的 I/O 事件(可读、可写、异常等),当任一被监控对象有事件发生时,任务才被唤醒。
- 系统节拍:kernel_liteos_m\kernel\src\los_tick.c定义系统的时间基准,由硬件定时器产生的周期性中断。用于驱动调度器的时间片轮转、更新系统全局时间戳、驱动延时/超时机制(扫描 SortLink)、驱动软件定时器(Swtmr)
各模块间关系如下
┌─────────────────────────────────────────────────────────────────┐
│ 内核工厂 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Sched (调度器) │ │
│ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ │
│ │ │ Task1 │ │ Task2 │ │ Task3 │ │ TaskN │ ← 工人队列 │ │
│ │ └───────┘ └───────┘ └───────┘ └───────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ 驱动切换 │
│ ┌──────────────────────────┴──────────────────────────┐ │
│ │ Tick (心跳) │ │
│ │ 周期性中断,驱动时间片轮转、超时检测、定时器倒计时 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ 驱动 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Swtmr (软件定时器) │ │
│ │ 到期后触发回调或唤醒等待的任务 │ │
│ └──────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ 管理到期时间 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ SortLink (排序链表) │ │
│ │ 按唤醒时间升序排列所有阻塞/延时的任务节点 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Queue │ │ Mutex │ │ Semaphore │ ← 工具 │
│ │ (消息传递) │ │ (互斥锁) │ │ (信号量) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ▲ ▲ ▲ │
│ └────────────────┼────────────────┘ │
│ │ 任务通过这些工具 │
│ ▼ 进行通信和同步 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Event (事件轮询) │ │
│ │ 任务同时监听多个 I/O 事件源,有事件才唤醒 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
三方库适配则主要是bounds_checking_function部件适配,它的核心功能是提供带有边界检查的安全内存和字符串操作函数,以替代传统 C 语言中不安全的标准库函数。
target_config.h则是系统关键参数的定义,包括 运行内存池大小设置,动态线程个数设置、时钟、信号量、互斥锁等设置,适配后内容如下:
#ifndef _TARGET_CONFIG_H
#define _TARGET_CONFIG_H
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#include "CH58x_common.h"
/*=============================================================================
System clock module configuration
=============================================================================*/
#define OS_SYS_CLOCK (60000000)
#define LOSCFG_BASE_CORE_TICK_PER_SECOND (1000UL)
#define LOSCFG_BASE_CORE_TICK_HW_TIME 1
#define LOSCFG_BASE_CORE_TICK_WTIMER 0
/*=============================================================================
Hardware interrupt module configuration
=============================================================================*/
#define LOSCFG_PLATFORM_HWI 0
#define LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT 0
#define LOSCFG_PLATFORM_HWI_LIMIT 32
/*=============================================================================
Task module configuration
=============================================================================*/
#define LOSCFG_BASE_CORE_TSK_LIMIT 16
#define LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE (0x200U)
#define LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE (0x2D0U)
#define LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE (0x130U)
#define LOSCFG_BASE_CORE_TIMESLICE 1
#define LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT 20000
#define LOSCFG_BASE_CORE_TICK_RESPONSE_MAX 0xFFFFFF
/*=============================================================================
Semaphore module configuration
=============================================================================*/
#define LOSCFG_BASE_IPC_SEM 1
#define LOSCFG_BASE_IPC_SEM_LIMIT 48
/*=============================================================================
Mutex module configuration
=============================================================================*/
#define LOSCFG_BASE_IPC_MUX 1
#define LOSCFG_BASE_IPC_MUX_LIMIT 64
/*=============================================================================
Queue module configuration
=============================================================================*/
#define LOSCFG_BASE_IPC_QUEUE 1
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 24
/*=============================================================================
Software timer module configuration
=============================================================================*/
#define LOSCFG_BASE_CORE_SWTMR 1
#define LOSCFG_BASE_CORE_SWTMR_ALIGN 1
#define LOSCFG_BASE_CORE_SWTMR_LIMIT 6
/*=============================================================================
Memory module configuration
=============================================================================*/
#define LOSCFG_SYS_HEAP_SIZE (80 * 1024)
#define LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK 0
#define LOSCFG_BASE_MEM_NODE_SIZE_CHECK 1
#define LOSCFG_MEM_MUL_POOL 0
#define LOSCFG_KERNEL_MEM_SLAB 0
#define OS_SYS_MEM_SIZE 0x00000400
#define OS_SYS_MEM_NUM 20
/*=============================================================================
Exception module configuration
=============================================================================*/
#define LOSCFG_PLATFORM_EXC 0
/* =============================================================================
printf module configuration
============================================================================= */
#define LOSCFG_KERNEL_PRINTF 1
/* =============================================================================
enable backtrace
============================================================================= */
#define LOSCFG_BACKTRACE_TYPE 0
#define LOSCFG_KERNEL_PM 0
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* _TARGET_CONFIG_H */
CMSIS适配
上面的适配时官方提供了的基础适配,如要集成liteos_m的部件并运行xts套件,则必须适配cmsis。克隆https://gitcode.com/openharmony/third_party_cmsis/tree/OpenHarmony-v6.1-Release%E5%88%B0third_party%E7%9B%AE%E5%BD%95%E4%B8%AD%EF%BC%8C%E6%B3%A8%E6%84%8F%E5%88%87%E6%8D%A2%E5%88%B0OpenHarmony-v6.1-Release%E5%88%86%E6%94%AF%E4%BB%A3%E7%A0%81%E3%80%82
创建third_party\cmsis\CMSIS\RTOS2\Include\kal.h文件:
#ifndef _KAL_H
#define _KAL_H
#include "los_config.h"
#include "los_compiler.h"
#include "cmsis_os2.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)
/**
* @brief Enumerates timer permissions.
*
* @since 1.0
* @version 1.0
*/
typedef enum {
/** The timer is not allowed to wake up the RTOS. */
osTimerRousesIgnore = 0,
/** The timer is allowed to wake up the RTOS. */
osTimerRousesAllow = 1
} osTimerRouses_t;
/**
* @brief Enumerates timer alignment modes.
*
*/
typedef enum {
/** The timer ignores alignment. */
osTimerAlignIgnore = 0,
/** The timer allows alignment. */
osTimerAlignAllow = 1
} osTimerAlign_t;
osTimerId_t osTimerExtNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr,
osTimerRouses_t ucRouses, osTimerAlign_t ucSensitive);
#endif
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* _KAL_H */
创建third_party\cmsis\CMSIS\RTOS2\Include\cmsis_liteos2.c文件
#include "cmsis_os2.h"
#include "kal.h"
#include "los_event.h"
#include "los_membox.h"
#include "los_memory.h"
#include "los_interrupt.h"
#include "los_mux.h"
#include "los_queue.h"
#include "los_sem.h"
#include "los_swtmr.h"
#include "los_task.h"
#include "los_timer.h"
#include "los_debug.h"
#include "string.h"
#include "securec.h"
#define LITEOS_VERSION_BUILD 0
static osKernelState_t g_kernelState;
extern BOOL g_taskScheduled;
/* OS_TASK_PRIORITY_HIGHEST and OS_TASK_PRIORITY_LOWEST is reserved for internal TIMER and IDLE task use only. */
#define ISVALID_LOS_PRIORITY(losPrio) ((losPrio) > OS_TASK_PRIORITY_HIGHEST && (losPrio) < OS_TASK_PRIORITY_LOWEST)
osKernelState_t osKernelGetState(void)
{
if (OS_INT_ACTIVE) {
return osKernelError;
}
if (!g_taskScheduled) {
if (g_kernelState == osKernelReady) {
return osKernelReady;
} else {
return osKernelInactive;
}
} else if (g_losTaskLock > 0) {
return osKernelLocked;
} else {
return osKernelRunning;
}
}
int32_t osKernelLock(void)
{
int32_t lock;
if (OS_INT_ACTIVE) {
return (int32_t)osErrorISR;
}
if (!g_taskScheduled) {
return (int32_t)osError;
}
if (g_losTaskLock > 0) {
lock = 1;
} else {
LOS_TaskLock();
lock = 0;
}
return lock;
}
int32_t osKernelUnlock(void)
{
int32_t lock;
if (OS_INT_ACTIVE) {
return (int32_t)osErrorISR;
}
if (!g_taskScheduled) {
return (int32_t)osError;
}
if (g_losTaskLock > 0) {
LOS_TaskUnlock();
if (g_losTaskLock != 0) {
return (int32_t)osError;
}
lock = 1;
} else {
lock = 0;
}
return lock;
}
uint32_t osKernelGetTickCount(void)
{
uint64_t ticks = LOS_TickCountGet();
return (uint32_t)ticks;
}
uint32_t osKernelGetTickFreq(void)
{
uint32_t freq;
if (OS_INT_ACTIVE) {
freq = 0U;
} else {
freq = LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
return (freq);
}
osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
{
UINT32 uwTid;
UINT32 uwRet;
LosTaskCB *pstTaskCB = NULL;
TSK_INIT_PARAM_S stTskInitParam = {NULL};
UINT16 usPriority;
if (OS_INT_ACTIVE || (func == NULL)) {
return (osThreadId_t)NULL;
}
usPriority = 28;//attr ? LOS_PRIORITY(attr->priority) : LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
if (!ISVALID_LOS_PRIORITY(usPriority)) {
/* unsupported priority */
return (osThreadId_t)NULL;
}
stTskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)func;
stTskInitParam.uwArg = (UINT32)argument;
stTskInitParam.uwStackSize = attr ? attr->stack_size : LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
stTskInitParam.pcName = (CHAR *)(attr ? attr->name : "[NULL]");
stTskInitParam.usTaskPrio = usPriority;
uwRet = LOS_TaskCreate(&uwTid, &stTskInitParam);
// PRINTK("0xc00 liteos ThreadNew task name: %s, task size: %lu Byte, Caller: 0x%lx\n\n", attr->name, stTskInitParam.uwStackSize, (unsigned long)caller);
if (LOS_OK != uwRet) {
return (osThreadId_t)NULL;
}
pstTaskCB = OS_TCB_FROM_TID(uwTid);
return (osThreadId_t)pstTaskCB;
}
osThreadId_t osThreadGetId(void)
{
if (OS_INT_ACTIVE) {
return NULL;
}
return (osThreadId_t)(g_losTask.runTask);
}
void *osThreadGetArgument(void)
{
if (OS_INT_ACTIVE) {
return 0;
}
LosTaskCB *taskCb = (LosTaskCB *)osThreadGetId();
if (taskCb == NULL) {
return NULL;
}
return (void *)(taskCb->arg);
}
uint32_t osThreadGetCount(void)
{
uint32_t uwCount = 0;
if (OS_INT_ACTIVE) {
return 0U;
}
for (uint32_t index = 0; index <= LOSCFG_BASE_CORE_TSK_LIMIT; index++) {
if (!((g_taskCBArray + index)->taskStatus & OS_TASK_STATUS_UNUSED)) {
uwCount++;
}
}
return uwCount;
}
osStatus_t osDelay(uint32_t ticks)
{
UINT32 uwRet = LOS_OK;
if (ticks == 0) {
return osOK;
}
if (osKernelGetState() != osKernelRunning) {
LOS_UDelay(ticks * OS_US_PER_TICK);
} else {
uwRet = LOS_TaskDelay(ticks);
}
if (uwRet == LOS_OK) {
return osOK;
} else {
return osError;
}
}
#if (LOSCFG_BASE_IPC_MUX == 1)
osMutexId_t osMutexNew(const osMutexAttr_t *attr)
{
UINT32 uwRet;
UINT32 uwMuxId;
UNUSED(attr);
if (OS_INT_ACTIVE) {
return NULL;
}
uwRet = LOS_MuxCreate(&uwMuxId);
if (uwRet == LOS_OK) {
return (osMutexId_t)(GET_MUX(uwMuxId));
} else {
return (osMutexId_t)NULL;
}
}
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
{
UINT32 uwRet;
if (mutex_id == NULL) {
return osErrorParameter;
}
if (OS_INT_ACTIVE && (timeout != LOS_NO_WAIT)) {
timeout = 0;
}
uwRet = LOS_MuxPend(((LosMuxCB *)mutex_id)->muxID, timeout);
if (uwRet == LOS_OK) {
return osOK;
} else if (uwRet == LOS_ERRNO_MUX_TIMEOUT) {
return osErrorTimeout;
} else if (uwRet == LOS_ERRNO_MUX_INVALID) {
return osErrorParameter;
} else {
return osErrorResource;
}
}
osStatus_t osMutexRelease(osMutexId_t mutex_id)
{
UINT32 uwRet;
if (mutex_id == NULL) {
return osErrorParameter;
}
uwRet = LOS_MuxPost(((LosMuxCB *)mutex_id)->muxID);
if (uwRet == LOS_OK) {
return osOK;
} else {
return osErrorResource;
}
}
#endif
#if (LOSCFG_BASE_IPC_QUEUE == 1)
osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr)
{
UINT32 uwQueueID;
UINT32 uwRet;
UNUSED(attr);
osMessageQueueId_t handle;
if (0 == msg_count || 0 == msg_size || OS_INT_ACTIVE) {
return (osMessageQueueId_t)NULL;
}
uwRet = LOS_QueueCreate((char *)NULL, (UINT16)msg_count, &uwQueueID, 0, (UINT16)msg_size);
if (uwRet == LOS_OK) {
handle = (osMessageQueueId_t)(GET_QUEUE_HANDLE(uwQueueID));
} else {
handle = (osMessageQueueId_t)NULL;
}
return handle;
}
osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout)
{
UNUSED(msg_prio);
UINT32 uwRet;
UINT32 uwBufferSize;
LosQueueCB *pstQueue = (LosQueueCB *)mq_id;
if (pstQueue == NULL || msg_ptr == NULL || ((OS_INT_ACTIVE) && (0 != timeout))) {
return osErrorParameter;
}
if (pstQueue->queueSize < sizeof(UINT32)) {
return osErrorParameter;
}
uwBufferSize = (UINT32)(pstQueue->queueSize - sizeof(UINT32));
uwRet = LOS_QueueWriteCopy((UINT32)pstQueue->queueID, (void *)msg_ptr, uwBufferSize, timeout);
if (uwRet == LOS_OK) {
return osOK;
} else if (uwRet == LOS_ERRNO_QUEUE_INVALID || uwRet == LOS_ERRNO_QUEUE_NOT_CREATE) {
return osErrorParameter;
} else if (uwRet == LOS_ERRNO_QUEUE_TIMEOUT) {
return osErrorTimeout;
} else {
return osErrorResource;
}
}
osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout)
{
UNUSED(msg_prio);
UINT32 uwRet;
UINT32 uwBufferSize;
LosQueueCB *pstQueue = (LosQueueCB *)mq_id;
if (pstQueue == NULL || msg_ptr == NULL || ((OS_INT_ACTIVE) && (0 != timeout))) {
return osErrorParameter;
}
uwBufferSize = (UINT32)(pstQueue->queueSize - sizeof(UINT32));
uwRet = LOS_QueueReadCopy((UINT32)pstQueue->queueID, msg_ptr, &uwBufferSize, timeout);
if (uwRet == LOS_OK) {
return osOK;
} else if (uwRet == LOS_ERRNO_QUEUE_INVALID || uwRet == LOS_ERRNO_QUEUE_NOT_CREATE) {
return osErrorParameter;
} else if (uwRet == LOS_ERRNO_QUEUE_TIMEOUT) {
return osErrorTimeout;
} else {
return osErrorResource;
}
}
osStatus_t osMessageQueueDelete(osMessageQueueId_t mq_id)
{
LosQueueCB *pstQueue = (LosQueueCB *)mq_id;
UINT32 uwRet;
if (pstQueue == NULL) {
return osErrorParameter;
}
if (OS_INT_ACTIVE) {
return osErrorISR;
}
uwRet = LOS_QueueDelete((UINT32)pstQueue->queueID);
if (uwRet == LOS_OK) {
return osOK;
} else if (uwRet == LOS_ERRNO_QUEUE_NOT_FOUND || uwRet == LOS_ERRNO_QUEUE_NOT_CREATE) {
return osErrorParameter;
} else {
return osErrorResource;
}
}
#endif
文件创建完成后添加到编译环境:


POSIX接口适配
posix主要是适配__errno_location以及文件操作接口打桩。
创建kernel_liteos_m\posix\src\errno.c文件
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <zephyr/kernel.h>
static int g_isrErrno;
int *__errno_location(void)
{
if (k_is_in_isr()) {
return NULL;
}
struct k_thread *runTask = k_current_get();
if (runTask == NULL) {
return &g_isrErrno;
}
return &runTask->errno_var;
}
创建kernel_liteos_m\posix\src\fs.c文件
int fsync(int fd)
{
return -1;
}
创建kernel_liteos_m\posix\include\time_internal.h文件
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <unistd.h>
int HalFileOpen(const char *path, int oflag, int mode)
{
(void)mode;
return open(path, oflag);
}
int HalFileClose(int fd)
{
return close(fd);
}
int HalFileRead(int fd, char *buf, unsigned int len)
{
return read(fd, buf, len);
}
int HalFileWrite(int fd, const char *buf, unsigned int len)
{
return write(fd, buf, len);
}
int HalFileDelete(const char *path)
{
return unlink(path);
}
int HalFileStat(const char *path, unsigned int *fileSize)
{
struct stat info = { 0 };
int ret = stat(path, &info);
if (ret < 0) {
return ret;
} else {
return info.st_size;
}
}
int HalFileSeek(int fd, int offset, unsigned int whence)
{
return lseek(fd, offset, whence);
}
/* internal functions */
STATIC INLINE BOOL ValidTimeSpec(const struct timespec *tp)
{
/* Fail a NULL pointer */
if (tp == NULL) {
return FALSE;
}
/* Fail illegal nanosecond values */
if ((tp->tv_nsec < 0) || (tp->tv_nsec >= OS_SYS_NS_PER_SECOND) || (tp->tv_sec < 0)) {
return FALSE;
}
return TRUE;
}
创建kernel_liteos_m\posix\include\time.h文件
#ifndef _ADAPT_TIME_H
#define _ADAPT_TIME_H
#define __TM_GMTOFF __tm_gmtoff
#define __TM_ZONE __tm_zone
#include_next <time.h>
# define CLOCK_REALTIME 0
# define CLOCK_MONOTONIC 1
# define CLOCK_PROCESS_CPUTIME_ID 2
# define CLOCK_THREAD_CPUTIME_ID 3
#ifdef __riscv
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW 12
#endif
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE 5
#endif
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE 6
#endif
#ifndef CLOCK_BOOTTIME
#define CLOCK_BOOTTIME 7
#endif
#ifndef CLOCK_REALTIME_ALARM
#define CLOCK_REALTIME_ALARM 8
#endif
#ifndef CLOCK_BOOTTIME_ALARM
#define CLOCK_BOOTTIME_ALARM 9
#endif
#ifndef CLOCK_SGI_CYCLE
#define CLOCK_SGI_CYCLE 10
#endif
#ifndef CLOCK_TAI
#define CLOCK_TAI 11
#endif
#endif /* __riscv */
#endif /* !_ADAPT_TIME_H */
创建kernel_liteos_m\posix\src\time.c文件
#include <time.h>
#include <sys/time.h>
#include <stdint.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include "los_debug.h"
#include "los_task.h"
#include "los_swtmr.h"
#include "los_tick.h"
#include "los_context.h"
#include "los_interrupt.h"
#include "sys/times.h"
#include "time_internal.h"
STATIC struct timespec g_accDeltaFromSet;
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
UINT64 nseconds;
UINT64 tick;
UINT32 ret;
const UINT32 nsPerTick = OS_SYS_NS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND;
if (!ValidTimeSpec(rqtp)) {
errno = EINVAL;
return -1;
}
nseconds = (UINT64)rqtp->tv_sec * OS_SYS_NS_PER_SECOND + rqtp->tv_nsec;
tick = (nseconds + nsPerTick - 1) / nsPerTick; // Round up for ticks
if (tick >= UINT32_MAX) {
errno = EINVAL;
return -1;
}
/* PS: skip the first tick because it is NOT a full tick. */
ret = LOS_TaskDelay(tick ? (UINT32)(tick + 1) : 0);
if (ret == LOS_OK || ret == LOS_ERRNO_TSK_YIELD_NOT_ENOUGH_TASK) {
if (rmtp) {
rmtp->tv_sec = rmtp->tv_nsec = 0;
}
return 0;
}
/* sleep in interrupt context or in task sched lock state */
errno = EINTR;
return -1;
}
unsigned sleep(unsigned seconds)
{
struct timespec specTime = { 0 };
UINT64 nanoseconds = (UINT64)seconds * OS_SYS_NS_PER_SECOND;
specTime.tv_sec = (time_t)(nanoseconds / OS_SYS_NS_PER_SECOND);
specTime.tv_nsec = (long)(nanoseconds % OS_SYS_NS_PER_SECOND);
return nanosleep(&specTime, NULL);
}
STATIC VOID OsGetHwTime(struct timespec *hwTime)
{
UINT64 cycle = LOS_SysCycleGet();
UINT64 nowNsec = (cycle / g_sysClock) * OS_SYS_NS_PER_SECOND +
(cycle % g_sysClock) * OS_SYS_NS_PER_SECOND / g_sysClock;
hwTime->tv_sec = nowNsec / OS_SYS_NS_PER_SECOND;
hwTime->tv_nsec = nowNsec % OS_SYS_NS_PER_SECOND;
}
STATIC VOID OsGetRealTime(struct timespec *realTime)
{
UINT32 intSave;
struct timespec hwTime = {0};
OsGetHwTime(&hwTime);
intSave = LOS_IntLock();
realTime->tv_nsec = hwTime.tv_nsec + g_accDeltaFromSet.tv_nsec;
realTime->tv_sec = hwTime.tv_sec + g_accDeltaFromSet.tv_sec + (realTime->tv_nsec >= OS_SYS_NS_PER_SECOND);
realTime->tv_nsec %= OS_SYS_NS_PER_SECOND;
LOS_IntRestore(intSave);
}
int clock_gettime(clockid_t clockID, struct timespec *tp)
{
if (tp == NULL) {
errno = EINVAL;
return -1;
}
switch (clockID) {
case CLOCK_MONOTONIC_RAW:
case CLOCK_MONOTONIC:
case CLOCK_MONOTONIC_COARSE:
OsGetHwTime(tp);
return 0;
case CLOCK_REALTIME:
case CLOCK_REALTIME_COARSE:
OsGetRealTime(tp);
return 0;
case CLOCK_THREAD_CPUTIME_ID:
case CLOCK_PROCESS_CPUTIME_ID:
case CLOCK_BOOTTIME:
#ifdef CLOCK_REALTIME_ALARM
case CLOCK_REALTIME_ALARM:
#endif
#ifdef CLOCK_BOOTTIME_ALARM
case CLOCK_BOOTTIME_ALARM:
#endif
#ifdef CLOCK_SGI_CYCLE
case CLOCK_SGI_CYCLE:
#endif
#ifdef CLOCK_TAI
case CLOCK_TAI:
#endif
errno = ENOTSUP;
return -1;
default:
errno = EINVAL;
return -1;
}
}
参考[# CMSIS适配](# CMSIS适配)cmsis将kernel_liteos_m\posix\src添加到编译环境中。
静态库集成
将ch585编译的的产物out/ch585/ch585/libs路径下的.a静态库拷贝到EVT\EXAM\HarmonyOS\libs目录下。然后加入到项目编译环境中:

添加"-Wl,--whole-archive"编译参数,在GNU RISC-V Cross C Linker -> Miscellaneous -> Other linker flags添加:
-Wl,--whole-archive -lbegetutil -ludidcomm -lbegetutil_static -lbootstrap -lbroadcast -lhal_sysparam -lhievent_lite_static -lhilog_lite_static -lhilog_static -lhiview_lite_static -linithook -linit_log -linit_utils -lnative_file -lparameterbase -lmbedtls -lexport_headers_lib -lparam_client_lite -lsamgr -lsamgr_adapter -lsamgr_source -lhal_token_static -ldevattest_core -ldevattest_sdk -lhctest -lcjson_static -lmodule_ActsSamgrTest -lmodule_ActsHieventLiteTest -lmodule_ActsDfxFuncTest -lmodule_ActsBootstrapTest -Wl,--no-whole-archive

链接器配置
当集成上面的适配代码及静态库后,非常重要的一点,lib文件需要手动加入强制链接,修改Ld\Link.ld文件,在 .text 段中添加如下配置:
.text :
{
. = ALIGN(4);
KEEP(*(SORT_NONE(.handle_reset)))
/**添加oh链接器********************/
__zinitcall_bsp_start = .;
KEEP (*(.zinitcall.bsp0.init))
KEEP (*(.zinitcall.bsp1.init))
KEEP (*(.zinitcall.bsp2.init))
KEEP (*(.zinitcall.bsp3.init))
KEEP (*(.zinitcall.bsp4.init))
__zinitcall_bsp_end = .;
__zinitcall_device_start = .;
KEEP (*(.zinitcall.device0.init))
KEEP (*(.zinitcall.device1.init))
KEEP (*(.zinitcall.device2.init))
KEEP (*(.zinitcall.device3.init))
KEEP (*(.zinitcall.device4.init))
__zinitcall_device_end = .;
__zinitcall_core_start = .;
KEEP (*(.zinitcall.core0.init))
KEEP (*(.zinitcall.core1.init))
KEEP (*(.zinitcall.core2.init))
KEEP (*(.zinitcall.core3.init))
KEEP (*(.zinitcall.core4.init))
__zinitcall_core_end = .;
__zinitcall_sys_service_start = .;
KEEP (*(.zinitcall.sys.service0.init))
KEEP (*(.zinitcall.sys.service1.init))
KEEP (*(.zinitcall.sys.service2.init))
KEEP (*(.zinitcall.sys.service3.init))
KEEP (*(.zinitcall.sys.service4.init))
__zinitcall_sys_service_end = .;
__zinitcall_sys_feature_start = .;
KEEP (*(.zinitcall.sys.feature0.init))
KEEP (*(.zinitcall.sys.feature1.init))
KEEP (*(.zinitcall.sys.feature2.init))
KEEP (*(.zinitcall.sys.feature3.init))
KEEP (*(.zinitcall.sys.feature4.init))
__zinitcall_sys_feature_end = .;
__zinitcall_run_start = .;
KEEP (*(.zinitcall.run0.init))
KEEP (*(.zinitcall.run1.init))
KEEP (*(.zinitcall.run2.init))
KEEP (*(.zinitcall.run3.init))
KEEP (*(.zinitcall.run4.init))
__zinitcall_run_end = .;
__zinitcall_app_service_start = .;
KEEP (*(.zinitcall.app.service0.init))
KEEP (*(.zinitcall.app.service1.init))
KEEP (*(.zinitcall.app.service2.init))
KEEP (*(.zinitcall.app.service3.init))
KEEP (*(.zinitcall.app.service4.init))
__zinitcall_app_service_end = .;
__zinitcall_app_feature_start = .;
KEEP (*(.zinitcall.app.feature0.init))
KEEP (*(.zinitcall.app.feature1.init))
KEEP (*(.zinitcall.app.feature2.init))
KEEP (*(.zinitcall.app.feature3.init))
KEEP (*(.zinitcall.app.feature4.init))
__zinitcall_app_feature_end = .;
__zinitcall_test_start = .;
KEEP (*(.zinitcall.test0.init))
KEEP (*(.zinitcall.test1.init))
KEEP (*(.zinitcall.test2.init))
KEEP (*(.zinitcall.test3.init))
KEEP (*(.zinitcall.test4.init))
__zinitcall_test_end = .;
__zinitcall_exit_start = .;
KEEP (*(.zinitcall.exit0.init))
KEEP (*(.zinitcall.exit1.init))
KEEP (*(.zinitcall.exit2.init))
KEEP (*(.zinitcall.exit3.init))
KEEP (*(.zinitcall.exit4.init))
__zinitcall_exit_end = .;
/**********************/
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.sdata2.*)
*(.glue_7)
*(.glue_7t)
*(.gnu.linkonce.t.*)
. = ALIGN(4);
} >FLASH AT>FLASH
OpenHarmony服务拉起
拉起轻量openharmony系统只需调用bootstrap部件的OHOS_SystemInit方法即可。
修改src\main.c文件,在LOS_Start();之前添加:
extern void OHOS_SystemInit(void);
OHOS_SystemInit();
注意要在LOS_KernelInit之后LOS_Start()之前。
XTS测试
编译部件配置
集成 XTS子系统适配需要在config.json添加xts_acts/xts_tools部件,配置如下:
{
"subsystem": "xts",
"components": [
{ "component": "device_attest_lite" },
{ "component": "tools" },
{ "component": "acts" }
]
},
编译命令
hb build -f --gn-args build_xts=true
编译成功后将相关静态库拷贝到EVT\EXAM\HarmonyOS\libs目录,注意上面的[# 静态库集成](# 静态库集成) 中设置的"-Wl,--whole-archive"编译参数已经包含了测试用例静态库,如果没有包含需要手动加上,如果不需要进行xts测试可以适当删减相关静态库链接。
更多推荐

所有评论(0)