Files
VesiScan-Basic_Zephyr/plan/system_pipeline.md
T

15 KiB
Raw Blame History

VesiScan-Basic — 시스템 전체 파이프라인

목차

  1. 전체 동작 개요
  2. 부팅 및 BLE 연결 흐름
  3. 커맨드/응답 테이블
  4. msp? 흐름 (1초 주기 IMU)
  5. mbb? 흐름 (10초 주기 전체 측정)
  6. 구현 현황
  7. 핀 배치 전체 정리
  8. IMU 테스트 가이드
  9. 다음 구현 순서

1. 전체 동작 개요

[앱]  ──BLE NUS──  [디바이스]
  │                     │
  │── msp? (1초마다) ──▶  │ IMU 측정 → rsp: (accel+gyro)
  │                     │
  │── mbb? (10초마다) ──▶ │ 6ch 피에조 측정 + 배터리/IMU/온도
  │                     │  → rbb: (센서 번들)
  │◀── rbb: ────────────│
  │◀── reb: × 6 ────────│  (채널별 echo 데이터)
  │◀── raa: ────────────│  (완료)

2. 부팅 및 BLE 연결 흐름

[부팅]
  │
  ▼
전원 버튼 2초 유지
  │
  ▼
P0.08 래치 ON  (전원 자가유지)
  │
  ▼
HW 초기화
  ├─ GPIO, LED
  ├─ Battery ADC (SAADC AIN2)
  ├─ IMU (I2C0, ICM42670P @ 0x68)
  ├─ Temperature ADC (SAADC AIN3, TMP235-Q1)
  ├─ [TODO] Piezo 드라이버 (GPIO + SW burst)
  └─ [TODO] Echo ADC (SPIM3, ADC121S051)
  │
  ▼
BLE 스택 초기화 (NUS)
  │
  ▼
Advertising 시작  →  LED: 파란불 깜빡임
  │
  ▼
앱 연결됨          →  LED: 연결 표시
  │
  ▼
앱에서 주기적 커맨드 수신
  ├─ msp? (1초마다)
  └─ mbb? (10초마다)

3. 커맨드/응답 테이블

커맨드 설명 응답 주기 구현 상태
msp? IMU 1회 측정 rsp: (accel+gyro, 12B) 1초 완료
mbb? 전체 측정 (센서+피에조 6ch) rbb: + reb: ×6 + raa: 10초 미구현
maa? 피에조 6ch 단독 측정 reb: ×6 + raa: 수동 미구현
msn? 배터리 전압 단독 측정 rsn: (mV) 수동 완료
mls? LED 상태 설정 rls: (state echo) 수동 완료

4. msp? 흐름 (1초 주기 IMU)

앱 → msp?
        │
        ▼
    imu_read(accel, gyro)
      ├─ GYRO_CONFIG0 = 0x09  (±2000dps, 100Hz)
      ├─ ACCEL_CONFIG0 = 0x29 (±4g, 100Hz)
      ├─ PWR_MGMT0 = 0x0F     (low-noise ON)
      ├─ 80ms 대기             (자이로 스타트업)
      ├─ 0x0B부터 12바이트 읽기
      └─ PWR_MGMT0 = 0x00     (슬립)
        │
        ▼
    rsp: [accel X(2)] [accel Y(2)] [accel Z(2)]
         [gyro  X(2)] [gyro  Y(2)] [gyro  Z(2)]
         [CRC16(2)]  = 18 bytes

구현 상태: 완료

  • src/drivers/imu/imu_i2c.c — ICM42670P I2C 드라이버
  • src/parser.cmsp? 핸들러, rsp: 응답

5. mbb? 흐름 (10초 주기 전체 측정)

