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 下载。

img

下载完成后解压到编译的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

具体的预编译适配步骤如下:

  1. 修改 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"        --- 产品驱动适配目录
       }
    
  2. 修改 vendor/qemu/ch585/ohos.build 文件,内容如下:

       {
         "parts": {
           "product_ch585": {
             "module_list": [
               "//vendor/ohemu/ch585:ch585"
             ]
           }
         },
         "subsystem": "product_ch585"
       }
    
  3. 修改 vendor/qemu/ch585/BUILD.gn 文件,内容如下:

       group("ch585") {
         deps = []
       }
    
  4. 修改 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 = ""
    
  5. 修改 device/qemu/ch585/ohos.build 文件,内容如下:

       {
         "parts": {
           "device_ch585": {
             "module_list": [
               "//device/qemu/ch585:ch585"
             ]
           }
         },
         "subsystem": "device_ch585"
       }
    
  6. 修改 vendor/qemu/ch585/BUILD.gn 文件,内容如下:

       group("ch585") {
       }
    
  7. 验证hb set配置是否正确,输入hb set能够显示如下图片表示配置正确。

    执行hb set输入项目根目录,并且回车,hb命令会遍历所有//vendor/<product_company>/<product_name>目录下的config.json,给出可选产品编译选项,config.jsonproduct_name用于显示产品名,device_companyboard用于关联出//device/board/<device_company>/<board>目录,并且匹配<any_dir_name>/config.gni文件,如果能够匹配多个文件,表示该单板适配了多个内核,那么可以根据config.jsonkernel_typekernel_version来唯一匹配config.gnikernel_typekernel_version,即可确定了需要编译适配了哪个内核的单板。

    img

    通过hb env可以查看选择出来的预编译环境变量。

    img

现在执行 hb build 即可编译出相关静态库:

img

CH585集成OpenHarmony子系统

下载IDE和代码

打开沁恒官网,查看ch585详情文档

img

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

img

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

文件创建完成后添加到编译环境:

img

img

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目录下。然后加入到项目编译环境中:

img

添加"-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

img

链接器配置

当集成上面的适配代码及静态库后,非常重要的一点,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测试可以适当删减相关静态库链接。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