# Lark **Repository Path**: qingefable/lark ## Basic Information - **Project Name**: Lark - **Description**: Lark 是一款借鉴 Zephyr RTOS 设计思路、针对嵌入式 MCU 的轻量级 RTOS 开发框架。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2026-08-03 - **Last Updated**: 2026-09-19 ## Categories & Tags **Categories**: iot **Tags**: None ## README # Lark SDK **Lark** 是一款借鉴 [Zephyr RTOS](https://zephyrproject.org/) 设计思路、针对嵌入式 MCU 的轻量级 RTOS 开发框架。它保留了 Zephyr 的核心价值(完整的 Kernel、用户空间、设备驱动模型、Devicetree/Kconfig 配置、中断表自动生成、迭代链接、链接脚本收集机制),同时彻底简化了工程组织与构建流程。 Lark 的定位是:**像 Zephyr 一样强大,像裸机工程一样简单**。 --- ## 特性 - **完整的内核**:多线程调度、信号量、互斥量(优先级继承)、消息队列、FIFO/LIFO/栈、定时器、事件、条件变量、内存池/slab、内核堆、工作队列、轮询 - **事件触发线程(Lark 扩展)**:`lark_event_thread_*` 线程阻塞在内部信号量,由周期定时器(TIMER)或外部事件(MANUAL,`lark_event_thread_trigger`)唤醒执行 body;支持最新值覆盖(limit=1 coalesce)、静态/动态创建与 `start`/`trigger`/`timer_start`/`timer_stop`/`abort` 控制 - **用户空间**:基于 ARM MPU 的内存域、syscall 机制、内核对象哈希表(gperf)、应用内存分区、三遍迭代链接 - **设备驱动模型**:与 Zephyr 兼容的 `struct device` / `DEVICE_DT_DEFINE` / 设备初始化级别 / devicetree 实例映射 - **Devicetree 驱动**:SOC 由 `board.dts` 根节点 `compatible` 直接决定(无需 Kconfig select 链) - **Kconfig 配置**:kconfiglib 纯 Python 实现,配置来源仅三类(SoC 默认 / SOC 选择 / app prj.conf) - **中断表自动生成**:`gen_isr_tables.py` 从链接产物提取 `.intList` 段生成 `_sw_isr_table` - **迭代链接(多遍链接)**:`pre0 → final`(无用户空间 2 遍)/ `pre0 → pre1 → final`(用户空间 3 遍),支持 ISR 表、内核对象表、应用分区生成 - **链接脚本收集机制**:`lark_linker_sources()` 收集各处 `.ld` 片段,C 预处理器生成最终脚本 - **环境简单**:仅依赖 `cmake + ninja + python3 + arm-none-eabi-gcc`,无 west、无复杂工具链 - **工具链可替换**:抽象工具链层,当前支持 `armgcc`,预留 `armclang(AC6)` --- ## 为什么选择 Lark(与 Zephyr 的对比) | 维度 | Zephyr | Lark | |---|---|---| | 工程组织 | boards 目录、app/sdk 混合、west 多仓库 | **app/sdk 分离**,board 下沉到 app(单工程 `app//board/`,产品线 `product_config/

