KOEN中HI

소프트웨어 구조 · 시험대

2026-10-11 설계 기록 · 처리부 NXP i.MX 95 · ECG AFE159RP8 · SpO2 AFE4490 · 부품 시험대 ESP32-S3 + ADS1293

표기: 확정 사양으로 확정된 항목 · 기본값 설계서가 정한 값(확정 아님) · 미확인 원문·실측으로 아직 확인하지 못한 값. 산수로 낸 값은 「계산」.

목차

  1. 전체 그림
  2. 코어 배치와 M33
  3. 샘플레이트와 신호 경로
  4. 코어 사이 통신 (공유 링 · RPMsg)
  5. 지연 예산
  6. 홀터 저장 · 트렌드
  7. 경보 엔진
  8. 상태기계
  9. 부팅 자가시험
  10. 클라우드 · 보안 · 업데이트
  11. 소프트웨어 등급 분리 · 모듈
  12. 개발 순서 · 실측 목록
  13. 시험대 펌웨어 (ESP32-S3 + ADS1293)
  14. 시험대 검증 결과

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)·홀터·트렌드·클라우드·OTA·로그·권한
                         Cortex-M33 (NXP SM)           전원·클록·리셋·PMIC·고장 반응(LM 단위 리셋)
 외부: TPS3430 윈도 워치독(M7 이 찬다) → WDO → 백업 부저 + A55 GPIO   [2단계] RM44L920 안전 MCU (SPI)
 LTC1760 + 스마트 팩 A/B (SMBus, M7 소유) · VSYS 저전압 비교기 → M7 IRQ

코어 배치 원칙 세 줄 기본값

  1. 환자 안전에 걸리는 경로(취득 → 판정 → 경보음)는 M7 하나로 닫는다. Linux 가 죽어도 소리는 난다.
  2. Linux 는 「보여주기·저장·보내기」만 한다. Linux 가 멈추면 M7 이 알아채고 고우선 「표시 고장」을 울린다.
  3. 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 (2안 Zephyr)AFE159RP8·AFE4490 취득, 공통 시간축, 페이스 검출, 데시메이션, 2중 적응형 노치, HPF/LPF, QRS·HR, SpO2·PR·PI, (옵션) 호흡·NIBP, 경보 조건 판정·우선순위·경보음 합성, 리드오프·센서오프, 전원 감시(LTC1760·팩·VSYS), 외부 워치독 차기, A55 감시
M33NXP SM (베어메탈, 자체 코드 없음)전원·클록·리셋·PMIC, TRDC 자원 격리, FCCU 고장 반응, 리셋 사유 기록
A55 ×6Linux (NXP 벤더 커널)Qt 6 화면, 홀터 기록, 트렌드 DB, 경보 표시·조작·로그, 설정·권한, 클라우드 동기화, OTA·USB 갱신, 서비스 모드, 보안
RM44L920 (2단계)TI HALCoGen + 자체 (미정)경보 판정 2중 대조, 백업 경보음, 외부 워치독 관리, 페일세이프 결정

자원 소유 (SM 설정으로 고정)

자원소유비고
LPSPI ×2 (ECG·PPG 전용 버스)M7AFE4490 은 비선택 때 3상태가 안 돼서 버스 공유 금지
DRDY·ADC_RDY 인터럽트 GPIO, 스위치 상태 GPIOM7
범용 타임스탬프 타이머 1개M7ECG·PPG 공통 시간축
SAI 또는 PWM + 경보음 앰프M7Linux 와 무관하게 소리가 나야 한다
I²C(SMBus) → LTC1760·팩 A/BM7전원 경보가 M7 판정이라서
(옵션) NIBP UARTM7펌프 동작 중 ECG 잡음 표시를 M7 이 알아야 한다
WDOG5M7 (SM 고장 반응)WDOG5 → LM_RESET lm 1
PMIC I²C, 클록, 리셋SM
디스플레이(LVDS)·GPU·eMMC·USB·Wi-Fi/BT·GbE ×2·백업 부저 GPIOA55
ELE(EdgeLock Secure Enclave)부트 체인·A55

자원 예산 (계산·기본값)

항목값비고
M7 ITCM / DTCM256 KB / 256 KBZephyr dts 기준. NXP 참조 매뉴얼 원문은 미확인
M7 코드 위치ITCM (DSP·ISR), 큰 표는 DDR기본값
M7 부하 추정8 kHz 인터럽트(1회 ≤ 5 µs → 4 %) + 데시메이션 FIR 약 0.75 M MAC/s + 노치·QRS(500 SPS) → 10 % 미만계산. DWT 사이클 카운터로 실측 예정
공유 DDR 예약 영역32 MiB (링 약 23.2 MiB + 여유)계산

3. 샘플레이트와 신호 경로

왜 8 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 (계산)
   ├─ ⑤ 「원자료」 분기 → 홀터 저장(500 SPS 24bit, 노치 전·HPF 전) + calib 행
   ├─ ⑥ HPF → 2중 적응형 노치(60·120 Hz) → LPF   (노치 전·후를 둘 다 남김 — 비교 화면용)
   ├─ ⑦ QRS 검출 (별도 대역 5~15 Hz, 노치 상태와 무관)
   │      페이스 사건은 「Paced=Yes」일 때만 HR 에서 제외·마커
   └─ ⑧ PPG: 500 SPS → 5표본 평균 100 SPS → 대역필터 → R·SpO2·PR·PI. 1초 주기

500 SPS 로 내리는 이유: 앞서 설계한 2중 노치 계수가 fs = 500 Hz 기준이라 그대로 쓸 수 있다. 블랭킹 길이와 FIR 탭 수는 신호처리 설계에서 실측으로 정한다.

채널 배정 기본값

AFE 채널기본 5전극12유도 옵션
CH1I (LA−RA)I
CH2II (LL−RA)II
CH3III (LL−LA) 직접 확정V1
CH4V (V1/V5 스위치)V2
CH5~8자가진단 순회(내부 시험 신호 → calib 행, 전원·온도)V3~V6
12유도 옵션과 「III 직접 측정」은 8채널에 동시에 들어가지 않는다(I·II·III·V1~V6 = 9채널). 12유도 때만 III 를 계산할지, AFE 를 둘로 할지는 미결정. 소프트웨어는 채널 맵을 설정 표로 받게 짜서 어느 쪽이든 코드 변경 없이 간다. CH5~8 자가진단 순회 기능이 AFE159RP8 에 있는지는 미확인.

표시용 다운샘플

4. 코어 사이 통신 — 공유 메모리 링 + RPMsg

경로무엇이유
공유 DDR 링 (SPSC, M7 쓰기·A55 읽기)파형(원자료·처리후·PPG)·박동/페이스 사건양이 많다(초당 수십 kB). 복사 0. A55 가 vsync 마다 쓰기 인덱스를 폴링 → 지연 ≤ 1프레임
RPMsg명령·설정·경보 상태·수치·하트비트메시지 단위·순서 보장. Linux 기본 버퍼 512 B

RPMsg 공통 머리 (24 B, 리틀엔디언) 기본값

필드형설명
magicu160xEC61
veru8프로토콜 판 (HELLO 에서 대조, 다르면 장치 고장)
typeu8메시지 종류
lenu16본문 길이 (≤ 472 B = 512 − RPMsg 머리 16 − 24)
flagsu16bit0 응답 요구, bit1 재전송
sequ32보내는 쪽 일련번호. 빠짐·역순 감지
t_idxu64500 SPS 기준 전역 표본번호 (공통 시간축)
crcu32CRC-32C (crc 칸 0 으로 두고 머리+본문)

엔드포인트 2개: ekg-ctrl (A55 → M7 명령, M7 응답) · ekg-evt (M7 → A55 사건·상태).

주요 메시지 기본값

type이름방향 · 주기핵심
0x01/0x02HELLO / HELLO_ACK기동 시M7 펌웨어 판·프로토콜 판·링 배치표 ↔ 릴리스 번호. 다르면 고우선 「소프트웨어 불일치」
0x10HB_M7M7→A55 10 Hz가동시간, 장치 상태, 링 쓰기 인덱스, CPU 부하, 표본 손실 수, 노치 상태
0x11HB_UIA55→M7 10 Hz실제로 플립된 프레임 카운터, 지금 화면에 띄운 경보 ID 목록
0x20~0x22CFG_SET / ACK / SNAPSHOT요청·응답·1분안전 설정을 보내고 적용된 값을 되읽어 확인. 허용 범위 밖이면 거부
0x30~0x32ALARM_STATE / CMD / CMD_ACK변경 즉시 + 1 Hz판정은 M7. A55 는 일시정지(기본 2분)·확인·래치 해제 조작만
0x40NUMERICS1 HzHR(출처 ECG/PPG/SIM), PR, SpO2(「참고값·미교정」 플래그), PI, 파라미터별 유효/무효
0x50~0x52DEVICE_STATE · POWER_STATUS · SELFTEST변경 시 · 1 Hz · POST장치 상태, 팩 A/B 잔량·온도·SOH, 자가시험 결과
0x60LEAD_STATUS변경 시전극별 리드오프, V1/V5 스위치 위치, sim/signal 위치, SpO2 센서 상태
0x70 · 0x80/0x81FAULT · SHUTDOWN_REQ/READY발생 시고장 코드 · 종료 전 홀터 파일 닫힘 확인
0x90SERVICE_CMD서비스 모드만측정 모드에서는 거부
0xA0TIME_SYNC1분UTC ↔ t_idx 대응 (기록용. 경보 판정은 t_idx 만 씀)

공유 메모리 링 (계산·기본값)

모든 링은 2의 거듭제곱 길이, 인덱스는 전역 표본번호 u64 마스킹. M7 은 데이터를 다 쓴 뒤 메모리 장벽 → 쓰기 인덱스 갱신. 블록(20 ms = 10 표본)마다 CRC-32C.

링형식길이크기용도
R_RAWint32 × 8ch, 500 SPS (노치 전·HPF 전)2¹⁹ = 17.5 분16 MiB홀터·calib. Linux 가 다시 뜨는 동안 기록을 붙잡는다
R_PRE / R_POSTfloat32 × 8ch × 22¹⁶ = 131 s4 MiB화면, 노치 비교 화면, 정지
R_PPG{red, ir int32, pleth float}, 100 SPS2¹⁷ = 21.8 분2.5 MiB5·6행, 홀터
R_EVT32 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. 홀터 저장 · 트렌드

원칙

1초 블록 기본값

고정 크기 슬롯: 4채널 8 KiB, 8채널 16 KiB (eMMC 4 KiB 정렬). 1시간 = 3600 슬롯짜리 세그먼트 파일을 미리 할당해 쓰는 동안 파일 메타데이터가 바뀌지 않게 한다.

위치필드크기
머리magic 'EKGB', 형식 판, 세션 UUID, 블록 일련번호, 첫 표본번호, UTC + 단조 시각, 표본화(500), 채널 수·맵·스케일, 필터 설정 사본, 노치 상태, 플래그(SIM·리드오프·Paced·충전 중)128 B
ECG500 × N채널 × 3 B (24비트 패킹)6,000 B (4ch) / 12,000 B (8ch)
PPG100 × 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

트렌드 DB 기본값

7. 경보 엔진 (IEC 60601-1-8 우선순위)

우선순위·신호 기본값

항목고중저
색#FF0000 채움노랑 채움 + 검정 글자청록 채움 + 검정 글자
깜박임현행 1 Hz 유지 (규격 원문 확인 전)같음없음
소리10펄스 버스트3펄스1~2펄스

경보 목록 (발췌) 기본값

종류경보우선순위
생리HR 상·하한 (기본 50~120, 조정 단계 ≤ 5 bpm)중
생리무수축고
생리SpO2 하한 (기본 90 %, 85 % 미만 기본값 금지) — 「참고값·미교정」 함께 표시중
생리PR 상·하한 (기본 50~120)중
기술리드오프(전극 이름 표시) · 증폭기 포화 · SpO2 센서 오프중
기술AC 끊김(정전 모드 진입) · SOC 10 % · 홀터 기록 실패중
기술남은 시간 ≤ 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 ACAC 있음충전. 충전 중 측정은 2단계 해제 규칙 — 1단계 동안은 「충전 중 측정 불가」 표시 + 하드웨어 연동
P1 정전 모드AC 끊김중우선 경보 1회, 백라이트 30 %, DVFS, 업로드 간격 늘림. 측정·기록·경보는 그대로
P2 부족남은 ≤ 20분고우선, 홀터 1 s 주기 유지, 업로드 중지
P3 종료 시퀀스남은 ≤ 5분 또는 셀 문턱M7 → SHUTDOWN_REQ → A55 홀터 닫기·fsync·로그 → SHUTDOWN_READY → 섬 전원 끔 → 백라이트·패널·SoM 순
P4 급정전VSYS 비교기쓰기 중단. 손실 ≤ 1~2 s

9. 부팅 자가시험 (POST) · 주기 시험

순서항목담당실패 시
1AHAB 서명 검증 체인 (ROM → 컨테이너)ELE / ROM부팅 안 함
2SM 리셋 사유 읽기 — 직전 워치독·고장 여부A55로그
3M7 자체: TCM 코드 CRC, RAM 패턴, 클록 대조(범용 타이머 vs AFE DRDY 주기)M7S2
4AFE159RP8: 칩 ID, 내부 시험 신호, 입력 단락 잡음, 전원·온도, 리드오프 비교기 (기능 목록 미확인)M7S2
5AFE4490: SPI 쓰고 읽기 대조, ADC_RDY = PRF, LED·PD 진단M7S2
6배터리 팩 A/B 상태·SOH, LTC1760 상태M7경보 등급대로
7경보음 짧게 1회M7S2
8DDR 인라인 ECC, eMMC 수명 레지스터, 데이터 파티션 마운트·홀터 복구A55경보 등급대로
9설정 CRC, M7 ↔ A55 릴리스 번호 대조A55·M7S2
10백업 부저 경로 (서비스 모드에서만)——

주기 시험 (측정 중): calib 행 = 내부 시험 신호를 연속 자가진단으로 겸용, 진폭이 ±2 % 밖이면 「AFE 이득 이상」. 전원·온도는 남는 채널을 수 초마다 순회.

10. 클라우드 · 보안 · 업데이트

클라우드 — 오프라인 저장 후 동기화 기본값

부트 체인 (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, 서명 필수) 기본값

사용자 권한 기본값

역할할 수 있는 것인증
사용자보기, 이벤트 버튼, 소리 일시정지(2분), 밝기없음
보호자+ 기록 시작·정지, 원격 알림 연결, 내보내기PIN
의료진+ 경보 한계·지연, 필터 모드, Paced 설정, 옵션 켜기PIN
서비스+ 서비스 모드, 로그 내보내기, 업데이트, 자가진단PIN + 서명된 서비스 토큰
제조시리얼·키 주입·교정값 기록 → 출하 후 잠금공장 전용

안전 설정(경보 한계·최소 음량·Paced)은 M7 에 CFG_SET → 되읽기 확인이 끝나야 「적용됨」. M7 은 확인된 마지막 값으로 계속 돈다.

11. 소프트웨어 등급 분리 (IEC 62304) · 모듈

소프트웨어 항목등급 (기본값)분리 근거
M7: 취득·필터·QRS·페이스·SpO2·AlarmCore·경보음·전원 감시·A55 감시C위해로 바로 이어지는 판정이 여기 있다
A55: 파형·수치 표시(Qt)BM7 이 프레임 카운터·띄운 경보 목록을 감시 → 멈추면 M7 이 고우선 소리
A55: AlarmUIB판정·소리는 M7. 일시정지 시간 상한은 M7 이 강제
A55: 홀터·트렌드·클라우드·OTA·권한·로그B실패는 기술 경보로 드러나거나 롤백. 경보 경로와 무관
M33: NXP SMSOUP코어 격리의 하드웨어 근거
RM44L920 (2단계)C

분리의 근거: 별개 코어 + SM 의 자원 격리(LM 단위) + M7 이 Linux 없이 돈다 + 외부 윈도 워치독. 이 분리가 규격상 인정되는지는 시험기관 판단이라 미확인.

모듈 (발췌)

모듈위치입력 → 출력
acq_ecg · acq_ppgM7AFE 인터럽트·SPI → 8 kSPS 프레임 / 500 SPS 6스트림 + 시각
pace · decim · notch2 · filtM78 kSPS → 페이스 사건 · 500 SPS · 노치 상태
qrs · spo2M7박동 사건·HR / SpO2·PR·PI·품질
power · alarm_core · supervisorM7전원 상태 · 경보 상태·경보음 · 워치독 차기·표시 고장
ipcM7·A55링·RPMsg (단일 정의에서 C/C++/파이썬 헤더 자동 생성)
ekg-ui · ekg-alarmuiA55링·수치·경보 상태 → 화면, HB_UI, 경보 조작
ekg-recorder · ekg-trend · ekg-syncA551초 블록 · SQLite · MQTT·업로드
ekg-config · ekg-update · ekg-serviceA55CFG_SET·감사 로그 · RAUC · 서비스 명령

신호처리 코드(dsp/)는 하드웨어와 무관한 C 로 두어 PC 에서도 빌드하고, 공개 심전도 데이터베이스 재생으로 단위 시험한다. RTOS 를 바꾸더라도 비용이 작다.

12. 개발 순서 · 실측 목록 기본값

단계내용끝났다고 보는 기준
0 (보드 없이)프로토콜 정의, 신호처리를 PC 에서 — 데시메이션·노치·QRS·경보 판정을 기록 파형·시뮬레이터 파형으로검출 성능 수치 출력, 노치 시험, 경보 계단 시험(80 → 40·120·0 bpm)
1i.MX 95 평가보드로 바로 시작. Yocto 기본 이미지, SM 설정, M7 hello + RPMsg + 공유 링HELLO/HB 왕복, A55 강제 리셋 실측 S-01
2AFE 연결, 8 kSPS 취득, Qt 6행 화면표본 손실 0 (24 h), 화면 지연 실측
3AlarmCore + 경보음 + 상태기계 + POST + 워치독결함 주입(M7 멈춤·A55 멈춤·AFE 선 뽑기)
4홀터·트렌드·전원 연동전원 강제 차단 반복 → 해시 체인 손실 ≤ 1~2 s
5보안: AHAB 서명, dm-verity, RAUC, USB 갱신잘못된 서명 거부, 3회 실패 롤백
6클라우드(국내 리전 시험 서버)통신 1주 끊김 후 순서대로 복구, 미확인분 안 지움
7옵션(12유도·호흡·NIBP), RM44L920 연동2중 판정 대조
실측 ID무엇
S-01A55 리셋 때 공유 DDR·M7 계속 동작 여부, Linux 재부팅 시간
S-02M7 리셋 후 재기동 시간 (그동안 기록 끊김 길이)
S-03M7 부하, 8 kHz 인터럽트 지터
S-04전극 → 화면 지연, AFE159RP8 필터 지연
S-05ext4 vs F2FS 전원 차단 시험, eMMC Reliable Write 동작
S-06U-Boot 에서 M7 기동까지 시간

미결정 항목: 12유도 옵션 때 lead III 처리(계산 또는 AFE 2개), V1/V5 파형의 화면 위치.

13. 시험대 펌웨어 — ESP32-S3 + ADS1293 + 심박·산소 모듈

본 제품(AFE159RP8 · AFE4490 · i.MX 95)과는 다른 시험대 전용 구성이다. 시중 모듈로 신호 경로·프레임·수신 화면을 먼저 확인하려는 목적이다.

상태(2026-10-11 기준): 부품 미도착. 컴파일만 통과, 보드 업로드·실측은 0건. 아래 「미확인」은 부품이 오면 재서 지운다.

배선 (ESP32-S3 N16R8)

신호ESP32-S3비고
ADS1293 SCLK / SDI / SDO / CSBGPIO 12 / 11 / 13 / 10HSPI 버스 (2.0" 화면용 버스·핀과 분리)
ADS1293 DRDYBGPIO 2하강 에지 인터럽트, 내부 풀업
ADS1293 ALARMBGPIO 1 (선택)상태 줄에만 표시
MAX30102 SDA / SCLGPIO 8 / 9400 kHz, INT 미사용 · 10 ms 폴링
전원3V3 · GNDADS1293 모듈에 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 값
CH1LA (IN2)RA (IN1)I0x11 (데이터시트 예시와 같음)
CH2LL (IN3)RA (IN1)II0x19 (예시와 같음)
CH3LL (IN3)LA (IN2)III (직접)0x1A — 예시는 CH3 를 끄고 III = II − I 로 계산
LA 가 CH1 의 + 와 CH3 의 − 에 동시에 걸린다. 같은 극성 공유는 데이터시트 예시가 하는 방식이지만, 서로 다른 극성 공유는 금지 문구도 허용 문구도 없다 미확인. 그래서 수신 화면에 아인트호벤 잔차 II − (I + III) 를 매 표본 그려 판정한다. ADS1293 은 3채널뿐이라 V1/V5 를 붙이면 III 직접 측정과 동시에 못 한다 — 시험대 한정 제약이다.

전극 배정 기본: RA→IN1, LA→IN2, LL→IN3, RL←IN4(RLD 출력). 모듈 잭 배선이 미확인이라 명령 e 로 IN 번호를 바꿀 수 있다.

주요 레지스터

주소값뜻
0x06 · 0x07 · 0x080x00 · 0x07 · 0x01DC 리드오프 켬, IN1~3 에 전류 주입, 8 nA. 비교 기준 VDD − 0.5 V. RL 귀환이 없으면 전부 「탈락」이 정상
0x0A · 0x0B · 0x0C0x07 · 0x00 · 0x04공통모드 = RA·LA·LL 평균 → RLD 출력 → IN4(RL)
0x11 · 0x13 · 0x140x00 · 0x07 · 0x00내부 2.4 V 기준, 세 채널 고분해능, 모두 켬
0x27 · 0x2F0x08 · 0x71DRDYB = CH1 ECG, 스트리밍 = 상태 + 3채널 (1+9 바이트)
0x12 · 0x000x04 · 0x01외부 4.096 MHz 수정 → 디지털, 15 ms 기다린 뒤 변환 시작. 모듈에 수정이 있는지 미확인 — 없으면 펌웨어가 1초마다 경고

RL 탈락은 리드오프로 잡히지 않아 RLD 출력이 레일 근처인지(RLDRAIL)를 따로 내보낸다. 오류 레지스터는 32표본마다, 또는 ALARMB 비트가 서면 바로 읽는다.

샘플레이트 (데이터시트 표 8, SDM 102.4 kHz, R1 = 4)

명령ODR대역ADCMAX잡음 (µV rms, 표 값)1 LSB1 mV 당 코드
r 533 기본533.33 Hz105 Hz0xF300002.070.0861 µV11,612
r 853853.33 Hz175 Hz0xB964F02.670.1129 µV8,859
r 400400 Hz80 Hz0x8000001.810.1635 µV6,117

533 을 기본으로 둔 것은 500 SPS 기준 노치 설계에 가장 가까워서다(노치 계수는 533.33 Hz 로 다시 계산해야 한다). 진단 대역 150 Hz 를 덮는 건 853 뿐이고, 모니터 대역 40 Hz 는 셋 다 덮는다. 입력 범위는 INA 차동 ±400 mV.

내장 시험신호

명령신호기대 코드 (533 모드)
t ++VTEST = VREF/12 = +200 mV DC10,285,056
t -−200 mV DC5,640,192
t 0입력 단락 (잡음 측정)7,962,624 (= ADCMAX/2)
t x끔 (전극)—

VTEST 와 VREF 가 같은 기준에서 나오므로 이득 교정은 아니고, 자가시험·채널 간 이득 차이 확인용이다. 1 mV 교정 신호(calib)는 외부 배터리 시뮬레이터 몫이다.

심박·산소 모듈 (MAX30102 추정, I2C 0x57)

시리얼 프로토콜

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 sADS1293 실측 / 합성 (모듈이 없으면 저절로 합성)
o b / o c이진 / CSV
r 533 · r 853 · r 400샘플레이트
t + · t - · t 0 · t x내장 시험신호
e 1 2 3 4RA 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 사각파
dADS1293 레지스터 덤프

합성 신호는 ADS1293 과 같은 ADC 코드 꼴로 나가므로, 받는 쪽은 실측과 합성을 구분할 필요가 없다(flags 64 만 다르다). 합성 모형은 사지 전위 φRA=0, φLA=I, φLL=II 로 두고 리드를 전위 차로 다시 계산해 III = II − I 가 정의상 성립한다. 전기축 50° 는 합성용 임의값이다.

수신·표시 스크립트 (PC · 라즈베리파이 공용)

안전 — 사람 몸에 닿기 전에

이 시험대는 절연이 없다. 모듈 → ESP32 → USB → 컴퓨터가 전기적으로 한 덩어리다.

  1. 노트북은 배터리로만. 충전기를 뽑는다
  2. 노트북에 다른 선(HDMI 모니터, 이더넷, 전원 어댑터 쓰는 외장 디스크, 오디오)을 꽂지 않는다
  3. 어댑터 전원을 쓰는 라즈베리파이 + 화면은 몸 전극 시험에 쓰지 않는다 — 합성·단락·시뮬레이터 단계에서만
  4. 접지된 데스크톱에 직접 꽂고 몸에 전극을 붙이지 않는다
  5. 붙이는 동안 금속 책상·라디에이터·수도관에 닿지 않는다
  6. 젖은 피부·상처 위에 붙이지 않는다. 전극은 일회용 1회
  7. 심장박동기·삽입형 기기를 쓰는 사람에게 붙이지 않는다
  8. 이 장치의 파형·숫자로 건강을 판단하지 않는다 — 시험대다
  9. 모듈에 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 xt 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초 스트림을 만들고 파이썬 수신 쪽으로 풀었다
    • ECG 10,666 프레임 중 고의 CRC 손상 1개를 정확히 버림(끊김 1 로 집계), PPG 2,000 프레임 손실 0
    • 0xA5 0xA5 바이트를 품은 한글 글자 줄이 섞여도 동기를 잃지 않음
    • 아인트호벤 잔차 최대 0.086 µV = 1 LSB, rms 0.042 µV → 검사 통과
    • CSV 경로(줄 파싱·seq 끊김·flags) 별도 확인
합성 신호 재생 수신 화면: lead I, II, III, 잔차, 맥파 적색, 맥파 IR 6줄
합성 스트림 재생 화면. 합성 60 Hz 50 µV 주입이 I·II·III 에 보이고, 잔차 II−(I+III) 줄은 0 근처다. 제목의 R 비율은 참고값이며 SpO2 숫자는 미교정이다. 센서 실측이 아닌 합성 신호다.

남은 미확인 (부품 도착 후 확인)

  1. ADS1293 모듈의 전원 구성(VDD·VDDIO), 4.096 MHz 수정 유무, 잭 핀 배정, 입력 보호·RLD 부품값
  2. 한 입력 핀을 CH1 + 와 CH3 − 에 동시에 거는 것의 허용 여부 (잔차로 판정)
  3. 센서 모듈이 MAX30102 인지, 적색·IR 이 바뀌었는지
  4. MAX30102 원문 데이터시트 대조
  5. ESP32-S3 보드의 RGB LED 핀, USB 포트 방식
  6. 리드오프 8 nA 가 케이블 용량에서 몇 초에 반응하는지
  7. 의료 규격의 전극 DC 전류 한계 수치