news 2026/10/21 2:36:26

嵌入式架构学习5--Brilliant Labs Halo(2)(TODO)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式架构学习5--Brilliant Labs Halo(2)(TODO)

书接上回。。。

6 Zeypher集成

6.1 整体内容

整体来说是基于Zephyr 3.6.0。核心的实现如下:

文件夹内容如下(GitHub - brilliantlabsAR/halo-firmware: Firmware for Halo, Brilliant Labs' AI glasses — Zephyr RTOS on the Alif Balletto, with a Lua runtime for on-device apps and BLE OTA updates · GitHub):

PathWhat it is
applications/halo/The Halo application (boot, BLE, Lua runtime, audio, display)
modules/halo/Reusable Halo C modules + Lua bindings (AEC, codecs, sensors, BLE services)
modules/lua/,modules/canvas/Lua 5.4 and the display/canvas + font stack
boards/arm/halo/ThehaloZephyr board definition
drivers/,subsys/Device drivers and subsystems (Halo-specific + inherited Alif SDK)
samples/halo/Small single-peripheral samples (mic, display, sensors, …)
west.ymlThe west manifest pinning Zephyr, HALs, and MCUboot
applications/halo/PROTOCOL.mdBLE protocol reference for host apps

因为芯片用的是Alif Semiconductor的,所以板级驱动是原厂直接在Zephyr包里面提供了。对于Halo产品来说实现的核心内容,就是app,modules,drivers。他们的顺序如下:

app应用,就是一个main.c,也没有太多东西。

6.2 Modules

modules,服务器上的目录包括canvas、halo、linker和lua:

  • modules/halo/:Halo 产品功能,包括 BLE 管理与 BLE 服务、Lua runtime 及其硬件 API、电源/电池/LED/watchdog/file/memory manager,以及音频流、AEC、EQ 和音效处理。
  • modules/lua/:Lua 解释器本身。
  • modules/canvas/:画布绘图和字体资源。
  • modules/linker/:链接脚本片段等构建辅助内容。

6.3 Drivers

drivers。大概有以下这些:

路径大致用途
audio/max98357a/MAX98357A I²S 扬声器功放及扬声器保护
audio/t5838/T5838 PDM 麦克风输入及音频活动检测(AAD)
audio/pwm_audio/PWM 音频输出
clock/si570/Si570 可编程时钟
codec/wm8904/WM8904 音频编解码器
display/display_vga020.cVGA020 显示器
i2s/i2s_sync/同步 I²S 音频接口
input/input_gpio_button.cGPIO 按键
regulator/regulator_tps65132.cTPS65132 电源/偏置管理
sensor/alif_vbat.cAlif 电池电压采集
sensor/bma580/BMA580 加速度计
sensor/qmc6308.cQMC6308 磁力计
sm/sm.cGPIO 控制的 shutdown/电源状态机制
video/pag7982.cPAG7982 摄像头

6.4 小结

从上面的内容可以看出,如果是基于zeypher开发,步骤大概就是:

  1. west init + 挪一个改名的manifest
  2. 依样画boards/foo/board.dts把外设别名摆好(一个也叫产品角色)
  3. 建一个跑main()的纯初始化骨架程序——log出一个Hello + 一个k_work`心跳
  4. 外设一个一个加进samples/式的最小例,然后接入应用
  5. 以sysbuild+mcuboot为底线,第一周就跑通“通过BLE掉固件→回滚”——OTA机制不是产品后期加的,是最早基础设施

7 音频子系统

整体来看,音频系统如下:

这里只看看驱动层,stream层,以及算法。再上面的app不在范围。

7.1 驱动

从硬件上来看,音频系统涉及的硬件是:

麦克风T5838 PDM(带Always-on Audio Detect,可单独唤醒)zephyr,micphone
扬声器MAX98357A(I2S功放)zephyr,speaker

关于98357,之前其实写过一篇:总线学习5--I2S_max98357数据手册-CSDN博客

在代码中有以下驱动:

作用如下:

路径大致用途
audio/max98357a/MAX98357A I²S 扬声器功放及扬声器保护
audio/t5838/T5838 PDM 麦克风输入及音频活动检测(AAD)
audio/pwm_audio/PWM 音频输出
codec/wm8904/WM8904 音频编解码器
i2s/i2s_sync/同步 I²S 音频接口

播放的DTS定义

/delete-node/ i2s0@49014000; i2s0: i2s0@49014000 { compatible = "alif,i2s-sync"; reg = <0x49014000 0x1000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2s0>; interrupts = <141 3>; bit-depth = <16>; sample-rate = <32000>; mono-mode; status = "okay"; }; max98357a: max98357a { compatible = "maxim,max98357a"; i2s = <&i2s0>; sd-mode-gpios = <&gpio8 5 GPIO_ACTIVE_HIGH>; }; pdm_audio: pdm_audio@43002000 { compatible = "alif,t5838-alif-pdm"; reg = <0x43002000 0x1000>; /* priority 2, above I2S0's 3: the 8-deep PDM FIFO at * 16kHz gives the ISR ~250us from the watermark to * overflow; at priority 4 under duplex load it missed * ~10x/second (732 counted overflows in 72s, EC * 2026-07-13). Bisect-exonerated for the round-2 * wedge (that was the unacked sticky ERROR status). */ interrupts = <49 2>; pinctrl-0 = < &pinctrl_pdm_audio >; pinctrl-names = "default"; /* almost-full IRQ threshold on the 8-deep FIFO: slack * to overflow is (8 - watermark) samples = 62.5us * each at 16kHz. 6 left 125us of ISR headroom and * overflowed under duplex BLE+LC3 load (capture * losses that slid the AEC window off its ring); * 4 doubles the headroom for a ~1.3x ISR rate. */ fifo-watermark = <4>; queue-depth = <128>; iir-bypass; fir-bypass; /* Snip the PDM decimator start-of-stream settling * transient (the "pop"): the front-end slews to the * ±full-scale rail for the first ~5-12ms after trigger * (measured on cold-start captures, tests/aec/pop_*.py), * a window with no recoverable audio. In the DMA drain * path the discard drops whole MIC_BLOCK_INTERVAL_MS * (20ms) blocks, so 20 = drop exactly one block, clearing * the rail with margin at ~20ms of startup latency. The * DC-settling tail past the rail is real audio and is * left to the downstream DC blocker (lua_microphone.c * mic_dc_block). The driver default is 0 (was regressed * 50->0 in 15bc6a1, which re-exposed the pop). Do NOT * un-bypass the IIR to fix this - the AEC relies on the * raw full-band mic (see mic_dc_block rationale). */ discard-duration-ms = <20>; /* LPPDM RX DMA drain (prototype): dma2 channel 4, * DMA request line 30 / group 2 = LPPDM_DMA_REQ * (B1 HWRM Table 14-95 + the DMA request MUX table). * The hardware FIFO watermark drives the DMA handshake * (PDM_CTL1 USE_DMA bit), replacing the almost-full ISR * that overflows on >250us CPU blackouts. Drop this * property to fall back to the ISR drain. */ dmas = <&dma2 4 30>; dma-names = "rxdma"; status = "okay"; #address-cells = < 0x1 >; #size-cells = < 0x0 >; t5838: t5838@53 { status = "okay"; compatible = "invensense,t5838-alif-pdm"; thsel-gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>, <&gpio5 2 GPIO_ACTIVE_HIGH>; wake-gpios = <&lpgpio 0 GPIO_ACTIVE_HIGH>; pdmclk-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>; reg = <0x53>; }; };

录音的DTS定义:

tps65132: tps65132@3e { compatible = "ti,tps65132"; reg = <0x3e>; vin-supply = <&cam_1v8>; supply-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; apps = "40ma"; veng: VENG { regulator-name = "veng"; regulator-init-microvolt = <4500000>; enable-gpios = <&gpio5 6 GPIO_ACTIVE_HIGH>; startup-delay-us = <5000>; status = "okay"; };

在这里,驱动把接口封装成zepyher的接口给上层使用。接口可以看Zephyr API Documentation: Audio

比如读取麦克风数据,alif_pdm_read(),就是封装成标准的zepyher接口dmic_read()供上层使用。但是在驱动中,也有一些也是HALO项目自己定义的。比如播放接口。max98357a_audio_write_impl。最后是封装成一个自己的接口audio_write()。

7.2 流抽象层

主要涉及的代码是audio_stream.c。封装了驱动,并且提供以下接口。

功能上层接口作用
扬声器播放audio_speaker_init()、audio_speaker_start()、audio_speaker_write()、audio_speaker_stop()、audio_speaker_destroy()初始化并控制播放会话、写入 PCM 数据、结束会话
播放控制与保护audio_speaker_set_volume()、audio_speaker_set_volume_transient()、audio_speaker_get_volume()、audio_speaker_set_stream_gain()、audio_speaker_set_stream_budget()、audio_speaker_notify_display_active()调节音量和每路增益、功耗预算,并根据显示状态调整音频保护
麦克风录音audio_microphone_init()、audio_microphone_start()、audio_microphone_read()、audio_microphone_free_buffer()、audio_microphone_stop()、audio_microphone_destroy()初始化录音、读取数据,并释放驱动交付的缓冲区
麦克风控制与资源管理audio_microphone_set_gain()、audio_microphone_get_gain()、audio_microphone_check_owner()、audio_microphone_read_owned()、audio_microphone_free_buffer_owned()控制增益;在指定资源拥有者的上下文中读取或释放数据
LC3 编解码audio_lc3_decoder_create()、audio_lc3_decode_frame()、audio_lc3_encoder_create()、audio_lc3_encode_frame(),以及对应的销毁和帧大小查询函数在 LC3 数据与 PCM 之间转换
音频活动检测audio_aad_set_callback()、audio_aad_rearm()、audio_aad_disable()、audio_aad_get_current_settings()注册音频活动检测回调、重新布防、禁用或查询设置
音频流源与接收端audio_stream_register_source()、audio_stream_source_read()、audio_stream_unregister_source();audio_stream_register_sink()、audio_stream_sink_write()、audio_stream_unregister_sink()用回调注册数据源和接收端,让不同组件通过统一的数据流接口交换音频

7.3 算法

Halo 的 AEC、EQ 等算法主要由 Halo 自己实现,放在音频模块或 MAX98357A 驱动里;Zephyr 提供设备与数据流接口,算法本身不是 Zephyr 通用音频 API。

处理主要实现位置实现方式与所在链路
AEC 回声消除modules/halo/src/audio_aec.c、modules/halo/include/halo/audio_aec.h默认使用分区块频域自适应滤波(FDAF);可配置为时域 NLMS。以扬声器输出作为参考,估算泄漏到麦克风的回声并从麦克风信号中扣除;还包括双讲检测、抑制滤波等机制。
AEC 接入录音链路modules/halo/src/lua_microphone.c麦克风数据经过audio_aec_process()后才进入后续编码。AEC 需要的扬声器参考信号则由 MAX98357A 驱动在发送路径上提供。
扬声器保护 DSP:HPF、音色 EQ、限幅drivers/audio/max98357a/speaker_protect.c、drivers/audio/max98357a/speaker_protect.h驱动在 PCM 播放路径中、音量处理之后应用保护链,包括高通滤波、分频和音色调整、能量限制、起播渐入及削波保护。配置MAX98357A_AUDIO_PROTECTION_EQ默认启用。
可选播放端 HPFmodules/halo/src/audio_eq.c、modules/halo/include/halo/audio_eq.haudio_speaker_write()可选地对 PCM 原地应用二阶或四阶 Butterworth 高通滤波。HALO_AUDIO_HPF默认关闭;Kconfig 说明 Halo 的扬声器保护主要由驱动里的 DSP 链负责。
录音端 DC 和语音频带处理modules/halo/src/lua_microphone.cAEC 之后还会做 DC 偏置抑制;语音模式下可再做带通处理,然后编码。

8 IMU子系统

对于系统来说,IMU包括了BMA580加速度计 + QMC6308磁力计。

驱动都在alif/drivers/sensor/,

这里是直接封装成zeypher的接口。接口描述是在Zephyr API Documentation: sensor_driver_api Struct Reference

在HALO项目中,IMU的数据全部都是上层控制读取,使用的接口是frame.imu.direction() / frame.imu.raw()。驱动或者下层不会去自动推送或者缓存。只有敲击手势,是产生中断,由imu_trigger_handler捕获。

数据模式频率归属MCU消耗
姿态 pitch/rollLua调用时拉取(现场I2C读)Lua想读多快读多快(≤~几十Hz现实上限)每次~几十µs I2C
磁场 raw同上,且QMC6308是现场触发转换同上每次含最长100ms DRDY等待(实际~几ms)
敲击手势中断推送(芯片检测→事件入环)事件频率(人类敲击速度)每次一个中断+一个字节搬运
原始804Hz样本流不存在(DATA_READY口子预留未用)芯片内部800Hz自转零(feature engine在芯片内消化)

9 Camera子系统

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 2:35:21

Ceph分布式存储深度解析-下篇

Ceph分布式存储深度解析&#xff1a;部署规划、运维调优与故障实战标签&#xff1a;Ceph运维、纠删码、cephadm、故障排查、性能调优前言 上篇看懂了Ceph架构与理论&#xff0c;理论再漂亮&#xff0c;最终要落地到生产环境。很多公司Ceph集群上线后卡顿、rebalance风暴、PG异常…

作者头像 李华
网站建设 2026/10/21 2:35:05

研究假设和数据结果对不上,往回查哪几个环节

跑完统计模型&#xff0c;发现系数方向与预设相左&#xff0c;或组间差异没有显现&#xff0c;不少研究生会在这里停住。与其推翻重来&#xff0c;不如沿「设计→测量→分析」这条回查轴倒着走一遍。知学术AIPaperGPT 的免费智能大纲能把回查清单先搭成骨架&#xff0c;免费科研…

作者头像 李华
网站建设 2026/10/21 2:35:02

混合研究设计里,定性和定量谁先谁后怎么定

"访谈做了十几场&#xff0c;问卷也收了三百多份&#xff0c;写方法章节时却卡住了&#xff1a;先讲哪一部分&#xff1f;"这类纠结在读研群体里很常见。混合研究设计的难点不在要不要用两种方法&#xff0c;而在顺序——定性定量谁在前、谁在后&#xff0c;直接决定…

作者头像 李华
网站建设 2026/10/21 2:35:01

为什么客户需求沟通后容易被遗漏?

很多人遇到过类似情况&#xff0c;沟通时觉得每句话都听清楚了&#xff0c;回到工位整理需求才发现&#xff0c;不少细节记不清&#xff0c;要么得反复找客户确认&#xff0c;要么到交付时才发现理解有偏差。沟通场景无辅助记录下的信息遗漏率最易被遗漏的信息类型1小时单客户面…

作者头像 李华
网站建设 2026/10/21 2:35:00

按能力出报告:SAST、组件、镜像、密钥和许可证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 2:34:56

CSI驱动开发实战:从信道状态信息采集到无线感知应用

1. 从“CSI驱动说明”说起&#xff1a;这个标题背后藏着什么第一次看到“CSI驱动说明”这个标题&#xff0c;很多人可能会愣一下——CSI不是那个犯罪现场调查的美剧吗&#xff1f;怎么跟驱动扯上关系了&#xff1f;其实在嵌入式和通信领域&#xff0c;CSI通常指Channel State I…

作者头像 李华