/board_config/`) | | 构建入口 | `west build -b ` | `cmake -B out -GNinja [-Dp=]`(在 app 目录) | | SOC 选择 | board Kconfig select 链 | **board.dts 根 compatible** | | Devicetree | board.dts + overlay | **单一 board.dts,无 overlay** | | 环境依赖 | west、Zephyr SDK、大量 Python 包 | cmake + ninja + python3 + 交叉编译器 | | 内核/用户空间 | 完整 | **完整移植** | | 驱动 | 海量(按需裁剪) | 核心驱动 + 用户自行扩展 | --- ## 快速开始 ### 0. 一键部署环境(推荐) 从仓库拉下代码后,**先进入 Lark SDK 根目录**再运行内置脚本。脚本会自动检查/安装构建依赖,并**根据自身位置自动算出 SDK 路径**写入 `LARK_BASE`——不需要手动填路径: ```sh # ① 进入 SDK 根目录:把 <你的路径> 换成你实际克隆 Lark 的位置 # (不确定就先 `ls`,确认里面能看到 `scripts/` 目录) cd <你的路径>/lark # 例如:cd ~/code/lark # ② 运行内置脚本(Linux / macOS / WSL,脚本会自动检测系统与包管理器) bash scripts/setup.sh ``` Windows(需要 Git Bash;没有则脚本会自动提示/用 winget 安装 Git for Windows): ```bat cd <你的路径>\lark scripts\setup.bat ``` 脚本会: - 检查 CMake / Ninja / Python3 / DTC / arm-none-eabi-gcc / git 是否存在、版本是否满足 - **缺失的工具**按检测到的包管理器自动安装(apt / dnf / pacman / zypper / brew / winget / choco) - **版本不满足**时提示所需版本并给出官方下载链接 - 把 `export LARK_BASE=` 幂等写入 `~/.bashrc`(zsh 则写 `~/.zshrc`),新终端即生效 只检查不安装:`bash scripts/setup.sh --check`。手动安装请按下表。 ### 1. 环境要求 | 工具 | 版本要求 | |---|---| | CMake | >= 3.20 | | Ninja | >= 1.10 | | Python3 | >= 3.12 | | DTC(devicetree 编译器,可选) | >= 1.4.6 | | arm-none-eabi-gcc | 任意可用版本 | > DTC 为**可选**工具:核心设备树解析由 python-devicetree 完成(纯 Python,无外部依赖)。 > 装了 DTC 只会在构建时对合并后的 DTS 多做一层语法/规范检查(诊断非致命),不装也不影响构建与产物。 ### 2. 设置环境变量 如果没用一键脚本(§0),可手动设置。**先 `cd` 进 SDK 根目录,再用 `$(pwd)` 自动取路径**,不用手写路径: ```sh cd <你的路径>/lark # 换成你实际克隆 Lark 的目录 export LARK_BASE=$(pwd) # 当前目录即 SDK 根目录 ``` `LARK_BASE` 指向 Lark SDK 根目录,也可在 cmake 时用 `-DLARK_BASE=...` 覆盖。 已跑过一键脚本则此步可跳过(`LARK_BASE` 已写入 `~/.bashrc` / `~/.zshrc`,新开终端即生效)。 ### 3. 创建应用 app 目录与 SDK 分离。按应用规模推荐两种目录结构,SDK 均统一支持。 **结构 A:单工程(独立小应用 / 单板验证)** 一个工程 = 一个独立目录,自带板级配置,在工程目录内直接构建: ``` app/ └── demo/ ├── CMakeLists.txt # cmake 入口 ├── app_main.c # 应用主程序 ├── prj.conf # 应用配置 └── board/ └── board.dts # 唯一的 devicetree 入口 ``` ```sh cd app/demo cmake -B out -GNinja # 直接在工程目录构建 ninja -C out ``` **结构 B:产品线(一套应用跑多块板 / 多个衍生型号)** `app/` 根为构建入口,共享代码放根目录,各工程板级配置在 `product_config/

/board_config/`,构建时用 `-Dp=

` 选工程: ``` app/ ├── CMakeLists.txt # 根 cmake 入口(-Dp 选工程) ├── Kconfig # app 级配置(可选,经 orsource 并入 SDK 配置树) ├── app_main.c # 共享应用代码 ├── motor/ support/ # 共享库 └── product_config/ ├── demo/ # 工程 A:STM32H743 │ └── board_config/ │ ├── board.dts │ └── prj.conf └── demo_gd32/ # 工程 B:GD32F303VET6 └── board_config/ ├── board.dts └── prj.conf ``` ```sh cd app cmake -B out -GNinja -Dp=demo # 构建工程 demo cmake -B out -GNinja -Dp=demo_gd32 # 切换工程(触发重配,建议独立 build 目录) ninja -C out ``` 两种结构都由 SDK 统一支持:`board.dts` / `prj.conf` 从「应用配置目录」`APPLICATION_CONFIG_DIR` 定位——结构 A 用默认值(= 应用源目录),结构 B 由根 `CMakeLists.txt` 预置为 `product_config/

