OMI 消费版固件完全解析:基于 nRF Connect SDK 2.9.0 的 nRF5340 双核架构、编译流程与模块开发状态
【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend
OMI 消费版(Consumer Version)固件是这款"看得见屏幕、听得见对话的 AI 可穿戴设备"的硬件大脑,本文以 omi/firmware/omi/README.md 为主线,结合仓库内的构建配置、源码与板级定义,系统讲解其基于 Zephyr RTOS / nRF Connect SDK(NCS)的编译方法、双核 nRF5340 架构、BLE 音频流链路,以及麦克风、蓝牙、按键、LED、SD 卡、触觉马达等模块的生产状态与已知待办。读完本文,你将掌握该固件的完整编译配置、各核心模块的实现原理,以及当前版本的已知问题与演进方向。
一、项目定位与文档概览
omi/firmware/omi/目录下存放的是 OMI 消费版(与开发者使用的 DevKit 版本相对)的固件工程。根目录的 README.md 给出了最核心的三条信息:
- 软件栈:基于nRF Connect SDK 2.9.0(NCS,Nordic 基于 Zephyr 的发行版);
- 应用与目标板:应用名为
omi,目标板为omi/nrf5340/cpuapp(nRF5340 双核 Cortex-M33 的应用核); - 当前状态:
WIP——已在生产环境运行(running on production),但仍缺少部分增强功能(missing some enhancement)。
该 README 是固件开发与烧录的入口文档:编译步骤以官方文档为参考,而仓库内 CMakePresets.json、omi.conf、Kconfig、sysbuild.conf 等文件则提供了可直接落地的完整配置。
注意:README 强调了一个对新手非常关键的目录陷阱——必须在代码编辑器中打开
firmware文件夹,而不是仓库根目录omi文件夹。否则 West 无法识别工程、找不到目标板("otherwise West wouldn't recognize the project and won't find your board")。
二、环境要求与编译方法
2.1 版本与工具链要求
根据 README 及仓库内 BUILD_AND_OTA_FLASH.md,编译该固件需要:
| 组件 | 要求 |
|---|---|
| nRF Connect SDK | 2.9.0(v2.9.0) |
| 目标板 | omi/nrf5340/cpuapp |
| 构建工具 | West(Zephyr 元工具)、CMake ≥ 3.20.0、Ninja |
| 其他 | Python 3.8+、ccache、nrfutil(可选,用于工具链管理) |
由于固件基于 Zephyr RTOS 且涉及双核、MCUboot、OPUS 编解码等复杂组件,README 明确它不是 Arduino IDE 能编译的工程,需要完整的 NCS 工具链(见 readme.md)。
2.2 工作区初始化
NCS 通过 West 管理多仓库工作区。仓库中的 BUILD_AND_OTA_FLASH.md 给出了完整流程:先用nrfutil toolchain-manager install --ncs-version v2.9.0安装 SDK,再启动工具链 shell,在v2.9.0目录下执行:
nrfutil toolchain-manager launch --ncs-version v2.9.0 --shell west init -m https://github.com/nrfconnect/sdk-nrf --mr v2.9.0 west updatewest update会下载约 1.5GB 的源码,包括 Zephyr RTOS、NCS 模块、MCUboot 引导程序等。
2.3 编译命令与 CMake Presets
README 推荐使用工程自带的 CMakePresets.json 来编译。该文件定义了OMI预设:
{ "version": 2, "cmakeMinimumRequired": { "major": 3, "minor": 20, "patch": 0 }, "configurePresets": [ { "name": "OMI", "displayName": "OMI", "configuration": "Debug", "generator": "Ninja", "binaryDir": "${sourceDir}/build/omi", "cacheVariables": { "CMAKE_EXPORT_COMPILE_COMMANDS": "YES", "CMAKE_BUILD_TYPE": "Debug", "BOARD": "omi/nrf5340/cpuapp", "CACHED_CONF_FILE": "${sourceDir}/omi.conf", "CONF_FILE": "${sourceDir}/omi.conf" } } ] }从中可以读出三个关键信息:
- Board为
omi/nrf5340/cpuapp,对应仓库中 boards/omi/ 目录下的板级定义(omi_nrf5340_cpuapp_defconfig、omi_nrf5340_cpuapp.dts等); - 配置文件指向 omi.conf,而非 Zephyr 默认的
prj.conf(这也是 BUILD_AND_OTA_FLASH.md 中提示cp omi.conf prj.conf的原因); - 输出目录固定在
build/omi,采用 Ninja 生成器与 Debug 构建类型。
在 NCS 环境内手动编译的等价命令为:
west build -b omi/nrf5340/cpuapp ../omi --sysbuild -- -DBOARD_ROOT=/path/to/omi/firmware--sysbuild会串联构建 MCUboot、网络核固件(ipc_radio)与网络核引导(b0n),最终生成经 RSA 签名并打包的 OTA 固件(详见下文第六节)。
三、工程结构与源码组织
3.1 目录布局
readme.md 说明了firmware/的整体结构:
omi/:消费版主应用工程(本文主角);devkit/:Omi DevKit1 / DevKit2 开发套件工程;test/:测试工程;boards/:自定义板级定义(nRF5340 双核的分区、引脚、SRAM 共享等);scripts/:构建与工具脚本。
消费版应用内部由 CMakeLists.txt 组织,其源码分为两大块:
- 应用源码(
src/顶层):main.c、mic.c、battery.c、led.c、haptic.c、sd_card.c、spi_flash.c、settings.c、feedback.c、wdog_facade.c、rtc.c、imu.c,以及可选编译的t5838_aad.c(T5838 硬件 AAD 底层驱动); - 核心库源码(
src/lib/core/):config.h、codec.c(编解码)、transport.c(BLE 传输)、button.c、monitor.c,以及可选编译的storage.c(离线存储)。
OPUS 编解码器以源码形式内嵌在src/lib/core/lib/opus-1.2.1/,当CONFIG_OMI_CODEC_OPUS开启时通过add_subdirectory链接进固件。
3.2 主循环与事件流
src/main.c 展示了固件的核心数据流:PDM 麦克风数据经mic_handler进入codec_receive_pcm,由 OPUS 编码后的音频经codec_handler调用broadcast_audio_packets通过 BLE 推送。此外它还实现了复位原因打印(看门狗复位、NFC 唤醒、引脚复位、软件复位、CPU lockup 等)以及开机 LED 反馈序列(蓝色脉冲 = "I'm alive",绿色呼吸 = "Ready!"),这些细节对应 README 中 LED 模块的状态反馈需求。
四、核心配置逐项解读:omi.conf 与 Kconfig
4.1 全局配置骨架(omi.conf)
omi.conf 是消费版固件的完整 Kconfig 配置,按功能域可拆解为:
外设与内核基础:
CONFIG_SERIAL=y / CONFIG_GPIO=y / CONFIG_PWM=y / CONFIG_INPUT=y CONFIG_I2C=y / CONFIG_SPI=y / CONFIG_SPI_NOR=y CONFIG_SETTINGS=y / CONFIG_SETTINGS_NVS=y / CONFIG_NVS=y CONFIG_PM_DEVICE=y / CONFIG_ADC=y / CONFIG_ADC_ASYNC=y CONFIG_AUDIO=y / CONFIG_AUDIO_DMIC=y / CONFIG_FLASH=y CONFIG_MAIN_STACK_SIZE=4096 / CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_HEAP_MEM_POOL_SIZE=40000 CONFIG_WATCHDOG=y / CONFIG_WDT_DISABLE_AT_BOOT=n音频链路采用 I2S + nRFX PDM:CONFIG_I2S=y、CONFIG_I2S_NRFX=y、CONFIG_AUDIO_DMIC_NRFX_PDM=y、CONFIG_NRFX_PDM0=y。文件系统选用LittleFS(CONFIG_FILE_SYSTEM_LITTLEFS=y),配置注释说明这是为 SD NAND 选择的掉电安全方案("power-loss safe, no FAT dirty-bit issues")。此外还挂载了 LSM6DSL 加速度计/陀螺仪(CONFIG_LSM6DSL=y),但生产固件中加速度计功能默认关闭(见下)。
BLE 与音频流关键参数(对应 README 中"音频字节丢失"问题):
CONFIG_BT_L2CAP_TX_MTU=498 CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 CONFIG_BT_CTLR_PHY_2M=y / CONFIG_BT_CTLR_PHY_CODED=y CONFIG_BT_L2CAP_TX_BUF_COUNT=20 / CONFIG_BT_BUF_ACL_RX_SIZE=1024 CONFIG_BT_BUF_ACL_TX_SIZE=2048 / CONFIG_BT_BUF_ACL_TX_COUNT=10 CONFIG_BT_ATT_TX_COUNT=20 # 首选连接参数:7.5ms ~ 15ms CONFIG_BT_PERIPHERAL_PREF_MIN_INT=6 CONFIG_BT_PERIPHERAL_PREF_MAX_INT=12 CONFIG_BT_PERIPHERAL_PREF_LATENCY=0 CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=600这些参数直接呼应 README 中关于音频字节丢失(约 30%)的修复记录:Android 端通过把 BLE 连接间隔收紧到7ms(PREF_MIN_INT=6,间隔单位 1.25ms)解决问题;而 iOS 不允许收紧连接间隔,可行间隔约为15ms(PREF_MAX_INT=12)。README 作者对此的评价是"100 rps、每包 50 字节并不是大事",暗示 Android 上的间隔调整更像是一个临时方案。
设备信息与电池服务:
CONFIG_BT_BAS=y / CONFIG_BT_DIS=y CONFIG_BT_DEVICE_NAME="Omi" CONFIG_BT_DIS_MODEL="Omi CV 1" / CONFIG_BT_DIS_MANUF="Based Hardware" CONFIG_BT_DIS_FW_REV_STR="3.0.21" / CONFIG_BT_DIS_HW_REV_STR="5.0"OMI 功能开关(生产默认值):
CONFIG_OMI_CODEC_OPUS=y # OPUS 编解码 CONFIG_OMI_ENABLE_OFFLINE_STORAGE=y # 离线存储(SD 卡) CONFIG_OMI_ENABLE_BUTTON=y # 按键 CONFIG_OMI_ENABLE_BATTERY=y # 电池 CONFIG_OMI_ENABLE_HAPTIC=y # 触觉马达 CONFIG_OMI_ENABLE_RFSW_CTRL=y # 射频开关控制 CONFIG_OMI_ENABLE_T5838_AAD=y # T5838 硬件 AAD(超低功耗麦克风休眠) CONFIG_OMI_ENABLE_ACCELEROMETER=n # 加速度计默认关闭 CONFIG_OMI_ENABLE_SPEAKER=n # 扬声器默认关闭 CONFIG_OMI_ENABLE_USB=n # USB 默认关闭 CONFIG_OMI_ENABLE_MONITOR=n # 监控/指标系统默认关闭4.2 OMI 功能菜单(Kconfig)
Kconfig 定义了上述开关的语义与默认值,其中较有特色的几项:
OMI_ENABLE_MONITOR:监控/指标系统,帮助文档明确建议生产环境关闭以省电、省 RAM 和 Flash("Disable in production to save power, RAM, and flash space"),与 omi.conf 中CONFIG_LOG=n、仅保留显式printk()的"最小化发布输出"策略一致;OMI_ENABLE_T5838_AAD(硬件 AAD):静音一段时间后暂停 PDM 时钟,让 T5838 MEMS 麦克风进入内置的声学活动检测模式(约 15µA),由麦克风硬件监听声音并拉高 WAKE 引脚来唤醒。相关三个调参项:OMI_VAD_ABS_THRESHOLD(默认 600,范围 1~32767):判定静音的绝对幅度阈值;OMI_VAD_HOLD_MS(默认 3000,范围 500~30000):进入硬件 AAD 休眠前的持续静音时间;OMI_AAD_SETTLE_MS(默认 800,范围 100~3000):进入 AAD 后、使能 WAKE 中断前的稳定等待时间,用于吞掉入口瞬态防止误唤醒。- 生产 omi.conf 中这三个值分别被设为
250/10000/800。
OMI_WATCHDOG_TIMEOUT_MS(默认 30000,范围 5000~300000):看门狗超时,注释提示在启动期存在较长操作(如 SD/LFS 预热)时应调大,避免误复位。
五、双核架构与安全启动(sysbuild)
nRF5340 是双核(双 Cortex-M33)SoC,本固件通过 sysbuild.conf 组织多镜像构建:
SB_CONFIG_BOOTLOADER_MCUBOOT=y SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="${APP_DIR}/../bootloader/mcuboot/root-rsa-2048.pem" SB_CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y SB_CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y SB_CONFIG_SECURE_BOOT_NETCORE=y SB_CONFIG_MCUBOOT_UPDATEABLE_IMAGES=2 SB_CONFIG_MCUBOOT_NRF53_MULTI_IMAGE_UPDATE=y SB_CONFIG_NETCORE_APP_UPDATE=y SB_CONFIG_MCUBOOT_MODE_OVERWRITE_ONLY=y要点:
- 启用MCUboot,使用仓库内 bootloader/mcuboot/root-rsa-2048.pem 作为 RSA-2048 签名密钥;
- 支持双镜像更新(应用核 + 网络核)、网络核安全启动(
SECURE_BOOT_NETCORE)、多镜像联合升级(NRF53_MULTI_IMAGE_UPDATE); - 采用overwrite-only升级模式。
配合 BUILD_AND_OTA_FLASH.md 中的内存布局说明,完整的双核分区为:应用核上 MCUboot(64KB)+ 应用主分区(982KB)+ 应用次分区(982KB,OTA 暂存)+ 设置/NVS;网络核上网络引导(34KB)+ 网络主分区(222KB)+ 网络次分区(222KB)。
板级定义位于 boards/omi/,其中omi_nrf5340_cpuapp_defconfig、omi_nrf5340_cpuapp.dts、omi_nrf5340_cpunet.dts、omi-shared_sram.dtsi、omi-cpuapp_partitioning.dtsi、pm_static.yml共同定义了双核各自的引脚、内存分区与共享 SRAM,是"每款硬件版本需要独立构建"(README 与 readme.md 均强调)的底层依据。
六、构建产物与 OTA 升级
6.1 构建产物
编译成功后,build/目录会产出(数据见 BUILD_AND_OTA_FLASH.md):
dfu_application.zip(约 440KB):给 nRF Connect 手机 App 用的主 OTA 包;dfu_application.zip_manifest.json:包元数据;merged.hex(约 869KB):完整固件,可直接编程器烧写;signed_by_mcuboot_and_b0_ipc_radio.hex:签名后的应用固件;merged_CPUNET.hex(约 533KB):网络核固件;build_info.yml、partitions.yml:构建配置摘要与分区布局;- 各子组件构建目录(
omi/、mcuboot/、ipc_radio/、b0n/)。
参考的编译内存占用(该文档示例数据):FLASH 262908 B / 982528 B(26.76%),RAM 244556 B / 440KB(54.28%)。
6.2 OTA 流程
OTA 升级依赖 omi.conf 中开启的CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y与CONFIG_MCUMGR_GRP_IMG_ALLOW_ERASE_PENDING=y。完整流程为:
- 将
dfu_application.zip传输到手机; - 打开 nRF Connect for Mobile,扫描并连接名为 "Omi" 的设备;
- 进入 DFU 标签页,选择
dfu_application.zip并开始升级; - 固件上传到次分区(约 2~3 分钟),随后校验、交换分区并自动重启。
升级期间设备重启后进入新固件即视为成功。MCUmgr 使用加密的 BLE 传输,配合 RSA-2048 签名实现安全升级与回滚保护。
七、模块开发状态与已知问题(WIP 清单全解)
README 的 WIP 章节是理解当前固件成熟度的核心,逐条解读如下:
7.1 新模块测试进度(7/9 通过)
| 模块 | 状态 | 说明 |
|---|---|---|
| 麦克风 Mic | ✅ 完成 | 采集音频字节、激活第二颗麦克风 |
| BLE | ✅ 完成 | 音频流传输 |
| 按键 Buttons | ✅ 完成 | 开关机(进入 deepsleep)、长按与 OMI 对话 |
| LEDs | ✅ 完成 | 充电、BLE 连接/断开状态反馈 |
| Wi-Fi | ⚠️ 部分完成 | README 标注 "partially" |
| 马达 Motors | ✅ 完成 | 触觉反馈 |
| QSPI Flash | ✅ 完成 | 片外 SPI NOR 存储 |
| IMU | ❌ 未完成 | 惯性测量单元尚未完成测试 |
| SD 卡 | ✅ 完成 | 文件存储 + BLE 传输 |
7.2 MCUboot 支持
已完成的子项包括:基础 MCUboot 集成、与 OMI App(iOS/Android)联调、以及纯电池供电(不带充电器)设备上的启动测试——这对可穿戴设备至关重要,因为不带充电器时无法通过外接供电掩盖功耗问题。
7.3 流式传输与转写(Streaming and Transcribing)
这是固件的核心业务链路,全部子项完成:
- 麦克风采集音频字节;
- 激活第二颗麦克风(双麦降噪/拾音);
- BLE 传输;
- OPUS 编码与发送(对应
CONFIG_OMI_CODEC_OPUS与内嵌的 opus-1.2.1 源码); - 修复音频字节丢失问题(曾约 30% 丢包率):
- Android:通过提高 BLE 连接间隔(7ms)修复,但作者坦承这并非理想方案("tbh i don't think this is a good solution"),因为 DevKit 在不调整连接间隔时也能正常工作;
- iOS:系统不允许提高连接间隔(CI),可行的 CI 约为 15ms。
7.4 外围反馈:LED、按键、触觉
- LED:充电、BLE 连接、BLE 断开三种状态均有反馈;已修复"充电 + 关机状态下只有绿灯、反馈不正确"的问题(充电功能本身正常)。
- 按键:开关机(进入 deepsleep)、长按与 OMI 对话;deepsleep 模式下的电池耗电已测试。
- 触觉(Haptic):开关机震动、长按对话震动;待办是复查量产版马达("the current motor is not good")。
7.5 存储与电量
- SD 卡(2/3 完成):文件存储 ✅、通过 BLE 传输 ✅、通过 Wi-Fi 传输 ❌(未完成)。
- 电池(1/2 完成):通过 BLE 上报电量百分比 ✅;修复充电时电量不准的问题❌。
- 充电器:模块本身无未完成子项。
7.6 离线存储机制
readme.md 补充说明了离线存储的完整行为:只要设备与 App 无 BLE 连接,存储即自动激活;每次开机都会新建一个文件并开始写入 OPUS 编码数据;一旦连接 App,存储内容开始向 App 流式传输,传输完成后尝试删除设备上的文件。需要留意的是,离线存储包的格式与实时流式音频包不同。此外,调试文档提示离线存储当前为实验性功能,开启日志会占用 BLE 传输或 SD 卡写入性能(可设置CONFIG_LOG_PROCESS_THREAD_PRIORITY=5与CONFIG_LOG_PROCESS_THREAD_CUSTOM_PRIORITY=y缓解)。
八、调试与开发建议
8.1 USB 串口调试
readme.md 给出了 DevKit2 上开启 USB 串口调试的方法,消费版同样适用:在对应.conf中开启CONFIG_CONSOLE=y、CONFIG_PRINTK=y、CONFIG_LOG=y、CONFIG_LOG_PRINTK=y、CONFIG_UART_CONSOLE=y,并用 nRF Serial Terminal(VS Code 扩展)查看输出;完整在线调试需要 J-Link 调试器。注意生产版 omi.conf 默认CONFIG_LOG=n,只保留显式printk()输出。
8.2 常见构建问题排查
ModuleNotFoundError: No module named 'cryptography':多半是没在 nrfutil 工具链 shell 内构建;No board named 'omi' found:检查BOARD_ROOT是否指向firmware目录;No prj.conf file found:先cp omi.conf prj.conf(或使用 CMakePresets,它会显式指定CONF_FILE=omi.conf);- 看门狗误复位:启动期有 SD/LFS 预热等长操作时调大
OMI_WATCHDOG_TIMEOUT_MS。
九、总结
OMI 消费版固件是一个典型的 Zephyr/NCS 双核可穿戴应用:nRF5340 应用核负责 OPUS 音频编码、BLE GATT 流式传输、离线 SD 存储与各外设管理,网络核承载 BLE 协议栈;MCUboot + RSA-2048 签名保障安全 OTA。README 中"production-ready 但仍有增强空间"的定位,与其 WIP 清单高度一致:核心音频链路(双麦采集 → OPUS 编码 → BLE 发送)已全部打通,Android 丢包问题通过连接间隔调优解决,而 iOS 间隔受限、Wi-Fi 传输、IMU、充电电量精度、量产马达手感等仍是后续迭代的重点方向。对想要深入 Zephyr 可穿戴固件开发或参与 OMI 固件改进的开发者,建议从 omi.conf 与 Kconfig 的 OMI 功能开关入手,配合 src/main.c 的主循环与 src/lib/core/transport.c 的 GATT 音频服务逐步阅读源码。
【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考