目录
1. 整体架构
处理部为 NXP i.MX 95。接触患者的测量部(患者岛)是隔离的,经数字隔离器(ISO7762)与处理部相连。处理部芯片构成(i.MX 95 · AFE159RP8 · AFE4490 · 第 2 阶段 RM44L920)为 已确定 规格,下面的内核分配为 默认值。
患者岛(隔离, CF) │ 非患者侧 (i.MX 95 SoM)
──────────────────────────────────────┼───────────────────────────────────────
AFE159RP8 (ECG 8ch, 电极 10, 起搏芯片内) ─ISO7762#1─ LPSPI-A ┐
AFE4490 (SpO2, PRF 500 Hz) ─ISO7762#2─ LPSPI-B ├─► Cortex-M7 800 MHz (FreeRTOS)
V1/V5 开关 · sim/signal 开关状态 ─(隔离 GPIO)────────┘ 采集·滤波·QRS·起搏·SpO2
(+选配) NIBP 模块 UART · Resp(AFE 内置) ·报警判定·报警音
│ 共享 DDR 环(波形) + RPMsg(命令·事件)
▼
Cortex-A55 ×6 (Linux, Yocto) 屏幕(Qt)·Holter·趋势·云·OTA·日志·权限
Cortex-M33 (NXP SM) 电源·时钟·复位·PMIC·故障响应(以 LM 为单位复位)
外部:TPS3430 窗口看门狗(由 M7 喂狗) → WDO → 备用蜂鸣器 + A55 GPIO [第 2 阶段] RM44L920 安全 MCU (SPI)
LTC1760 + 智能电池组 A/B (SMBus, 归 M7) · VSYS 欠压比较器 → M7 IRQ
内核分配原则三条 默认值
- 涉及患者安全的路径(采集 → 判定 → 报警音)由 M7 一颗内核闭环完成。 即使 Linux 崩溃,声音仍会响。
- Linux 只负责「显示·存储·发送」。 Linux 停止时,M7 会察觉并发出高优先级「显示故障」报警。
- M7 停止时,System Manager(SM)只复位 M7,在此期间 TPS3430 鸣响备用蜂鸣器,A55 将波形变为灰色。
2. 内核分配与 M33
设计审查中改变的一点 — M33 上不能放监视·报警备份。 i.MX 95 的 M33 是 NXP System Manager 专用内核。NXP imx-sm 文档(sm/doc/arch.md)原文:
- 「SM owns the M33 core and does not support customers adding workloads to this core.」
- 「the Cortex-M33 is not available to run customer applications. … additional customer functionality may interfere with the real-time response of the SM.」
因此 默认值 定为如下。M33 保持 NXP SM 原样(不改代码,只改配置文件),将 SM 的故障响应(FCCU·看门狗 → 只复位相应 LM)用作「第 1 层硬件监视」。SM 配置中已包含 M7_LOCKUP → M7(LM1) 复位、WDOG3/WDOG4 → AP(LM2) 复位 响应。监视·报警备份为 第 1 阶段:M7 ↔ A55 互相监视 + 外部窗口看门狗 TPS3430 + 备用蜂鸣器,第 2 阶段:由 RM44L920 接管。
各内核职责 默认值
| 内核 | OS | 职责 |
|---|---|---|
| M7 (800 MHz,SoM 供应商标称) | FreeRTOS + MCUXpresso SDK + RPMsg-Lite (备选方案 Zephyr) | AFE159RP8·AFE4490 采集,公共时间轴,起搏检测,抽取,双重自适应陷波,HPF/LPF,QRS·HR,SpO2·PR·PI,(选配) 呼吸·NIBP,报警条件判定·优先级·报警音合成,导联脱落·传感器脱落,电源监视(LTC1760·电池组·VSYS),外部看门狗喂狗,A55 监视 |
| M33 | NXP SM (裸机,无自有代码) | 电源·时钟·复位·PMIC,TRDC 资源隔离,FCCU 故障响应,复位原因记录 |
| A55 ×6 | Linux (NXP 供应商内核) | Qt 6 屏幕,Holter 记录,趋势 DB,报警显示·操作·日志,设置·权限,云同步,OTA·USB 更新,服务模式,安全 |
| RM44L920 (第 2 阶段) | TI HALCoGen + 自研 (未定) | 报警判定双重比对,备用报警音,外部看门狗管理,失效安全决策 |
资源归属 (由 SM 配置固定)
| 资源 | 归属 | 备注 |
|---|---|---|
| LPSPI ×2 (ECG·PPG 专用总线) | M7 | AFE4490 在未选中时不能进入三态,因此禁止共享总线 |
| DRDY·ADC_RDY 中断 GPIO,开关状态 GPIO | M7 | |
| 通用时间戳定时器 1 个 | M7 | ECG·PPG 公共时间轴 |
| SAI 或 PWM + 报警音放大器 | M7 | 必须与 Linux 无关地发出声音 |
| I²C(SMBus) → LTC1760·电池组 A/B | M7 | 因为电源报警由 M7 判定 |
| (选配) NIBP UART | M7 | M7 需要知道泵工作期间的 ECG 噪声标示 |
| WDOG5 | M7 (SM 故障响应) | WDOG5 → LM_RESET lm 1 |
| PMIC I²C,时钟,复位 | SM | |
| 显示(LVDS)·GPU·eMMC·USB·Wi-Fi/BT·GbE ×2·备用蜂鸣器 GPIO | A55 | |
| ELE(EdgeLock Secure Enclave) | 启动链·A55 |
资源预算 (计算·默认值)
| 项目 | 值 | 备注 |
|---|---|---|
| M7 ITCM / DTCM | 256 KB / 256 KB | 以 Zephyr dts 为准。NXP 参考手册原文 未确认 |
| M7 代码位置 | ITCM (DSP·ISR),大表放 DDR | 默认值 |
| M7 负载估算 | 8 kHz 中断(每次 ≤ 5 µs → 4 %) + 抽取 FIR 约 0.75 M MAC/s + 陷波·QRS(500 SPS) → 低于 10 % | 计算。计划用 DWT 周期计数器实测 |
| 共享 DDR 保留区 | 32 MiB (环约 23.2 MiB + 余量) | 计算 |
3. 采样率与信号路径
为什么是 8 kSPS
- IEC 60601-2-27 要求在 HR 计算中排除起搏脉冲。范围 ±2~±700 mV,0.1~2 ms (宽度下限取较宽一侧的 0.1 ms)
- TI ADS1298 数据手册:软件检测需要「8 kSPS or more」。论文数值 8 kHz Se 95.5 % · 16 kHz 97.1 % · 32 kHz 99.3 % (CinC 2018)
- AFE159RP8 芯片内有 4 导联起搏算法 + 128 kSPS 起搏输出。但公开版本为摘要版,判定输出格式·宽度·幅度范围 未确认
默认值 ECG 所有通道以 8 kSPS 24 位 采集。起搏采用 芯片内检测(第 1 级) + M7 软件检测(第 2 级确认)。若通过详细数据手册确认芯片内检测完全满足要求,再考虑降到 2 kSPS,在此之前固定为 8 kSPS。
M7 内部路径
AFE159RP8 8 kSPS × 8ch × 24bit ── DRDY ISR → LPSPI DMA ─┐
├─ ① 打时间戳 (通用定时器 32bit, 样本号 u64)
AFE4490 500 SPS × 6 流 ── ADC_RDY ISR → LPSPI ───────────┘
├─ ② 起搏:芯片标志 + 8 kSPS 斜率·宽度确认 → 事件 {样本号, 导联, 宽度}
├─ ③ 起搏消隐:在 8 kSPS 下用直线插值填补脉冲区间
├─ ④ 抽取 8000 → 2000 → 500 SPS (线性相位 FIR 2 级, ÷4·÷4)
│ 群延迟估算:31 抽头(8k) 1.9 ms + 63 抽头(2k) 15.5 ms ≈ 17.4 ms (计算)
├─ ⑤ 「原始数据」分支 → Holter 存储(500 SPS 24bit, 陷波前·HPF 前) + calib 行
├─ ⑥ HPF → 双重自适应陷波(60·120 Hz) → LPF (陷波前·后都保留 — 供比较画面用)
├─ ⑦ QRS 检测 (独立频带 5~15 Hz, 与陷波状态无关)
│ 起搏事件仅在「Paced=Yes」时才从 HR 中排除·打标记
└─ ⑧ PPG:500 SPS → 5 样本平均 100 SPS → 带通滤波 → R·SpO2·PR·PI。1 秒周期
降到 500 SPS 的原因:之前设计的双重陷波系数以 fs = 500 Hz 为基准,可以直接沿用。消隐长度和 FIR 抽头数在信号处理设计中通过实测确定。
通道分配 默认值
| AFE 通道 | 基本 5 电极 | 12 导联选配 |
|---|---|---|
| CH1 | I (LA−RA) | I |
| CH2 | II (LL−RA) | II |
| CH3 | III (LL−LA) 直接 已确定 | V1 |
| CH4 | V (V1/V5 开关) | V2 |
| CH5~8 | 自诊断轮询(内部测试信号 → calib 行,电源·温度) | V3~V6 |
显示用降采样
- 每列(px)用 min/max 竖线绘制,保留 QRS 顶点。禁止简单抽点
- PPG 100 SPS 采用相邻样本线性插值
- 屏幕行顺序为 6 行固定:calib · lead1 · lead2 · lead3 · SpO2 · pulse 已确定。V 导联(V1/V5)在屏幕上的位置未定,但始终计入记录
4. 内核间通信 — 共享内存环 + RPMsg
| 路径 | 内容 | 理由 |
|---|---|---|
| 共享 DDR 环 (SPSC,M7 写·A55 读) | 波形(原始数据·处理后·PPG)·心搏/起搏事件 | 数据量大(每秒数十 kB)。零拷贝。A55 每个 vsync 轮询写索引 → 延迟 ≤ 1 帧 |
| RPMsg | 命令·设置·报警状态·数值·心跳 | 以消息为单位·保证顺序。Linux 默认缓冲区 512 B |
RPMsg 公共头 (24 B,小端) 默认值
| 字段 | 类型 | 说明 |
|---|---|---|
| magic | u16 | 0xEC61 |
| ver | u8 | 协议版本 (在 HELLO 中比对,不同则为设备故障) |
| type | u8 | 消息类型 |
| len | u16 | 正文长度 (≤ 472 B = 512 − RPMsg 头 16 − 24) |
| flags | u16 | bit0 要求应答,bit1 重发 |
| seq | u32 | 发送方序列号。检测丢失·乱序 |
| t_idx | u64 | 以 500 SPS 为基准的全局样本号 (公共时间轴) |
| crc | u32 | CRC-32C (crc 字段置 0,对头+正文计算) |
端点 2 个:ekg-ctrl (A55 → M7 命令,M7 应答) · ekg-evt (M7 → A55 事件·状态)。
主要消息 默认值
| type | 名称 | 方向 · 周期 | 要点 |
|---|---|---|---|
| 0x01/0x02 | HELLO / HELLO_ACK | 启动时 | M7 固件版本·协议版本·环布局表 ↔ 发布版本号。不同则高优先级「软件不一致」 |
| 0x10 | HB_M7 | M7→A55 10 Hz | 运行时间,设备状态,环写索引,CPU 负载,样本丢失数,陷波状态 |
| 0x11 | HB_UI | A55→M7 10 Hz | 实际翻转的帧计数器,当前屏幕上显示的报警 ID 列表 |
| 0x20~0x22 | CFG_SET / ACK / SNAPSHOT | 请求·应答·1 分钟 | 发送安全设置并回读已生效的值进行确认。超出允许范围则拒绝 |
| 0x30~0x32 | ALARM_STATE / CMD / CMD_ACK | 变化时立即 + 1 Hz | 判定在 M7。A55 只做暂停(默认 2 分钟)·确认·解除闭锁操作 |
| 0x40 | NUMERICS | 1 Hz | HR(来源 ECG/PPG/SIM),PR,SpO2(「参考值·未校准」标志),PI,各参数有效/无效 |
| 0x50~0x52 | DEVICE_STATE · POWER_STATUS · SELFTEST | 变化时 · 1 Hz · POST | 设备状态,电池组 A/B 剩余电量·温度·SOH,自检结果 |
| 0x60 | LEAD_STATUS | 变化时 | 各电极导联脱落,V1/V5 开关位置,sim/signal 位置,SpO2 传感器状态 |
| 0x70 · 0x80/0x81 | FAULT · SHUTDOWN_REQ/READY | 发生时 | 故障代码 · 关机前确认 Holter 文件已关闭 |
| 0x90 | SERVICE_CMD | 仅服务模式 | 测量模式下拒绝 |
| 0xA0 | TIME_SYNC | 1 分钟 | UTC ↔ t_idx 对应 (用于记录。报警判定只用 t_idx) |
共享内存环 (计算·默认值)
所有环长度均为 2 的幂,索引为全局样本号 u64 掩码。M7 写完数据后 内存屏障 → 更新写索引。每个块(20 ms = 10 样本)附 CRC-32C。
| 环 | 格式 | 长度 | 大小 | 用途 |
|---|---|---|---|---|
| R_RAW | int32 × 8ch,500 SPS (陷波前·HPF 前) | 2¹⁹ = 17.5 分钟 | 16 MiB | Holter·calib。在 Linux 重新启动期间保住记录 |
| R_PRE / R_POST | float32 × 8ch × 2 | 2¹⁶ = 131 s | 4 MiB | 屏幕,陷波比较画面,冻结 |
| R_PPG | {red, ir int32, pleth float},100 SPS | 2¹⁷ = 21.8 分钟 | 2.5 MiB | 第 5·6 行,Holter |
| R_EVT | 32 B 事件 | 2¹⁴ | 512 KiB | 心形图标同步,注释 |
| 控制块 | 布局表·写索引·覆盖计数器 | — | 4 KiB | |
| 合计 | 约 23.2 MiB → 保留 32 MiB |
保留区为 non-cacheable。仅 A55 复位时该 DDR 区域是否保持原样 未确认 — 实测项目 S-01。
5. 延迟预算
电极 → 屏幕 (计算·默认值)
| 阶段 | 延迟 |
|---|---|
| AFE159RP8 内部数字滤波器 | 未确认 |
| 抽取 FIR 2 级 | ≈ 17.4 ms |
| M7 块处理 (20 ms 块) | ≤ 20 ms |
| 共享环 → A55 轮询 | ≤ 16.7 ms |
| 固定显示延迟 D (吸收 QRS 检测延迟,心形图标同步) | 初始值 300 ms |
| 渲染 + 页面翻转 (双缓冲 2 帧) | ≤ 33 ms |
| 合计 | 约 390 ms + AFE 延迟 |
报警 默认值
| 路径 | 预算 |
|---|---|
| 心率上·下限,心搏停止 (条件延迟 + 信号生成延迟) | 合计 ≤ 10 s (条件判定 ≤ 8 s + 声音开始 ≤ 1 s + 余量) — 主动采用对家用不适用的 IEC 60601-2-27 标准 |
| 导联脱落·饱和显示 | ≤ 1 s (标准 ≤ 10 s) |
| SpO2 更新停止 | > 30 s 则低优先级 |
| 电池耗尽 | 剩余 20 分钟时高优先级 (标准「至少提前 5 分钟」) |
| M7 判定 → A55 屏幕显示 | ≤ 50 ms |
| M7 判定 → 云·监护人通知 | 尽力而为(无保证) — 不算作报警系统的一部分 |
6. Holter 存储 · 趋势
原则
- 设备内记录为正本,云端为副本
- 存储信号为 陷波·HPF 前的原始数据(500 SPS 24 位)。查看时再施加滤波 → 可以重新分析
- 基本 5 电极 4 通道每天 518.4 MB,12 导联 8 通道每天 1.04 GB (计算) → eMMC pSLC 32 GB 以上
1 秒块 默认值
固定大小槽位:4 通道 8 KiB,8 通道 16 KiB (eMMC 4 KiB 对齐)。预先分配 1 小时 = 3600 个槽位的分段文件,使写入期间文件元数据不变。
| 位置 | 字段 | 大小 |
|---|---|---|
| 头部 | magic 'EKGB',格式版本,会话 UUID,块序列号,首个样本号,UTC + 单调时间,采样率(500),通道数·映射·刻度,滤波设置副本,陷波状态,标志(SIM·导联脱落·Paced·充电中) | 128 B |
| ECG | 500 × N 通道 × 3 B (24 位打包) | 6,000 B (4ch) / 12,000 B (8ch) |
| PPG | 100 × 2 × 3 B (red·IR) | 600 B |
| 趋势 | 这 1 秒的 HR·PR·SpO2·PI·(RR·NIBP) + 有效标志 | 32 B |
| 注释 TLV | 心搏(类型「仅供参考」),起搏时刻(8 kSPS 分辨率),导联变化,V1/V5 切换,报警开始·结束,患者按钮,时间校正 | 可变 |
| 尾部 | CRC-32C + 包含前一块 SHA-256 的哈希链 | 36 B |
- 起搏不高速存储原始波形,只记录时刻 (若存 128 kSPS 原始波形,每天约 88 GB)
- 写入:每 1 秒
pwrite1 个槽位 +fdatasync。写线程不与渲染线程共享锁 - 文件系统:默认 ext4
data=ordered+ 预分配 + 每块 fdatasync,F2FS 作为备选。最终选择依据反复强制断电后的哈希链检查 - 丢失量:仅在两组电池同时断开的突然断电时 ≤ 1~2 秒。正常关机路径下为 0
- 启动时恢复:从末尾开始检查最后一个分段的 CRC·哈希链 → 损坏的尾部标记为「未记录」+「记录中断」注释。不填补中断区间
- 导出:默认 EDF+/BDF(24 位) 或 WFDB-FLAC,兼容用 ISHNE·DICOM Ambulatory(16 位)。正本块保持原样
趋势 DB 默认值
- 正本是 Holter 块内的 1 秒趋势记录。DB 损坏也可从块重建
- 查询用 SQLite (WAL, synchronous=FULL) — 1 秒表 + 1 分钟·5 分钟·1 小时汇总表
- 保存 1 年 (5~6 个参数 1 秒 2 B → 315~378 MB,计算)。窗口 30 min ~ 7 天
- 源自 SpO2 的指标标注「参考值·未校准」
7. 报警引擎 (IEC 60601-1-8 优先级)
- M7
AlarmCore:条件判定,优先级,闭锁,暂停定时器,报警音合成。若未收到设置,则按编译内置的默认限值运行 - A55
AlarmUI:视觉信号(颜色·闪烁·文字),操作,报警日志,远程辅助通知。不做判定 - 视觉比对:M7 接收 HB_UI 中的「已显示报警 ID 列表」,若有效报警超过 2 s 未出现在屏幕上,则判为「显示故障」(高)
- 第 2 阶段:RM44L920 用相同输入独立判定,并与 M7 结果比对
优先级·信号 默认值
| 项目 | 高 | 中 | 低 |
|---|---|---|---|
| 颜色 | #FF0000 填充 | 黄色填充 + 黑色文字 | 青绿色填充 + 黑色文字 |
| 闪烁 | 维持现行 1 Hz (标准原文确认前) | 相同 | 无 |
| 声音 | 10 脉冲突发 | 3 脉冲 | 1~2 脉冲 |
- 声音频率:主能量 500~1000 Hz,扬声器 + 合成波形 (考虑老年性听力损失,不单独使用 4 kHz 压电)
- 暂停默认 2 分钟,结束后自动恢复。技术报警非闭锁,生理报警按设置(默认闭锁)
- 不只靠颜色区分:填充 + 文字 + 图标 + 闪烁 + 声音
报警列表 (摘录) 默认值
| 类别 | 报警 | 优先级 |
|---|---|---|
| 生理 | HR 上·下限 (默认 50~120,调整步长 ≤ 5 bpm) | 中 |
| 生理 | 心搏停止 | 高 |
| 生理 | SpO2 下限 (默认 90 %,禁止默认值低于 85 %) — 同时显示「参考值·未校准」 | 中 |
| 生理 | PR 上·下限 (默认 50~120) | 中 |
| 技术 | 导联脱落(显示电极名称) · 放大器饱和 · SpO2 传感器脱落 | 中 |
| 技术 | AC 断开(进入停电模式) · SOC 10 % · Holter 记录失败 | 中 |
| 技术 | 剩余时间 ≤ 20 分钟 · 设备故障 · 显示故障(A55 停止) | 高 |
| 技术 | SpO2 更新停止 > 30 s · 存储空间 90 % · 云连接断开 | 低 |
| 信息 | SIMULATION(全屏) · 充电中无法测量 · AC 恢复 | — |
心律失常分类结果不用于报警,仅供记录·参考。
8. 状态机
三个维度叠加:设备状态(S) × 各参数信号有效性 × 电源状态(P)。
设备状态 默认值
| 状态 | 进入条件 | 屏幕 | 声音 |
|---|---|---|---|
| BOOT/POST | 开机,M7 启动 | 白色启动画面 + 进度 | POST 结束时短促自检发声 1 次 |
| S0 正常 | POST 通过 | 6 行波形·数值 | 生理报警时 |
| S1 信号无效 (按参数) | 导联脱落·传感器脱落·饱和·NaN·自诊断偏离·环数据中断 0.5 s | 相应行显示虚线/灰色,数值「---」(不保留上次的值) | 技术报警 中/低 |
| S2 设备故障 | POST 失败,看门狗复位记录,AFE 通信中断,版本不一致,心跳丢失 | 「设备故障 — 无法测量」全屏 | 高 (M7 扬声器或备用蜂鸣器) |
| S3 安全停止 | 患者岛电源异常,电路板过热,剩余时间 ≤ 5 分钟 | 「测量停止」+ 原因 | 高 |
| SERVICE | 未连接患者 + 服务权限 | 服务画面 | — |
两条原则:不显示冻结的正常波形 · 即使主处理部崩溃,报警音依然存活。
电源状态 默认值
| 状态 | 条件 | 动作 |
|---|---|---|
| P0 AC | 有 AC | 充电。充电中测量遵循两级解除规则 — 第 1 级期间显示「充电中无法测量」+ 硬件联锁 |
| P1 停电模式 | AC 断开 | 中优先级报警 1 次,背光 30 %,DVFS,延长上传间隔。测量·记录·报警照常 |
| P2 电量不足 | 剩余 ≤ 20 分钟 | 高优先级,Holter 维持 1 s 周期,停止上传 |
| P3 关机序列 | 剩余 ≤ 5 分钟或电芯阈值 | M7 → SHUTDOWN_REQ → A55 关闭 Holter·fsync·日志 → SHUTDOWN_READY → 关闭岛电源 → 依次关闭背光·面板·SoM |
| P4 突然断电 | VSYS 比较器 | 中止写入。丢失 ≤ 1~2 s |
9. 启动自检 (POST) · 周期性测试
| 顺序 | 项目 | 负责 | 失败时 |
|---|---|---|---|
| 1 | AHAB 签名验证链 (ROM → 容器) | ELE / ROM | 不启动 |
| 2 | 读取 SM 复位原因 — 之前是否有看门狗·故障 | A55 | 日志 |
| 3 | M7 自身:TCM 代码 CRC,RAM 模式,时钟比对(通用定时器 vs AFE DRDY 周期) | M7 | S2 |
| 4 | AFE159RP8:芯片 ID,内部测试信号,输入短路噪声,电源·温度,导联脱落比较器 (功能列表 未确认) | M7 | S2 |
| 5 | AFE4490:SPI 写读比对,ADC_RDY = PRF,LED·PD 诊断 | M7 | S2 |
| 6 | 电池组 A/B 状态·SOH,LTC1760 状态 | M7 | 按报警等级 |
| 7 | 报警音短促 1 次 | M7 | S2 |
| 8 | DDR 内联 ECC,eMMC 寿命寄存器,数据分区挂载·Holter 恢复 | A55 | 按报警等级 |
| 9 | 设置 CRC,M7 ↔ A55 发布版本号比对 | A55·M7 | S2 |
| 10 | 备用蜂鸣器路径 (仅在服务模式) | — | — |
周期性测试 (测量中):calib 行 = 内部测试信号兼作连续自诊断,幅度超出 ±2 % 则判为「AFE 增益异常」。电源·温度每隔数秒轮询空闲通道。
10. 云 · 安全 · 更新
云 — 离线存储后同步 默认值
- 先积存在发件箱(SQLite 队列),连接后从积压最早的开始按顺序发送
- 实时通道:MQTT 5 QoS1,TLS 1.3 双向认证 — 只发状态·事件·1 分钟趋势·报警 (因消息大小限制不发送波形)
- 波形:1 小时分段文件断点续传上传。服务器确认哈希链后返回「接收确认」
- 删除:只删除已确认接收的,且在 14 天之后。未确认部分绝不自动删除
- 设备认证:每台设备 X.509,私钥存于安全芯片。服务器位于国内区域,首次设置时显示健康信息单独同意画面
- 监护人应用通知是不算作报警系统一部分的辅助通知。主机的声音·屏幕为第一位
- 防火墙:入站连接为 0。服务用本地端口仅在服务模式下开放
启动链 (AHAB)
Boot ROM ─(ELE 验证)─► 启动容器 [SM(M33) · U-Boot SPL · ATF · OP-TEE · U-Boot]
U-Boot ─(AHAB 认证)─► M7 固件容器 (位于 A/B 槽内) → M7 启动 → 开始采集
U-Boot ─(签名 FIT)──► 内核 + DTB + initramfs (A/B 槽) → rootfs dm-verity
将 M7 固件放在 A/B 槽中,与 Linux 作为一个包一起更新·一起回滚。代价是 M7 启动推迟到 U-Boot 阶段(数秒,计划实测)。i.MX 95 用 AHAB 签名流程·回滚计数器 未确认。
OTA (RAUC A/B,必须签名) 默认值
- 更新包 = rootfs + 内核 FIT + M7 固件 + 设置迁移脚本 = 1 个发布版本号
- 安装条件:未连接患者(全部电极导联脱落 + SpO2 传感器脱落) + 已连接 AC + Holter 会话已关闭 + 有权限人员确认。 测量中只下载
- 健康检查:新槽位启动 → POST 通过 + M7 HELLO 版本一致 + UI 首帧 → 标记为 good。失败 3 次 → 回到上一个槽位
- USB 离线更新也使用同样的签名更新包。签名验证之前不执行任何内容
- 数据保护:/data 加密,DDR 内联加密,通信 TLS 1.3
用户权限 默认值
| 角色 | 可执行操作 | 认证 |
|---|---|---|
| 用户 | 查看,事件按钮,声音暂停(2 分钟),亮度 | 无 |
| 监护人 | + 记录开始·停止,远程通知连接,导出 | PIN |
| 医护人员 | + 报警限值·延迟,滤波模式,Paced 设置,开启选配 | PIN |
| 服务 | + 服务模式,日志导出,更新,自诊断 | PIN + 已签名的服务令牌 |
| 制造 | 序列号·密钥注入·校准值写入 → 出厂后锁定 | 工厂专用 |
安全设置(报警限值·最小音量·Paced)须在 M7 完成 CFG_SET → 回读确认后才算「已生效」。M7 按最后确认的值持续运行。
11. 软件等级划分 (IEC 62304) · 模块
| 软件项 | 等级 (默认值) | 划分依据 |
|---|---|---|
| M7:采集·滤波·QRS·起搏·SpO2·AlarmCore·报警音·电源监视·A55 监视 | C | 直接关系到危害的判定在这里 |
| A55:波形·数值显示(Qt) | B | M7 监视帧计数器·已显示报警列表 → 停止时由 M7 发出高优先级声音 |
| A55:AlarmUI | B | 判定·声音在 M7。暂停时间上限由 M7 强制 |
| A55:Holter·趋势·云·OTA·权限·日志 | B | 失败会以技术报警体现或回滚。与报警路径无关 |
| M33:NXP SM | SOUP | 内核隔离的硬件依据 |
| RM44L920 (第 2 阶段) | C |
划分依据:独立内核 + SM 的资源隔离(以 LM 为单位) + M7 不依赖 Linux 运行 + 外部窗口看门狗。该划分在标准上是否被认可需由检测机构判断,因此 未确认。
模块 (摘录)
| 模块 | 位置 | 输入 → 输出 |
|---|---|---|
acq_ecg · acq_ppg | M7 | AFE 中断·SPI → 8 kSPS 帧 / 500 SPS 6 流 + 时间戳 |
pace · decim · notch2 · filt | M7 | 8 kSPS → 起搏事件 · 500 SPS · 陷波状态 |
qrs · spo2 | M7 | 心搏事件·HR / SpO2·PR·PI·质量 |
power · alarm_core · supervisor | M7 | 电源状态 · 报警状态·报警音 · 看门狗喂狗·显示故障 |
ipc | M7·A55 | 环·RPMsg (由单一定义自动生成 C/C++/Python 头文件) |
ekg-ui · ekg-alarmui | A55 | 环·数值·报警状态 → 屏幕,HB_UI,报警操作 |
ekg-recorder · ekg-trend · ekg-sync | A55 | 1 秒块 · SQLite · MQTT·上传 |
ekg-config · ekg-update · ekg-service | A55 | CFG_SET·审计日志 · RAUC · 服务命令 |
信号处理代码(dsp/)用与硬件无关的 C 编写,也可在 PC 上构建,并通过回放公开心电数据库进行单元测试。即使更换 RTOS,代价也很小。
12. 开发顺序 · 实测清单 默认值
| 阶段 | 内容 | 视为完成的标准 |
|---|---|---|
| 0 (无电路板) | 协议定义,在 PC 上做信号处理 — 用记录波形·模拟器波形验证抽取·陷波·QRS·报警判定 | 输出检测性能数值,陷波测试,报警阶跃测试(80 → 40·120·0 bpm) |
| 1 | 直接从 i.MX 95 评估板开始。Yocto 基础镜像,SM 配置,M7 hello + RPMsg + 共享环 | HELLO/HB 往返,A55 强制复位实测 S-01 |
| 2 | 连接 AFE,8 kSPS 采集,Qt 6 行屏幕 | 样本丢失 0 (24 h),屏幕延迟实测 |
| 3 | AlarmCore + 报警音 + 状态机 + POST + 看门狗 | 故障注入(M7 停止·A55 停止·拔出 AFE 线) |
| 4 | Holter·趋势·电源联动 | 反复强制断电 → 哈希链丢失 ≤ 1~2 s |
| 5 | 安全:AHAB 签名,dm-verity,RAUC,USB 更新 | 拒绝错误签名,失败 3 次回滚 |
| 6 | 云(国内区域测试服务器) | 通信中断 1 周后按顺序恢复,不删除未确认部分 |
| 7 | 选配(12 导联·呼吸·NIBP),RM44L920 联动 | 双重判定比对 |
| 实测 ID | 内容 |
|---|---|
| S-01 | A55 复位时共享 DDR·M7 是否继续工作,Linux 重启时间 |
| S-02 | M7 复位后重启时间 (期间记录中断的长度) |
| S-03 | M7 负载,8 kHz 中断抖动 |
| S-04 | 电极 → 屏幕延迟,AFE159RP8 滤波器延迟 |
| S-05 | ext4 vs F2FS 断电测试,eMMC Reliable Write 行为 |
| S-06 | 从 U-Boot 到 M7 启动的时间 |
未决定事项:12 导联选配时 lead III 的处理(计算或 2 颗 AFE),V1/V5 波形在屏幕上的位置。
13. 试验台固件 — ESP32-S3 + ADS1293 + 心率·血氧模块
这是与本产品(AFE159RP8 · AFE4490 · i.MX 95)不同的试验台专用构成。目的是先用市售模块确认信号路径·帧·接收画面。
接线 (ESP32-S3 N16R8)
| 信号 | ESP32-S3 | 备注 |
|---|---|---|
| ADS1293 SCLK / SDI / SDO / CSB | GPIO 12 / 11 / 13 / 10 | HSPI 总线 (与 2.0" 屏幕用总线·引脚分开) |
| ADS1293 DRDYB | GPIO 2 | 下降沿中断,内部上拉 |
| ADS1293 ALARMB | GPIO 1 (可选) | 仅在状态行显示 |
| MAX30102 SDA / SCL | GPIO 8 / 9 | 400 kHz,不使用 INT · 10 ms 轮询 |
| 电源 | 3V3 · GND | 禁止给 ADS1293 模块接 5 V — VDDIO 最大 3.6 V |
避开的引脚:4·5·6·7·15(2.0" 屏幕) · 19·20(USB) · 43·44(UART0) · 26~32(闪存) · 33~37(OPI PSRAM) · 0·3·45·46(启动配置引脚) · 38·48(视电路板而定为 RGB LED)。
ADS1293 — lead I·II·III 全部直接测量
| 通道 | + | − | 导联 | FLEX 值 |
|---|---|---|---|---|
| CH1 | LA (IN2) | RA (IN1) | I | 0x11 (与数据手册示例相同) |
| CH2 | LL (IN3) | RA (IN1) | II | 0x19 (与示例相同) |
| CH3 | LL (IN3) | LA (IN2) | III (直接) | 0x1A — 示例中关闭 CH3,以 III = II − I 计算 |
电极分配默认:RA→IN1,LA→IN2,LL→IN3,RL←IN4(RLD 输出)。由于模块插孔接线未确认,可用命令 e 更改 IN 编号。
主要寄存器
| 地址 | 值 | 含义 |
|---|---|---|
| 0x06 · 0x07 · 0x08 | 0x00 · 0x07 · 0x01 | 开启 DC 导联脱落,向 IN1~3 注入电流,8 nA。比较基准 VDD − 0.5 V。若没有 RL 回路,全部显示「脱落」属正常 |
| 0x0A · 0x0B · 0x0C | 0x07 · 0x00 · 0x04 | 共模 = RA·LA·LL 平均 → RLD 输出 → IN4(RL) |
| 0x11 · 0x13 · 0x14 | 0x00 · 0x07 · 0x00 | 内部 2.4 V 基准,三个通道高分辨率,全部开启 |
| 0x27 · 0x2F | 0x08 · 0x71 | DRDYB = CH1 ECG,流式输出 = 状态 + 3 通道 (1+9 字节) |
| 0x12 · 0x00 | 0x04 · 0x01 | 外部 4.096 MHz 晶振 → 数字部分,等待 15 ms 后开始转换。模块上是否有晶振 未确认 — 若没有,固件每 1 秒发出警告 |
RL 脱落无法通过导联脱落检测到,因此另行输出 RLD 输出是否接近电源轨(RLDRAIL)。错误寄存器每 32 个样本读取一次,或在 ALARMB 位置位时立即读取。
采样率 (数据手册表 8,SDM 102.4 kHz,R1 = 4)
| 命令 | ODR | 带宽 | ADCMAX | 噪声 (µV rms,表中值) | 1 LSB | 每 1 mV 码值 |
|---|---|---|---|---|---|---|
r 533 默认 | 533.33 Hz | 105 Hz | 0xF30000 | 2.07 | 0.0861 µV | 11,612 |
r 853 | 853.33 Hz | 175 Hz | 0xB964F0 | 2.67 | 0.1129 µV | 8,859 |
r 400 | 400 Hz | 80 Hz | 0x800000 | 1.81 | 0.1635 µV | 6,117 |
以 533 为默认是因为它最接近以 500 SPS 为基准的陷波设计(陷波系数需按 533.33 Hz 重新计算)。覆盖诊断带宽 150 Hz 的只有 853,监护带宽 40 Hz 三者都能覆盖。输入范围为 INA 差分 ±400 mV。
内置测试信号
| 命令 | 信号 | 期望码值 (533 模式) |
|---|---|---|
t + | +VTEST = VREF/12 = +200 mV DC | 10,285,056 |
t - | −200 mV DC | 5,640,192 |
t 0 | 输入短路 (噪声测量) | 7,962,624 (= ADCMAX/2) |
t x | 关闭 (电极) | — |
VTEST 与 VREF 来自同一基准,因此不是增益校准,而是用于自检·确认通道间增益差。1 mV 校准信号(calib)由外部电池模拟器承担。
心率·血氧模块 (推测为 MAX30102,I2C 0x57)
- 仅在 PART_ID 为 0x15 时使用,否则视为「无」并输出合成脉搏波 (芯片是否为 MAX30102 未确认)
- SpO2 模式(红光+IR),100 sps,18 位,每样本 6 字节。寄存器值以公开库定义为准,与原文数据手册的比对 未确认
- 不输出 SpO2 数值。 没有校准曲线。接收画面仅以「参考」显示 R 比值
- 这是反射式模块,仅用于波形路径测试。本产品为夹式透射探头 + AFE4490
串口协议
533 SPS × 16 B + 100 × 12 B ≈ 9.7 kB/s (853 SPS 时为 14.9 kB/s)。二进制帧 + 以 # 开头的文本行(信息·1 秒状态·警告),也有 CSV 模式。
ECG 帧 16 B : A5 5A 'E' seq(u16 LE) CH1 CH2 CH3(u24, MSB 在前) flags crc8
PPG 帧 12 B : A5 5A 'P' seq(u16 LE) RED IR(u24) crc8
crc8 = 多项式 0x07, 初值 0, 从 'E'/'P' 到 flags
flags: 1 RA 脱落 · 2 LA 脱落 · 4 LL 脱落 · 8 RLD 电源轨 · 16 共模超范围
32 输入超范围 · 64 合成 · 128 测试信号
CRC 计算部分摘录(固件与 PC 测试代码使用同一头文件):
static inline uint8_t ekg_crc8(const uint8_t *p, size_t n) { // 多项式 0x07, 初值 0
uint8_t c = 0;
for (size_t i = 0; i < n; i++) {
c ^= p[i];
for (int b = 0; b < 8; b++) c = (c & 0x80) ? (uint8_t)((c << 1) ^ 0x07) : (uint8_t)(c << 1);
}
return c;
}
码值 → 电压转换采用数据手册式 13:V = (ADC_OUT/ADCMAX − ½)·2·VREF/3.5。
| 命令 | 含义 |
|---|---|
m a / m s | ADS1293 实测 / 合成 (无模块时自动切换为合成) |
o b / o c | 二进制 / CSV |
r 533 · r 853 · r 400 | 采样率 |
t + · t - · t 0 · t x | 内置测试信号 |
e 1 2 3 4 | RA LA LL RL 的 IN 编号 |
l 1 · g 1 / g 0 | 导联脱落电流 ×8 nA (0 = 关) · RLD 开/关 |
h 72 · n 50 · w 2 · c 1 | 合成:心率 · 60 Hz 注入 µV(RA 0 倍·LA 1 倍·LL 2 倍) · 白噪声 µV rms · calib 方波 |
d | ADS1293 寄存器转储 |
合成信号以与 ADS1293 相同的 ADC 码值形式输出,因此接收端无需区分实测与合成(只有 flags 64 不同)。合成模型将肢体电位设为 φRA=0,φLA=I,φLL=II,并以电位差重新计算导联,因此 III = II − I 按定义成立。电轴 50° 是合成用的任意值。
接收·显示脚本 (PC · 树莓派通用)
- 无损保存接收到的全部字节(raw) + ECG·PPG CSV + 日志
- 画面:白色背景,I · II · III · 残差 II−(I+III) · 脉搏波红光 · 脉搏波 IR。标题中显示心率(简单阈值法) · R 比值 · fs · 中断 · 报警
- 有将保存文件重新解开进行检查的回放·检查模式
安全 — 接触人体之前
本试验台没有隔离。模块 → ESP32 → USB → 计算机在电气上连成一体。
- 笔记本电脑只用电池供电。拔掉充电器
- 笔记本电脑上不要插其他线缆(HDMI 显示器、以太网、使用电源适配器的外置硬盘、音频)
- 使用适配器供电的树莓派 + 屏幕不用于人体电极测试 — 仅用于合成·短路·模拟器阶段
- 不要直接插在接地的台式机上并在身体上贴电极
- 贴电极期间不要接触金属桌·暖气片·水管
- 不要贴在潮湿皮肤·伤口上。电极为一次性,只用 1 次
- 不要给使用心脏起搏器·植入式器械的人贴电极
- 不要用本装置的波形·数值判断健康状况 — 这是试验台
- 不要给模块接入 5 V (VDDIO 最大 3.6 V)
测试顺序
| 阶段 | 内容 | 通过标准 |
|---|---|---|
| ① 合成 | 只将 ESP32 接 USB。不接模块,确认接收端全路径 (m s · n 50 · c 1) | 中断 0 · 残差 ≤ 2 LSB · 心率 72 · 60 Hz 幅度 I·III 相同,II 为其 2 倍 |
| ② 短路噪声 | 连接模块,不接电极。确认 REVID=0x01 后 t 0 10 秒 · t + · t -,接着在插孔处将四个电极接到一点并执行 t x | t 0 噪声 rms ≈ 表中值(533 模式 2.07 µV rms) · t ± 码值与期望值相同 · 无 DRDYB 警告 · 导联脱落位为 0 |
| ③ 模拟器 | 外部电池模拟器(1 V p-p → 1000:1 → 1 mV)。尚未制作 | 1 mV 测得 1 mV · 残差处于噪声水平(判定 III 直接测量成立) · 保存 60 Hz 陷波前/后原始数据 · 逐个拔下电极检查导联脱落响应 |
| ④ 人体电极 | 在遵守上述全部安全事项后,接 RA·LA·LL·RL 4 个 | 导联脱落 0 · RLD 电源轨 0 · 可见 QRS · 心率与手腕脉搏一致 · 记录 60 Hz 残留幅度 |
④ 之前必须经过 ②·③。若在 ② 中出现 DRDYB 警告(怀疑无晶振),就在此停止。
14. 试验台验证结果 (2026-10-11)
- 编译通过 2 种,试验台源码警告 0 条 (
--warnings all,arduino-cli 1.5.2-rc.1 · esp32 内核 3.3.12)- 基本 ESP32-S3 — 闪存 365,710 B (27 %) · RAM 24,336 B (7 %)
- 原生 USB CDC + OPI PSRAM + 16 MB — 366,348 B (27 %) · 25,016 B (7 %)
- 未进行电路板上传 (器件未到货)
- 帧交叉验证:在 PC 上编译与固件相同的头文件(帧·合成信号),生成 20 秒数据流,并用 Python 接收端解析
- ECG 10,666 帧中,准确丢弃了 1 个故意损坏 CRC 的帧(计为中断 1),PPG 2,000 帧丢失 0
- 即使混入含有 0xA5 0xA5 字节的韩文文本行,也不会失去同步
- 爱因托芬残差最大 0.086 µV = 1 LSB,rms 0.042 µV → 检查通过
- 另行确认了 CSV 路径(行解析·seq 中断·flags)
剩余未确认事项 (器件到货后确认)
- ADS1293 模块的电源构成(VDD·VDDIO),有无 4.096 MHz 晶振,插孔引脚分配,输入保护·RLD 器件值
- 将一个输入引脚同时接到 CH1 + 和 CH3 − 是否允许 (以残差判定)
- 传感器模块是否为 MAX30102,红光·IR 是否调换
- 与 MAX30102 原文数据手册比对
- ESP32-S3 板的 RGB LED 引脚,USB 端口方式
- 导联脱落 8 nA 在电缆电容下需要几秒做出响应
- 医疗标准中电极 DC 电流限值的数值