/board_config`。 仓库内已附带可直接构建的完整示例:`doc/examples/demo/`(结构 A,STM32H743,含用户空间)、`doc/examples/demo_gd32/`(结构 A,GD32F303)、`doc/examples/product/`(结构 B,双工程)。 `app/demo/CMakeLists.txt`(结构 A 推荐写法,find_package 在 project() **之前**加载交叉工具链): ```cmake cmake_minimum_required(VERSION 3.20.0) # 定位 Lark SDK:-DLARK_BASE > $LARK_BASE > 自动探测(示例位于 SDK 仓库内时) if(NOT DEFINED LARK_BASE) set(LARK_BASE $ENV{LARK_BASE}) endif() if(NOT LARK_BASE) get_filename_component(_sdk_root "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE) if(EXISTS "${_sdk_root}/cmake/lark.cmake") set(LARK_BASE "${_sdk_root}") endif() endif() if(NOT LARK_BASE) message(FATAL_ERROR "LARK_BASE is not set. Point it at the Lark SDK root.") endif() find_package(Lark REQUIRED HINTS ${LARK_BASE}) project(demo) target_sources(app PRIVATE app_main.c) ``` 结构 B 的 `app/CMakeLists.txt` 在结构 A 基础上多两行:`-Dp` 选工程 + 预置配置目录。 ```cmake # ...(LARK_BASE 三级探测,同结构 A)... if(NOT DEFINED p) set(p demo) # 默认工程 endif() set(APPLICATION_CONFIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/product_config/${p}/board_config") find_package(Lark REQUIRED HINTS ${LARK_BASE}) project(app) target_sources(app PRIVATE app_main.c) # + motor/ support/ 等共享库 ``` `app/demo/board/board.dts`(两种结构相同,SOC 由 compatible 决定,直接 include 芯片 dtsi,无 overlay): ```dts /dts-v1/; #include / { compatible = "st,stm32h743"; /* ← 唯一的 SOC 声明 */ chosen { lark,console = &usart3; zephyr,sram = &sram0; zephyr,flash = &flash0; }; }; ``` ### 4. 构建与编译 ```sh cd app/demo cmake -B out -GNinja # 配置(DTS→SOC→Kconfig→kernel 全流程) ninja -C out # 编译(含迭代链接) ``` 仓库内示例位于 SDK 内部,自动探测 `LARK_BASE`,无需设置环境变量: ```sh # 结构 A:在示例工程目录内构建 cd doc/examples/demo cmake -B out -GNinja # 自动探测 LARK_BASE=SDK 根目录 ninja -C out # 结构 B:在 app 根用 -Dp 选工程 cd doc/examples/product cmake -B out -GNinja -Dp=demo # STM32H743 cmake -B out -GNinja -Dp=demo_gd32 # GD32F303(切换触发重配) ninja -C out ``` 产物生成在 `out/lark/`: - `lark.elf` / `lark.bin` / `lark.hex` / `lark.map` --- ## 构建系统 ### 配置流程 ``` app/CMakeLists.txt ├─ find_package(Lark) ── LarkConfig.cmake │ ├─ 工具链(armgcc,在 project() 前加载) │ └─ include(lark.cmake) ├─ project(demo) └─ lark.cmake 内部: ├─ board 定位(APPLICATION_CONFIG_DIR:结构A /board,结构B product_config/

