- Piezo 6ch 측정 + 센서(배터리, IMU, 온도) 측정: mbb 명령어 추가

- Flash Memory Piezo 측정 파라미터 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jhChun
2026-03-18 13:54:06 +09:00
parent 96a46a26dd
commit 3ecd81c252
12 changed files with 507 additions and 306 deletions

View File

@@ -1,6 +1,6 @@
# VesiScan-Basic 코드 리뷰 현황 보고서 # VesiScan-Basic 코드 리뷰 현황 보고서
작성일: 2026-03-16 작성일: 2026-03-17
대상: VesiScan BASIC 펌웨어 전체 (nRF52840 + S140 SoftDevice) 대상: VesiScan BASIC 펌웨어 전체 (nRF52840 + S140 SoftDevice)
기준 문서: CODE_REVIEW.pdf (2026-03-15) 기준 문서: CODE_REVIEW.pdf (2026-03-15)
현재 빌드: DEBUG_MINIMAL_BOOT=1, BLE_DEV_MODE=1 현재 빌드: DEBUG_MINIMAL_BOOT=1, BLE_DEV_MODE=1
@@ -157,8 +157,8 @@ cat_interface.c 삭제(EEPROM/AES 코드 전체 삭제). TWI 인스턴스(m_twi)
| m_encrypted_text[16] | main.c:194 | 삭제 | **미완료** | | m_encrypted_text[16] | main.c:194 | 삭제 | **미완료** |
| m_encrypted_text2[16] | main.c:195 | 삭제 | **미완료** | | m_encrypted_text2[16] | main.c:195 | 삭제 | **미완료** |
| m_decrypted_text[16] | main.c:196 | 삭제 | **미완료** | | m_decrypted_text[16] | main.c:196 | 삭제 | **미완료** |
| DEVICE_NAME | cmd_parse.c | 삭제 | 확인 필요 | | DEVICE_NAME | cmd_parse.c | 삭제 | **완료** (cmd_parse.c 삭제됨) |
| HW_NO[12] | cmd_parse.c | 삭제 | **완료** | | HW_NO[12] | cmd_parse.c | 삭제 | **완료** (cmd_parse.c 삭제됨) |
| AES_KEY_SIZE | main.c:154 | 삭제 | **미완료** | | AES_KEY_SIZE | main.c:154 | 삭제 | **미완료** |
| AES_BLOCK_SIZE | main.c:155 | 삭제 | **미완료** | | AES_BLOCK_SIZE | main.c:155 | 삭제 | **미완료** |
| suppress_unused_warnings() | main.c:239 | 삭제 | **미완료** | | suppress_unused_warnings() | main.c:239 | 삭제 | **미완료** |
@@ -167,7 +167,7 @@ cat_interface.c 삭제(EEPROM/AES 코드 전체 삭제). TWI 인스턴스(m_twi)
### 2.3.1 cmd_parse.c → parser.c 통합 현황 ### 2.3.1 cmd_parse.c → parser.c 통합 현황
현재 구조: main.c → `received_command_process()` [cmd_parse.c] → `dr_cmd_parser()` [parser.c] → 실패 시 레거시 if-else 체인 [cmd_parse.c] 현재 구조: main.c → `dr_cmd_parser()` [parser.c] (cmd_parse.c 삭제 완료)
#### parser.c 명령어 테이블 (g_cmd_table) #### parser.c 명령어 테이블 (g_cmd_table)
@@ -207,40 +207,40 @@ cat_interface.c 삭제(EEPROM/AES 코드 전체 삭제). TWI 인스턴스(m_twi)
| `sst?` | Cmd_sst | false | Ready 응답 | 비활성 | | `sst?` | Cmd_sst | false | Ready 응답 | 비활성 |
| `mfv?` | Cmd_mfv | true | 펌웨어 버전 읽기 | ssv? 대체 | | `mfv?` | Cmd_mfv | true | 펌웨어 버전 읽기 | ssv? 대체 |
#### cmd_parse.c 레거시 명령어 (parser.c에 없는 것) #### cmd_parse.c 레거시 명령어 parser.c 이전 완료
| 태그 | 상태 | 기능 | 비고 | | 태그 | 기능 | 비고 |
|------|------|------|------| |------|------|------|
| `spz?` | 활성 | 패스키 쓰기 | → parser.c `mpz?`로 대체 완료 | | `spz?` | 패스키 쓰기 | → parser.c `mpz?`로 대체 완료 |
| `sqz?` | 활성 | 패스키 읽기 | → parser.c `mqz?`로 대체 완료 | | `sqz?` | 패스키 읽기 | → parser.c `mqz?`로 대체 완료 |
| `sxz?` | 활성 | life_cycle 쓰기 | → parser.c `mxz?`로 대체 완료 | | `sxz?` | life_cycle 쓰기 | → parser.c `mxz?`로 대체 완료 |
| `syz?` | 활성 | life_cycle 읽기 | → parser.c `myz?`로 대체 완료 | | `syz?` | life_cycle 읽기 | → parser.c `myz?`로 대체 완료 |
| `sez?` | 활성 (stub) | AGC gain — HW 제거됨 | param_error만 응답 | | `sez?` | AGC gain (stub) | cmd_parse.c와 함께 삭제 |
| `sfz?` | 활성 (stub) | AGC gain — HW 제거됨 | param_error만 응답 | | `sfz?` | AGC gain (stub) | cmd_parse.c와 함께 삭제 |
| `ssv?` | `if(0&&)` 비활성 | 펌웨어 버전 | → parser.c `mfv?`로 대체됨 | | `ssv?` | 펌웨어 버전 | → parser.c `mfv?`로 대체됨 |
| `ssz?` | `if(0&&)` 비활성 | 시리얼번호 쓰기 | → parser.c `mws?`로 대체됨 | | `ssz?` | 시리얼번호 쓰기 | → parser.c `mws?`로 대체됨 |
| `srz?` | `if(0&&)` 비활성 | 시리얼번호 읽기 | → parser.c `mrs?`로 대체됨 | | `srz?` | 시리얼번호 읽기 | → parser.c `mrs?`로 대체됨 |
| `siz?` | `if(0&&)` 비활성 | HW번호 읽기 | → parser.c `mrh?`로 대체됨 | | `siz?` | HW번호 읽기 | → parser.c `mrh?`로 대체됨 |
| `shz?` | `if(0&&)` 비활성 | HW번호 쓰기 | → parser.c `mwh?`로 대체됨 | | `shz?` | HW번호 쓰기 | → parser.c `mwh?`로 대체됨 |
#### 통합 남은 작업 #### 통합 작업 현황
| # | 작업 | 현재 상태 | | # | 작업 | 현재 상태 |
|---|------|----------| |---|------|----------|
| 1 | parser.c에 누락 명령어 추가 (mpz/mqz/mxz/myz) | **완료** | | 1 | parser.c에 누락 명령어 추가 (mpz/mqz/mxz/myz) | **완료** |
| 2 | received_command_process() 래퍼를 main.c로 이동 | **완료** | | 2 | received_command_process() 래퍼를 main.c로 이동 | **완료** (cmd_parse.c 삭제됨) |
| 3 | 전역 변수 (SERIAL_NO, m_static_passkey 등) main.c로 이동 | **완료** | | 3 | 전역 변수 (SERIAL_NO, m_static_passkey 등) main.c로 이동 | **완료** (cmd_parse.c 삭제됨) |
| 4 | cmd_parse.h include 정리 (7개 파일) | **완료** | | 4 | cmd_parse.h include 정리 (7개 파일) | **완료** (cmd_parse.h 삭제됨) |
| 5 | cmd_parse.c / cmd_parse.h 삭제 | **완료** | | 5 | cmd_parse.c / cmd_parse.h 삭제 | **완료** |
| 6 | Keil 프로젝트 파일 업데이트 | **완료** | | 6 | Keil 프로젝트 파일 업데이트 | **완료** |
### 2.4 주석 처리된 코드 ### 2.4 주석 처리된 코드
| 위치 | 내용 | 판정 | 현재 상태 | | 위치 | 내용 | 판정 | 현재 상태 |
|------|------|------|----------| |------|------|------|----------|
| main_timer.c:37-88 | FEATURE_DETAIL_VALUE_FULL 주석 블록 | 삭제 | **미완료** | | main_timer.c:37-88 | FEATURE_DETAIL_VALUE_FULL 주석 블록 | 삭제 | **미완료** |
| cmd_parse.c:282-317 | serial_to_passkey_hash, test_eeprom_page_rw | 삭제 | **완료** | | cmd_parse.c:282-317 | serial_to_passkey_hash, test_eeprom_page_rw | 삭제 | **완료** (cmd_parse.c 삭제됨) |
| cmd_parse.c:87-88 | pd_adc_half/full_a_start extern | 삭제 | 확인 필요 | | cmd_parse.c:87-88 | pd_adc_half/full_a_start extern | 삭제 | **완료** (cmd_parse.c 삭제됨) |
| battery_saadc.c:22 | //#include "fstorage.h" | 삭제 | **미완료** | | battery_saadc.c:22 | //#include "fstorage.h" | 삭제 | **미완료** |
--- ---
@@ -297,11 +297,11 @@ uvprojx 수정 작업 없음.
- `binary_tx_handler()` 함수 본체 삭제 - `binary_tx_handler()` 함수 본체 삭제
- 모든 호출처를 `dr_binary_tx_safe()`로 교체 완료 - 모든 호출처를 `dr_binary_tx_safe()`로 교체 완료
- cmd_parse.c (22곳 + 함수 포인터 1곳) - parser.c (17곳)
- battery_saadc.c (2곳) - battery_saadc.c (2곳)
- app_raw.c (2곳) - app_raw.c (2곳)
- tmp235_q1.c (1곳) - tmp235_q1.c (1곳)
- parser.c (17곳) - cmd_parse.c (22곳) → 이후 cmd_parse.c 삭제됨
- main.h 선언 제거, dr_util.c/dr_adc121s051.c의 옛날 extern 선언 제거 - main.h 선언 제거, dr_util.c/dr_adc121s051.c의 옛날 extern 선언 제거
- `dr_binary_tx_safe()`는 NRF_ERROR_RESOURCES 시 최대 100회 재시도 후 패킷 드롭, 연결 에러 시 graceful 리턴 - `dr_binary_tx_safe()`는 NRF_ERROR_RESOURCES 시 최대 100회 재시도 후 패킷 드롭, 연결 에러 시 graceful 리턴
- `data_tx_handler()`의 APP_ERROR_CHECK도 DBG_PRINTF로 교체 — 예상치 못한 에러 시에도 패킷 드롭 후 정상 동작 유지 - `data_tx_handler()`의 APP_ERROR_CHECK도 DBG_PRINTF로 교체 — 예상치 못한 에러 시에도 패킷 드롭 후 정상 동작 유지
@@ -316,11 +316,11 @@ uvprojx 수정 작업 없음.
#### B3: extern + 초기화 동시 사용 #### B3: extern + 초기화 동시 사용
파일: cmd_parse.c 파일: cmd_parse.c (삭제됨)
현재 상태: **완료** 현재 상태: **완료**
`extern int8_t pd_adc_counts[4] = {8, 16, 24, 32};` 선언이 제거됨. `extern int8_t pd_adc_counts[4] = {8, 16, 24, 32};` 선언이 제거됨. 이후 cmd_parse.c 삭제.
#### B4: memset/memcpy 버퍼 크기 불일치 및 매직 넘버 #### B4: memset/memcpy 버퍼 크기 불일치 및 매직 넘버
@@ -334,6 +334,33 @@ uvprojx 수정 작업 없음.
스택/힙 오버플로우로 인한 메모리 손상 가능성이 있는 심각한 버그. 스택/힙 오버플로우로 인한 메모리 손상 가능성이 있는 심각한 버그.
#### B5: maa? 명령 err=2 (MAA_NUM_SAMPLES 초과)
파일: parser.c, dr_adc121s051.c
현재 상태: **완료** — jhChun 26.03.17
MAA_NUM_SAMPLES(140)이 DR_ADC_ECHO_SAMPLES_MAX(100)보다 커서 maa_async_start()에서 무조건 DR_ADC_ERR_INVALID_PARAM(err=2) 반환. MAA_NUM_SAMPLES를 100으로 변경하여 해결.
#### B5-2: mec/maa 명령 시 Piezo 전원 미관리
파일: parser.c, dr_adc121s051.c
현재 상태: **완료** — jhChun 26.03.17
- mec?, maa? 수신 시 `dr_piezo_is_power_on()` 확인 후 꺼져있으면 자동 `dr_piezo_system_init()` (Active)
- mec: 응답 송신 후 즉시 `dr_piezo_power_off()` (Sleep)
- maa: 비동기 완료 콜백에서 `dr_piezo_power_off()` (Sleep)
- `dr_piezo_is_power_on()` 함수 신규 추가 (dr_piezo.c/h)
#### B5-3: Cmd_mpa dr_piezo_power_on() 중복 호출
파일: parser.c
현재 상태: **완료** — jhChun 26.03.17
`dr_piezo_power_on()` + `dr_piezo_system_init()` 둘 다 호출하고 있었으나, `dr_piezo_system_init()` 내부에 이미 `dr_piezo_power_on()`이 포함되어 있어 중복 제거.
### 5.2 심각도 중간 (MEDIUM) ### 5.2 심각도 중간 (MEDIUM)
#### B6: battery_event_handler에서 floating-point 연산 #### B6: battery_event_handler에서 floating-point 연산
@@ -360,11 +387,7 @@ batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0 * 142) / 100;
파일: cmd_parse.c:57 파일: cmd_parse.c:57
현재 상태: **완료** (해결됨) 현재 상태: **완료** (cmd_parse.c 삭제됨)
변수가 5초 타임아웃 추적에 활용되고 있음:
- cmd_parse.c:483에서 초기값 확인
- cmd_parse.c:489에서 5초 경과 비교
#### B9: config_load() goto 기반 흐름 #### B9: config_load() goto 기반 흐름
@@ -509,6 +532,9 @@ BLE_GAP_EVT_CONNECTED/DISCONNECTED 핸들러에 IMU 타이머 start/stop 로직
| 2 | B1: BLE TX 큐 풀 시 시스템 먹통 (binary_tx_handler → dr_binary_tx_safe 교체) | HIGH | **완료** | | 2 | B1: BLE TX 큐 풀 시 시스템 먹통 (binary_tx_handler → dr_binary_tx_safe 교체) | HIGH | **완료** |
| 3 | B2: BLE TX 에러 핸들링 로직 반전 | HIGH | **완료** | | 3 | B2: BLE TX 에러 핸들링 로직 반전 | HIGH | **완료** |
| 4 | B3: extern + 초기화 동시 사용 | HIGH | **완료** | | 4 | B3: extern + 초기화 동시 사용 | HIGH | **완료** |
| 5 | B5: maa? err=2 (MAA_NUM_SAMPLES > DR_ADC_ECHO_SAMPLES_MAX) | HIGH | **완료** |
| 6 | B5-2: mec/maa Piezo 자동 전원 관리 | MEDIUM | **완료** |
| 7 | B5-3: Cmd_mpa dr_piezo_power_on 중복 호출 | LOW | **완료** |
### 1차 정리 (미사용 코드/EEPROM 삭제) ### 1차 정리 (미사용 코드/EEPROM 삭제)
@@ -517,7 +543,7 @@ BLE_GAP_EVT_CONNECTED/DISCONNECTED 핸들러에 IMU 타이머 start/stop 로직
| 5 | 미사용 HW 드라이버 삭제 (1.2절) | **완료** | | 5 | 미사용 HW 드라이버 삭제 (1.2절) | **완료** |
| 6 | cat_interface.c EEPROM 기능 삭제 + TWI를 i2c_manager.c로 통합 (1.5절) | **완료** | | 6 | cat_interface.c EEPROM 기능 삭제 + TWI를 i2c_manager.c로 통합 (1.5절) | **완료** |
| 7 | cmd_parse.c EEPROM 호출 -> FDS 전환 (1.5.4절) | **완료** | | 7 | cmd_parse.c EEPROM 호출 -> FDS 전환 (1.5.4절) | **완료** |
| 8 | cmd_parse.c → parser.c 통합 (2.3.1절) | **진행 중** (명령어 이전 완료, 파일 삭제 미완료) | | 8 | cmd_parse.c → parser.c 통합 (2.3.1절) | **완료** |
| 9 | 미사용 전역변수 + HW_NO 삭제 (2.2-2.3절) | **미완료** | | 9 | 미사용 전역변수 + HW_NO 삭제 (2.2-2.3절) | **미완료** |
| 10 | DEBUG_MINIMAL_BOOT 조건 제거 (3절) | **미완료** | | 10 | DEBUG_MINIMAL_BOOT 조건 제거 (3절) | **미완료** |
| 11 | Keil uvprojx 소스 참조 제거 (4절) | 확인 필요 | | 11 | Keil uvprojx 소스 참조 제거 (4절) | 확인 필요 |