앱 → mbb?
        │
        ▼
    [Phase 1] 피에조 6채널 캡처 (타이밍 크리티컬)
    ┌──────────────────────────────────────────────┐
    │ piezo_power_on()   ← PWR_EN=HIGH, 3ms 대기   │
    │ echo_adc_init()    ← SPIM3 초기화            │
    │                                              │
    │ for ch = 0 ~ 5:                              │
    │   piezo_select_channel(ch)  ← MUX, 1.3ms    │
    │   for avg = 0 ~ 2:          ← 3회 평균       │
    │     piezo_burst_sw(5)       ← 2.1MHz SW burst│
    │     delay 20us                               │
    │     echo_adc_capture(buf, 100)  ← SPIM3     │
    │   channel_data[ch] = 평균값                  │
    └──────────────────────────────────────────────┘
        │
        ▼
    [Phase 2] 센서 측정 (피에조 캡처 완료 후)
    ┌──────────────────────────────────────────────┐
    │ battery_read_mv()       → info_batt (mV)     │
    │ imu_read(accel, gyro)   → info_imu[6]        │
    │ temperature_read()      → info_temp (°Cx100) │
    └──────────────────────────────────────────────┘
        │
        ▼
    [Phase 3] BLE 전송
    ┌──────────────────────────────────────────────┐
    │ rbb: [batt(2)][IMU(12)][temp(2)][CRC(2)]     │
    │      = 20 bytes                              │
    │                                              │
    │ for ch = 0 ~ 5:                              │
    │   reb: [num_samples(2)][raw(200)][CRC(2)]    │
    │        = 204 bytes per channel               │
    │                                              │
    │ raa: [status(2)][CRC(2)] = 8 bytes           │
    └──────────────────────────────────────────────┘
        │
        ▼
    piezo_power_off()

rbb: 패킷 포맷

[r][b][b][:] [batt_L][batt_H]
             [imu0_L][imu0_H] ... [imu5_L][imu5_H]   ← accel XYZ + gyro XYZ
             [temp_L][temp_H]
             [CRC_L][CRC_H]
= 4 + 2 + 12 + 2 + 2 = 22 bytes

reb: 패킷 포맷 (채널당)

[r][e][b][:] [num_samples_H][num_samples_L]
             [s0_H][s0_L] [s1_H][s1_L] ... [s99_H][s99_L]
             [CRC_L][CRC_H]
= 4 + 2 + 200 + 2 = 208 bytes

6. 구현 현황

완료

모듈 파일 기능
BLE NUS src/ble/ble_service.c advertising, 연결, RX/TX
전원 제어 src/power_control.c, src/main.c 버튼 상태머신, 래치, 슬립
LED src/drivers/led/led_control.c 상태별 LED 패턴
배터리 ADC src/drivers/battery/battery_adc.c SAADC AIN2, 주기 모니터링
IMU src/drivers/imu/imu_i2c.c ICM42670P I2C (SCL=P1.14, SDA=P1.15)
온도 센서 src/drivers/temperature/tmp235.c TMP235-Q1, SAADC AIN3 (P0.05)
파서 src/parser.c msn?, mls?, msp?

SAADC 채널 공유 (배터리 ↔ 온도)

배터리(AIN2)와 온도(AIN3)는 nRF52840 SAADC 하나를 공유한다.

nRF5 SDK에서는 채널 전환 시 nrfx_saadc_uninit()을 명시적으로 호출하지 않으면 다음 nrfx_saadc_channel_init() 호출에서 NRFX_ERROR_BUSY가 발생하는 문제가 있었다.

Zephyr에서는 adc_channel_setup_dt() + adc_read_dt() 내부적으로 init/uninit 처리가 되므로 명시적 uninit 불필요. battery_read_mv()temp_read_cdeg() 모두 읽기 전에 adc_channel_setup_dt()를 호출하여 해당 채널로 SAADC를 재설정하기 때문에 임의 순서로 교대 호출해도 정상 동작한다.

단, 두 함수를 서로 다른 스레드에서 동시에 호출하면 안 됨. mbb? 핸들러에서 직렬로 호출하는 한 문제없음.

🔲 테스트 필요

모듈 테스트 방법 확인 항목
배터리 ADC (msn?) RTT 로그 확인 + 앱에서 msn? 전송 아래 테스트 가이드 참고
온도 센서 RTT 로그 확인 아래 테스트 가이드 참고
IMU (msp?) RTT 로그 확인 + 앱에서 msp? 전송 아래 테스트 가이드 참고

배터리 ADC 테스트 가이드 (msn?)

1. 부팅 시 확인 (RTT 로그)

[1] HW Init 단계에서 아래 줄이 나와야 함:

[BATT] ADC init OK (DT-based, ch=2, res=12, os=2)

실패 패턴:

로그 원인 조치
[BATT] ADC device not ready SAADC 드라이버 초기화 실패 CONFIG_ADC=y 확인, overlay channel@2 확인
[BATT] Channel setup failed (err -x) 채널 설정 실패 overlay AIN2 설정 확인