/board_config) ├─ DTS 预处理 → SOC 解析(soc_from_dts.py) ├─ Kconfig(SoC 默认 + soc_defconfig + prj.conf) ├─ DTS 完整处理(gen_edt → devicetree_generated.h) └─ kernel 模块(add_subdirectory(lark)) ``` ### 迭代链接 ``` 无用户空间: pre0 ──(生成 isr_tables.c)──▶ final (2 遍) 有用户空间: pre0 ──▶ pre1 ──(生成 isr_tables.c / kobject_hash.c / device_deps.c / app_smem_aligned.ld)──▶ final (3 遍) ``` ### 工具链抽象 ``` cmake/toolchain/ ├── armgcc.cmake # arm-none-eabi-gcc(当前) └── lark-armgcc/ # Zephyr 兼容的 toolchain port ``` 切换工具链只需设置 `-DLARK_TOOLCHAIN=`。 --- ## 版本管理 版本号格式:**`SDK_MAJOR.SDK_MINOR.SDK_PATCH.APP_TWEAK`**,如 `4.4.99.1`。 - **前 3 段**:来自 `lark/VERSION` 文件(SDK 版本,当前 `4.4.99`) - **第 4 段(APP_TWEAK)** 来源优先级: 1. 用户在 app `CMakeLists.txt` 显式 `set(APP_VERSION N)` 2. app 目录是 git 仓库 → `git rev-list --count HEAD`(提交次数) 3. 都没有 → `0`(版本显示三段 `4.4.99`) 在 app 的 `CMakeLists.txt` 中(`include(lark.cmake)` 之前): ```cmake set(APP_VERSION 1) # 显式指定第 4 段,最终 4.4.99.1 ``` 生成的 `version.h` 中: - `KERNEL_VERSION_STRING` = `"4.4.99.1"` - `KERNELVERSION` = `0x04046301` --- ## 目录结构 ``` lark/ ├── CMakeLists.txt # SDK 顶层(由 kernel 模块 add_subdirectory 引入) ├── Kconfig # Kconfig 入口(双菜单:SDK + Application) ├── Kconfig.lark # Kconfig 配置树 ├── VERSION # SDK 版本号(MAJOR.MINOR.PATCH) ├── version.h.in # 版本头模板 ├── arch/ │ ├── arm/ # ARM 架构(Cortex-M) │ │ ├── core/cortex_m/ # 内核实现(reset/irq/swap/syscall/mpu) │ │ └── core/mpu/ # MPU(PMSAv7/v8) │ └── common/ ├── cmake/ │ ├── lark.cmake # 构建系统入口 │ ├── modules/ # 构建模块(kconfig/dts/kernel/version...) │ ├── toolchain/ # 工具链抽象 │ ├── linker/ # 链接脚本处理 │ └── gen_version_h.cmake # 版本头生成 ├── dts/ │ ├── arm/ # 架构/厂商 devicetree │ └── bindings/ # devicetree binding YAML ├── drivers/ │ ├── clock_control/ # 时钟(STM32H7 RCC) │ ├── serial/ # 串口(uart_stm32) │ ├── gpio/ # GPIO(gpio_stm32) │ ├── pinctrl/ # 引脚复用(pinctrl_stm32) │ ├── timer/ # 定时器(cortex_m_systick) │ ├── reset/ # 复位(reset_stm32) │ ├── interrupt_controller/ # 中断控制器(EXTI) │ ├── cache/ # 缓存 │ └── console/ # 控制台(uart console) ├── doc/ # 文档(按性质分七类,索引见 doc/README.md) │ ├── README.md # 文档索引(分类总览 + 每篇状态) │ ├── api/ # 接口参考(UART/PWM/ADC/SPI/counter/线程/参数存储) │ ├── design/ # 设计文档(详细设计总纲、FOC 采样链、GD32、LNP 链路层…) │ ├── internals/ # 机制说明(Kconfig 树、链接脚本、shell↔UART、事件线程时序) │ ├── explore/ # 调研探索(ESP-IDF 参照、GD32 外设 IP 全貌) │ ├── notes/ # 应用笔记(jm012 ADC 触发/PWM 时序实测) │ ├── process/ # 过程记录(CHANGELOG / 交接文档 / 历史意见) │ ├── archive/ # 归档(已废弃方案) │ └── examples/ │ ├── demo/ # 示例·结构 A(STM32H743,含用户空间) │ ├── demo_gd32/ # 示例·结构 A(GD32F303VET6) │ └── product/ # 示例·结构 B(双工程,-Dp 选板) ├── include/lark/ # 公共头文件 ├── kernel/ # 内核源码 ├── lib/ # libc + os + heap ├── misc/ # 杂项 ├── modules/cmsis_6/ # CMSIS(ARM 内核级,顶层模块) ├── scripts/ # 构建脚本(kconfig/dts/build) ├── soc/ │ └── st/stm32/ │ ├── stm32h7x/ # STM32H7 系列 SoC │ ├── stm32cube/ # STM32Cube HAL │ └── common/ # stm32 公共 └── subsys/ # 子系统(console/debug/logging 完整移植/pm) ``` --- ## Demo 示例(doc/examples) 仓库内置三种示例工程,均可直接构建: - **`doc/examples/demo/`**(结构 A,STM32H743,含用户空间):完整内核 + 用户空间示例 - **`doc/examples/demo_gd32/`**(结构 A,GD32F303VET6):USART/console + shell 最小验证 - **`doc/examples/product/`**(结构 B,双工程):一套共享应用(led0 心跳)经 `-Dp=demo` / `-Dp=demo_gd32` 分别构建到 STM32H743 与 GD32F303 **`doc/examples/demo/`**(STM32H743,可直接 `cmake -B out -GNinja && ninja -C out` 构建): 基于 STM32H743(Cortex-M7),演示: - `printk` 串口控制台输出 - GPIO LED 点灯(gpio + pinctrl) - 内核线程(`k_thread_create`)+ 信号量(`k_sem`)+ 调度(`k_sleep`) - 设备模型(`device_is_ready`) - 完整用户空间(`CONFIG_USERSPACE=y` + ARM MPU) ```c int main(void) { const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios); printk("Lark demo running on STM32H743\n"); if (device_is_ready(led.port)) { gpio_pin_configure_dt(&led, GPIO_OUTPUT); } while (1) { gpio_pin_toggle_dt(&led); k_sleep(K_MSEC(500)); } } ``` --- ## VS Code 开发环境(推荐) Lark 由 **CMake + Kconfig + Devicetree** 三套配置系统驱动。配合以下插件与工作区配置,可获得完整的 补全 / 悬停 / 跳转 / 校验体验。构建一次后 `out/compile_commands.json` 会自动生成 (`cmake/modules/kernel.cmake` 已打开 `CMAKE_EXPORT_COMPILE_COMMANDS`),它是 C/C++ 代码跳转的基础。 ### 推荐插件 | 用途 | 扩展 ID | 作用 | |---|---|---| | 设备树 Devicetree | `kylemicallefbonnici.dts-lsp` | `.dts/.dtsi` 节点/属性跳转、补全、悬停、binding 校验 | | CMake | `ms-vscode.cmake-tools` | IDE 内配置(`-Dp=

`)、构建、调试目标 | | Kconfig | `trond-snekvik.kconfig-lang` | Kconfig 语法高亮与补全 | | C/C++ 跳转(二选一) | `llvm-vs-code-extensions.vscode-clangd` | 基于 `compile_commands.json` 的精确跳转/重构 | | | `ms-vscode.cpptools` | 官方 C/C++ 扩展,同样基于 `compile_commands.json` | | 链接脚本(可选) | `zixuanwang.linkerscript` | `.ld` 高亮 | ### 工作区配置(`.vscode/settings.json`) ```json { "devicetree.cwd": "${workspaceFolder}", "devicetree.defaultIncludePaths": [ "lark/dts", "lark/dts/arm", "lark/dts/common", "lark/include" ], "devicetree.defaultBindingType": "Zephyr", "devicetree.defaultZephyrBindings": ["lark/dts/bindings"], "devicetree.allowAdhocContexts": true, "[devicetree]": { "editor.tabSize": 4 }, "files.associations": { "Kconfig.*": "kconfig" }, "clangd.arguments": ["--compile-commands-dir=${workspaceFolder}/out"], "C_Cpp.default.compileCommands": "${workspaceFolder}/out/compile_commands.json" } ``` ### C/C++ 代码跳转 - 先构建一次(`cmake -B out -GNinja -Dp=

`),`out/compile_commands.json` 即自动生成,内含全部 `-I`/`-isystem`(含 `out/lark/include/generated`、CMSIS、STM32Cube HAL 等)——clangd/cpptools 据此 精确解析,**不会再有「宏未定义 / 头文件找不到」的误报**。 - clangd:`"clangd.arguments": ["--compile-commands-dir=${workspaceFolder}/out"]`。 - cpptools:`"C_Cpp.default.compileCommands": "${workspaceFolder}/out/compile_commands.json"`。 - 配好后在 `app_main.c`/`motor/` 里可直达 `DEVICE_DT_GET`、`pwm_set`、`DT_*` 宏等的定义处。 ### 设备树跳转(dts-lsp) - **Lark 无 `ZEPHYR_BASE`**,扩展无法自动发现 include 根,必须在 settings 里手动声明 `devicetree.defaultIncludePaths` 与 `devicetree.defaultZephyrBindings`(见上)。 - 路径相对 `devicetree.cwd` 解析(通常 `${workspaceFolder}`):把整个 larkproject 当工作区打开用 `lark/dts`;单独打开 lark SDK 仓库则改用 `dts`、`dts/arm` 等。 - 支持节点/属性跳转、悬停查看属性、`&label` 交叉引用、binding 校验。 - 若 dts-lsp 报「属性未在 binding 中定义」等误报,先核对上述 include/binding 路径是否正确; 一切以真实构建(`ninja`)为准。 ### 构建与调试(CMake Tools) - 终端构建最直接:`cmake -B out -GNinja -Dp=