View File

@@ -791,7 +791,7 @@ dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_u
if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX) if (num_samples == 0 || num_samples > DR_ADC_ECHO_SAMPLES_MAX)
return DR_ADC_ERR_INVALID_PARAM; return DR_ADC_ERR_INVALID_PARAM;
if (freq_option > 9) freq_option = 0; /* Invalid -> default 1.8MHz */ if (freq_option > 9) freq_option = 0; /* Invalid -> default 1.8MHz */
if (cycles < 3 || cycles > 9) cycles = 5; /* Valid range: 3~9, default 5 */ if (cycles < 3 || cycles > 7) cycles = 5; /* Valid range: 3~7, default 5 */
if (averaging == 0) averaging = 1; /* Minimum 1 */ if (averaging == 0) averaging = 1; /* Minimum 1 */
if (averaging > 1000) averaging = 1000; /* Maximum 1000 */ if (averaging > 1000) averaging = 1000; /* Maximum 1000 */
if (piezo_ch >= MAA_NUM_CHANNELS) piezo_ch = 0; /* 채널 범위 검증 */ if (piezo_ch >= MAA_NUM_CHANNELS) piezo_ch = 0; /* 채널 범위 검증 */
@@ -1018,7 +1018,7 @@ dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
if (num_samples == 0 || num_samples > MAA_SAMPLES_MAX) if (num_samples == 0 || num_samples > MAA_SAMPLES_MAX)
return DR_ADC_ERR_INVALID_PARAM; return DR_ADC_ERR_INVALID_PARAM;
if (freq_option > 3) freq_option = 0; if (freq_option > 3) freq_option = 0;
if (cycles < 3 || cycles > 9) cycles = 5; if (cycles < 3 || cycles > 7) cycles = 5;
if (averaging == 0) averaging = 1; if (averaging == 0) averaging = 1;
if (averaging > 1000) averaging = 1000; if (averaging > 1000) averaging = 1000;
if (piezo_ch > (MAA_NUM_CHANNELS - 1)) piezo_ch = 0; if (piezo_ch > (MAA_NUM_CHANNELS - 1)) piezo_ch = 0;
@@ -1448,6 +1448,13 @@ static void maa_async_send_completion(uint16_t status)
g_maa_ctx.state = MAA_ASYNC_IDLE; g_maa_ctx.state = MAA_ASYNC_IDLE;
ADC_LOG("maa_async: complete, status=0x%04X", status); ADC_LOG("maa_async: complete, status=0x%04X", status);
/* 완료 콜백 호출 (mbb? 등에서 센서 측정 체인 트리거용) */
if (g_maa_ctx.on_complete_cb) {
void (*cb)(void) = g_maa_ctx.on_complete_cb;
g_maa_ctx.on_complete_cb = NULL; /* 1회성: 재호출 방지 */
cb();
}
} }
/*============================================================================== /*==============================================================================
@@ -1471,12 +1478,13 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us,
g_maa_ctx.freq_option = freq_option; g_maa_ctx.freq_option = freq_option;
g_maa_ctx.delay_us = delay_us; g_maa_ctx.delay_us = delay_us;
g_maa_ctx.num_samples = num_samples; g_maa_ctx.num_samples = num_samples;
g_maa_ctx.cycles = (cycles < 3 || cycles > 9) ? 5 : cycles; g_maa_ctx.cycles = (cycles < 3 || cycles > 7) ? 5 : cycles;
g_maa_ctx.averaging = (averaging == 0) ? 1 : ((averaging > 1000) ? 1000 : averaging); g_maa_ctx.averaging = (averaging == 0) ? 1 : ((averaging > 1000) ? 1000 : averaging);
g_maa_ctx.ble_buffer = ble_buffer; g_maa_ctx.ble_buffer = ble_buffer;
g_maa_ctx.current_ch = 0; g_maa_ctx.current_ch = 0;
g_maa_ctx.current_pkt = 0; g_maa_ctx.current_pkt = 0;
g_maa_ctx.data_offset = 0; g_maa_ctx.data_offset = 0;
g_maa_ctx.on_complete_cb = NULL; /* 기본: 콜백 없음 (maa?) */
ADC_LOG("maa_async_start: freq=%u delay=%u samples=%u cycles=%u avg=%u", ADC_LOG("maa_async_start: freq=%u delay=%u samples=%u cycles=%u avg=%u",
freq_option, delay_us, num_samples, g_maa_ctx.cycles, g_maa_ctx.averaging); freq_option, delay_us, num_samples, g_maa_ctx.cycles, g_maa_ctx.averaging);
@@ -1568,3 +1576,8 @@ void maa_async_set_auto_power(bool on)
g_maa_ctx.auto_powered = on; g_maa_ctx.auto_powered = on;
} }
void maa_async_set_on_complete(void (*cb)(void))
{
g_maa_ctx.on_complete_cb = cb;
}

View File

@@ -191,7 +191,7 @@ dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t
/** /**
* @brief Piezo burst + Echo capture in one call * @brief Piezo burst + Echo capture in one call
* @param cycles Number of burst cycles (3~9) * @param cycles Number of burst cycles (3~7)
* @param delay_us Delay before capture (us) * @param delay_us Delay before capture (us)
* @param num_samples Number of samples to capture * @param num_samples Number of samples to capture
* @param echo Pointer to echo result structure * @param echo Pointer to echo result structure
@@ -455,6 +455,7 @@ typedef struct {
uint16_t total_packets; /**< Total packets for current channel */ uint16_t total_packets; /**< Total packets for current channel */
uint16_t data_packets; /**< Data packets for current channel */ uint16_t data_packets; /**< Data packets for current channel */
bool auto_powered; /**< true: 자동 전원 ON → 완료 후 OFF */ bool auto_powered; /**< true: 자동 전원 ON → 완료 후 OFF */
void (*on_complete_cb)(void); /**< 비동기 캡처 완료 후 호출될 콜백 (NULL이면 미사용) */
} maa_async_ctx_t; } maa_async_ctx_t;
/** /**
@@ -466,7 +467,7 @@ typedef struct {
* @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz * @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
* @param delay_us Capture delay (us) * @param delay_us Capture delay (us)
* @param num_samples Samples per channel (1~200) * @param num_samples Samples per channel (1~200)
* @param cycles Burst cycles (3~9) * @param cycles Burst cycles (3~7)
* @param averaging Averaging count (1~1000) * @param averaging Averaging count (1~1000)
* @param ble_buffer Working buffer (>= 240 bytes) * @param ble_buffer Working buffer (>= 240 bytes)
* @return dr_adc_err_t DR_ADC_OK if started successfully * @return dr_adc_err_t DR_ADC_OK if started successfully
@@ -507,5 +508,11 @@ void maa_async_abort(void);
*/ */
void maa_async_set_auto_power(bool on); void maa_async_set_auto_power(bool on);
/**
* @brief 비동기 캡처 완료 콜백 설정
* raa: 전송 + 전원 OFF 이후 호출된다. NULL이면 콜백 없음.
*/
void maa_async_set_on_complete(void (*cb)(void));
#endif /* DR_ADC121S051_H */ #endif /* DR_ADC121S051_H */

View File

@@ -80,13 +80,18 @@ extern bool con_single; /* 단일 연결 모드 플래그 */
extern bool lock_check; /* 보안 잠금 상태 플래그 */ extern bool lock_check; /* 보안 잠금 상태 플래그 */
extern bool info4; /* true: 추가 정보(배터리/온도/IMU) 포함 측정 */ extern bool info4; /* true: 센서값을 전역 변수에 저장 (BLE 전송 안 함) */
extern bool ble_got_new_data; /* true: BLE로 새 데이터 수신됨 (처리 대기) */ extern bool ble_got_new_data; /* true: BLE로 새 데이터 수신됨 (처리 대기) */
extern bool go_batt; /* true: 배터리 측정 요청 플래그 */ extern bool go_batt; /* true: 배터리 측정 요청 플래그 */
extern bool motion_data_once; /* true: IMU 1회 측정, false: 연속 측정 */ extern bool motion_data_once; /* true: IMU 1회 측정, false: 연속 측정 */
extern bool motion_raw_data_enabled;/* true: IMU 원시 데이터 전송 활성화 */ extern bool motion_raw_data_enabled;/* true: IMU 원시 데이터 전송 활성화 */
extern int imu_read_direct(void); /* IMU 레지스터 직접 읽기 + BLE 전송 */ extern int imu_read_direct(void); /* IMU 레지스터 직접 읽기 + BLE 전송 */
/* info4 모드 센서값 저장 변수 (mbb? rbb: 패킷 조립용) */
extern volatile uint16_t info_batt; /* 배터리 전압 (mV) */
extern volatile uint16_t info_temp; /* 온도 (°C x 100) */
extern volatile uint16_t info_imu[6]; /* IMU 6축 (accel XYZ + gyro XYZ) */
extern void pressure_all_level_meas(void); /* 압력 센서 전체 측정 */ extern void pressure_all_level_meas(void); /* 압력 센서 전체 측정 */
extern void battery_timer_stop(void); /* 배터리 타이머 중지 */ extern void battery_timer_stop(void); /* 배터리 타이머 중지 */
extern void main_timer_start(void); /* 메인 타이머 시작 (주기적 측정 트리거) */ extern void main_timer_start(void); /* 메인 타이머 시작 (주기적 측정 트리거) */
@@ -108,7 +113,7 @@ extern config_data_t m_config; /* 전체 설정 구조체 (FDS 저장 대
#define AGC_GAIN_SW(x) do { if(x) nrf_gpio_pin_set(GAIN_SW_PIN); else nrf_gpio_pin_clear(GAIN_SW_PIN); } while(0) #define AGC_GAIN_SW(x) do { if(x) nrf_gpio_pin_set(GAIN_SW_PIN); else nrf_gpio_pin_clear(GAIN_SW_PIN); } while(0)
/* 피에조 초음파 트랜스듀서 제어 함수 */ /* ---- 피에조 관련 제어 함수 ---- */
extern void dr_piezo_power_on( void ); /* 피에조 회로 전원 ON (TX/RX 보드) */ extern void dr_piezo_power_on( void ); /* 피에조 회로 전원 ON (TX/RX 보드) */
extern void dr_piezo_power_off( void ); /* 피에조 회로 전원 OFF */ extern void dr_piezo_power_off( void ); /* 피에조 회로 전원 OFF */
extern bool dr_piezo_is_power_on( void ); /* 피에조 전원 상태 확인 */ extern bool dr_piezo_is_power_on( void ); /* 피에조 전원 상태 확인 */
@@ -117,6 +122,7 @@ extern void dr_piezo_burst_sw_18mhz(uint8_t cycles); /* 1.8MHz 버스트 펄스
extern void dr_piezo_burst_sw_20mhz(uint8_t cycles); /* 2.0MHz 버스트 펄스 발생 */ extern void dr_piezo_burst_sw_20mhz(uint8_t cycles); /* 2.0MHz 버스트 펄스 발생 */
extern void dr_piezo_burst_sw_17mhz(uint8_t cycles); /* 1.7MHz 버스트 펄스 발생 */ extern void dr_piezo_burst_sw_17mhz(uint8_t cycles); /* 1.7MHz 버스트 펄스 발생 */
/* ---- 전역 변수 정의 (헤더에서 extern 선언) ---- */ /* ---- 전역 변수 정의 (헤더에서 extern 선언) ---- */
dr_platform_if_t g_plat = { 0, 0, 0 }; dr_platform_if_t g_plat = { 0, 0, 0 };
/* 플랫폼 인터페이스 구조체: /* 플랫폼 인터페이스 구조체:
@@ -126,10 +132,11 @@ dr_platform_if_t g_plat = { 0, 0, 0 };
bool g_log_enable = false; bool g_log_enable = false;
/* 디버그 로그 전역 활성화 플래그 (g_plat.log와 함께 사용) */ /* 디버그 로그 전역 활성화 플래그 (g_plat.log와 함께 사용) */
/* ---- 내부 상수/구조체 정의 ---- */
/* ---- 내부 상수/구조체 정의 ---- */
#define DR_MAX_DATA 128 /* TAG 이후 데이터의 최대 바이트 수 */ #define DR_MAX_DATA 128 /* TAG 이후 데이터의 최대 바이트 수 */
/* 파싱된 명령 구조체 - 수신 패킷을 TAG와 데이터로 분리한 결과 */ /* 파싱된 명령 구조체 - 수신 패킷을 TAG와 데이터로 분리한 결과 */
typedef struct { typedef struct {
char tag[5]; /* 명령 TAG 문자열 (예: "sta?") 4글자 + '\0' */ char tag[5]; /* 명령 TAG 문자열 (예: "sta?") 4글자 + '\0' */
@@ -328,8 +335,8 @@ static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out)
* BLE 명령어 * BLE 명령어
* *
* A. 디바이스 상태 제어 * A. 디바이스 상태 제어
* - 전원 OFF (msq? / rsq:) : 확인 필요 * - 전원 OFF (msq? / rsq:)
* - 재부팅 (mss? / rss:) : 확인 필요 * - 재부팅 (mss? / rss:)
* - 본딩 정보 삭제 및 재부팅 (msr? / rsr:) : 확인 필요 * - 본딩 정보 삭제 및 재부팅 (msr? / rsr:) : 확인 필요
* - GPIO 제어(핀 테스트용, cmd? / rmd:) * - GPIO 제어(핀 테스트용, cmd? / rmd:)
* *
@@ -339,21 +346,22 @@ static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out)
* - 시리얼 넘버 읽기 (mrs? / rrs:) * - 시리얼 넘버 읽기 (mrs? / rrs:)
* - 시리얼 넘버 쓰기 (mws? / rws:) * - 시리얼 넘버 쓰기 (mws? / rws:)
* - 펌웨어 버전 읽기 (mfv? / rfv:) * - 펌웨어 버전 읽기 (mfv? / rfv:)
* - 패스키 읽기 (mqz? / rqz:) : 확인 필요, 필요 유무 검토(암호화 혹은 삭제) * - 패스키 읽기 (mqz? / rqz:) : 필요 유무 검토(암호화 혹은 삭제)
* - 패스키 쓰기 (mpz? / rpz:) : 확인 필요 * - 패스키 쓰기 (mpz? / rpz:)
* *
* C. 각종 센서 측정 * C. 각종 센서 측정
* - 배터리 전압 측정 (msn? / rsn:) - test용 * - 배터리 전압 측정 (msn? / rsn:) - test용
* - IMU 단발 측정 (msp? / rsp:) : 동기 - test용 * - IMU 단발 측정 (msp? / rsp:) : 동기 - test용
* - IMU 연속 스트리밍 (msi? / rsi:) : 비동기(타이머) 1초 주기, 확인 필요 - test용 * - IMU 연속 스트리밍 (msi? / rsi:) : 비동기(타이머) 1초 주기, 확인 필요 - test용
* - 온도 측정 (mso? / rso:) : 확인 필요 - test용 * - 온도 측정 (mso? / rso:) - test용
* *
* D. Piezo 초음파 측정 * D. Piezo 초음파 측정
* - TX/RX 전원 활성화 (mpa? / rpa:) * - TX/RX 전원 활성화 (mpa? / rpa:) - test용
* - TX/RX 전원 비활성화 (mpb? / rpb:) * - TX/RX 전원 비활성화 (mpb? / rpb:) - test용
* - 단일 채널 Burst (mpc? / rpc:) - test용 * - 단일 채널 Burst (mpc? / rpc:) - test용
* - 단일 채널 Burst + ADC -> echo capture (mec? / reb: -> red: -> ree:) * - 단일 채널 Burst + ADC -> echo capture (mec? / reb: -> red: -> ree:) : TX/RX Active -> 응답 -> TX/RX Sleep
* - 모든 채널 Burst + ADC -> echo capture (maa? / reb: -> red: -> raa:) : 확인 필요, 현재 모든 채널 = 4 * - 모든 채널 Burst + ADC -> echo capture (maa? / reb: -> red: -> raa:) : TX/RX Active -> 응답 -> TX/RX Sleep
* - 모든 채널 Burst + ADC -> echo capture (mbb? / reb: -> red: -> raa:) + 각종 센서 측정(배터리, IMU, 온도) : TX/RX Active -> 응답 -> TX/RX Sleep (NEW!)
* *
* 삭제 명령어 * 삭제 명령어
* - 디바이스 활성화/슬립 : TX 전원 활성화/비활성화와 동일 기능 * - 디바이스 활성화/슬립 : TX 전원 활성화/비활성화와 동일 기능
@@ -364,7 +372,6 @@ static bool dr_parse_cmd(const uint8_t *buffer, uint8_t length, ParsedCmd *out)
* - 단일 채널 ADC * - 단일 채널 ADC
*============================================================================*/ *============================================================================*/
/*============================================================================== /*==============================================================================
* 핸들러 함수 프로토타입 선언 * 핸들러 함수 프로토타입 선언
* - 반환값: 1=성공, 0=실패/비활성 * - 반환값: 1=성공, 0=실패/비활성
@@ -399,7 +406,8 @@ static int Cmd_mpa(const ParsedCmd *cmd); /* mpa? 피에조 TX/RX 회로 활
static int Cmd_mpb(const ParsedCmd *cmd); /* mpb? 피에조 TX/RX 회로 비활성화 (전원 OFF) */ static int Cmd_mpb(const ParsedCmd *cmd); /* mpb? 피에조 TX/RX 회로 비활성화 (전원 OFF) */
static int Cmd_mpc(const ParsedCmd *cmd); /* mpc? 피에조 버스트 발생 (주파수/사이클 제어) */ static int Cmd_mpc(const ParsedCmd *cmd); /* mpc? 피에조 버스트 발생 (주파수/사이클 제어) */
static int Cmd_mec(const ParsedCmd *cmd); /* mec? 피에조 버스트 + 에코 캡처 (16비트 원시) */ static int Cmd_mec(const ParsedCmd *cmd); /* mec? 피에조 버스트 + 에코 캡처 (16비트 원시) */
static int Cmd_maa(const ParsedCmd *cmd); /* maa? 4채널 전체 캡처 (비동기 전송) */ static int Cmd_maa(const ParsedCmd *cmd); /* maa? 6채널 전체 캡처 (비동기 전송) */
static int Cmd_mbb(const ParsedCmd *cmd); /* mbb? 6채널 캡처 + 센서 측정 (배터리 + 온도 + IMU) */
/* ---- 명령 테이블 ---- */ /* ---- 명령 테이블 ---- */
@@ -411,13 +419,8 @@ typedef struct {
int (*handler)(const ParsedCmd *cmd); /* 핸들러 함수 포인터 (1=성공, 0=실패) */ int (*handler)(const ParsedCmd *cmd); /* 핸들러 함수 포인터 (1=성공, 0=실패) */
} CmdEntry; } CmdEntry;
/* 전체 명령 테이블 - 수신된 TAG와 순차 비교하여 일치하는 핸들러 호출 /* 전체 명령 테이블 - 수신된 TAG와 순차 비교하여 일치하는 핸들러 호출 */
*
* enabled=false인 명령은 개발 중
* 동일 핸들러를 여러 TAG에 매핑하여 레거시 호환성 유지 (예: mcj?=scj?, msn?=ssn?) -> 레거시 정리 중
*/
static CmdEntry g_cmd_table[] = { static CmdEntry g_cmd_table[] = {
/* A. 디바이스 상태 제어 */ /* A. 디바이스 상태 제어 */
{ "msq?", true, Cmd_msq }, { "msq?", true, Cmd_msq },
{ "mss?", true, Cmd_mss }, { "mss?", true, Cmd_mss },
@@ -447,6 +450,7 @@ static CmdEntry g_cmd_table[] = {
{ "mpc?", true, Cmd_mpc }, { "mpc?", true, Cmd_mpc },
{ "mec?", true, Cmd_mec }, { "mec?", true, Cmd_mec },
{ "maa?", true, Cmd_maa }, { "maa?", true, Cmd_maa },
{ "mbb?", true, Cmd_mbb },
}; };
/* 명령 테이블 엔트리 수 (컴파일 타임 계산) */ /* 명령 테이블 엔트리 수 (컴파일 타임 계산) */
@@ -512,7 +516,6 @@ static int dr_cmd_dispatch(const ParsedCmd *cmd)
int dr_cmd_parser(const uint8_t *buf, uint8_t len) int dr_cmd_parser(const uint8_t *buf, uint8_t len)
{ {
ParsedCmd cmd; ParsedCmd cmd;
g_plat.log("parser!!!!!!!!\r\n");
if (g_plat.log) g_plat.log("[PARSER] in len=%u crc=%u\r\n", len, g_plat.crc_check); if (g_plat.log) g_plat.log("[PARSER] in len=%u crc=%u\r\n", len, g_plat.crc_check);
@@ -538,9 +541,6 @@ int dr_cmd_parser(const uint8_t *buf, uint8_t len)
* 각 명령 핸들러 구현부 * 각 명령 핸들러 구현부
*============================================================================*/ *============================================================================*/
/* 2026-03-17: mta?, mtr? 삭제 */
/* msn? - 배터리 잔량 ADC 측정 /* msn? - 배터리 잔량 ADC 측정
* 응답: battery_level_meas() 내부에서 BLE 전송 처리 */ * 응답: battery_level_meas() 내부에서 BLE 전송 처리 */
static int Cmd_msn(const ParsedCmd *cmd) static int Cmd_msn(const ParsedCmd *cmd)
@@ -553,14 +553,9 @@ static int Cmd_msn(const ParsedCmd *cmd)
return 1; return 1;
} }
/* 2026-03-17: mpn? 삭제 (압력센서 미탑재) */
/* mso? - TMP235-Q1 온도 센서 전압 측정 /* mso? - TMP235-Q1 온도 센서 전압 측정
* SAADC로 TMP235 출력 전압을 측정하여 BLE로 응답한다. * SAADC로 TMP235 출력 전압을 측정하여 BLE로 응답
* 응답은 tmp235_q1.c의 콜백에서 자동 전송. */ * 응답은 tmp235_q1.c의 콜백에서 자동 전송 */
static int Cmd_mso(const ParsedCmd *cmd) static int Cmd_mso(const ParsedCmd *cmd)
{ {
(void)cmd; (void)cmd;
@@ -675,8 +670,6 @@ static int Cmd_mss(const ParsedCmd *cmd)
return 1; return 1;
} }
/* 2026-03-17: mst? 삭제 */
/* mfv? - 펌웨어 버전 읽기 /* mfv? - 펌웨어 버전 읽기
* *
* 응답: "rfv:" + 12자 ASCII 버전 문자열 (DR_DEVICE_VERSION) * 응답: "rfv:" + 12자 ASCII 버전 문자열 (DR_DEVICE_VERSION)
@@ -748,7 +741,7 @@ static int Cmd_mpb(const ParsedCmd *cmd)
* 에코 캡처 없이 버스트만 발생 (테스트/디버그용) * 에코 캡처 없이 버스트만 발생 (테스트/디버그용)
* *
* 파라미터 (Little-Endian uint16 x 3): * 파라미터 (Little-Endian uint16 x 3):
* word 0: cycles (3~9, 기본값=5) - 버스트 펄스 사이클 수 * word 0: cycles (3~7, 기본값=5) - 버스트 펄스 사이클 수
* word 1: freq_option (기본값=1) - 주파수 선택 * word 1: freq_option (기본값=1) - 주파수 선택
* 0=1.8MHz, 1=2.1MHz(기본), 2=2.0MHz, 3=1.7MHz, 4=2.2MHz * 0=1.8MHz, 1=2.1MHz(기본), 2=2.0MHz, 3=1.7MHz, 4=2.2MHz
* word 2: piezo_ch (0~7, 기본값=0) - 피에조 채널 선택 * word 2: piezo_ch (0~7, 기본값=0) - 피에조 채널 선택
@@ -785,8 +778,8 @@ static int Cmd_mpc(const ParsedCmd *cmd)
cycles, freq_option, freq_str, piezo_ch); cycles, freq_option, freq_str, piezo_ch);
} }
/* 사이클 범위 검증: 3~9 유효 */ /* 사이클 범위 검증: 3~7 유효 */
if (cycles < 3 || cycles > 9) { if (cycles < 3 || cycles > 7) {
dr_ble_return_1("rpc:", 2); /* 에러 응답: 범위 초과 */ dr_ble_return_1("rpc:", 2); /* 에러 응답: 범위 초과 */
return 1; return 1;
} }
@@ -840,7 +833,7 @@ static int Cmd_mec(const ParsedCmd *cmd)
{ {
uint16_t freq_option = 0; /* 기본 1.8MHz */ uint16_t freq_option = 0; /* 기본 1.8MHz */
uint16_t delay_us = 20; /* 기본 20us 딜레이 */ uint16_t delay_us = 20; /* 기본 20us 딜레이 */
uint16_t num_samples = 140; /* 기본 140샘플 (약 20cm 거리) */ uint16_t num_samples = 140; /* 기본 100샘플 */
uint16_t cycles = 5; /* 기본 5사이클 (유효: 3~7) */ uint16_t cycles = 5; /* 기본 5사이클 (유효: 3~7) */
uint16_t averaging = 1; /* 기본 1 (평균화 없음), 최대 1000 */ uint16_t averaging = 1; /* 기본 1 (평균화 없음), 최대 1000 */
uint16_t piezo_ch = 0; /* 기본 채널 0 (유효: 0~7) */ uint16_t piezo_ch = 0; /* 기본 채널 0 (유효: 0~7) */
@@ -979,11 +972,7 @@ static int Cmd_cmd(const ParsedCmd *cmd)
* *
* 버전 마커: 0xA000 (vA) = 비동기 4채널 * 버전 마커: 0xA000 (vA) = 비동기 4채널
*/ */
#define MAA_FREQ_OPTION 1 /* 기본 2.1MHz */ /* 피에조 캡처 파라미터: FDS(m_config)에서 로드, 앱에서 변경 가능 */
#define MAA_DELAY_US 10 /* 버스트 후 10us 딜레이 */
#define MAA_NUM_SAMPLES 100 /* 140샘플 (약 25cm 거리) */
#define MAA_CYCLES 7 /* 7사이클 버스트 */
#define MAA_AVERAGING 5 /* 5회 평균화 */
static int Cmd_maa(const ParsedCmd *cmd) static int Cmd_maa(const ParsedCmd *cmd)
{ {
@@ -1023,11 +1012,11 @@ static int Cmd_maa(const ParsedCmd *cmd)
* - auto_powered=true면 완료 후 자동 전원 OFF * - auto_powered=true면 완료 후 자동 전원 OFF
*=======================================================================*/ *=======================================================================*/
err = maa_async_start( err = maa_async_start(
(uint8_t)MAA_FREQ_OPTION, m_config.piezo_freq_option,
MAA_DELAY_US, m_config.piezo_delay_us,
MAA_NUM_SAMPLES, m_config.piezo_num_samples,
(uint8_t)MAA_CYCLES, m_config.piezo_cycles,
(uint16_t)MAA_AVERAGING, m_config.piezo_averaging,
ble_bin_buffer ble_bin_buffer
); );
@@ -1049,6 +1038,128 @@ static int Cmd_maa(const ParsedCmd *cmd)
} }
/**
* @brief mbb? 비동기 캡처 완료 후 콜백 - 센서 측정 체인 실행
*
* raa: 전송 + 피에조 전원 OFF 이후 호출
* info4 모드로 센서값을 전역 변수에 저장한 뒤, rbb: 패킷으로 일괄 전송
* SAADC 측정은 비동기(콜백)이므로 dr_sd_delay_ms()로 완료 대기
*
* 순서: 배터리 → IMU → (피에조 ON) → 온도
* 응답: rbb: [배터리mV(2)] [IMU 6축(12)] [온도°Cx100(2)] = 20바이트
*/
static void all_sensors(void)
{
if (g_plat.log) g_plat.log("[Cmd_mbb] measuring sensors\r\n");
info4 = true; /* 센서값을 전역 변수에 저장 (BLE 전송 안 함) */
/* 1) 배터리 전압 측정 → info_batt에 저장 */
battery_level_meas();
dr_sd_delay_ms(50); /* SAADC 콜백 완료 대기 */
/* 2) IMU 6축 단발 읽기 → info_imu[6]에 저장 */
hw_i2c_init_once();
imu_read_direct();
/* 3) 온도 측정 → info_temp에 저장 (TMP235는 피에조 전원 필요) */
if (!dr_piezo_is_power_on())
{
if (g_plat.log) g_plat.log("[Cmd_mbb] TX/RX Sleep -> Active for TEMP\r\n");
dr_piezo_system_init();
}
tmp235_voltage_level_meas();
dr_sd_delay_ms(50); /* SAADC 콜백 완료 대기 */
info4 = false;
/* rbb: 패킷 조립 및 전송 : [TAG 4B] [배터리 2B] [IMU 12B] [온도 2B] = 20바이트 = 10워드 */
uint8_t *buf = ble_bin_buffer;
buf[0] = 'r'; buf[1] = 'b'; buf[2] = 'b'; buf[3] = ':';
buf[4] = (uint8_t)(info_batt & 0xFF);
buf[5] = (uint8_t)(info_batt >> 8);
for (int i = 0; i < 6; i++) {
buf[6 + i * 2] = (uint8_t)(info_imu[i] & 0xFF);
buf[6 + i * 2 + 1] = (uint8_t)(info_imu[i] >> 8);
}
buf[18] = (uint8_t)(info_temp & 0xFF);
buf[19] = (uint8_t)(info_temp >> 8);
dr_binary_tx_safe(buf, 10); /* 20바이트 = 10워드 */
if (g_plat.log) g_plat.log("[Cmd_mbb] rbb: sent (batt=%u temp=%u)\r\n", info_batt, info_temp);
}
/**
* @brief mbb? - 6채널 전체 캡처 + 센서 측정 (배터리/온도/IMU)
*
* 센서 측정(rbb:) → 6채널 비동기 캡처(reb:/red:/raa:) → TX/RX OFF
*
* 파라미터: mode (uint16, word 0) - 현재 mode=0만 지원
*
* 응답 흐름:
* 1) 센서 측정: rbb: [배터리(2) + IMU 6축(12) + 온도(2)]
* 2) 각 채널(CH0~CH5): reb: [헤더] → red: [데이터...]
* 3) 캡처 완료: raa: [상태]
*/
static int Cmd_mbb(const ParsedCmd *cmd)
{
uint16_t mode = 0;
dr_adc_err_t err;
(void)dr_get_u16(cmd, 0, &mode);
if (mode > 0)
{
dr_ble_return_1("raa:", 0xFFFF);
return 1;
}
all_sensors();
if (maa_async_is_busy())
{
dr_ble_return_1("raa:", 0xFFFE);
return 1;
}
/* 피에조 전원: OFF일 경우 ON → 완료 후 OFF */
if (!dr_piezo_is_power_on())
{
if (g_plat.log) g_plat.log("[Cmd_mbb] TX/RX Sleep -> Active\r\n");
dr_piezo_system_init();
}
/* 비동기 6채널 캡처 시작 (m_config 파라미터 사용) */
err = maa_async_start(
m_config.piezo_freq_option,
m_config.piezo_delay_us,
m_config.piezo_num_samples,
m_config.piezo_cycles,
m_config.piezo_averaging,
ble_bin_buffer
);
if (err != DR_ADC_OK)
{
if (g_plat.log) g_plat.log("[Cmd_mbb] start failed err=%d\r\n", err);
single_format_data(ble_bin_buffer, "raa:", (uint16_t)(0xFF00 | err));
dr_binary_tx_safe(ble_bin_buffer, 3);
dr_piezo_power_off();
return 1;
}
/* 완료 시 무조건 전원 OFF (전체 측정 사이클) */
maa_async_set_auto_power(true);
return 1;
}
/*============================================================================== /*==============================================================================
* 설정: HW/시리얼 넘버 FDS 읽기/쓰기 * 설정: HW/시리얼 넘버 FDS 읽기/쓰기
* *

View File

@@ -7,9 +7,9 @@
******************************************************************************/ ******************************************************************************/
/******************************************************************************* /*******************************************************************************
* [모듈 개요] 배터리 전압 및 압력센서 ADC 측정 모듈 * [모듈 개요] 배터리 전압 및 압력센서 ADC 측정 모듈 ---> 압력 센서 미탑재로 압력 센서 부분 삭제 예정
* *
* nRF52840의 SAADC(Successive Approximation ADC)를 사용하여 다음을 수행한다: * nRF52840의 SAADC(Successive Approximation ADC)를 사용하여 다음을 수행:
* 1) 배터리 전압 측정 (AIN2 채널, 1/3 프리스케일링) * 1) 배터리 전압 측정 (AIN2 채널, 1/3 프리스케일링)
* - 5초 주기 타이머(battery_loop)로 반복 측정 * - 5초 주기 타이머(battery_loop)로 반복 측정
* - 저전압(3100mV 이하) 10회 연속 감지 시 자동 전원 OFF * - 저전압(3100mV 이하) 10회 연속 감지 시 자동 전원 OFF
@@ -42,18 +42,22 @@
//#include "fstorage.h" //#include "fstorage.h"
#include "battery_saadc.h" #include "battery_saadc.h"
#include "main_timer.h" #include "main_timer.h"
#include "main.h" /* 2026-03-17: cmd_parse.h 삭제 → main.h */ #include "main.h"
#include "debug_print.h" #include "debug_print.h"
/* SAADC 내부 기준전압 600mV */ /* SAADC 내부 기준전압 600mV */
#define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS 600 /**< Reference voltage (in milli volts) used by ADC while doing conversion. */ #define BATTERY_REF_VOLTAGE_IN_MILLIVOLTS 600 /**< Reference voltage (in milli volts) used by ADC while doing conversion. */
/* 1/3 프리스케일링 보상 계수 (입력 전압을 1/3로 분압하므로 x3, 추가 x2 = 총 x6) */ /* 1/3 프리스케일링 보상 계수 (입력 전압을 1/3로 분압하므로 x3, 추가 x2 = 총 x6) */
#define BATTERY_PRE_SCALING_COMPENSATION 6 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/ #define BATTERY_PRE_SCALING_COMPENSATION 6 /**< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.*/
/* 10비트 ADC 최대 디지털 값 */ /* 10비트 ADC 최대 디지털 값 */
#define BATTERY_ADC_RES_10BITS 1023 /**< Maximum digital value for 10-bit ADC conversion. */ #define BATTERY_ADC_RES_10BITS 1023 /**< Maximum digital value for 10-bit ADC conversion. */
//#define PRESSURE_RESULT_IN_MILLI_VOLTS(adc) ((adc * 3600) / 1023) //#define PRESSURE_RESULT_IN_MILLI_VOLTS(adc) ((adc * 3600) / 1023)
#define PRESSURE_OFFSET_DEFAULT 0 // 압력 offset. 캘리브레이션 시 사용 가능 #define PRESSURE_OFFSET_DEFAULT 0 // 압력 offset. 캘리브레이션 시 사용 가능
#define MV_PER_ADC_STEP 805 // 약 0.805mV per 1 LSB (nRF 12bit + scaling) #define MV_PER_ADC_STEP 805 // 약 0.805mV per 1 LSB (nRF 12bit + scaling)
/**@brief Macro to convert the result of ADC conversion in millivolts. /**@brief Macro to convert the result of ADC conversion in millivolts.
* *
* @param[in] ADC_VALUE ADC result. * @param[in] ADC_VALUE ADC result.
@@ -65,29 +69,33 @@
/* 배터리 측정용 더블 버퍼 (SAADC가 비동기로 교대 사용) */ /* 배터리 측정용 더블 버퍼 (SAADC가 비동기로 교대 사용) */
static nrf_saadc_value_t adc_bufs[2]; static nrf_saadc_value_t adc_bufs[2];
/* 압력센서 2채널 ADC 버퍼 [0]=AIN7(P1), [1]=AIN4(P2) */ /* 압력센서 2채널 ADC 버퍼 [0]=AIN7(P1), [1]=AIN4(P2) */
static int16_t pressure_adc_buf[2]; //cj add 25/11/19 static int16_t pressure_adc_buf[2]; //cj add 25/11/19
static uint16_t convert_adc_to_mV(int16_t raw_adc); //cj add 25/11/19 static uint16_t convert_adc_to_mV(int16_t raw_adc); //cj add 25/11/19
/* 배터리 모니터링 반복 타이머 정의 */ /* 배터리 모니터링 반복 타이머 정의 */
APP_TIMER_DEF(m_battery_loop_timer_id); APP_TIMER_DEF(m_battery_loop_timer_id);
/* 배터리 측정 주기: 5초 (밀리초 단위) */ /* 배터리 측정 주기: 5초 (밀리초 단위) */
#define BATTERY_LOOP_INTERVAL 5000 #define BATTERY_LOOP_INTERVAL 5000
/* 저전압 체크 플래그 — battery_loop에서 true로 설정, 핸들러에서 소비 */ /* 저전압 체크 플래그 — battery_loop에서 true로 설정, 핸들러에서 소비 */
bool low_battery_check = false; bool low_battery_check = false;
/* info4: 전체 센서 데이터 수집 모드 플래그 (cmd_parse에서 설정) */ /* info4: 전체 센서 데이터 수집 모드 플래그 (cmd_parse에서 설정) */
extern bool info4; //cmd_parse extern bool info4; // main.c
// cj add edit 25/11/24 // cj add edit 25/11/24
/* info4 모드에서 압력센서 측정값을 임시 저장하는 변수 (mV 단위) */ /* info4 모드에서 압력센서 측정값을 임시 저장하는 변수 (mV 단위) */
volatile uint16_t info_p1; volatile uint16_t info_p1;
volatile uint16_t info_p2; volatile uint16_t info_p2;
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
/* true가 되면 main_timer에서 전원 OFF 시퀀스 실행 */ /* true가 되면 main_timer에서 전원 OFF 시퀀스 실행 */
extern bool go_device_power_off; extern bool go_device_power_off;
/* 다른 작업(IMU 등) 처리 중이면 true — 배터리 측정 스킵용 */ /* 다른 작업(IMU 등) 처리 중이면 true — 배터리 측정 스킵용 */
extern volatile bool processing; extern volatile bool processing;
@@ -95,8 +103,10 @@ extern volatile bool processing;
extern which_cmd_t cmd_type_t; extern which_cmd_t cmd_type_t;
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ; extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
/* info4 모드에서 배터리 전압을 임시 저장 (mV 단위) */ /* info4 모드에서 배터리 전압을 임시 저장 (mV 단위) */
volatile uint16_t info_batt; //48_c volatile uint16_t info_batt; //48_c
/* info4 순차 측정 제어 플래그: go_batt→ go_temp → motion */ /* info4 순차 측정 제어 플래그: go_batt→ go_temp → motion */
extern bool go_temp; // extern bool go_temp; //
extern bool go_batt; //cmd_parse extern bool go_batt; //cmd_parse
@@ -123,7 +133,9 @@ extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
{ {
/* 음수 ADC 값은 0으로 처리 (노이즈 등으로 발생 가능) */ /* 음수 ADC 값은 0으로 처리 (노이즈 등으로 발생 가능) */
if (raw_adc < 0) if (raw_adc < 0)
{
raw_adc = 0; raw_adc = 0;
}
/* 805 uV/LSB 스케일링: raw x 805 = uV, /1000 = mV */ /* 805 uV/LSB 스케일링: raw x 805 = uV, /1000 = mV */
int32_t mv = (int32_t)raw_adc * MV_PER_ADC_STEP; // 단위: 805 uV int32_t mv = (int32_t)raw_adc * MV_PER_ADC_STEP; // 단위: 805 uV
@@ -131,11 +143,14 @@ extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
/* 0~3500mV 범위로 클램핑하여 유효 범위 보장 */ /* 0~3500mV 범위로 클램핑하여 유효 범위 보장 */
if (mv < 0) if (mv < 0)
{
mv = 0; mv = 0;
}
if (mv > 3500) if (mv > 3500)
{
mv = 3500; mv = 3500;
}
return (uint16_t)mv; return (uint16_t)mv;
} }
@@ -192,15 +207,11 @@ void pressure_all_event_handler(nrf_drv_saadc_evt_t const * p_event)
result_data[1] = p2_mV; result_data[1] = p2_mV;
format_data(ble_bin_buffer, "rpn:", result_data,2); format_data(ble_bin_buffer, "rpn:", result_data,2);
dr_binary_tx_safe(ble_bin_buffer,4); dr_binary_tx_safe(ble_bin_buffer,4);
} }
} }
} }
/** /**
* @brief 배터리 전압 ADC 완료 콜백 * @brief 배터리 전압 ADC 완료 콜백
* *
@@ -214,7 +225,6 @@ void pressure_all_event_handler(nrf_drv_saadc_evt_t const * p_event)
*/ */
void battery_event_handler( nrf_drv_saadc_evt_t const * p_event ) void battery_event_handler( nrf_drv_saadc_evt_t const * p_event )
{ {
/* 저전압 연속 감지 카운터 (static으로 호출 간 유지) */ /* 저전압 연속 감지 카운터 (static으로 호출 간 유지) */
static uint8_t low_battery_cnt = 0; static uint8_t low_battery_cnt = 0;
@@ -238,60 +248,60 @@ void battery_event_handler( nrf_drv_saadc_evt_t const * p_event )
/* ADC값 → mV 변환 (매크로: ADC x 600/1023 x 6) */ /* ADC값 → mV 변환 (매크로: ADC x 600/1023 x 6) */
batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val); batt_lvl_in_milli_volt_0 = BATTERY_RESULT_IN_MILLI_VOLTS(register_val);
/* 분압 저항 보정 계수 1.42 적용 → 실제 배터리 전압 */ /* 분압 저항 보정 계수 1.42 적용 → 실제 배터리 전압 */
batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0) *1.42; batt_lvl_in_milli_volt_1 = (batt_lvl_in_milli_volt_0) *1.42;
/* === 저전압 체크 모드 (battery_loop 타이머에서 설정) === */ /* === 저전압 체크 모드 (battery_loop 타이머에서 설정) === */
if(low_battery_check == true) { if(low_battery_check == true)
{
low_battery_check = false; low_battery_check = false;
/* 배터리 전압이 LOW_BATTERY_VOLTAGE(3100mV) 이하인지 확인 */ /* 배터리 전압이 LOW_BATTERY_VOLTAGE(3100mV) 이하인지 확인 */
if(batt_lvl_in_milli_volt_1 <= LOW_BATTERY_VOLTAGE) { if(batt_lvl_in_milli_volt_1 <= LOW_BATTERY_VOLTAGE)
{
/* 10회 연속 저전압 감지 시 전원 OFF 시퀀스 시작 */ /* 10회 연속 저전압 감지 시 전원 OFF 시퀀스 시작 */
if(low_battery_cnt >= 10) { if(low_battery_cnt >= 10)
{
low_battery_cnt = 0; low_battery_cnt = 0;
/*go to power off and fds save */ /*go to power off and fds save */
DBG_PRINTF("Save FDS parameters and then Power OFF\r\n"); DBG_PRINTF("Save FDS parameters and then Power OFF\r\n");
go_device_power_off = true; go_device_power_off = true;
main_timer_start(); main_timer_start();
}else{ }
else
{
/* 아직 10회 미만 — 카운터 증가 후 경고 출력 */ /* 아직 10회 미만 — 카운터 증가 후 경고 출력 */
low_battery_cnt++; low_battery_cnt++;
DBG_PRINTF("WARNING!!! low_battery cnt = %d, Batt = %d(mV)\r\n", low_battery_cnt, batt_lvl_in_milli_volt_1); DBG_PRINTF("WARNING!!! low_battery cnt = %d, Batt = %d(mV)\r\n", low_battery_cnt, batt_lvl_in_milli_volt_1);
} }
} }
} }
/* === info4 모드: 전체 센서 수집 중 배터리 값 저장 === */
else if (info4 == true){
/* === info4 모드: 전체 센서 수집 중 배터리 값 저장 === */
else if (info4 == true)
{
info_batt = batt_lvl_in_milli_volt_1; info_batt = batt_lvl_in_milli_volt_1;
DBG_PRINTF("INFOTn%d\r\n\r\n", batt_lvl_in_milli_volt_1); DBG_PRINTF("INFOTn%d\r\n\r\n", batt_lvl_in_milli_volt_1);
} }
/* === 일반 모드: 단독 배터리 측정 요청에 대한 응답 전송 === */ /* === 일반 모드: 단독 배터리 측정 요청에 대한 응답 전송 === */
else { else
if(cmd_type_t == CMD_UART) { {
if (cmd_type_t == CMD_UART)
{
DBG_PRINTF("Tn%d\r\n\r\n", batt_lvl_in_milli_volt_1); DBG_PRINTF("Tn%d\r\n\r\n", batt_lvl_in_milli_volt_1);
} else if(cmd_type_t == CMD_BLE) { }
else if (cmd_type_t == CMD_BLE)
{
/* "rsn:" 헤더와 함께 배터리 전압을 바이너리로 BLE 전송 */ /* "rsn:" 헤더와 함께 배터리 전압을 바이너리로 BLE 전송 */
single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1); single_format_data(ble_bin_buffer, "rsn:", batt_lvl_in_milli_volt_1);
dr_binary_tx_safe(ble_bin_buffer,3); dr_binary_tx_safe(ble_bin_buffer,3);
//data_tx_handler(ble_tx_buffer); //data_tx_handler(ble_tx_buffer);
} }
} }
} }
/* info4 모드: 배터리 측정 완료 → 다음 단계(온도 측정)로 전환 */
if (info4 == true){
go_batt =false; /* 배터리 측정 완료 표시 */
go_temp = true; /* 온도 측정 시작 플래그 설정 */
main_timer_start(); /* 메인 타이머 시작 → 온도 측정 트리거 */
}
} }
@@ -309,8 +319,7 @@ static void battery_configure(void)
APP_ERROR_CHECK(err_code); APP_ERROR_CHECK(err_code);
/* AIN2 채널 설정: 싱글엔드 입력, 1/3 프리스케일링 (기본값) */ /* AIN2 채널 설정: 싱글엔드 입력, 1/3 프리스케일링 (기본값) */
nrf_saadc_channel_config_t config = nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
err_code = nrf_drv_saadc_channel_init(0, &config); err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code); APP_ERROR_CHECK(err_code);
@@ -335,33 +344,40 @@ void pressure_all_configure(void)
/* SAADC 드라이버 초기화 (이미 초기화된 경우 무시) */ /* SAADC 드라이버 초기화 (이미 초기화된 경우 무시) */
err_code = nrf_drv_saadc_init(NULL, pressure_all_event_handler); err_code = nrf_drv_saadc_init(NULL, pressure_all_event_handler);
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) {
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE)
{
DBG_PRINTF("SAADC init err=%d\r\n", err_code); DBG_PRINTF("SAADC init err=%d\r\n", err_code);
return; return;
} }
/* 채널 0: AIN7 (압력센서1, P1) */ /* 채널 0: AIN7 (압력센서1, P1) */
nrf_saadc_channel_config_t ch0_cfg = nrf_saadc_channel_config_t ch0_cfg = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
/* 채널 1: AIN4 (압력센서2, P2) */ /* 채널 1: AIN4 (압력센서2, P2) */
nrf_saadc_channel_config_t ch1_cfg = nrf_saadc_channel_config_t ch1_cfg = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
err_code = nrf_drv_saadc_channel_init(0, &ch0_cfg); err_code = nrf_drv_saadc_channel_init(0, &ch0_cfg);
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) {
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE)
{
DBG_PRINTF("SAADC ch0 init err=%d\r\n", err_code); DBG_PRINTF("SAADC ch0 init err=%d\r\n", err_code);
return; return;
} }
err_code = nrf_drv_saadc_channel_init(1, &ch1_cfg); err_code = nrf_drv_saadc_channel_init(1, &ch1_cfg);
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE) {
if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_INVALID_STATE)
{
DBG_PRINTF("SAADC ch1 init err=%d\r\n", err_code); DBG_PRINTF("SAADC ch1 init err=%d\r\n", err_code);
return; return;
} }
/* 2채널 ADC 버퍼 등록 ([0]=P1, [1]=P2) */ /* 2채널 ADC 버퍼 등록 ([0]=P1, [1]=P2) */
err_code = nrf_drv_saadc_buffer_convert(pressure_adc_buf, 2); err_code = nrf_drv_saadc_buffer_convert(pressure_adc_buf, 2);
if (err_code != NRF_SUCCESS) {
if (err_code != NRF_SUCCESS)
{
DBG_PRINTF("SAADC buf conv err=%d\r\n", err_code); DBG_PRINTF("SAADC buf conv err=%d\r\n", err_code);
return; return;
} }
@@ -380,8 +396,6 @@ void battery_level_meas(void)
battery_configure(); /* SAADC 배터리용 초기화 */ battery_configure(); /* SAADC 배터리용 초기화 */
err_code = nrf_drv_saadc_sample(); /* ADC 샘플링 트리거 (비동기) */ err_code = nrf_drv_saadc_sample(); /* ADC 샘플링 트리거 (비동기) */
APP_ERROR_CHECK(err_code); APP_ERROR_CHECK(err_code);
} }
/** /**
@@ -409,13 +423,16 @@ void pressure_all_level_meas(void) //add cj add 25/11/19
void battery_loop(void * p_context) /* For 1sec */ void battery_loop(void * p_context) /* For 1sec */
{ {
UNUSED_PARAMETER(p_context); UNUSED_PARAMETER(p_context);
/* 다른 센서 처리 중이면 배터리 측정 스킵 (충돌 방지) */ /* 다른 센서 처리 중이면 배터리 측정 스킵 (충돌 방지) */
if(processing==true) if(processing==true)
{ {
processing = false ; // add 20241218 processing = false ; // add 20241218
//low_battery_check = true; //low_battery_check = true;
return;} return;
else{ }
else
{
low_battery_check = true; /* 저전압 감지 모드로 측정 */ low_battery_check = true; /* 저전압 감지 모드로 측정 */
battery_level_meas(); /* 배터리 ADC 1회 측정 시작 */ battery_level_meas(); /* 배터리 ADC 1회 측정 시작 */
} }

View File

@@ -63,7 +63,7 @@
#define CONFIG_REC_KEY (0x7010) #define CONFIG_REC_KEY (0x7010)
/* 매직 넘버: 플래시에 저장된 데이터가 유효한 설정인지 판별하는 데 사용 */ /* 매직 넘버: 플래시에 저장된 데이터가 유효한 설정인지 판별하는 데 사용 */
#define CONFIG_MAGIC_NUMBER_VALUE (0x20231226) #define CONFIG_MAGIC_NUMBER_VALUE (0x20260318)
/* 전역 설정 데이터 구조체 인스턴스 */ /* 전역 설정 데이터 구조체 인스턴스 */
config_data_t m_config; config_data_t m_config;
@@ -118,12 +118,15 @@ void fds_default_value_set(void)
/* Reset status */ /* Reset status */
m_config.reset_status = reset_status_dflt; m_config.reset_status = reset_status_dflt;
/* Measurement parameters */
m_config.pd_adc_cnt = 8;
m_config.pd_delay_us = 8000;
/* Device usage count */ /* Device usage count */
m_config.life_cycle = 0; m_config.life_cycle = 0;
/* 피에조 캡처 파라미터 기본값 */
m_config.piezo_freq_option = 1; /* 2.1MHz */
m_config.piezo_delay_us = 10; /* 버스트 후 10us */
m_config.piezo_num_samples = 100; /* 100샘플 */
m_config.piezo_cycles = 7; /* 7사이클 */
m_config.piezo_averaging = 5; /* 5회 평균화 */
} }
@@ -209,7 +212,8 @@ static void wait_for_fds_ready( void )
nrf_pwr_mgmt_run(); nrf_pwr_mgmt_run();
nrf_delay_ms(1); nrf_delay_ms(1);
timeout++; timeout++;
if (timeout > 3000) { /* 3 second timeout */ if (timeout > 3000) /* 3 second timeout */
{
DBG_PRINTF("[FDS] TIMEOUT!\r\n"); DBG_PRINTF("[FDS] TIMEOUT!\r\n");
break; break;
} }
@@ -245,7 +249,8 @@ void config_load( void )
DBG_PRINTF("[FDS] find rc=%u\r\n", rc); DBG_PRINTF("[FDS] find rc=%u\r\n", rc);
/* FDS may not be fully ready yet - retry before writing defaults */ /* FDS may not be fully ready yet - retry before writing defaults */
if (rc != NRF_SUCCESS && cfg_retry < 10) { if (rc != NRF_SUCCESS && cfg_retry < 10)
{
cfg_retry++; cfg_retry++;
DBG_PRINTF("[FDS] retry %u/10\r\n", cfg_retry); DBG_PRINTF("[FDS] retry %u/10\r\n", cfg_retry);
nrf_delay_ms(100); nrf_delay_ms(100);
@@ -259,7 +264,8 @@ void config_load( void )
/* Open the record and read its contents. */ /* Open the record and read its contents. */
rc = fds_record_open(&desc, &config); rc = fds_record_open(&desc, &config);
if (rc != NRF_SUCCESS) { if (rc != NRF_SUCCESS)
{
/* CRC error or corrupt record - delete and use defaults */ /* CRC error or corrupt record - delete and use defaults */
DBG_PRINTF("[FDS] open ERR=%u, deleting\r\n", rc); DBG_PRINTF("[FDS] open ERR=%u, deleting\r\n", rc);
(void)fds_record_delete(&desc); (void)fds_record_delete(&desc);
@@ -275,8 +281,7 @@ void config_load( void )
rc = fds_record_close(&desc); rc = fds_record_close(&desc);
APP_ERROR_CHECK(rc); APP_ERROR_CHECK(rc);
DBG_PRINTF("[FDS] magic=0x%08X (expect 0x%08X)\r\n", DBG_PRINTF("[FDS] magic=0x%08X (expect 0x%08X)\r\n", m_config.magic_number, CONFIG_MAGIC_NUMBER_VALUE);
m_config.magic_number, CONFIG_MAGIC_NUMBER_VALUE);
if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE ) if( m_config.magic_number != (uint32_t)CONFIG_MAGIC_NUMBER_VALUE )
{ // first init { // first init
@@ -315,14 +320,18 @@ void config_load( void )
fds_flag_write = true; fds_flag_write = true;
rc = fds_record_write(&desc, &m_dummy_record); rc = fds_record_write(&desc, &m_dummy_record);
if (rc != NRF_SUCCESS) {
if (rc != NRF_SUCCESS)
{
DBG_PRINTF("[FDS] Write ERR=%u\r\n", rc); DBG_PRINTF("[FDS] Write ERR=%u\r\n", rc);
fds_flag_write = false; fds_flag_write = false;
} }
while( fds_flag_write ) while( fds_flag_write )
{ {
nrf_pwr_mgmt_run(); nrf_pwr_mgmt_run();
} }
if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) ) if( (rc != NRF_SUCCESS) && (rc == FDS_ERR_NO_SPACE_IN_FLASH) )
{ {
rc = fds_gc(); rc = fds_gc();
@@ -332,6 +341,7 @@ void config_load( void )
{ {
APP_ERROR_CHECK(rc); APP_ERROR_CHECK(rc);
} }
NRF_LOG_FLUSH(); NRF_LOG_FLUSH();
goto cfg_load_start; goto cfg_load_start;
} }
@@ -362,15 +372,19 @@ void config_save( void )
DBG_PRINTF("[CFG_SAVE] start\r\n"); DBG_PRINTF("[CFG_SAVE] start\r\n");
/* Wait for any previous FDS operation to complete */ /* Wait for any previous FDS operation to complete */
if (fds_flag_write) { if (fds_flag_write)
{
uint32_t wait_cnt = 0; uint32_t wait_cnt = 0;
DBG_PRINTF("[CFG_SAVE] waiting for prev FDS op...\r\n"); DBG_PRINTF("[CFG_SAVE] waiting for prev FDS op...\r\n");
while (fds_flag_write && wait_cnt < 3000) { while (fds_flag_write && wait_cnt < 3000)
{
nrf_pwr_mgmt_run(); nrf_pwr_mgmt_run();
nrf_delay_ms(1); nrf_delay_ms(1);
wait_cnt++; wait_cnt++;
} }
if (fds_flag_write) { if (fds_flag_write)
{
DBG_PRINTF("[CFG_SAVE] TIMEOUT! forcing flag clear\r\n"); DBG_PRINTF("[CFG_SAVE] TIMEOUT! forcing flag clear\r\n");
fds_flag_write = false; fds_flag_write = false;
} }
@@ -391,6 +405,7 @@ void config_save( void )
fds_flag_write = true; fds_flag_write = true;
rc = fds_record_update(&desc, &m_dummy_record); rc = fds_record_update(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] update rc=%u\r\n", rc); DBG_PRINTF("[CFG_SAVE] update rc=%u\r\n", rc);
if( rc == FDS_ERR_NO_SPACE_IN_FLASH ) if( rc == FDS_ERR_NO_SPACE_IN_FLASH )
{ {
fds_flag_write = false; fds_flag_write = false;
@@ -400,6 +415,7 @@ void config_save( void )
rc = fds_record_update(&desc, &m_dummy_record); rc = fds_record_update(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] retry rc=%u\r\n", rc); DBG_PRINTF("[CFG_SAVE] retry rc=%u\r\n", rc);
} }
if( rc != NRF_SUCCESS ) if( rc != NRF_SUCCESS )
{ {
DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc); DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);
@@ -412,6 +428,7 @@ void config_save( void )
fds_flag_write = true; fds_flag_write = true;
rc = fds_record_write(&desc, &m_dummy_record); rc = fds_record_write(&desc, &m_dummy_record);
DBG_PRINTF("[CFG_SAVE] write rc=%u\r\n", rc); DBG_PRINTF("[CFG_SAVE] write rc=%u\r\n", rc);
if( rc != NRF_SUCCESS ) if( rc != NRF_SUCCESS )
{ {
DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc); DBG_PRINTF("[CFG_SAVE] FAIL rc=%u\r\n", rc);

View File

@@ -40,15 +40,20 @@
typedef struct typedef struct
{ {
uint32_t magic_number; /* 4B - 0x20231226 */ uint32_t magic_number; /* 4B - 0x20231226 */
char hw_no[12]; /* 12B - HW Number */ char hw_no[12]; /* 12B - HW Version */
char serial_no[12]; /* 12B - Serial Number */ char serial_no[12]; /* 12B - Serial Number */
uint8_t static_passkey[6]; /* 6B - BLE Passkey */ uint8_t static_passkey[6]; /* 6B - BLE Passkey */
uint8_t bond_data_delete; /* 1B - Bond delete flag */ uint8_t bond_data_delete; /* 1B - Bond delete flag */
int8_t reset_status; /* 1B - Reset status */ int8_t reset_status; /* 1B - Reset status */
uint8_t pd_adc_cnt; /* 1B - ADC sample count */ uint32_t life_cycle; /* 4B - Device usage count */
uint16_t pd_delay_us; /* 2B - PD delay (us) */
uint32_t life_cycle; /* 4B - Device usage count (sxz/syz command) */ /* Piezo 측정 파라미터 - 8B */
} config_data_t; /* Total: 45 bytes - FDS에 저장하는 디바이스 설정 */ uint8_t piezo_freq_option; /* 1B - Frequency : 송신 펄스 주파수 (0=1.8M, 1=2.1M, 2=2.0M, 3=1.7M) */
uint8_t piezo_cycles; /* 1B - Burst Cycle : 송신 펄스 사이클 수 (3~7) */
uint16_t piezo_averaging; /* 2B - 채널당 반복 측정 횟수 */
uint16_t piezo_delay_us; /* 2B - 송신 펄스 출력 후 ADC 시작 시까지 대기시간(us) */
uint16_t piezo_num_samples; /* 2B - 측정 ADC 샘플 개수(80~140) */
} config_data_t; /* Total: 48 bytes - FDS에 저장하는 디바이스 설정 */
extern config_data_t m_config; extern config_data_t m_config;

View File

@@ -9,8 +9,8 @@
/******************************************************************************* /*******************************************************************************
* [모듈 개요] ICM42670P IMU 드라이버 상위 레이어 * [모듈 개요] ICM42670P IMU 드라이버 상위 레이어
* *
* ICM42670P IMU 센서의 초기화, 설정, 데이터 읽기를 담당하는 애플리케이션 * ICM42670P IMU 센서의 초기화, 설정, 데이터 읽기를 담당하는 애플리케이션 레이어 모듈
* 레이어 모듈이다. InvenSense 드라이버 API를 래핑하여 사용한다. * InvenSense 드라이버 API를 래핑하여 사용
* *
* 주요 기능: * 주요 기능:
* 1) setup_imu_device() - IMU 초기화 및 WHOAMI 확인 (0x67 = ICM42670P) * 1) setup_imu_device() - IMU 초기화 및 WHOAMI 확인 (0x67 = ICM42670P)
@@ -28,8 +28,7 @@
* - 센서 설정 → 전원 ON → 80ms 대기 → 12바이트 읽기 → 슬립 * - 센서 설정 → 전원 ON → 80ms 대기 → 12바이트 읽기 → 슬립
* *
* 마운팅 매트릭스: * 마운팅 매트릭스:
* Q30 고정소수점 형식의 3x3 회전 매트릭스로, 보드에 장착된 센서의 * Q30 고정소수점 형식의 3x3 회전 매트릭스로, 보드에 장착된 센서의물리적 방향을 소프트웨어 좌표계에 맞춰 보정
* 물리적 방향을 소프트웨어 좌표계에 맞춰 보정한다.
******************************************************************************/ ******************************************************************************/
#include "sdk_config.h" #include "sdk_config.h"
@@ -43,7 +42,6 @@
#include "app_util_platform.h" #include "app_util_platform.h"
#include "main.h" #include "main.h"
/* 2026-03-17: cmd_parse.h 삭제 — main.h는 이미 포함됨 */
#include "debug_print.h" #include "debug_print.h"
#include "nrf_delay.h" #include "nrf_delay.h"
@@ -60,7 +58,7 @@
* Static and extern variables * Static and extern variables
* -------------------------------------------------------------------------------------- */ * -------------------------------------------------------------------------------------- */
/* IMU 드라이버 객체 — 드라이버 API 호출 시 항상 이 구조체 전달 */ /* IMU 드라이버 객체 — 드라이버 API 호출 시 항상 이 구조체 전달 */
static struct inv_imu_device icm_driver; static struct inv_imu_device icm_driver;
/* BLE 전송용 바이너리 버퍼 */ /* BLE 전송용 바이너리 버퍼 */
@@ -69,7 +67,7 @@ static struct inv_imu_device icm_driver;
/* /*
* ICM42670P 마운팅 매트릭스 (Q30 고정소수점) * ICM42670P 마운팅 매트릭스 (Q30 고정소수점)
* *
* 센서가 보드에 장착된 물리적 방향에 따라 좌표 변환을 수행한다. * 센서가 보드에 장착된 물리적 방향에 따라 좌표 변환
* Q30 형식: 1.0 = (1 << 30) = 0x40000000 * Q30 형식: 1.0 = (1 << 30) = 0x40000000
* *
* SM_REVB_DB (개발보드): X→-Y, Y→X 변환 (90도 회전) * SM_REVB_DB (개발보드): X→-Y, Y→X 변환 (90도 회전)
@@ -143,7 +141,7 @@ int setup_imu_device(struct inv_imu_serif *icm_serif)
/* /*
* configure_imu_device() * configure_imu_device()
* IMU 센서 동작 파라미터 설정한다. * IMU 센서 동작 파라미터 설정
* *
* 설정 항목: * 설정 항목:
* - FIFO: 비활성화 (USE_FIFO=0일 때, 레지스터 직접 읽기 모드) * - FIFO: 비활성화 (USE_FIFO=0일 때, 레지스터 직접 읽기 모드)
@@ -161,7 +159,7 @@ int configure_imu_device(void)
{ {
int rc = 0; int rc = 0;
/* FIFO 비활성화 — 레지스터에서 직접 데이터를 읽는다 */ /* FIFO 비활성화 — 레지스터에서 직접 데이터를 읽 */
if (!USE_FIFO) if (!USE_FIFO)
rc |= inv_imu_configure_fifo(&icm_driver, INV_IMU_FIFO_DISABLED); rc |= inv_imu_configure_fifo(&icm_driver, INV_IMU_FIFO_DISABLED);
@@ -199,9 +197,9 @@ int configure_imu_device(void)
/* /*
* get_imu_data() * get_imu_data()
* IMU에서 센서 데이터는다. * IMU에서 센서 데이터 읽
* USE_FIFO 설정에 따라 FIFO 또는 레지스터에서 데이터를 가져온다. * USE_FIFO 설정에 따라 FIFO 또는 레지스터에서 데이터를 가져
* 읽은 데이터는 imu_callback()을 통해 처리된다. * 읽은 데이터는 imu_callback()을 통해 처리
*/ */
int get_imu_data(void) int get_imu_data(void)
{ {
@@ -255,7 +253,7 @@ static void get_accel_and_gyr_fsr(int16_t * accel_fsr_g, int16_t * gyro_fsr_dps)
/* /*
* imu_callback() * imu_callback()
* IMU 드라이버가 새 센서 데이터를 읽을 때마다 호출되는 콜백 함수. * IMU 드라이버가 새 센서 데이터를 읽을 때마다 호출되는 콜백 함수
* *
* 처리 흐름: * 처리 흐름:
* 1) 이벤트에서 가속도/자이로 원시 데이터 추출 * 1) 이벤트에서 가속도/자이로 원시 데이터 추출
@@ -370,12 +368,9 @@ void imu_callback(inv_imu_sensor_event_t *event)
{ {
motion_raw_data_enabled = false; motion_raw_data_enabled = false;
/* info4 모드: 전역 배열 info_imu[6]에 데이터 저장, 외부 모듈에서 이 배열을 폴링하여 데이터 사용 */
if (info4 == true) if (info4 == true)
{ {
/*
* info4 모드: 전역 배열 info_imu[6]에 데이터를 저장한다.
* 외부 모듈에서 이 배열을 폴링하여 데이터를 사용한다.
*/
info_imu[0] = (uint16_t)accel[0]; info_imu[0] = (uint16_t)accel[0];
info_imu[1] = (uint16_t)accel[1]; info_imu[1] = (uint16_t)accel[1];
info_imu[2] = (uint16_t)accel[2]; info_imu[2] = (uint16_t)accel[2];
@@ -384,27 +379,30 @@ void imu_callback(inv_imu_sensor_event_t *event)
info_imu[5] = (uint16_t)gyro[2]; info_imu[5] = (uint16_t)gyro[2];
} }
else if(cmd_type_t == CMD_UART) {
/* UART 모드: "Tp" 접두사로 6축 데이터를 텍스트 형식으로 출력 */ /* UART 모드: "Tp" 접두사로 6축 데이터를 텍스트 형식으로 출력 */
else if(cmd_type_t == CMD_UART) {
printf("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]); printf("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);
} else if(cmd_type_t == CMD_BLE) { }
/* /*
* BLE 모드: 6축 데이터를 바이너리 패킷으로 BLE 전송 * BLE 모드: 6축 데이터를 바이너리 패킷으로 BLE 전송
* ssp_data[0~2] = 가속도 XYZ, ssp_data[3~5] = 자이로 XYZ * ssp_data[0~2] = 가속도 XYZ, ssp_data[3~5] = 자이로 XYZ
* format_data()로 "rsp:" 태그 + 12바이트 데이터를 패킷화 * format_data()로 "rsp:" 태그 + 12바이트 데이터를 패킷화
* dr_binary_tx_safe()로 8바이트 BLE 전송 * dr_binary_tx_safe()로 8바이트 BLE 전송
*/ */
else if(cmd_type_t == CMD_BLE) {
ssp_data[0] = (uint16_t)accel[0]; ssp_data[0] = (uint16_t)accel[0];
ssp_data[1] = (uint16_t)accel[1]; ssp_data[1] = (uint16_t)accel[1];
ssp_data[2] = (uint16_t)accel[2]; ssp_data[2] = (uint16_t)accel[2];
ssp_data[3] = (uint16_t)gyro[0]; ssp_data[3] = (uint16_t)gyro[0];
ssp_data[4] = (uint16_t)gyro[1]; ssp_data[4] = (uint16_t)gyro[1];
ssp_data[5] = (uint16_t)gyro[2]; ssp_data[5] = (uint16_t)gyro[2];
format_data(imu_bin_buffer, "rsp:", ssp_data,12); format_data(imu_bin_buffer, "rsp:", ssp_data,12);
printf("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]); printf("Tp%d,%d,%d,%d,%d,%d\r\n\r\n", accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);
dr_binary_tx_safe(imu_bin_buffer,8); dr_binary_tx_safe(imu_bin_buffer,8);
if(custom_add_data==true)
{ if(custom_add_data==true) {
custom_add_data = false; custom_add_data = false;
} }
else { else {
@@ -544,7 +542,7 @@ int imu_read_direct(void)
DBG_PRINTF("[IMU] A:%d,%d,%d G:%d,%d,%d\r\n", DBG_PRINTF("[IMU] A:%d,%d,%d G:%d,%d,%d\r\n",
accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]); accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);
/* BLE 전송용 데이터 패킹: "rsp:" 태그 + 6축 데이터(12바이트) */ /* 데이터 패킹 */
ssp_data[0] = (uint16_t)accel[0]; ssp_data[0] = (uint16_t)accel[0];
ssp_data[1] = (uint16_t)accel[1]; ssp_data[1] = (uint16_t)accel[1];
ssp_data[2] = (uint16_t)accel[2]; ssp_data[2] = (uint16_t)accel[2];
@@ -552,8 +550,19 @@ int imu_read_direct(void)
ssp_data[4] = (uint16_t)gyro[1]; ssp_data[4] = (uint16_t)gyro[1];
ssp_data[5] = (uint16_t)gyro[2]; ssp_data[5] = (uint16_t)gyro[2];
if (info4 == true) {
/* info4 모드: 전역 배열에 저장 (mbb?에서 rbb: 패킷으로 일괄 전송) */
info_imu[0] = ssp_data[0];
info_imu[1] = ssp_data[1];
info_imu[2] = ssp_data[2];
info_imu[3] = ssp_data[3];
info_imu[4] = ssp_data[4];
info_imu[5] = ssp_data[5];
} else {
/* 일반 모드: "rsp:" 태그로 BLE 즉시 전송 */
format_data(imu_bin_buffer, "rsp:", ssp_data, 12); format_data(imu_bin_buffer, "rsp:", ssp_data, 12);
dr_binary_tx_safe(imu_bin_buffer, 8); dr_binary_tx_safe(imu_bin_buffer, 8);
}
/* IMU 슬립 모드: PWR_MGMT0 = 0x00 → 가속도/자이로 모두 OFF (전력 절감) */ /* IMU 슬립 모드: PWR_MGMT0 = 0x00 → 가속도/자이로 모두 OFF (전력 절감) */
{ {

View File

@@ -278,7 +278,7 @@ char HW_NO[HW_NO_LENGTH]; /* 하드웨어 번호 (FDS
bool bond_data_delete; /* 본딩 데이터 삭제 요청 플래그 */ bool bond_data_delete; /* 본딩 데이터 삭제 요청 플래그 */
uint32_t m_life_cycle; /* 디바이스 수명 사이클 카운터 */ uint32_t m_life_cycle; /* 디바이스 수명 사이클 카운터 */
uint8_t resetCount = 0; /* 통신 타임아웃 카운터 (리셋 감지용) */ uint8_t resetCount = 0; /* 통신 타임아웃 카운터 (리셋 감지용) */
bool info4; /* 추가 정보(배터리/온도/IMU) 포함 측정 플래그 */ bool info4; /* 센서 측정 정보(배터리/IMU/온도) 포함 측정 플래그 */
uint8_t m_reset_status; /* 리셋 상태 코드 (1=정상, 2=SW리셋, 5=보안리셋, 10=본딩완료) */ uint8_t m_reset_status; /* 리셋 상태 코드 (1=정상, 2=SW리셋, 5=보안리셋, 10=본딩완료) */
/*============================================================================== /*==============================================================================
@@ -318,10 +318,13 @@ static void power_hold_init(void)
*/ */
static void power_control_handler(on_off_cont_t device_power_st) static void power_control_handler(on_off_cont_t device_power_st)
{ {
if (device_power_st == OFF) { if (device_power_st == OFF)
{
nrf_gpio_pin_clear(POWER_HOLD); /* P0.8 LOW → 전원 래치 해제 → 전원 차단 */ nrf_gpio_pin_clear(POWER_HOLD); /* P0.8 LOW → 전원 래치 해제 → 전원 차단 */
DBG_PRINTF("[PWR] OFF\r\n"); DBG_PRINTF("[PWR] OFF\r\n");
} else if (device_power_st == ON) { }
else if (device_power_st == ON)
{
nrf_gpio_pin_set(POWER_HOLD); /* P0.8 HIGH → 전원 유지 */ nrf_gpio_pin_set(POWER_HOLD); /* P0.8 HIGH → 전원 유지 */
DBG_PRINTF("[PWR] ON\r\n"); DBG_PRINTF("[PWR] ON\r\n");
} }
@@ -404,7 +407,8 @@ static void load_flash_config(void)
m_need_save_defaults = false; m_need_save_defaults = false;
/* 하드웨어 번호 — 비어있으면 기본값 채움 */ /* 하드웨어 번호 — 비어있으면 기본값 채움 */
if (m_config.hw_no[0] == 0 || m_config.hw_no[0] == (char)0xFF) { if (m_config.hw_no[0] == 0 || m_config.hw_no[0] == (char)0xFF)
{
memset(m_config.hw_no, 0, HW_NO_LENGTH); memset(m_config.hw_no, 0, HW_NO_LENGTH);
memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION)); memcpy(m_config.hw_no, HARDWARE_VERSION, strlen(HARDWARE_VERSION));
DBG_PRINTF("[CFG] HW empty, set default: %s\r\n", HARDWARE_VERSION); DBG_PRINTF("[CFG] HW empty, set default: %s\r\n", HARDWARE_VERSION);
@@ -412,7 +416,8 @@ static void load_flash_config(void)
} }
/* 시리얼 번호 — 비어있으면 기본값 채움 */ /* 시리얼 번호 — 비어있으면 기본값 채움 */
if (m_config.serial_no[0] == 0 || m_config.serial_no[0] == (char)0xFF) { if (m_config.serial_no[0] == 0 || m_config.serial_no[0] == (char)0xFF)
{
memset(m_config.serial_no, 0, SERIAL_NO_LENGTH); memset(m_config.serial_no, 0, SERIAL_NO_LENGTH);
memcpy(m_config.serial_no, FIRMWARE_SERIAL_NO, strlen(FIRMWARE_SERIAL_NO)); memcpy(m_config.serial_no, FIRMWARE_SERIAL_NO, strlen(FIRMWARE_SERIAL_NO));
DBG_PRINTF("[CFG] S/N empty, set default: %s\r\n", FIRMWARE_SERIAL_NO); DBG_PRINTF("[CFG] S/N empty, set default: %s\r\n", FIRMWARE_SERIAL_NO);
@@ -472,7 +477,8 @@ static void PM_s(void * p_context)
UNUSED_PARAMETER(p_context); UNUSED_PARAMETER(p_context);
APP_ERROR_CHECK(app_timer_stop(m_PM_timer_id)); APP_ERROR_CHECK(app_timer_stop(m_PM_timer_id));
if (m_reset_status == 5) { if (m_reset_status == 5)
{
DBG_PRINTF("[PM] Kill\r\n"); DBG_PRINTF("[PM] Kill\r\n");
sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
} }
@@ -628,7 +634,8 @@ static void nus_data_handler(ble_nus_evt_t * p_evt)
DBG_PRINTF("[NUS] RX len=%d\r\n", p_evt->params.rx_data.length); DBG_PRINTF("[NUS] RX len=%d\r\n", p_evt->params.rx_data.length);
/* 콜백에서는 복사만 하고, 메인 루프에서 처리 */ /* 콜백에서는 복사만 하고, 메인 루프에서 처리 */
if (p_evt->params.rx_data.length <= BLE_NUS_MAX_DATA_LEN) { if (p_evt->params.rx_data.length <= BLE_NUS_MAX_DATA_LEN)
{
memcpy((void *)pending_cmd_buf, p_evt->params.rx_data.p_data, p_evt->params.rx_data.length); memcpy((void *)pending_cmd_buf, p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
pending_cmd_len = p_evt->params.rx_data.length; pending_cmd_len = p_evt->params.rx_data.length;
} }

View File

@@ -215,16 +215,11 @@ void main_loop(void * p_context) /* For x ms */
} }
/* For System Control */
/* ---- 시스템 제어 이벤트 처리 ---- */ /* ---- 시스템 제어 이벤트 처리 ---- */
/* 디바이스 전원 OFF 처리 */ /* 디바이스 전원 OFF 처리 */
if(go_device_power_off == true){ if(go_device_power_off == true){
main_timer_stop(); /* 타이머 정지 */ main_timer_stop(); /* 타이머 정지 */
DBG_PRINTF("Off main_timer\r\n"); DBG_PRINTF("Off main_timer\r\n");
device_power_off(); /* 디바이스 전원 OFF 실행 */ device_power_off(); /* 디바이스 전원 OFF 실행 */
} }
@@ -232,20 +227,13 @@ void main_loop(void * p_context) /* For x ms */
/* 슬립 모드 진입 처리 */ /* 슬립 모드 진입 처리 */
if(go_sleep_mode_enter == true){ if(go_sleep_mode_enter == true){
main_timer_stop(); /* 타이머 정지 */ main_timer_stop(); /* 타이머 정지 */
DBG_PRINTF("sleep main timer\r\n"); DBG_PRINTF("sleep main timer\r\n");
sleep_mode_enter(); /* 슬립 모드 진입 실행 */ sleep_mode_enter(); /* 슬립 모드 진입 실행 */
} }
/* NVIC 시스템 리셋 처리 */ /* NVIC 시스템 리셋 처리 */
if(go_NVIC_SystemReset == true) { if(go_NVIC_SystemReset == true) {
main_timer_stop(); /* 타이머 정지 */ main_timer_stop(); /* 타이머 정지 */
NVIC_SystemReset(); /* ARM Cortex-M4 시스템 리셋 */ NVIC_SystemReset(); /* ARM Cortex-M4 시스템 리셋 */
} }
} }
@@ -254,7 +242,7 @@ void main_loop(void * p_context) /* For x ms */
/** /**
* @brief 메인 루프 타이머 시작 * @brief 메인 루프 타이머 시작
* *
* 싱글샷 모드로 MAIN_LOOP_INTERVAL(10ms 또는 80ms) 후 main_loop()를 호출한다. * 싱글샷 모드로 MAIN_LOOP_INTERVAL(10ms 또는 80ms) 후 main_loop()를 호출
*/ */
void main_timer_start(void) void main_timer_start(void)
{ {
@@ -264,7 +252,7 @@ void main_timer_start(void)
/** /**
* @brief 지정된 간격(ms)으로 메인 루프 타이머 시작 * @brief 지정된 간격(ms)으로 메인 루프 타이머 시작
* *
* IMU 연속 스트리밍 등 기본 간격과 다른 주기가 필요할 때 사용. * IMU 연속 스트리밍 등 기본 간격과 다른 주기가 필요할 때 사용
*/ */
void main_timer_start_ms(uint32_t interval_ms) void main_timer_start_ms(uint32_t interval_ms)
{ {
@@ -282,8 +270,8 @@ void main_timer_stop(void)
/** /**
* @brief 메인 루프 타이머 초기화 (앱 시작 시 1회 호출) * @brief 메인 루프 타이머 초기화 (앱 시작 시 1회 호출)
* *
* 싱글샷 모드 타이머를 생성하고, 콜백으로 main_loop()를 등록한다. * 싱글샷 모드 타이머를 생성하고, 콜백으로 main_loop()를 등록
* 싱글샷이므로 매 호출마다 main_timer_start()로 수동 재시작해야 한다. * 싱글샷이므로 매 호출마다 main_timer_start()로 수동 재시작해야
*/ */
void main_timer_init(void) void main_timer_init(void)
{ {

View File

@@ -7,11 +7,11 @@
******************************************************************************/ ******************************************************************************/
/******************************************************************************* /*******************************************************************************
* [한국어 설명] PWM 펄스 생성기 * PWM 펄스 생성기
* *
* === 현재 상태 === * === 현재 상태 ===
* SKIP_PWM 매크로가 정의되어 있어 PWM 기능이 비활성화됨. * SKIP_PWM 매크로가 정의되어 있어 PWM 기능이 비활성화됨.
* init/start/stop 함수는 모두 Stub(빈 껍데기) 구현으로, * init/start/stop 함수는 모두 Stub으로,
* 로그만 출력하고 실제 PWM 동작은 하지 않는다. * 로그만 출력하고 실제 PWM 동작은 하지 않는다.
* 빌드 호환성을 위해 함수 인터페이스만 유지. * 빌드 호환성을 위해 함수 인터페이스만 유지.
* *

View File

@@ -9,9 +9,8 @@
/******************************************************************************* /*******************************************************************************
* [모듈 개요] TMP235-Q1 아날로그 온도센서 드라이버 * [모듈 개요] TMP235-Q1 아날로그 온도센서 드라이버
* *
* TMP235-Q1은 온도에 비례하는 아날로그 전압(Vout)을 출력하는 센서이다. * TMP235-Q1은 온도에 비례하는 아날로그 전압(Vout)을 출력하는 센서
* nRF52840 SAADC의 AIN3 채널로 Vout을 읽고, mV로 변환한 뒤 * nRF52840 SAADC의 AIN3 채널로 Vout을 읽고, mV로 변환한 뒤 온도(°C)로 계산
* 온도(°C)로 계산한다.
* *
* 온도 계산 공식 (구간별 선형 보간): * 온도 계산 공식 (구간별 선형 보간):
* - Vout <= 1500mV (0~100°C): Ta = (Vout - 500) / 10.0 * - Vout <= 1500mV (0~100°C): Ta = (Vout - 500) / 10.0
@@ -61,13 +60,17 @@
static nrf_saadc_value_t adc_buf; static nrf_saadc_value_t adc_buf;
extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN]; extern char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN];
extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ; extern uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] ;
/* 현재 명령 소스: CMD_UART 또는 CMD_BLE */ /* 현재 명령 소스: CMD_UART 또는 CMD_BLE */
extern which_cmd_t cmd_type_t; extern which_cmd_t cmd_type_t;
/* info4: 전체 센서 데이터 수집 모드 플래그 */ /* info4: 전체 센서 데이터 수집 모드 플래그 */
extern bool info4; //cmd_parse extern bool info4; // main.c
/* 온도 측정 순서 제어 플래그 */ /* 온도 측정 순서 제어 플래그 */
extern bool go_temp; //cmd_parse extern bool go_temp; // main_timer.c
/* info4 모드에서 온도값을 임시 저장 (°C x 100, 정수 표현) */
/* info4 모드에서 온도값 임시 저장 (°C x 100, 정수 표현) */
volatile uint16_t info_temp; //48_C volatile uint16_t info_temp; //48_C
extern bool motion_raw_data_enabled; extern bool motion_raw_data_enabled;
@@ -87,9 +90,9 @@ extern bool motion_raw_data_enabled;
*/ */
void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout reading */ void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout reading */
{ {
float led_temp; /* 계산된 온도 (°C, 부동소수점) */ float led_temp; /* 계산된 온도 (°C, 부동소수점) */
uint16_t led_temp_16; /* BLE 전송용 온도 (°C x 100, 정수) */ uint16_t led_temp_16; /* BLE 전송용 온도 (°C x 100, 정수) */
if (p_event->type == NRF_DRV_SAADC_EVT_DONE) if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{ {
nrf_saadc_value_t adc_result; nrf_saadc_value_t adc_result;
@@ -113,31 +116,40 @@ void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout
* 100~125°C 구간: 기울기 10.1 mV/°C * 100~125°C 구간: 기울기 10.1 mV/°C
* 125~150°C 구간: 기울기 10.6 mV/°C * 125~150°C 구간: 기울기 10.6 mV/°C
*/ */
if(tmp235_voltage_in_milli_volts <= 1500) { if(tmp235_voltage_in_milli_volts <= 1500)
{
/* 0~100°C: Ta = (Vout - 500mV) / 10.0 mV/°C */ /* 0~100°C: Ta = (Vout - 500mV) / 10.0 mV/°C */
led_temp = (tmp235_voltage_in_milli_volts - 500.0f) / 10.0f + 0.0f; led_temp = (tmp235_voltage_in_milli_volts - 500.0f) / 10.0f + 0.0f;
}else if(tmp235_voltage_in_milli_volts <= 1750) { }
else if(tmp235_voltage_in_milli_volts <= 1750)
{
/* 100~125°C: 기울기가 10.1로 약간 증가 */ /* 100~125°C: 기울기가 10.1로 약간 증가 */
led_temp = (tmp235_voltage_in_milli_volts - 1500.0f) / 10.1f + 100.0f; led_temp = (tmp235_voltage_in_milli_volts - 1500.0f) / 10.1f + 100.0f;
}else if(tmp235_voltage_in_milli_volts <= 2000) { }
else if(tmp235_voltage_in_milli_volts <= 2000)
{
/* 125~150°C: 기울기가 10.6으로 더 증가 */ /* 125~150°C: 기울기가 10.6으로 더 증가 */
led_temp = (tmp235_voltage_in_milli_volts - 1752.5f) / 10.6f + 125.0f; led_temp = (tmp235_voltage_in_milli_volts - 1752.5f) / 10.6f + 125.0f;
}else { }
else
{
/* 150°C 초과 — 센서 측정 범위 벗어남 */ /* 150°C 초과 — 센서 측정 범위 벗어남 */
DBG_PRINTF("ERR!!! Temprature is over 150c\r\n"); DBG_PRINTF("ERR!!! Temprature is over 150c\r\n");
} }
/* info4 모드: 온도값을 정수(°C x 100)로 저장 (예: 36.50°C → 3650) */ /* info4 모드: 온도값을 정수(°C x 100)로 저장 (예: 36.50°C → 3650) */
if (info4 == true){ if (info4 == true)
{
info_temp =(uint16_t)(led_temp*100); info_temp =(uint16_t)(led_temp*100);
} }
/* UART 모드: 소수점 2자리까지 텍스트로 출력 */ /* UART 모드: 소수점 2자리까지 텍스트로 출력 */
else if(cmd_type_t == CMD_UART) { else if(cmd_type_t == CMD_UART)
{
DBG_PRINTF("To%.2f\r\n\r\n",led_temp); DBG_PRINTF("To%.2f\r\n\r\n",led_temp);
}
/* BLE 모드: °C x 100 정수를 "rso:" 헤더로 바이너리 전송 */ /* BLE 모드: °C x 100 정수를 "rso:" 헤더로 바이너리 전송 */
} else if(cmd_type_t == CMD_BLE) { else if(cmd_type_t == CMD_BLE)
{
led_temp_16 = (uint16_t)(led_temp*100); led_temp_16 = (uint16_t)(led_temp*100);
single_format_data(ble_bin_buffer, "rso:", led_temp_16); single_format_data(ble_bin_buffer, "rso:", led_temp_16);
@@ -148,15 +160,6 @@ void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout
} }
} }
/* info4 모드: 온도 측정 완료 → 다음 단계(IMU 측정)로 전환 */
if (info4 == true){
go_temp = false; /* 온도 측정 완료 표시 */
motion_raw_data_enabled = true; /* IMU 데이터 수집 시작 플래그 */
main_timer_start(); /* 메인 타이머 시작 → IMU 측정 트리거 */
}
} }
@@ -173,8 +176,7 @@ void tmp235_init(void)
APP_ERROR_CHECK(err_code); APP_ERROR_CHECK(err_code);
/* AIN3 채널 설정: TMP235-Q1 Vout 핀 (싱글엔드 입력) */ /* AIN3 채널 설정: TMP235-Q1 Vout 핀 (싱글엔드 입력) */
nrf_saadc_channel_config_t config = nrf_saadc_channel_config_t config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3); /* TMP235_Q1 Voltage Output Measurement */
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3); /* TMP235_Q1 Voltage Output Measurement */
err_code = nrf_drv_saadc_channel_init(0, &config); err_code = nrf_drv_saadc_channel_init(0, &config);
APP_ERROR_CHECK(err_code); APP_ERROR_CHECK(err_code);
@@ -197,8 +199,7 @@ void tmp235_init(void)
*/ */
void tmp235_voltage_level_meas(void) void tmp235_voltage_level_meas(void)
{ {
tmp235_init(); tmp235_init(); // init 함수에 있는 걸 그냥 여기 넣어도
//tmp235_uninit(); //tmp235_uninit();
} }