2. msn? 전송 시 확인 (RTT 로그)

앱에서 msn? 전송 시 아래 형식으로 출력됨:

[CMD] msn -> 3800 mV
  • 정상 범위: 3500 ~ 4200 mV (완충 4200mV, 저전압 경고 3500mV)
  • 3500mV 미만이 10회 연속이면 자동 전원 OFF

3. BLE 응답 패킷 포맷

[r][s][n][:] [mV_H][mV_L] [CRC_L][CRC_H]  = 8 bytes

온도 센서 테스트 가이드 (TMP235)

1. 부팅 시 확인 (RTT 로그)

[1] HW Init 단계에서 아래 줄이 나와야 함:

[TEMP] OK — TMP235 ch=3, res=12, os=2

실패 패턴:

로그 원인 조치
[TEMP] FAIL — ADC device not ready SAADC 드라이버 초기화 실패 overlay channel@3 확인
[TEMP] FAIL — channel setup (err=-x) 채널 설정 실패 overlay AIN3 설정 확인, P0.05 핀 확인

2. 측정 시 확인 (RTT 로그)

temp_read_cdeg() 호출 시 아래 형식으로 출력됨:

[TEMP] raw=1234 -> 25.50 C
  • 실온(25°C) 기준 raw 값 약 1404 (V = 750mV, raw = 750 × 4095 / 3600 ≈ 853)

    실제 분압 회로가 있으면 값이 다를 수 있음, 첫 측정값 보고 판단

  • INT16_MIN(-32768) 반환 시 ADC 읽기 실패

3. mbb? 패킷 내 위치

rbb: ... [temp_L][temp_H] ...   ← °C × 100 단위 (25.50°C = 2550)

IMU 테스트 가이드 (msp?)

1. 부팅 시 확인 (RTT 로그)

[1] HW Init 단계에서 아래 줄이 나와야 함:

[IMU] OK — ICM42670P detected (WHOAMI=0x67, addr=0x68)

실패 패턴:

로그 원인 조치
[IMU] FAIL — I2C bus not ready Zephyr I2C 드라이버 초기화 실패 CONFIG_I2C=y 확인, overlay 확인
[IMU] FAIL — WHOAMI read error (check SCL=P1.14, SDA=P1.15) I2C 통신 자체 실패 핀 납땜/연결 확인, 풀업 저항 확인
[IMU] FAIL — WHOAMI mismatch (got=0x00, expected=0x67) 버스는 살아있으나 응답 이상 I2C 주소(0x68) 확인, AD0 핀 상태 확인

2. msp? 전송 시 확인 (RTT 로그)

앱에서 msp? 전송 시 아래 형식으로 출력됨:

[IMU] msp: A=( 12345, -1234,  3210) G=(   100,   -50,   200)
  • A= : 가속도 XYZ (int16, ±4g 풀스케일 → 1g ≈ 8192)
  • G= : 자이로 XYZ (int16, ±2000dps 풀스케일 → 1dps ≈ 16.4)
  • 디바이스 수평 정치 시 Z축 가속도 약 +8192 근처, 자이로 0 근처 (±수십 이내)

실패 패턴:

로그 원인
[IMU] FAIL — gyro config write (ret=-5) I2C TX 에러
[IMU] FAIL — data read (ret=-5) I2C RX 에러
BLE로 rsp: 0xFFFF 수신 위 에러 발생 시 앱으로 전송되는 에러 응답

3. BLE 응답 패킷 포맷

[r][s][p][:] [AX_H][AX_L] [AY_H][AY_L] [AZ_H][AZ_L]
             [GX_H][GX_L] [GY_H][GY_L] [GZ_H][GZ_L]
             [CRC_L][CRC_H]  = 18 bytes

미구현

모듈 목표 파일 필요 기능
피에조 드라이버 src/drivers/piezo/piezo.c SW burst (2.1MHz), MUX, 전원 제어
Echo ADC src/drivers/echo_adc/echo_adc.c ADC121S051, SPIM3 @ 16MHz
maa? 커맨드 src/parser.c 추가 피에조 6ch 단독 측정 → reb: ×6 + raa:
mbb? 커맨드 src/parser.c 추가 전체 측정 오케스트레이션 → rbb: + reb: ×6 + raa:

7. 핀 배치 전체 정리