&& ninja -C out`;`ninja -C out menuconfig` 进入 Kconfig 配置界面(D 键保存写回 `prj.conf`)。 - CMake Tools 中:`configureArgs` 填 `-Dp=

`,构建目录设为 `out`,即可在 IDE 内一键配置/构建/调试。 --- ## 移植指南 ### 新增 SoC 1. 在 `soc/st/stm32/soc.yml` 添加条目,并指定 `dts-binding`(compatible 字符串) 2. 新建 `//` 目录,编写 Kconfig、soc.c、CMakeLists.txt 3. 提供芯片级 dtsi(如 `stm32h743.dtsi`) 4. 在 `dts/bindings/` 补充所需 binding ### 新增驱动 1. 在 `drivers//` 新建驱动源文件 2. 使用 `DEVICE_DT_INST_DEFINE` 定义设备实例 3. 编写 `Kconfig.` 并在驱动类 `Kconfig` 中 source 4. 驱动通过 devicetree binding + Kconfig 开关自动启用 ### 新增工具链 在 `cmake/toolchain/` 添加 `.cmake`,定义编译器/链接器/标志,并通过 `-DLARK_TOOLCHAIN=` 启用。 --- ## 目录约定 - **app 与 sdk 分离**:SDK 在 `lark/`,应用在独立的 app 目录;`doc/examples/` 是随仓库发布的可构建示例(两种结构的副本) - **board 归属 app**:SDK 无 boards 目录——单工程在 `app//board/`,产品线在 `product_config/

/board_config/`(两者都含 `board.dts`,由 `APPLICATION_CONFIG_DIR` 统一定位) - **无 overlay**:`board.dts` 是唯一 devicetree 入口,直接 `#include` 芯片 dtsi - **生成文件进构建目录**:SOC 选择片段、`devicetree_generated.h`、`autoconf.h` 等均在 `out/` 下 --- ## 文档 完整索引见 **[`doc/README.md`](doc/README.md)**。`doc/` 按文档性质分七类,**每篇开头的「状态」行标明可信度**——区分「当前能力」与「未施工的计划」: | 目录 | 拿它干什么 | |---|---| | [`doc/api/`](doc/api/) | 查某个驱动/子系统当前有哪些接口、怎么调 | | [`doc/design/`](doc/design/) | 理解为什么这么设计、施工到哪一步(**状态行必读**) | | [`doc/internals/`](doc/internals/) | 搞懂 Kconfig 树 / 链接脚本 / shell↔UART 等内部机制 | | [`doc/explore/`](doc/explore/) | 选型时的外部参照(ESP-IDF、GD32 外设 IP 调研) | | [`doc/notes/`](doc/notes/) | 具体板子的硬件实测结论(jm012 ADC 触发/PWM 时序) | | [`doc/process/`](doc/process/) | 变更历史(CHANGELOG)、会话交接 | | [`doc/archive/`](doc/archive/) | 已废弃方案(避免重复踩坑) | 新手路径:`doc/design/Lark详细设计文档.md`(总纲)→ `doc/process/交接文档.md`(当前进度与切入点)→ 按需查 `doc/api/`。 --- ## 许可证 - 内核/arch/驱动/脚本:从 Zephyr v4.4 移植,保留原版权头,**Apache-2.0** - STM32Cube HAL:ST 许可(BSD-3-Clause) - pyelftools 0.33、kconfiglib、python-devicetree:各自许可(BSD/ISC/Apache-2.0) 详见各文件头部版权声明。