maa samples 140->100 변경, mec/maa 수신 시 Piezo 자동 Active/Sleep
- MAA_NUM_SAMPLES 140에서 100으로 변경 (DR_ADC_ECHO_SAMPLES_MAX 제한) - 단일(mec) 및 모든 채널(maa) 에코 캡처 명령 수신 시 Piezo 자동 Active, 응답 송신 후 Sleep - Cmd_mpa 중복 호출 정리 (dr_piezo_system_init 내부에 power_on 포함) - 채널별 디버그 로그 추가 - 코드 리뷰 주석 정리 및 기타 파일 업데이트 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,19 +3,39 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [헤더 개요] 배터리 전압 및 압력센서 SAADC 측정 인터페이스
|
||||
*
|
||||
* nRF52840 SAADC를 이용한 배터리 전압 측정과 압력센서 2채널 측정의
|
||||
* 외부 호출용 API를 선언한다.
|
||||
*
|
||||
* 주요 API:
|
||||
* - battery_level_meas() : 배터리 전압 1회 측정 (AIN2)
|
||||
* - pressure_all_level_meas() : 압력센서 2채널 1회 측정 (AIN7, AIN4)
|
||||
* - battery_timer_init/start/stop() : 5초 주기 배터리 모니터링 타이머 제어
|
||||
*
|
||||
* LOW_BATTERY_VOLTAGE(3100mV) 이하가 10회 연속 감지되면 자동 전원 OFF
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _BATTERY_SAADC_H_
|
||||
#define _BATTERY_SAADC_H_
|
||||
|
||||
/* 저전압 판정 임계값 (mV) — 이 값 이하가 10회 연속이면 자동 전원 OFF */
|
||||
#define LOW_BATTERY_VOLTAGE 3100 /* Low Battery 임계값 */
|
||||
|
||||
|
||||
/** @brief 배터리 전압 1회 측정 시작 (비동기, 결과는 콜백에서 처리) */
|
||||
void battery_level_meas(void);
|
||||
/** @brief 압력센서 2채널(AIN7, AIN4) 1회 측정 시작 (비동기) */
|
||||
void pressure_all_level_meas(void);
|
||||
/** @brief 배터리 모니터링 5초 반복 타이머 시작 */
|
||||
void battery_timer_start(void);
|
||||
/** @brief 배터리 모니터링 타이머 정지 */
|
||||
void battery_timer_stop(void);
|
||||
/** @brief 배터리 모니터링 타이머 초기화 (앱 시작 시 1회 호출) */
|
||||
void battery_timer_init(void);
|
||||
|
||||
#endif //_BATTERY_SAADC_H_
|
||||
|
||||
@@ -1,13 +1,32 @@
|
||||
// file: debug_print.h
|
||||
/*******************************************************************************
|
||||
* [한국어 설명] 디버그 출력 매크로 (조건부 컴파일)
|
||||
*
|
||||
* SEGGER RTT(Real Time Transfer)를 이용한 디버그 출력 매크로.
|
||||
* J-Link 디버거를 통해 실시간으로 로그를 PC에 전송한다.
|
||||
* UART를 사용하지 않으므로 시스템 타이밍에 미치는 영향이 적다.
|
||||
*
|
||||
* === 조건부 컴파일 ===
|
||||
* ENABLE_PRINTF = 1: DBG_PRINTF가 SEGGER_RTT_printf(채널0)로 치환됨
|
||||
* -> 실제 로그 출력 (디버깅 시 사용)
|
||||
* ENABLE_PRINTF = 0: DBG_PRINTF가 빈 매크로로 치환됨
|
||||
* -> 코드에서 완전히 제거 (릴리스 빌드 시 사용)
|
||||
*
|
||||
* === 사용법 ===
|
||||
* DBG_PRINTF("값: %d\r\n", value); // printf와 동일한 포맷 문자열
|
||||
* 출력은 SEGGER RTT Viewer 또는 J-Link RTT Client에서 확인.
|
||||
******************************************************************************/
|
||||
#ifndef DEBUG_PRINT_H
|
||||
#define DEBUG_PRINT_H
|
||||
|
||||
#define ENABLE_PRINTF 1 // Set to 0 to disable globally
|
||||
#define ENABLE_PRINTF 1 /* 1=디버그 출력 활성화, 0=전역 비활성화 */
|
||||
|
||||
#if ENABLE_PRINTF
|
||||
#include "SEGGER_RTT.h"
|
||||
/* SEGGER RTT 채널 0으로 포맷 문자열 출력 */
|
||||
#define DBG_PRINTF(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
/* 빈 매크로: 컴파일러가 호출 코드를 완전히 제거 */
|
||||
#define DBG_PRINTF(...) // Do nothing
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,6 +2,36 @@
|
||||
TEST medi50 Dec 23
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @file fstorage.c
|
||||
* @brief FDS(Flash Data Storage) 기반 설정 저장 모듈
|
||||
*
|
||||
* 외부 EEPROM을 대체하여 nRF52840 내장 플래시에 장치 설정을 저장/로드한다.
|
||||
*
|
||||
* [레코드 관리]
|
||||
* - CONFIG_FILE = 0x8010, CONFIG_REC_KEY = 0x7010 으로 단일 레코드를 관리한다.
|
||||
*
|
||||
* [config_data_t 구조체 필드]
|
||||
* - magic(4B) : 포맷 확인용 매직 넘버 (MAGIC = 0x20231226)
|
||||
* - hw_no(12B) : 하드웨어 번호 (BLE 명령으로 설정)
|
||||
* - serial_no(12B) : 시리얼 번호 (기본값: "VB026030000")
|
||||
* - passkey(6B) : BLE 페어링용 정적 패스키
|
||||
* - bond_delete(1B) : 본딩 데이터 삭제 플래그
|
||||
* - reset_status(1B) : 리셋 상태 값
|
||||
* - pd_adc_cnt : 포토다이오드 ADC 측정 횟수
|
||||
* - pd_delay_us : 포토다이오드 측정 간 지연 시간(us)
|
||||
* - life_cycle : 장치 사용 횟수
|
||||
*
|
||||
* [매직 넘버 검증]
|
||||
* - 플래시에서 로드한 데이터의 magic 값이 0x20231226과 일치하는지 확인하여
|
||||
* 유효한 설정인지 판별한다. 불일치 시 기본값으로 초기화한다.
|
||||
*
|
||||
* [FDS 이벤트 후처리]
|
||||
* - FDS 쓰기/업데이트 완료 이벤트 수신 후, 대기 중인 후처리를 수행한다:
|
||||
* 전원 OFF (go_device_power_off), 슬립 진입 (go_sleep_mode_enter),
|
||||
* 시스템 리셋 (go_NVIC_SystemReset)
|
||||
*/
|
||||
|
||||
#include "sdk_config.h"
|
||||
|
||||
#include <string.h>
|
||||
@@ -27,23 +57,29 @@
|
||||
#include "debug_print.h"
|
||||
|
||||
|
||||
/* File ID and Key used for the configuration record. */
|
||||
/* FDS 레코드 식별자: 파일 ID와 레코드 키로 단일 설정 레코드를 관리 */
|
||||
|
||||
#define CONFIG_FILE (0x8010)
|
||||
#define CONFIG_REC_KEY (0x7010)
|
||||
|
||||
/* 매직 넘버: 플래시에 저장된 데이터가 유효한 설정인지 판별하는 데 사용 */
|
||||
#define CONFIG_MAGIC_NUMBER_VALUE (0x20231226)
|
||||
|
||||
/* 전역 설정 데이터 구조체 인스턴스 */
|
||||
config_data_t m_config;
|
||||
|
||||
extern bool go_device_power_off;
|
||||
extern bool go_sleep_mode_enter;
|
||||
extern bool go_NVIC_SystemReset;
|
||||
/* FDS 쓰기 완료 후 수행할 후처리 플래그 (main.c에서 선언) */
|
||||
extern bool go_device_power_off; /* 전원 OFF 요청 */
|
||||
extern bool go_sleep_mode_enter; /* 슬립 모드 진입 요청 */
|
||||
extern bool go_NVIC_SystemReset; /* 시스템 리셋 요청 */
|
||||
|
||||
/* Flag to check fds initialization. */
|
||||
/* FDS 초기화 완료 여부 플래그 (fds_evt_handler에서 true로 설정) */
|
||||
static bool volatile m_fds_initialized;
|
||||
|
||||
/* FDS 쓰기 진행 중 플래그: true이면 쓰기 완료 대기 중 */
|
||||
bool fds_flag_write = false;
|
||||
/* A record containing dummy configuration data. */
|
||||
|
||||
/* FDS에 기록할 레코드 템플릿 (m_config 데이터를 가리킴) */
|
||||
static fds_record_t const m_dummy_record =
|
||||
{
|
||||
.file_id = CONFIG_FILE,
|
||||
@@ -54,9 +90,16 @@ static fds_record_t const m_dummy_record =
|
||||
};
|
||||
|
||||
|
||||
int8_t reset_status_dflt = 99;
|
||||
uint8_t static_passkey_dflt[6] = "123456";
|
||||
/* 기본 설정값 상수 */
|
||||
int8_t reset_status_dflt = 99; /* 리셋 상태 기본값 */
|
||||
uint8_t static_passkey_dflt[6] = "123456"; /* BLE 패스키 기본값 */
|
||||
|
||||
/**
|
||||
* @brief 기본 설정값 초기화
|
||||
*
|
||||
* m_config 구조체의 각 필드를 공장 초기값으로 설정한다.
|
||||
* 플래시에 유효한 설정이 없거나 매직 넘버가 불일치할 때 호출된다.
|
||||
*/
|
||||
void fds_default_value_set(void)
|
||||
{
|
||||
/* HW Number - empty (set via BLE command) */
|
||||
@@ -84,8 +127,19 @@ void fds_default_value_set(void)
|
||||
}
|
||||
|
||||
|
||||
/* 마지막 FDS 이벤트 ID 저장 (디버깅용) */
|
||||
static volatile uint8_t fds_last_evt = 0xFF;
|
||||
|
||||
/**
|
||||
* @brief FDS 이벤트 콜백 핸들러
|
||||
*
|
||||
* FDS 내부에서 비동기 작업이 완료될 때 호출된다.
|
||||
* - FDS_EVT_INIT : FDS 초기화 완료 → m_fds_initialized 플래그 설정
|
||||
* - FDS_EVT_WRITE : 새 레코드 쓰기 완료 → fds_flag_write 해제
|
||||
* - FDS_EVT_UPDATE : 레코드 업데이트 완료 → fds_flag_write 해제 후
|
||||
* 대기 중인 전원 OFF / 슬립 진입 / 시스템 리셋 수행
|
||||
* - FDS_EVT_DEL_RECORD / FDS_EVT_DEL_FILE / FDS_EVT_GC : 현재 미사용
|
||||
*/
|
||||
static void fds_evt_handler( fds_evt_t const *p_evt )
|
||||
{
|
||||
fds_last_evt = p_evt->id;
|
||||
@@ -140,7 +194,13 @@ static void fds_evt_handler( fds_evt_t const *p_evt )
|
||||
}
|
||||
|
||||
|
||||
/**@brief Wait for fds to initialize. */
|
||||
/**
|
||||
* @brief FDS 초기화 완료 대기
|
||||
*
|
||||
* m_fds_initialized 플래그가 true가 될 때까지 대기한다.
|
||||
* 최대 3초(3000ms) 타임아웃이 설정되어 있으며,
|
||||
* 타임아웃 시 에러 로그를 출력하고 반환한다.
|
||||
*/
|
||||
static void wait_for_fds_ready( void )
|
||||
{
|
||||
uint32_t timeout = 0;
|
||||
@@ -157,6 +217,20 @@ static void wait_for_fds_ready( void )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief FDS에서 설정 로드
|
||||
*
|
||||
* 플래시에서 CONFIG_FILE/CONFIG_REC_KEY 레코드를 검색하여 m_config에 로드한다.
|
||||
*
|
||||
* 동작 흐름:
|
||||
* 1. fds_record_find()로 레코드 검색 (실패 시 최대 10회 재시도, 100ms 간격)
|
||||
* 2. 레코드 발견 시:
|
||||
* - fds_record_open()으로 열기 (CRC 에러 시 삭제 후 기본값으로 재생성)
|
||||
* - 데이터를 m_config로 복사
|
||||
* - 매직 넘버 불일치 시 기존 레코드 삭제 → 기본값 설정 → 재기록
|
||||
* 3. 레코드 미발견 시:
|
||||
* - 기본값으로 새 레코드 생성 후 다시 로드
|
||||
*/
|
||||
void config_load( void )
|
||||
{
|
||||
ret_code_t rc;
|
||||
@@ -264,6 +338,21 @@ void config_load( void )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 현재 설정을 FDS에 저장
|
||||
*
|
||||
* m_config의 내용을 플래시에 기록한다.
|
||||
*
|
||||
* 동작 흐름:
|
||||
* 1. 이전 FDS 쓰기 작업이 진행 중이면 최대 3초 대기
|
||||
* 2. 매직 넘버가 올바르지 않으면 보정
|
||||
* 3. 기존 레코드가 있으면 fds_record_update()로 갱신
|
||||
* - 플래시 공간 부족 시 GC(가비지 컬렉션) 수행 후 재시도
|
||||
* 4. 기존 레코드가 없으면 fds_record_write()로 새로 생성
|
||||
*
|
||||
* 참고: 쓰기 완료는 fds_evt_handler()에서 비동기로 처리되며,
|
||||
* 완료 후 전원 OFF/슬립/리셋 등의 후처리가 수행될 수 있다.
|
||||
*/
|
||||
void config_save( void )
|
||||
{
|
||||
ret_code_t rc;
|
||||
@@ -334,11 +423,25 @@ void config_save( void )
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief config_load()의 래퍼 함수
|
||||
*
|
||||
* 외부 모듈에서 설정 로드를 요청할 때 사용한다.
|
||||
*/
|
||||
void fs_set_value(void)
|
||||
{
|
||||
config_load();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief FDS 초기화
|
||||
*
|
||||
* 부팅 시 호출되어 FDS 모듈을 초기화한다.
|
||||
* 1. fds_register()로 이벤트 핸들러 등록
|
||||
* 2. fds_init()로 FDS 초기화 시작
|
||||
* 3. wait_for_fds_ready()로 초기화 완료 대기 (최대 3초)
|
||||
* 4. fds_stat()로 플래시 상태 확인
|
||||
*/
|
||||
void fs_storage_init(void)
|
||||
{
|
||||
ret_code_t rc;
|
||||
|
||||
@@ -3,7 +3,29 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief FDS(Flash Data Storage) 기반 설정 저장 모듈 인터페이스
|
||||
*******************************************************************************
|
||||
*
|
||||
* [헤더 개요]
|
||||
* nRF52840 내장 플래시에 디바이스 설정을 저장/로드하는 FDS 모듈의 공용 API.
|
||||
* 외부 EEPROM을 대체하며, SoftDevice와 공존하여 플래시를 안전하게 관리한다.
|
||||
*
|
||||
* [config_data_t 구조체] (45바이트, 패킹됨)
|
||||
* magic_number(4B): 포맷 확인용 (0x20231226)
|
||||
* hw_no(12B): 하드웨어 번호
|
||||
* serial_no(12B): 시리얼 번호 (BLE 디바이스 이름으로도 사용)
|
||||
* static_passkey(6B): BLE 페어링 패스키 (숫자 6자리)
|
||||
* bond_data_delete(1B): 본딩 삭제 플래그
|
||||
* reset_status(1B): 리셋 상태 코드
|
||||
* pd_adc_cnt(1B): ADC 샘플링 횟수
|
||||
* pd_delay_us(2B): PD 안정화 딜레이 (마이크로초)
|
||||
* life_cycle(4B): 디바이스 사용 횟수
|
||||
*
|
||||
* [주요 API]
|
||||
* fs_storage_init(): FDS 초기화 (부트 시 1회)
|
||||
* config_load(): FDS에서 설정 로드 (없으면 기본값 생성)
|
||||
* config_save(): 현재 설정을 FDS에 저장
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef IHP_FSTORAGE_H_
|
||||
|
||||
@@ -1,6 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* @file i2c_manager.c
|
||||
* @brief Reliable HW↔SW I2C Switching Logic (with Mode Set Logging)
|
||||
*******************************************************************************
|
||||
*
|
||||
* [모듈 개요]
|
||||
* I2C 버스의 HW(하드웨어 TWI) / SW(소프트웨어 비트뱅) 모드 전환을 관리하는 모듈.
|
||||
*
|
||||
* - HW I2C: nRF52840 내장 TWI 하드웨어 주변장치를 사용 (ICM42670P IMU 센서 통신용, 400kHz)
|
||||
* - SW I2C: GPIO 비트뱅 방식의 소프트웨어 I2C (현재 사용하지 않는 레거시 코드)
|
||||
*
|
||||
* [핀 설정]
|
||||
* SCL = P1.14 (ICM42670_I2C_SCL_PIN)
|
||||
* SDA = P1.15 (ICM42670_I2C_SDA_PIN)
|
||||
*
|
||||
* [주요 함수]
|
||||
* hw_i2c_init_once() : SW→HW 전환 또는 HW 초기화 (이미 HW 모드면 중복 초기화 방지)
|
||||
* sw_i2c_init_once() : HW→SW 전환 (TWI 해제 후 SW 모드 진입, 레거시)
|
||||
* i2c_reset_state() : 모든 I2C 모드 플래그를 초기화 (HW/SW 모두 false)
|
||||
*
|
||||
* [동작 원리]
|
||||
* HW_I2C_FRQ, SW_I2C_FRQ 두 개의 bool 플래그로 현재 모드를 추적하며,
|
||||
* 한 번에 하나의 모드만 활성화되도록 상호 배제(mutex) 방식으로 관리한다.
|
||||
* 모드 전환 시 기존 모드의 리소스를 먼저 해제한 후 새 모드를 초기화한다.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "i2c_manager.h"
|
||||
@@ -12,40 +34,52 @@
|
||||
#include "boards.h"
|
||||
#include "system_interface.h"
|
||||
|
||||
bool HW_I2C_FRQ = true;
|
||||
bool SW_I2C_FRQ = false;
|
||||
/* 현재 I2C 모드 상태 플래그 (true = 해당 모드 활성화) */
|
||||
bool HW_I2C_FRQ = true; /* HW TWI 모드 활성 여부 (기본값: true, 초기 상태는 HW) */
|
||||
bool SW_I2C_FRQ = false; /* SW 비트뱅 모드 활성 여부 */
|
||||
|
||||
/* TWI 인스턴스 번호 (nRF52840은 TWI0, TWI1 두 개 지원) */
|
||||
#define TWI_INSTANCE 0
|
||||
|
||||
/* TWI (I2C) 하드웨어 인스턴스 : IMU 드라이버에서 사용 - jhChun 26.03.16 */
|
||||
const nrfx_twi_t m_twi = NRFX_TWI_INSTANCE(TWI_INSTANCE);
|
||||
|
||||
/* TWI (I2C) 해제 - jhChun 26.03.16 */
|
||||
/* TWI 하드웨어를 비활성화하고 초기화 해제하여 GPIO 핀을 반환한다 */
|
||||
static void twi_uninitialize(void){
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
nrfx_twi_disable(&m_twi); /* TWI 주변장치 비활성화 */
|
||||
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 (핀 리소스 반환) */
|
||||
}
|
||||
|
||||
/* TWI (I2C) 하드웨어 초기화 (SCL/SDA핀, 400kHz) - jhChun 26.03.16 */
|
||||
/* SCL, SDA 핀을 설정하고 400kHz Fast Mode로 TWI를 초기화 및 활성화한다 */
|
||||
static void twi_initialize(void){
|
||||
ret_code_t err_code;
|
||||
|
||||
/* TWI 설정 구조체: 핀 번호, 클럭 속도, 인터럽트 우선순위 지정 */
|
||||
const nrfx_twi_config_t twi_config = {
|
||||
.scl = ICM42670_I2C_SCL_PIN,
|
||||
.sda = ICM42670_I2C_SDA_PIN,
|
||||
.frequency = NRF_TWI_FREQ_400K,
|
||||
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
|
||||
.scl = ICM42670_I2C_SCL_PIN, /* SCL 핀 (P1.14) */
|
||||
.sda = ICM42670_I2C_SDA_PIN, /* SDA 핀 (P1.15) */
|
||||
.frequency = NRF_TWI_FREQ_400K, /* 400kHz Fast Mode */
|
||||
.interrupt_priority = APP_IRQ_PRIORITY_HIGH, /* 높은 인터럽트 우선순위 */
|
||||
};
|
||||
|
||||
/* TWI 초기화 (이벤트 핸들러 NULL = 블로킹 모드) */
|
||||
err_code = nrfx_twi_init(&m_twi, &twi_config, NULL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
nrfx_twi_enable(&m_twi);
|
||||
nrfx_twi_enable(&m_twi); /* TWI 주변장치 활성화 → I2C 통신 가능 */
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* HW (TWI) 초기화 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* HW I2C 모드로 전환하거나 초기화하는 함수.
|
||||
* - SW 모드가 활성화되어 있으면 SW 플래그를 해제하고 HW로 전환
|
||||
* - 이미 HW 모드이면 중복 초기화를 방지하여 바로 리턴
|
||||
* - 최초 HW 초기화 시 twi_initialize()를 호출하여 TWI 하드웨어 설정
|
||||
*/
|
||||
void hw_i2c_init_once(void)
|
||||
{
|
||||
// SW 모드일 경우 강제 해제 후 HW 전환
|
||||
@@ -55,9 +89,10 @@ void hw_i2c_init_once(void)
|
||||
|
||||
// SW 리소스 해제 (필요 시 추가)
|
||||
SW_I2C_FRQ = false;
|
||||
nrf_delay_ms(2);
|
||||
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
|
||||
}
|
||||
|
||||
/* 이미 HW 모드가 활성화되어 있으면 중복 초기화 방지를 위해 즉시 리턴 */
|
||||
// 이미 HW면 스킵
|
||||
if (HW_I2C_FRQ)
|
||||
{
|
||||
@@ -65,10 +100,12 @@ void hw_i2c_init_once(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* HW TWI 하드웨어 초기화 수행 (SCL/SDA 핀 설정, 400kHz, 활성화) */
|
||||
// 실제 HW 초기화
|
||||
twi_initialize();
|
||||
nrf_delay_ms(2);
|
||||
nrf_delay_ms(2); /* 초기화 후 안정화 대기 (2ms) */
|
||||
|
||||
/* 모드 플래그 갱신: HW 활성, SW 비활성 */
|
||||
HW_I2C_FRQ = true;
|
||||
SW_I2C_FRQ = false;
|
||||
|
||||
@@ -78,6 +115,12 @@ void hw_i2c_init_once(void)
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* SW (Port Bang-Bang) 초기화 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* SW I2C(비트뱅) 모드로 전환하는 함수. (현재 레거시, 사용하지 않음)
|
||||
* - HW 모드가 활성화되어 있으면 TWI를 해제하고 SW로 전환
|
||||
* - 이미 SW 모드이면 중복 초기화를 방지하여 바로 리턴
|
||||
* - power_control.c의 power_loop()에서 Step 0에서 호출됨
|
||||
*/
|
||||
void sw_i2c_init_once(void)
|
||||
{
|
||||
// HW 모드일 경우 강제 해제 후 SW 전환
|
||||
@@ -85,9 +128,9 @@ void sw_i2c_init_once(void)
|
||||
{
|
||||
//DBG_PRINTF("[I2C]HW→SW\r\n");
|
||||
|
||||
nrfx_twi_disable(&m_twi);
|
||||
nrfx_twi_uninit(&m_twi);
|
||||
nrf_delay_ms(2);
|
||||
nrfx_twi_disable(&m_twi); /* TWI 비활성화 */
|
||||
nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 */
|
||||
nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */
|
||||
|
||||
HW_I2C_FRQ = false;
|
||||
}
|
||||
@@ -99,10 +142,12 @@ void sw_i2c_init_once(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* TWI 라인 완전 해제 후 SW 비트뱅 모드 진입 */
|
||||
// 실제 SW 초기화
|
||||
twi_uninitialize(); // TWI 라인 해제
|
||||
nrf_delay_ms(1);
|
||||
nrf_delay_ms(1); /* 해제 후 안정화 대기 (1ms) */
|
||||
|
||||
/* 모드 플래그 갱신: SW 활성, HW 비활성 */
|
||||
SW_I2C_FRQ = true;
|
||||
HW_I2C_FRQ = false;
|
||||
|
||||
@@ -112,9 +157,14 @@ void sw_i2c_init_once(void)
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 전체 리셋 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
* 모든 I2C 모드 플래그를 초기화하는 함수.
|
||||
* HW/SW 모두 비활성 상태로 만들어, 다음 init 호출 시 강제로 재초기화되도록 한다.
|
||||
* 주로 시스템 리셋이나 에러 복구 시 사용.
|
||||
*/
|
||||
void i2c_reset_state(void)
|
||||
{
|
||||
HW_I2C_FRQ = false;
|
||||
SW_I2C_FRQ = false;
|
||||
HW_I2C_FRQ = false; /* HW 모드 플래그 초기화 */
|
||||
SW_I2C_FRQ = false; /* SW 모드 플래그 초기화 */
|
||||
DBG_PRINTF("Flags reset\r\n");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
/*******************************************************************************
|
||||
* @file i2c_manager.h
|
||||
* @brief Common header for HW/SW I2C mutex control
|
||||
*******************************************************************************
|
||||
*
|
||||
* [헤더 개요]
|
||||
* I2C 버스 HW/SW 모드 전환 관리자의 공용 인터페이스 헤더.
|
||||
*
|
||||
* - HW_I2C_FRQ: HW TWI 모드 활성 여부 (true = HW I2C 사용 중)
|
||||
* - SW_I2C_FRQ: SW 비트뱅 모드 활성 여부 (true = SW I2C 사용 중)
|
||||
*
|
||||
* 두 플래그는 상호 배제적으로 동작하며, 동시에 true가 되지 않도록 관리된다.
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifndef __I2C_MANAGER_H__
|
||||
#define __I2C_MANAGER_H__
|
||||
@@ -8,11 +18,33 @@
|
||||
#include <stdbool.h>
|
||||
#include "app_error.h"
|
||||
|
||||
extern bool HW_I2C_FRQ;
|
||||
extern bool SW_I2C_FRQ;
|
||||
/* I2C 모드 상태 플래그 (외부 참조용) */
|
||||
extern bool HW_I2C_FRQ; /* HW TWI 모드 활성 여부 */
|
||||
extern bool SW_I2C_FRQ; /* SW 비트뱅 모드 활성 여부 */
|
||||
|
||||
/**
|
||||
* @brief HW I2C(TWI) 모드 초기화 (중복 초기화 방지)
|
||||
*
|
||||
* SW 모드가 활성화되어 있으면 해제 후 HW로 전환한다.
|
||||
* 이미 HW 모드이면 아무 동작 없이 리턴한다.
|
||||
* ICM42670P IMU 센서 통신 전에 호출하여 HW I2C를 준비한다.
|
||||
*/
|
||||
void hw_i2c_init_once(void);
|
||||
|
||||
/**
|
||||
* @brief SW I2C(비트뱅) 모드 초기화 (레거시, 현재 미사용)
|
||||
*
|
||||
* HW 모드가 활성화되어 있으면 TWI를 해제한 후 SW로 전환한다.
|
||||
* 이미 SW 모드이면 아무 동작 없이 리턴한다.
|
||||
*/
|
||||
void sw_i2c_init_once(void);
|
||||
|
||||
/**
|
||||
* @brief I2C 모드 플래그 전체 초기화
|
||||
*
|
||||
* HW_I2C_FRQ, SW_I2C_FRQ를 모두 false로 리셋한다.
|
||||
* 다음 init 호출 시 강제로 재초기화가 수행된다.
|
||||
*/
|
||||
void i2c_reset_state(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,20 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [헤더 개요] ICM42670P IMU 드라이버 상위 레이어 선언
|
||||
*
|
||||
* IMU 센서의 초기화, 설정, 데이터 읽기를 위한 함수 프로토타입과
|
||||
* 동작 모드 설정 매크로를 정의한다.
|
||||
*
|
||||
* 주요 설정 매크로:
|
||||
* SERIF_TYPE - 통신 인터페이스 (UI_I2C)
|
||||
* USE_LOW_NOISE_MODE - 1:저잡음(800Hz), 0:저전력(100Hz)
|
||||
* USE_HIGH_RES_MODE - 1:20비트 고해상도, 0:16비트 표준
|
||||
* USE_FIFO - 1:FIFO 사용, 0:레지스터 직접 읽기
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _APP_RAW_H_
|
||||
@@ -16,64 +29,71 @@
|
||||
#include "inv_imu_driver.h"
|
||||
|
||||
|
||||
/*** Example configuration ***/
|
||||
/*** 설정 매크로 ***/
|
||||
|
||||
/*
|
||||
* Select communication link between SmartMotion and IMU
|
||||
/*
|
||||
* MCU와 IMU 간 통신 인터페이스 선택
|
||||
* UI_I2C: I2C 통신 사용 (기본)
|
||||
*/
|
||||
#define SERIF_TYPE UI_I2C
|
||||
|
||||
/*
|
||||
* Set power mode flag
|
||||
* Set this flag to run example in low-noise mode.
|
||||
* Reset this flag to run example in low-power mode.
|
||||
* Note: low-noise mode is not available with sensor data frequencies less than 12.5Hz.
|
||||
* 전원 모드 설정
|
||||
* 1: 저잡음 모드 — 800Hz ODR, 높은 정밀도, 높은 전력 소모
|
||||
* 0: 저전력 모드 — 100Hz ODR, 낮은 전력 소모
|
||||
* 주의: 12.5Hz 미만 ODR에서는 저잡음 모드 사용 불가
|
||||
*/
|
||||
#define USE_LOW_NOISE_MODE 1
|
||||
|
||||
/*
|
||||
* Select Fifo resolution Mode (default is low resolution mode)
|
||||
* Low resolution mode: 16 bits data format
|
||||
* High resolution mode: 20 bits data format
|
||||
* Warning: Enabling High Res mode will force FSR to 16g and 2000dps
|
||||
* FIFO 해상도 모드 선택
|
||||
* 0: 저해상도 — 16비트 데이터 (기본)
|
||||
* 1: 고해상도 — 20비트 데이터 (FSR이 16g/2000dps로 강제 고정됨)
|
||||
*/
|
||||
#define USE_HIGH_RES_MODE 0
|
||||
|
||||
/*
|
||||
* Select to use FIFO or to read data from registers
|
||||
* 데이터 읽기 방식 선택
|
||||
* 0: 레지스터 직접 읽기 (현재 사용 중)
|
||||
* 1: FIFO에서 읽기
|
||||
*/
|
||||
#define USE_FIFO 0
|
||||
|
||||
|
||||
/**
|
||||
* \brief This function is in charge of reseting and initializing IMU device. It should
|
||||
* be successfully executed before any access to IMU device.
|
||||
* \brief IMU 디바이스를 리셋하고 초기화한다. WHOAMI 확인 포함.
|
||||
* 다른 IMU 접근 함수 호출 전에 반드시 성공적으로 실행되어야 한다.
|
||||
*
|
||||
* \return 0 on success, negative value on error.
|
||||
* \return 0=성공, 음수=에러
|
||||
*/
|
||||
int setup_imu_device(struct inv_imu_serif *icm_serif);
|
||||
|
||||
/**
|
||||
* \brief This function configures the device in order to output gyro and accelerometer.
|
||||
* \return 0 on success, negative value on error.
|
||||
* \brief 자이로 및 가속도계 출력을 위한 디바이스 설정을 수행한다.
|
||||
* FSR, ODR, 전원 모드, FIFO 설정 등을 적용한다.
|
||||
* \return 0=성공, 음수=에러
|
||||
*/
|
||||
int configure_imu_device(void);
|
||||
|
||||
/**
|
||||
* \brief This function extracts data from the IMU FIFO.
|
||||
* \return 0 on success, negative value on error.
|
||||
* \brief FIFO 또는 레지스터에서 IMU 데이터를 추출한다.
|
||||
* 내부적으로 imu_callback()이 호출되어 데이터를 처리한다.
|
||||
* \return 0=성공, 음수=에러
|
||||
*/
|
||||
int get_imu_data(void);
|
||||
|
||||
/**
|
||||
* \brief This function is the custom handling packet function.
|
||||
* \param[in] event structure containing sensor data from one packet
|
||||
* \brief 센서 데이터 수신 콜백. 마운팅 매트릭스 적용 후
|
||||
* info4/BLE/UART 모드에 따라 데이터를 출력한다.
|
||||
* \param[in] event 하나의 센서 데이터 패킷을 담은 구조체
|
||||
*/
|
||||
void imu_callback(inv_imu_sensor_event_t *event);
|
||||
|
||||
/**
|
||||
* \brief Direct IMU register read — bypasses DRDY, sends rsp: via BLE.
|
||||
* \return 0 on success, negative value on error.
|
||||
* \brief 드라이버 API를 우회한 직접 I2C 레지스터 읽기.
|
||||
* DRDY 인터럽트 없이 즉시 센서 데이터를 읽어 BLE로 전송한다.
|
||||
* 읽기 후 IMU를 슬립 모드로 전환하여 전력을 절감한다.
|
||||
* \return 0=성공, 음수=에러
|
||||
*/
|
||||
int imu_read_direct(void);
|
||||
|
||||
|
||||
@@ -3,16 +3,29 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [헤더 개요] ICM42670P 메인 초기화/폴링 루프 선언
|
||||
*
|
||||
* ICM42670P IMU 센서의 전체 초기화 및 메인 루프 함수를 선언한다.
|
||||
* - icm42670_init() : 전체 초기화 (MCU설정 → IMU초기화 → 센서설정 → 인터럽트 활성화)
|
||||
* - icm42670_main() : 메인 폴링 루프 (INT1 인터럽트 확인 → 데이터 읽기)
|
||||
* - icm42670_uninit() : 해제 (프로토타입만 선언, 구현은 별도)
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _APP_RAW_MAIN_H_
|
||||
#define _APP_RAW_MAIN_H_
|
||||
#include "sdk_config.h"
|
||||
|
||||
/* ICM42670P 전체 초기화 — MCU I2C 설정 → IMU 드라이버 초기화 → 센서 설정 → 인터럽트 활성화 */
|
||||
int icm42670_init(void);
|
||||
|
||||
/* ICM42670P 메인 폴링 루프 — INT1 인터럽트 플래그 확인 후 센서 데이터 읽기 */
|
||||
void icm42670_main(void);
|
||||
|
||||
/* ICM42670P 해제 (프로토타입 선언) */
|
||||
int icm42670_uninit(void);
|
||||
|
||||
#endif /* !_APP_RAW_MAIN_H_ */
|
||||
|
||||
|
||||
@@ -3,7 +3,29 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [모듈 개요] ICM42670P IMU 센서 I2C 통신 인터페이스
|
||||
*
|
||||
* nRF52840의 TWI(I2C) 하드웨어를 사용하여 ICM42670P IMU 센서와 통신하는
|
||||
* 저수준 인터페이스 모듈이다.
|
||||
*
|
||||
* - I2C 슬레이브 주소: 0x68 (ICM42670P 기본 주소)
|
||||
* - I2C 핀 설정: SCL=P1.14, SDA=P1.15 (system_interface.h에서 정의)
|
||||
* - TWI 인스턴스: NRFX_TWI_INSTANCE(0) 사용
|
||||
* - 통신 속도: 100kHz (NRF_TWI_FREQ_100K)
|
||||
*
|
||||
* 주요 함수 흐름:
|
||||
* inv_io_hal_init() → I2C 또는 SPI 초기화 (현재 I2C만 구현)
|
||||
* inv_io_hal_read_reg() → 레지스터 읽기 (TX로 주소 전송 → RX로 데이터 수신)
|
||||
* inv_io_hal_write_reg() → 레지스터 쓰기 (주소+데이터를 한번에 TX)
|
||||
*
|
||||
* 에러 처리: 모든 I2C 읽기/쓰기에서 실패 시 1회 재시도 후 에러 출력
|
||||
*
|
||||
* 참고: SPI4 인터페이스 코드 경로도 존재하지만 현재 미구현 상태이며,
|
||||
* 실제 운용에서는 I2C(UI_I2C)만 사용한다.
|
||||
******************************************************************************/
|
||||
|
||||
/* board driver */
|
||||
@@ -21,18 +43,31 @@
|
||||
#include "system_interface.h"
|
||||
#include "nrf_delay.h"
|
||||
|
||||
/* I2C number and slave address for INV device */
|
||||
/* ICM42670P I2C 슬레이브 주소 및 직렬 쓰기 최대 바이트 수 */
|
||||
#define ICM_I2C_ADDR 0x68
|
||||
#define INV_MAX_SERIAL_WRITE 16
|
||||
|
||||
/* TWI instance. */
|
||||
/* TWI(I2C) 인스턴스 생성 — system_interface.h의 ICM42670_I2C_INSTANCE(0)을 사용 */
|
||||
const nrfx_twi_t m_twi_icm42670 = NRFX_TWI_INSTANCE(ICM42670_I2C_INSTANCE);
|
||||
|
||||
/*
|
||||
* inv_i2c_master_uninitialize()
|
||||
* I2C 버스를 비활성화하고 TWI 인스턴스를 해제한다.
|
||||
* 슬립 모드 진입 전 또는 재초기화 전에 호출된다.
|
||||
*/
|
||||
void inv_i2c_master_uninitialize(void){
|
||||
nrfx_twi_disable(&m_twi_icm42670);
|
||||
nrfx_twi_uninit(&m_twi_icm42670);
|
||||
}
|
||||
|
||||
/*
|
||||
* inv_i2c_master_initialize()
|
||||
* nRF52840 TWI 하드웨어를 초기화하고 활성화한다.
|
||||
* - SCL: P1.14, SDA: P1.15
|
||||
* - 속도: 100kHz
|
||||
* - 인터럽트 우선순위: 최고 (APP_IRQ_PRIORITY_HIGH)
|
||||
* - 이벤트 핸들러 없음 (블로킹 모드로 동작)
|
||||
*/
|
||||
void inv_i2c_master_initialize(void){
|
||||
ret_code_t err_code;
|
||||
|
||||
@@ -43,50 +78,75 @@ void inv_i2c_master_initialize(void){
|
||||
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
|
||||
};
|
||||
|
||||
/* TWI 드라이버 초기화 (이벤트 핸들러=NULL → 블로킹 모드) */
|
||||
err_code = nrfx_twi_init(&m_twi_icm42670, &twi_icm42670_config, NULL, NULL);
|
||||
APP_ERROR_CHECK(err_code);
|
||||
|
||||
/* TWI 하드웨어 활성화 — 이후 tx/rx 가능 */
|
||||
nrfx_twi_enable(&m_twi_icm42670);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* icm42670_twi_tx()
|
||||
* I2C 전송 래퍼 함수. nrfx_twi_tx를 호출하여 데이터를 송신한다.
|
||||
* no_stop=true이면 STOP 컨디션을 보내지 않음 (Repeated START를 위해 사용)
|
||||
*/
|
||||
uint32_t icm42670_twi_tx( uint8_t device_id,
|
||||
uint8_t const * p_data,
|
||||
uint8_t length,
|
||||
bool no_stop)
|
||||
{
|
||||
ret_code_t ret;
|
||||
ret = nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
|
||||
ret_code_t ret;
|
||||
ret = nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* icm42670_twi_rx()
|
||||
* I2C 수신 래퍼 함수. nrfx_twi_rx를 호출하여 데이터를 수신한다.
|
||||
*/
|
||||
uint32_t icm42670_twi_rx( uint8_t device_id,
|
||||
uint8_t * p_data,
|
||||
uint8_t length)
|
||||
{
|
||||
ret_code_t ret;
|
||||
ret_code_t ret;
|
||||
ret = nrfx_twi_rx(&m_twi_icm42670, device_id, p_data, length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* inv_i2c_master_read_register()
|
||||
* ICM42670P의 특정 레지스터에서 데이터를 읽는다.
|
||||
*
|
||||
* 동작 순서:
|
||||
* 1) TX: 레지스터 주소 1바이트 전송 (no_stop=true → Repeated START 준비)
|
||||
* 2) RX: 지정된 길이만큼 데이터 수신
|
||||
*
|
||||
* 에러 처리: TX, RX 각각 실패 시 1회 재시도한다.
|
||||
*/
|
||||
static unsigned long inv_i2c_master_read_register(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, unsigned char *RegisterValue){
|
||||
//ret_code_t ret;
|
||||
uint32_t ret;
|
||||
uint8_t addr8 = (uint8_t)RegisterAddr;
|
||||
|
||||
/* 1단계: 읽을 레지스터 주소를 전송 (STOP 없이 → Repeated START 사용) */
|
||||
ret = icm42670_twi_tx(Address, &addr8, 1, true);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
/* 실패 시 1회 재시도 */
|
||||
ret = icm42670_twi_tx(Address, &addr8, 1, true);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
printf("ERR! i2c read-1\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
|
||||
/* 2단계: 해당 레지스터에서 데이터 수신 */
|
||||
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
|
||||
/* 실패 시 1회 재시도 */
|
||||
ret = icm42670_twi_rx(Address, RegisterValue, RegisterLen);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
printf("ERR! i2c read-2\r\n");
|
||||
}
|
||||
@@ -95,14 +155,28 @@ static unsigned long inv_i2c_master_read_register(unsigned char Address, unsigne
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* inv_i2c_master_write_register()
|
||||
* ICM42670P의 특정 레지스터에 데이터를 쓴다.
|
||||
*
|
||||
* 동작 순서:
|
||||
* 1) 버퍼[0]에 레지스터 주소, 버퍼[1~N]에 쓸 데이터를 배치
|
||||
* 2) TX: 주소+데이터를 한번에 전송 (no_stop=false → STOP 컨디션 포함)
|
||||
*
|
||||
* 에러 처리: 실패 시 1회 재시도한다.
|
||||
*/
|
||||
static unsigned long inv_i2c_master_write_register(unsigned char Address, unsigned char RegisterAddr, unsigned short RegisterLen, const unsigned char *RegisterValue){
|
||||
uint32_t ret;
|
||||
uint8_t buffer[1 + INV_MAX_SERIAL_WRITE]; /* Addr + data */
|
||||
uint8_t buffer[1 + INV_MAX_SERIAL_WRITE]; /* 레지스터 주소(1) + 데이터(최대 16바이트) */
|
||||
|
||||
/* 버퍼 구성: [레지스터 주소][데이터 바이트들] */
|
||||
buffer[0] = (uint8_t)RegisterAddr;
|
||||
memcpy(buffer+1, RegisterValue, RegisterLen);
|
||||
|
||||
/* 주소+데이터를 한번에 전송 */
|
||||
ret = icm42670_twi_tx(Address, buffer, RegisterLen+1, false);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
/* 실패 시 1회 재시도 */
|
||||
ret = icm42670_twi_tx(Address, buffer, RegisterLen+1, false);
|
||||
if(ret != NRF_SUCCESS) {
|
||||
printf("ERR! i2c write\r\n");
|
||||
@@ -114,7 +188,12 @@ static unsigned long inv_i2c_master_write_register(unsigned char Address, unsign
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* inv_io_hal_init()
|
||||
* IMU 드라이버가 사용하는 시리얼 인터페이스(I2C 또는 SPI)를 초기화한다.
|
||||
* serif->serif_type에 따라 분기하며, 현재는 I2C만 구현되어 있다.
|
||||
* 반환값: 0=성공, -1=지원하지 않는 인터페이스 타입
|
||||
*/
|
||||
|
||||
int inv_io_hal_init(struct inv_imu_serif *serif)
|
||||
{
|
||||
@@ -122,13 +201,14 @@ int inv_io_hal_init(struct inv_imu_serif *serif)
|
||||
switch (serif->serif_type) {
|
||||
case UI_SPI4:
|
||||
{
|
||||
/* SPI4 초기화 — 현재 미구현 (I2C만 사용) */
|
||||
break;
|
||||
}
|
||||
|
||||
case UI_I2C:
|
||||
inv_i2c_master_initialize();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@@ -137,12 +217,17 @@ int inv_io_hal_init(struct inv_imu_serif *serif)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* inv_io_hal_read_reg()
|
||||
* IMU 드라이버 콜백: 지정된 레지스터에서 데이터를 읽는다.
|
||||
* 시리얼 타입에 따라 I2C 또는 SPI 읽기를 수행한다.
|
||||
*/
|
||||
int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen)
|
||||
{
|
||||
switch (serif->serif_type) {
|
||||
case UI_SPI4:
|
||||
return 0;
|
||||
|
||||
|
||||
case UI_I2C:
|
||||
return inv_i2c_master_read_register(ICM_I2C_ADDR, reg, rlen, rbuffer);
|
||||
|
||||
@@ -151,12 +236,17 @@ int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuf
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* inv_io_hal_write_reg()
|
||||
* IMU 드라이버 콜백: 지정된 레지스터에 데이터를 쓴다.
|
||||
* 시리얼 타입에 따라 I2C 또는 SPI 쓰기를 수행한다.
|
||||
*/
|
||||
int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen)
|
||||
{
|
||||
switch (serif->serif_type) {
|
||||
case UI_SPI4:
|
||||
return 0;
|
||||
|
||||
|
||||
case UI_I2C:
|
||||
return inv_i2c_master_write_register(ICM_I2C_ADDR, reg, wlen, wbuffer);
|
||||
|
||||
@@ -164,20 +254,30 @@ int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, const uint8_t
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cat_read()
|
||||
* 범용 I2C 읽기 함수 (디버그/레거시용).
|
||||
* 8바이트를 읽어 첫 번째 바이트를 반환하고, 읽은 데이터를 콘솔에 출력한다.
|
||||
* 참고: 현재 실제 운용에서는 사용되지 않으며, 디버그 목적으로 남아 있다.
|
||||
*/
|
||||
uint8_t cat_read(uint8_t device_id, uint8_t address, uint8_t *data)
|
||||
{
|
||||
|
||||
|
||||
uint8_t read_data = 0;
|
||||
char adata[8];
|
||||
ret_code_t err_code;
|
||||
//address = 1|(address<<1);
|
||||
address = (address & 0xFF);
|
||||
|
||||
/* 레지스터 주소 전송 (STOP 없이, Repeated START 준비) */
|
||||
err_code = nrfx_twi_tx(&m_twi_icm42670, device_id, &address, 1, true);
|
||||
if (err_code != NRF_SUCCESS) {
|
||||
// Handle error
|
||||
// return;
|
||||
}
|
||||
|
||||
/* 8바이트 데이터 수신 */
|
||||
err_code = nrfx_twi_rx(&m_twi_icm42670, device_id, data, 8);
|
||||
if (err_code != NRF_SUCCESS) {
|
||||
// Handle error
|
||||
@@ -187,41 +287,48 @@ uint8_t cat_read(uint8_t device_id, uint8_t address, uint8_t *data)
|
||||
memcpy(adata,data,8);
|
||||
printf("Data %s . \r\n", adata);
|
||||
return read_data;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* cat_write()
|
||||
* 범용 I2C 쓰기 함수 (디버그/레거시용).
|
||||
* 주소 1바이트 + 데이터 1바이트를 전송한다.
|
||||
* 참고: buffer에 6바이트를 복사하지만, 실제 전송은 2바이트만 수행한다.
|
||||
*/
|
||||
void cat_write(uint8_t device_id, uint8_t address, uint8_t *data){
|
||||
|
||||
|
||||
uint8_t buffer[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
|
||||
|
||||
address = (address & 0xFF);
|
||||
|
||||
|
||||
buffer[0] = (address);
|
||||
//buffer[1] =(data & 0xFF);
|
||||
memcpy(buffer+1,data,6);
|
||||
ret_code_t err_code;
|
||||
//err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, 0x00, 1, false);
|
||||
|
||||
/* 주소(1바이트) + 데이터(1바이트) = 2바이트 전송 */
|
||||
err_code = nrfx_twi_tx(&m_twi_icm42670, device_id, buffer, 2, false);
|
||||
// err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, buffer, 2, false);
|
||||
// nrfx_twi_rx(&m_twi_icm42670, device_id, p_data, length);
|
||||
// nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
|
||||
// nrfx_twi_tx(&m_twi_icm42670, device_id, p_data, length, no_stop);
|
||||
printf("Data %x %x %x %x. \r\n", buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
|
||||
|
||||
//err_code = nrf_drv_twi_tx(&m_twi_ir, device_id, buffer, 6, false);
|
||||
if (err_code != NRF_SUCCESS) {
|
||||
|
||||
|
||||
printf("TWI Error.");
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,22 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [헤더 개요] ICM42670P I2C 통신 인터페이스 선언
|
||||
*
|
||||
* nRF52840 TWI 하드웨어를 통해 ICM42670P IMU 센서와 통신하기 위한
|
||||
* 핀 정의, 함수 프로토타입을 선언한다.
|
||||
*
|
||||
* 핀 배치:
|
||||
* - I2C SCL : P1.14
|
||||
* - I2C SDA : P1.15
|
||||
* - INT1 : P1.13 (데이터 준비 인터럽트)
|
||||
* - INT2 : P0.26 (보조 인터럽트, 현재 미사용)
|
||||
*
|
||||
* TWI 인스턴스: 0번 사용
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _SYSTEM_INTERFACE_H_
|
||||
@@ -17,25 +32,42 @@
|
||||
#endif
|
||||
|
||||
|
||||
#define ICM42670_I2C_INSTANCE 0 /**< I2C instance index. */
|
||||
#define ICM42670_I2C_SDA_PIN NRF_GPIO_PIN_MAP(1,15)
|
||||
#define ICM42670_I2C_SCL_PIN NRF_GPIO_PIN_MAP(1,14)
|
||||
#define ICM42670_INT1_PIN NRF_GPIO_PIN_MAP(1,13)
|
||||
#define ICM42670_INT2_PIN NRF_GPIO_PIN_MAP(0,26)
|
||||
#define ICM42670_I2C_INSTANCE 0 /**< I2C(TWI) 인스턴스 인덱스 */
|
||||
#define ICM42670_I2C_SDA_PIN NRF_GPIO_PIN_MAP(1,15) /**< SDA 핀: P1.15 */
|
||||
#define ICM42670_I2C_SCL_PIN NRF_GPIO_PIN_MAP(1,14) /**< SCL 핀: P1.14 */
|
||||
#define ICM42670_INT1_PIN NRF_GPIO_PIN_MAP(1,13) /**< INT1 핀: P1.13 (데이터 준비 인터럽트) */
|
||||
#define ICM42670_INT2_PIN NRF_GPIO_PIN_MAP(0,26) /**< INT2 핀: P0.26 (보조, 현재 미사용) */
|
||||
|
||||
/* I2C 전송 래퍼 — no_stop=true이면 Repeated START를 위해 STOP 컨디션 생략 */
|
||||
uint32_t icm42670_twi_tx( uint8_t device_id,
|
||||
uint8_t const * p_data,
|
||||
uint8_t length,
|
||||
bool no_stop);
|
||||
|
||||
/* I2C 수신 래퍼 */
|
||||
uint32_t icm42670_twi_rx( uint8_t device_id,
|
||||
uint8_t * p_data,
|
||||
uint8_t length);
|
||||
|
||||
/* 범용 I2C 읽기 (디버그/레거시용) — 8바이트를 읽어 첫 바이트 반환 */
|
||||
uint8_t cat_read (uint8_t device_id, uint8_t address, uint8_t *data);
|
||||
void cat_write (uint8_t device_id, uint8_t address, uint8_t *data);
|
||||
|
||||
/* 범용 I2C 쓰기 (디버그/레거시용) — 주소+데이터 2바이트 전송 */
|
||||
void cat_write (uint8_t device_id, uint8_t address, uint8_t *data);
|
||||
|
||||
/* I2C 하드웨어 해제 (슬립 또는 재초기화 전 호출) */
|
||||
void inv_i2c_master_uninitialize(void);
|
||||
|
||||
/* I2C 하드웨어 초기화 (100kHz, 블로킹 모드) */
|
||||
void inv_i2c_master_initialize(void);
|
||||
|
||||
/* IMU 드라이버용 시리얼 인터페이스 초기화 (I2C/SPI 분기) */
|
||||
int inv_io_hal_init(struct inv_imu_serif *serif);
|
||||
|
||||
/* IMU 드라이버 콜백: 레지스터 읽기 */
|
||||
int inv_io_hal_read_reg(struct inv_imu_serif *serif, uint8_t reg, uint8_t * rbuffer, uint32_t rlen);
|
||||
|
||||
/* IMU 드라이버 콜백: 레지스터 쓰기 */
|
||||
int inv_io_hal_write_reg(struct inv_imu_serif *serif, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen);
|
||||
|
||||
#endif /* !_SYSTEM_INTERFACE_H_ */
|
||||
|
||||
|
||||
@@ -608,11 +608,15 @@ static void nrf_qwr_error_handler(uint32_t nrf_error)
|
||||
extern bool maa_async_on_tx_ready(void);
|
||||
extern bool maa_async_is_busy(void);
|
||||
|
||||
/* 2026-03-17: BLE 콜백에서 블로킹 방지 — 명령을 버퍼에 저장 후 메인 루프에서 처리 */
|
||||
static volatile uint8_t pending_cmd_buf[BLE_NUS_MAX_DATA_LEN];
|
||||
static volatile uint8_t pending_cmd_len = 0;
|
||||
|
||||
/**
|
||||
* @brief NUS(Nordic UART Service) 데이터 수신 핸들러
|
||||
*
|
||||
* BLE를 통해 스마트폰 앱에서 데이터를 수신했을 때 호출됨
|
||||
* - RX_DATA 이벤트: 수신된 명령을 received_command_process()로 전달
|
||||
* - RX_DATA 이벤트: 수신 데이터를 버퍼에 복사 (메인 루프에서 dr_cmd_parser 호출)
|
||||
* - TX_RDY 이벤트: BLE TX 버퍼에 공간이 생겼을 때 비동기 MAA 전송 계속
|
||||
*/
|
||||
static void nus_data_handler(ble_nus_evt_t * p_evt)
|
||||
@@ -622,7 +626,12 @@ static void nus_data_handler(ble_nus_evt_t * p_evt)
|
||||
cmd_type_t = CMD_BLE;
|
||||
ble_got_new_data = true;
|
||||
DBG_PRINTF("[NUS] RX len=%d\r\n", p_evt->params.rx_data.length);
|
||||
dr_cmd_parser(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
|
||||
|
||||
/* 콜백에서는 복사만 하고, 메인 루프에서 처리 */
|
||||
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);
|
||||
pending_cmd_len = p_evt->params.rx_data.length;
|
||||
}
|
||||
}
|
||||
else if (p_evt->type == BLE_NUS_EVT_TX_RDY)
|
||||
{
|
||||
@@ -1771,6 +1780,13 @@ int main(void)
|
||||
// MAIN LOOP
|
||||
for (;;)
|
||||
{
|
||||
/* BLE 콜백에서 수신된 명령이 있으면 여기서 처리 (블로킹 방지) */
|
||||
if (pending_cmd_len > 0) {
|
||||
uint8_t len = pending_cmd_len;
|
||||
pending_cmd_len = 0;
|
||||
dr_cmd_parser((const uint8_t *)pending_cmd_buf, len);
|
||||
}
|
||||
|
||||
idle_state_handle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,35 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
*******************************************************************************
|
||||
*
|
||||
* [헤더 개요]
|
||||
* 메인 이벤트 루프 타이머의 공용 인터페이스 헤더.
|
||||
*
|
||||
* 10ms(일반) 또는 80ms(디테일) 간격의 싱글샷 타이머를 사용하여
|
||||
* main_loop() 콜백에서 센서 데이터 수집 및 시스템 제어를 수행한다.
|
||||
*
|
||||
* [주요 함수]
|
||||
* main_timer_start() : 타이머 시작 (싱글샷, 수동 재시작 필요)
|
||||
* main_timer_stop() : 타이머 정지
|
||||
* main_timer_init() : 타이머 초기화 (앱 시작 시 1회 호출)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef TIMER_ROUTINE_H__
|
||||
#define TIMER_ROUTINE_H__
|
||||
|
||||
/** @brief 메인 루프 타이머 시작 (싱글샷, MAIN_LOOP_INTERVAL 후 main_loop 호출) */
|
||||
void main_timer_start(void);
|
||||
|
||||
/** @brief 지정된 간격(ms)으로 메인 루프 타이머 시작 */
|
||||
void main_timer_start_ms(uint32_t interval_ms);
|
||||
|
||||
/** @brief 메인 루프 타이머 정지 */
|
||||
void main_timer_stop(void);
|
||||
|
||||
/** @brief 메인 루프 타이머 초기화 (앱 시작 시 1회, 싱글샷 모드로 생성) */
|
||||
void main_timer_init(void);
|
||||
|
||||
#endif //TIMER_ROUTINE_H__
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -418,16 +418,6 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\..\..\fstorage.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>cmd_parse.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\..\..\cmd_parse.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>cmd_parse.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\..\..\cmd_parse.h</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>debug_print.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
@@ -4631,16 +4621,6 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\..\..\fstorage.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>cmd_parse.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\..\..\cmd_parse.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>cmd_parse.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
<FilePath>..\..\..\cmd_parse.h</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>debug_print.h</FileName>
|
||||
<FileType>5</FileType>
|
||||
|
||||
@@ -11473,7 +11473,7 @@
|
||||
// <i> or this value is actually used. It depends on which one is bigger.
|
||||
|
||||
#ifndef SEGGER_RTT_CONFIG_BUFFER_SIZE_UP
|
||||
#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 512
|
||||
#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 1024 // 512 -> 1024 jhChun 26.03.17
|
||||
#endif
|
||||
|
||||
// <o> SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS - Maximum number of upstream buffers.
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
/*******************************************************************************
|
||||
TEST medi50 Dec 23
|
||||
//=========power_control.c====================
|
||||
*******************************************************************************
|
||||
*
|
||||
* [모듈 개요]
|
||||
* 디바이스 전원 시퀀스를 관리하는 모듈 (전원 켜기 / 끄기 / 슬립).
|
||||
*
|
||||
* [전원 켜기 흐름]
|
||||
* device_activated()
|
||||
* → p_order=0으로 초기화, power_loop 타이머 시작
|
||||
* → power_loop() 상태머신이 20ms 간격으로 Step 0→1→2 순서대로 실행
|
||||
* - Step 0: I2C 초기화 (sw_i2c_init_once)
|
||||
* - Step 1: 예약 (현재 미사용)
|
||||
* - Step 2: 전원 시퀀스 완료
|
||||
*
|
||||
* [슬립 모드]
|
||||
* device_sleep_mode()
|
||||
* → EEPROM OFF → processing 플래그 해제
|
||||
*
|
||||
* [재활성화]
|
||||
* device_reactivated()
|
||||
* → I2C 재초기화 후 전원 시퀀스를 처음부터 다시 시작
|
||||
*
|
||||
* [EEPROM 쓰기 보호 핀]
|
||||
* EEP_WP = P0.24 (레거시, 현재는 FDS를 사용하므로 실질적으로 미사용)
|
||||
*
|
||||
* [타이머]
|
||||
* 싱글샷 모드 app_timer, 20ms 간격으로 power_loop 호출
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -15,50 +42,89 @@
|
||||
#include "app_timer.h"
|
||||
#include "debug_print.h"
|
||||
#include "i2c_manager.h"
|
||||
|
||||
/* EEPROM 쓰기 보호 핀 (P0.24) - 레거시, 현재는 FDS 사용 */
|
||||
#define EEP_WP NRF_GPIO_PIN_MAP(0, 24)
|
||||
|
||||
/* 전원 시퀀스용 싱글샷 타이머 인스턴스 */
|
||||
APP_TIMER_DEF(m_power_timer_id);
|
||||
|
||||
/* 전원 시퀀스 상태머신의 타이머 간격 (20ms) */
|
||||
// 2025-12-08 change to #define POWER_LOOP_INTERVAL 30 -> 20
|
||||
#define POWER_LOOP_INTERVAL 20
|
||||
|
||||
|
||||
|
||||
|
||||
/* 전원 시퀀스 현재 단계 (0: I2C 초기화, 1: 예약, 2: 완료) */
|
||||
static uint8_t p_order;
|
||||
|
||||
/* 데이터 처리 중 플래그 (외부 모듈에서 선언) */
|
||||
extern volatile bool processing;
|
||||
|
||||
/* 전원 시퀀스 잠금 플래그 (true = 전원 시퀀스 진행 중) */
|
||||
bool lock_check = false;
|
||||
|
||||
/**
|
||||
* @brief 전원 관련 GPIO 핀 초기화
|
||||
*
|
||||
* EEP_WP 핀을 출력 모드로 설정한다.
|
||||
*/
|
||||
void power_gpio_init(void)
|
||||
{
|
||||
nrf_gpio_cfg_output(EEP_WP);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief EEPROM 전원 제어 (ON/OFF)
|
||||
*
|
||||
* @param eeprom_st ON: EEP_WP 핀 HIGH (쓰기 허용), OFF: LOW (쓰기 보호)
|
||||
* 레거시 기능으로, 현재는 FDS(Flash Data Storage)를 사용하여 실질적으로 미사용.
|
||||
*/
|
||||
void eeprom_control(on_off_cont_t eeprom_st)
|
||||
{
|
||||
if(eeprom_st == OFF) {
|
||||
nrf_gpio_pin_clear(EEP_WP);
|
||||
nrf_gpio_pin_clear(EEP_WP); /* LOW: EEPROM 쓰기 보호 활성화 */
|
||||
}else if(eeprom_st == ON){
|
||||
nrf_gpio_pin_set(EEP_WP);
|
||||
nrf_gpio_pin_set(EEP_WP); /* HIGH: EEPROM 쓰기 허용 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 디바이스 슬립 모드 진입
|
||||
*
|
||||
* EEPROM을 OFF하고, 데이터 처리 플래그(processing)를 해제하여
|
||||
* 메인 루프가 더 이상 센서 데이터를 처리하지 않도록 한다.
|
||||
*
|
||||
* @return 0 (항상 성공)
|
||||
*/
|
||||
int device_sleep_mode(void){
|
||||
int rc = 0;
|
||||
eeprom_control(OFF);
|
||||
eeprom_control(OFF); /* EEPROM 쓰기 보호 활성화 */
|
||||
nrf_delay_ms(2);
|
||||
DBG_PRINTF("Device_Sleep_Mode OK!\r\n");
|
||||
nrf_delay_ms(10);
|
||||
processing = false;
|
||||
processing = false; /* 데이터 처리 플래그 해제 → 센서 처리 중단 */
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 디바이스 전원 켜기 (전원 시퀀스 시작)
|
||||
*
|
||||
* 전원 시퀀스 단계를 0으로 초기화하고, 잠금 플래그를 설정한 뒤
|
||||
* 타이머를 시작하여 power_loop() 상태머신을 구동한다.
|
||||
* EEPROM은 OFF 상태로 시작한다.
|
||||
*
|
||||
* @return 0 (항상 성공)
|
||||
*/
|
||||
int device_activated(void){
|
||||
int rc = 0;
|
||||
p_order = 0;
|
||||
lock_check =true;
|
||||
power_timer_start();
|
||||
eeprom_control(OFF);
|
||||
p_order = 0; /* 상태머신 시작 단계 (Step 0: I2C 초기화) */
|
||||
lock_check =true; /* 전원 시퀀스 진행 중 잠금 */
|
||||
power_timer_start(); /* 20ms 후 power_loop() 첫 호출 */
|
||||
eeprom_control(OFF); /* EEPROM OFF 상태로 시작 */
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -74,32 +140,49 @@ int device_activated(void){
|
||||
* 1: (reserved)
|
||||
* 2: Complete
|
||||
*/
|
||||
/*
|
||||
* 전원 시퀀스 상태머신 (20ms 싱글샷 타이머 콜백).
|
||||
*
|
||||
* [실행 흐름]
|
||||
* 1) 타이머 콜백 진입 → 타이머 정지 (싱글샷이므로)
|
||||
* 2) 현재 p_order에 해당하는 초기화 단계 실행
|
||||
* 3) p_order < 2이면 다음 단계로 진행하고 타이머 재시작
|
||||
* 4) p_order == 2이면 전원 시퀀스 완료
|
||||
*
|
||||
* [DEBUG_MINIMAL_BOOT 모드]
|
||||
* 센서 초기화를 건너뛰고 즉시 완료 단계(Step 2)로 점프
|
||||
*/
|
||||
void power_loop(void *p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(p_context);
|
||||
|
||||
power_timer_stop();
|
||||
power_timer_stop(); /* 현재 타이머 정지 (싱글샷 → 수동 재시작 필요) */
|
||||
|
||||
#if DEBUG_MINIMAL_BOOT
|
||||
/* Minimal Boot: Skip sensor initialization */
|
||||
/* 미니멀 부트 모드: 센서 초기화 생략하고 바로 완료 */
|
||||
DBG_PRINTF("[PWR] Minimal mode - skipping sensor init\r\n");
|
||||
p_order = 2; // Jump to complete
|
||||
#else
|
||||
/* Full Boot: Execute power sequence */
|
||||
/* 풀 부트 모드: 전원 시퀀스 단계별 실행 */
|
||||
switch (p_order) {
|
||||
/* Step 0: I2C Initialize */
|
||||
/* 단계 0: I2C 버스를 SW 모드로 초기화 (레거시 흐름) */
|
||||
case 0:
|
||||
sw_i2c_init_once();
|
||||
nrf_delay_ms(10);
|
||||
sw_i2c_init_once(); /* SW I2C 초기화 (TWI 해제 → 비트뱅 모드) */
|
||||
nrf_delay_ms(10); /* I2C 버스 안정화 대기 */
|
||||
DBG_PRINTF("[PWR] Step %d: I2C Init\r\n", p_order);
|
||||
break;
|
||||
|
||||
/* Step 1: Reserved */
|
||||
/* 단계 1: 예약 (추후 센서 초기화 등 추가 가능) */
|
||||
case 1:
|
||||
DBG_PRINTF("[PWR] Step %d: (reserved)\r\n", p_order);
|
||||
break;
|
||||
|
||||
/* Step 2: Complete */
|
||||
/* 단계 2: 전원 시퀀스 완료 → 디바이스 사용 준비 완료 */
|
||||
case 2:
|
||||
DBG_PRINTF("[PWR] Step %d: Sequence Complete\r\n", p_order);
|
||||
break;
|
||||
@@ -110,31 +193,49 @@ void power_loop(void *p_context)
|
||||
#endif
|
||||
|
||||
/* Advance to next step or finish */
|
||||
/* 다음 단계로 진행하거나, 시퀀스 완료 처리 */
|
||||
if (p_order < 2) {
|
||||
p_order++;
|
||||
power_timer_start();
|
||||
p_order++; /* 다음 단계로 이동 */
|
||||
power_timer_start(); /* 20ms 후 다음 단계 실행 */
|
||||
} else {
|
||||
/* 전원 시퀀스 전체 완료 */
|
||||
DBG_PRINTF("[PWR] Device Activated OK!\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 디바이스 재활성화 (슬립 복귀 시)
|
||||
*
|
||||
* I2C를 재초기화하고, 전원 시퀀스를 처음부터 다시 시작한다.
|
||||
* 슬립 모드에서 깨어날 때 호출된다.
|
||||
*
|
||||
* @return 0 (항상 성공)
|
||||
*/
|
||||
int device_reactivated(void){
|
||||
int rc = 0;
|
||||
sw_i2c_init_once();
|
||||
nrf_delay_ms(10);
|
||||
lock_check = true;
|
||||
p_order = 0;
|
||||
power_timer_start();
|
||||
sw_i2c_init_once(); /* I2C 버스 재초기화 */
|
||||
nrf_delay_ms(10); /* 안정화 대기 */
|
||||
lock_check = true; /* 전원 시퀀스 진행 중 잠금 */
|
||||
p_order = 0; /* 상태머신을 Step 0부터 재시작 */
|
||||
power_timer_start(); /* 20ms 후 power_loop() 시작 */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 전원 시퀀스 타이머 시작
|
||||
*
|
||||
* 싱글샷 모드로 POWER_LOOP_INTERVAL(20ms) 후 power_loop()를 호출한다.
|
||||
*/
|
||||
void power_timer_start(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_start(m_power_timer_id, APP_TIMER_TICKS(POWER_LOOP_INTERVAL), NULL));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 전원 시퀀스 타이머 정지
|
||||
*/
|
||||
void power_timer_stop(void)
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_stop(m_power_timer_id));
|
||||
@@ -142,6 +243,12 @@ void power_timer_stop(void)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 전원 시퀀스 타이머 초기화 (앱 시작 시 1회 호출)
|
||||
*
|
||||
* 싱글샷 모드 타이머를 생성하고, 콜백으로 power_loop()를 등록한다.
|
||||
* 싱글샷이므로 매 단계마다 power_timer_start()로 수동 재시작해야 한다.
|
||||
*/
|
||||
void power_timer_init(void) //active start
|
||||
{
|
||||
APP_ERROR_CHECK(app_timer_create(&m_power_timer_id, APP_TIMER_MODE_SINGLE_SHOT, power_loop));
|
||||
|
||||
@@ -3,7 +3,22 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
*******************************************************************************
|
||||
*
|
||||
* [헤더 개요]
|
||||
* 디바이스 전원 시퀀스 관리 모듈의 공용 인터페이스 헤더.
|
||||
*
|
||||
* [주요 함수 요약]
|
||||
* power_gpio_init() : 전원 관련 GPIO 초기화 (EEP_WP 핀)
|
||||
* eeprom_control() : EEPROM 쓰기 보호 ON/OFF (레거시)
|
||||
* device_activated() : 전원 켜기 → power_loop 상태머신 시작
|
||||
* device_sleep_mode() : 슬립 모드 진입 (EEPROM OFF, 처리 중단)
|
||||
* device_reactivated() : 슬립 복귀 → I2C 재초기화 후 전원 시퀀스 재시작
|
||||
* power_loop() : 20ms 간격 전원 시퀀스 상태머신 콜백
|
||||
* power_timer_start/stop : 전원 시퀀스 타이머 제어
|
||||
* power_timer_init() : 전원 시퀀스 타이머 초기화 (앱 시작 시 1회)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _POWER_CONTROL_H_
|
||||
@@ -11,14 +26,31 @@
|
||||
|
||||
#include "main.h"
|
||||
|
||||
/** @brief 전원 관련 GPIO 핀 초기화 (EEP_WP 출력 설정) */
|
||||
void power_gpio_init(void);
|
||||
|
||||
/** @brief EEPROM 쓰기 보호 제어 (ON=허용, OFF=보호) - 레거시 */
|
||||
void eeprom_control(on_off_cont_t eeprom_st);
|
||||
|
||||
/** @brief 디바이스 슬립 모드 진입 (EEPROM OFF, processing 해제) */
|
||||
int device_sleep_mode(void);
|
||||
|
||||
/** @brief 디바이스 전원 켜기 (전원 시퀀스 상태머신 시작) */
|
||||
int device_activated(void);
|
||||
|
||||
/** @brief 디바이스 재활성화 (슬립 복귀 시 I2C 재초기화 후 시퀀스 재시작) */
|
||||
int device_reactivated(void);
|
||||
|
||||
/** @brief 전원 시퀀스 상태머신 (20ms 타이머 콜백, Step 0→1→2) */
|
||||
void power_loop(void * p_context); /* For x ms */
|
||||
|
||||
/** @brief 전원 시퀀스 타이머 시작 (20ms 싱글샷) */
|
||||
void power_timer_start(void);
|
||||
|
||||
/** @brief 전원 시퀀스 타이머 정지 */
|
||||
void power_timer_stop(void);;
|
||||
|
||||
/** @brief 전원 시퀀스 타이머 초기화 (앱 시작 시 1회 호출) */
|
||||
void power_timer_init(void);
|
||||
#endif //_POWER_CONTROL_H_
|
||||
|
||||
|
||||
@@ -6,6 +6,26 @@
|
||||
* @date 2025-10-13
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [한국어 설명] PWM 펄스 생성기
|
||||
*
|
||||
* === 현재 상태 ===
|
||||
* SKIP_PWM 매크로가 정의되어 있어 PWM 기능이 비활성화됨.
|
||||
* init/start/stop 함수는 모두 Stub(빈 껍데기) 구현으로,
|
||||
* 로그만 출력하고 실제 PWM 동작은 하지 않는다.
|
||||
* 빌드 호환성을 위해 함수 인터페이스만 유지.
|
||||
*
|
||||
* === 실제 구현 (SKIP_PWM 미정의 시) ===
|
||||
* nrfx_pwm 드라이버 + app_timer를 사용하여 3핀(P28/P29/P30) PWM 제어.
|
||||
* PWM 인스턴스 0, 16MHz 클럭, TOP=8, 개별 채널 로드 모드.
|
||||
* 6단계 시퀀스로 채널별 듀티 사이클 조절.
|
||||
* app_timer(10ms)로 주기적 반복 재생.
|
||||
*
|
||||
* === 비활성화 사유 ===
|
||||
* 현재 프로젝트에서는 피에조 구동을 dr_piezo 드라이버가 담당하므로
|
||||
* 이 PWM 펄스 생성기는 사용하지 않음.
|
||||
******************************************************************************/
|
||||
|
||||
#define SKIP_PWM // ? ?? ???? PWM ?? ???
|
||||
|
||||
#include "pulse_gen.h"
|
||||
@@ -15,57 +35,72 @@
|
||||
|
||||
#ifdef SKIP_PWM
|
||||
/* ========================================================================== */
|
||||
/* PWM ?? ???? Stub ?? */
|
||||
/* PWM 비활성화 모드: Stub 구현 (로그만 출력, 실제 동작 없음) */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* Stub 초기화: 아무 동작 없이 성공 반환 */
|
||||
ret_code_t pulse_gen_init(void)
|
||||
{
|
||||
DBG_PRINTF("[PWM] skipped init\r\n");
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/* Stub 시작: 아무 동작 없음 */
|
||||
void pulse_gen_start(void)
|
||||
{
|
||||
DBG_PRINTF("[PWM] skipped start\r\n");
|
||||
}
|
||||
|
||||
/* Stub 정지: 아무 동작 없음 */
|
||||
void pulse_gen_stop(void)
|
||||
{
|
||||
DBG_PRINTF("[PWM] skipped stop\r\n");
|
||||
}
|
||||
|
||||
#else /* ==================================================================== */
|
||||
/* ?? PWM ?? ?? (SKIP_PWM ?? ?? ? ???) */
|
||||
/* 실제 PWM 구현 코드 (SKIP_PWM 미정의 시에만 컴파일됨) */
|
||||
/* ========================================================================== */
|
||||
|
||||
#include "nrfx_pwm.h"
|
||||
|
||||
/* --- Configuration --- */
|
||||
#define PULSE_PIN_1 28
|
||||
#define PULSE_PIN_2 29
|
||||
#define PULSE_PIN_3 30
|
||||
#define PULSE_DELAY_MS 10
|
||||
/* --- 설정값 --- */
|
||||
#define PULSE_PIN_1 28 /* PWM 출력 핀 1 (P0.28) */
|
||||
#define PULSE_PIN_2 29 /* PWM 출력 핀 2 (P0.29) */
|
||||
#define PULSE_PIN_3 30 /* PWM 출력 핀 3 (P0.30) */
|
||||
#define PULSE_DELAY_MS 10 /* 반복 재생 간격 (ms) */
|
||||
|
||||
#define PWM_INSTANCE_ID 0
|
||||
#define PWM_TOP_VALUE 8
|
||||
#define SEQUENCE_LENGTH 6
|
||||
#define PWM_INSTANCE_ID 0 /* PWM 하드웨어 인스턴스 번호 */
|
||||
#define PWM_TOP_VALUE 8 /* PWM 카운터 최대값 (듀티 사이클 분해능) */
|
||||
#define SEQUENCE_LENGTH 6 /* PWM 시퀀스 단계 수 */
|
||||
|
||||
static nrfx_pwm_t m_pwm = NRFX_PWM_INSTANCE(PWM_INSTANCE_ID);
|
||||
APP_TIMER_DEF(m_pulse_delay_timer_id);
|
||||
static volatile bool m_pulses_running = false;
|
||||
static nrfx_pwm_t m_pwm = NRFX_PWM_INSTANCE(PWM_INSTANCE_ID); /* PWM 인스턴스 */
|
||||
APP_TIMER_DEF(m_pulse_delay_timer_id); /* 반복 재생용 앱 타이머 */
|
||||
static volatile bool m_pulses_running = false; /* 펄스 생성 동작 중 플래그 */
|
||||
|
||||
/* PWM 시퀀스 데이터: 6단계에 걸쳐 3채널의 듀티 사이클을 개별 설정 */
|
||||
static nrf_pwm_values_individual_t m_pulse_seq_values[SEQUENCE_LENGTH];
|
||||
static nrf_pwm_sequence_t const m_pulse_sequence =
|
||||
{
|
||||
.values.p_individual = m_pulse_seq_values,
|
||||
.length = NRF_PWM_VALUES_LENGTH(m_pulse_seq_values),
|
||||
.repeats = 0,
|
||||
.end_delay = 0
|
||||
.repeats = 0, /* 각 단계 반복 없음 */
|
||||
.end_delay = 0 /* 시퀀스 종료 후 추가 지연 없음 */
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Local Handlers */
|
||||
/* 내부 핸들러 함수 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* PWM 시퀀스 값 초기화
|
||||
* 6단계에 걸쳐 CH0/CH1/CH2의 듀티 사이클을 교대 설정:
|
||||
* 단계0: CH0=100%, CH1=0, CH2=0
|
||||
* 단계1: CH0=0, CH1=100%, CH2=0
|
||||
* 단계2: CH0=100%, CH1=0, CH2=0
|
||||
* 단계3: CH0=0, CH1=100%, CH2=0
|
||||
* 단계4: CH0=0, CH1=0, CH2=0 (모두 OFF)
|
||||
* 단계5: CH0=0, CH1=0, CH2=100%
|
||||
*/
|
||||
static void prepare_pulse_sequence(void)
|
||||
{
|
||||
m_pulse_seq_values[0].channel_0 = PWM_TOP_VALUE; m_pulse_seq_values[0].channel_1 = 0; m_pulse_seq_values[0].channel_2 = 0;
|
||||
@@ -76,6 +111,7 @@ static void prepare_pulse_sequence(void)
|
||||
m_pulse_seq_values[5].channel_0 = 0; m_pulse_seq_values[5].channel_1 = 0; m_pulse_seq_values[5].channel_2 = PWM_TOP_VALUE;
|
||||
}
|
||||
|
||||
/* 타이머 타임아웃 핸들러: m_pulses_running이면 PWM 시퀀스 1회 재생 후 타이머 재시작 */
|
||||
static void pulse_delay_timeout_handler(void * p_context)
|
||||
{
|
||||
if (m_pulses_running)
|
||||
@@ -86,8 +122,14 @@ static void pulse_delay_timeout_handler(void * p_context)
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Public Functions */
|
||||
/* 공개 함수 */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* PWM 초기화: PWM 인스턴스 설정 + 앱 타이머 생성
|
||||
* PWM: 16MHz 클럭, UP 카운트 모드, TOP=8, 개별 채널 로드
|
||||
* 타이머: 단발(SINGLE_SHOT) 모드, 10ms 후 시퀀스 재생
|
||||
*/
|
||||
ret_code_t pulse_gen_init(void)
|
||||
{
|
||||
ret_code_t err_code;
|
||||
@@ -121,18 +163,20 @@ ret_code_t pulse_gen_init(void)
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/* 펄스 생성 시작: 플래그 설정 후 타임아웃 핸들러를 직접 호출하여 즉시 첫 재생 */
|
||||
void pulse_gen_start(void)
|
||||
{
|
||||
if (m_pulses_running) return;
|
||||
if (m_pulses_running) return; /* 이미 동작 중이면 무시 */
|
||||
m_pulses_running = true;
|
||||
pulse_delay_timeout_handler(NULL);
|
||||
pulse_delay_timeout_handler(NULL); /* 첫 번째 재생 즉시 시작 */
|
||||
}
|
||||
|
||||
/* 펄스 생성 정지: 플래그 해제 + 타이머 정지 + PWM 즉시 정지 */
|
||||
void pulse_gen_stop(void)
|
||||
{
|
||||
m_pulses_running = false;
|
||||
app_timer_stop(m_pulse_delay_timer_id);
|
||||
nrfx_pwm_stop(&m_pwm, true);
|
||||
nrfx_pwm_stop(&m_pwm, true); /* true = 즉시 정지 (현재 시퀀스 중단) */
|
||||
}
|
||||
|
||||
#endif /* SKIP_PWM */
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
/*******************************************************************************
|
||||
* [한국어 설명] PWM 펄스 생성기 헤더
|
||||
*
|
||||
* PWM 기반 펄스 생성 모듈의 공개 인터페이스.
|
||||
* 현재 SKIP_PWM 매크로로 비활성화되어 있으며, Stub 구현만 동작함.
|
||||
* 실제 구현 시 nrfx_pwm + app_timer로 3핀(P28/P29/P30) PWM 제어.
|
||||
*
|
||||
* 비활성화 사유: 피에조 구동은 dr_piezo 드라이버가 담당하므로
|
||||
* 이 PWM 모듈은 현재 프로젝트에서 사용하지 않음.
|
||||
* 빌드 호환성을 위해 인터페이스만 유지.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef PULSE_GEN_H__
|
||||
#define PULSE_GEN_H__
|
||||
|
||||
@@ -6,20 +18,23 @@
|
||||
#include "sdk_errors.h"
|
||||
|
||||
/**
|
||||
* @brief Initializes the PWM peripheral and app_timer for pulse generation.
|
||||
* @brief PWM 주변장치 및 app_timer를 초기화한다.
|
||||
* (SKIP_PWM 정의 시 아무 동작 없이 NRF_SUCCESS 반환)
|
||||
*
|
||||
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
|
||||
*/
|
||||
ret_code_t pulse_gen_init(void);
|
||||
|
||||
/**
|
||||
* @brief Starts the repeating pulse generation.
|
||||
* Generates a burst of pulses, waits a few ms, and repeats.
|
||||
* @brief 반복 펄스 생성을 시작한다.
|
||||
* 버스트 펄스를 생성하고, 수 ms 대기 후 반복.
|
||||
* (SKIP_PWM 정의 시 아무 동작 없음)
|
||||
*/
|
||||
void pulse_gen_start(void);
|
||||
|
||||
/**
|
||||
* @brief Stops the repeating pulse generation.
|
||||
* @brief 반복 펄스 생성을 정지한다.
|
||||
* (SKIP_PWM 정의 시 아무 동작 없음)
|
||||
*/
|
||||
void pulse_gen_stop(void);
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ void tmp235_voltage_handler(nrf_drv_saadc_evt_t const * p_event) /* TMP325 Vout
|
||||
|
||||
/* ADC 변환 결과 읽기 */
|
||||
adc_result = p_event->data.done.p_buffer[0];
|
||||
DBG_PRINTF("[TMP] adc=%d\r\n", adc_result);
|
||||
|
||||
/* SAADC 해제 — 배터리/압력센서 측정과 하드웨어 공유 */
|
||||
nrf_drv_saadc_uninit();
|
||||
|
||||
@@ -3,13 +3,28 @@
|
||||
* @author CandyPops Co.
|
||||
* @version V1.0.0
|
||||
* @date 2022-09-05
|
||||
* @brief
|
||||
* @brief
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* [헤더 개요] TMP235-Q1 아날로그 온도센서 드라이버 인터페이스
|
||||
*
|
||||
* TMP235-Q1의 아날로그 전압 출력을 SAADC(AIN3)로 읽어
|
||||
* 온도(°C)로 변환하는 기능의 외부 호출용 API를 선언한다.
|
||||
*
|
||||
* 주요 API:
|
||||
* - tmp235_init() : SAADC 초기화 + 즉시 측정 시작 (내부 사용)
|
||||
* - tmp235_voltage_level_meas() : 온도 1회 측정 (외부 호출용 래퍼)
|
||||
*
|
||||
* 온도 변환: Vout(mV) → Ta(°C) = (Vout - 500) / 10.0 (0~100°C 구간)
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _TMP235_Q1_H_
|
||||
#define _TMP235_Q1_H_
|
||||
|
||||
/** @brief TMP235 SAADC 초기화 및 측정 시작 (AIN3 채널) */
|
||||
void tmp235_init(void);
|
||||
/** @brief 온도 1회 측정 외부 호출 함수 (내부적으로 tmp235_init 호출) */
|
||||
void tmp235_voltage_level_meas(void);
|
||||
|
||||
#endif /* !_TMP235_Q1_H_ */
|
||||
|
||||
Reference in New Issue
Block a user