신호 방향 모듈 상태
POWER_HOLD P0.08 OUT 전원 래치
POWER_BTN P1.08 IN 전원 버튼
LED_BLE P0.12 OUT 파란 LED
LED_FUNC P0.29 OUT 주황 LED
BATT_ADC P0.04 (AIN2) AIN 배터리 ADC
IMU_SCL P1.14 I2C ICM42670P
IMU_SDA P1.15 I2C ICM42670P
TEMP_ADC P0.05 (AIN3) AIN TMP235-Q1 🔲
PIEZO_PWR_EN P1.09 OUT DC/DC +/-20V
PIEZO_PE P0.25 OUT Pulse Enable
PIEZO_P_OUT P1.07 OUT 양극 출력
PIEZO_N_OUT P1.06 OUT 음극 출력
PIEZO_DMP P1.00 OUT Dump
MUX_EN_A P0.21 OUT MUXA 활성화
MUX_EN_B P0.23 OUT MUXB 활성화
MUX_SEL0 P1.10 OUT MUX 채널 선택
MUX_SEL1 P0.28 OUT MUX 채널 선택
ECHO_SCLK P0.14 SPI ADC121S051 CLK
ECHO_MISO P0.15 SPI ADC121S051 DATA
ECHO_CS P0.19 OUT ADC121S051 CS

8. IMU 테스트 가이드 (msp?)

부팅 시 확인 (RTT 로그)

부팅 직후 [1] HW Init 단계에서 아래 줄이 나와야 함:

[IMU] OK — ICM42670P detected (WHOAMI=0x67, addr=0x68)

실패 패턴별 원인

로그 원인 조치
[IMU] FAIL — I2C bus not ready Zephyr I2C 드라이버 초기화 실패 CONFIG_I2C=y 확인, overlay 확인
[IMU] FAIL — WHOAMI read error (check SCL=P1.14, SDA=P1.15) I2C 통신 자체 실패 핀 납땜/연결 확인, 풀업 저항 확인
[IMU] FAIL — WHOAMI mismatch (got=0x00, expected=0x67) 버스는 살아있으나 응답 이상 I2C 주소(0x68) 확인, AD0 핀 상태 확인

msp? 커맨드 전송 시 확인 (RTT 로그)

앱에서 msp? 전송 시 아래 형식으로 출력됨:

[IMU] msp: A=( 12345, -1234,  3210) G=(   100,   -50,   200)
  • A= : 가속도 XYZ (int16, ±4g 풀스케일 → 1g ≈ 8192)
  • G= : 자이로 XYZ (int16, ±2000dps 풀스케일 → 1dps ≈ 16.4)
  • 디바이스가 수평으로 놓여 있으면 Z축 가속도가 약 +8192 근처여야 함
  • 자이로는 정지 상태에서 0 근처 (±수십 이내)

실패 패턴

로그 원인
[IMU] FAIL — gyro config write (ret=-5) I2C TX 에러 (부팅 후 재연결 문제)
[IMU] FAIL — data read (ret=-5) I2C RX 에러
BLE로 rsp: 0xFFFF 수신 위 에러 발생 시 앱으로 전송되는 에러 응답

BLE 응답 패킷 확인

정상 수신 시 앱에서 받는 rsp: 패킷 포맷:

[r][s][p][:] [AX_H][AX_L] [AY_H][AY_L] [AZ_H][AZ_L]
             [GX_H][GX_L] [GY_H][GY_L] [GZ_H][GZ_L]
             [CRC_L][CRC_H]
= 18 bytes

9. 다음 구현 순서

Step 1  ✅ 온도 센서 (tmp235.c) — 완료

Step 2  피에조 드라이버 (piezo.c)
          └─ GPIO 초기화, MUX, SW burst (NOP 기반, nrf HAL 직접 사용)
          └─ CONFIG_NRFX_GPIOTE=y 추가

Step 3  Echo ADC (echo_adc.c)
          └─ SPIM3 초기화, 연속 샘플 캡처
          └─ CONFIG_NRFX_SPIM3=y 추가

Step 4  maa? 커맨드 (parser.c 추가)
          └─ 피에조 6ch 측정 + BLE 전송 (reb: ×6 + raa:)
          └─ 센서 번들 없음 — 피에조/ADC 단독 검증용

Step 5  mbb? 커맨드 (parser.c 추가)
          └─ 배터리 + IMU + 온도 + 피에조 6ch 전체 오케스트레이션
          └─ rbb: + reb: ×6 + raa: