/******************************************************************************* * @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" #include "debug_print.h" #include "nrf_delay.h" #include "nrf_drv_twi.h" #include "nrfx_twi.h" #include "boards.h" #include "system_interface.h" /* 현재 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); /* 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, /* 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); /* TWI 주변장치 활성화 → I2C 통신 가능 */ } /* -------------------------------------------------------------------------- */ /* HW (TWI) 초기화 */ /* -------------------------------------------------------------------------- */ /* * HW I2C 모드로 전환하거나 초기화하는 함수. * - SW 모드가 활성화되어 있으면 SW 플래그를 해제하고 HW로 전환 * - 이미 HW 모드이면 중복 초기화를 방지하여 바로 리턴 * - 최초 HW 초기화 시 twi_initialize()를 호출하여 TWI 하드웨어 설정 */ void hw_i2c_init_once(void) { // SW 모드일 경우 강제 해제 후 HW 전환 if (SW_I2C_FRQ) { //DBG_PRINTF("[I2C]SW→HW\r\n"); // SW 리소스 해제 (필요 시 추가) SW_I2C_FRQ = false; nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */ } /* 이미 HW 모드가 활성화되어 있으면 중복 초기화 방지를 위해 즉시 리턴 */ // 이미 HW면 스킵 if (HW_I2C_FRQ) { // DBG_PRINTF("[I2C] HW I2C set\r\n"); return; } /* HW TWI 하드웨어 초기화 수행 (SCL/SDA 핀 설정, 400kHz, 활성화) */ // 실제 HW 초기화 twi_initialize(); nrf_delay_ms(2); /* 초기화 후 안정화 대기 (2ms) */ /* 모드 플래그 갱신: HW 활성, SW 비활성 */ HW_I2C_FRQ = true; SW_I2C_FRQ = false; // DBG_PRINTF("[I2C] HW I2C Mode set!\r\n"); } /* -------------------------------------------------------------------------- */ /* 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 전환 if (HW_I2C_FRQ) { //DBG_PRINTF("[I2C]HW→SW\r\n"); nrfx_twi_disable(&m_twi); /* TWI 비활성화 */ nrfx_twi_uninit(&m_twi); /* TWI 초기화 해제 */ nrf_delay_ms(2); /* 모드 전환 안정화 대기 (2ms) */ HW_I2C_FRQ = false; } // 이미 SW 모드면 재실행 금지 if (SW_I2C_FRQ) { // DBG_PRINTF("[I2C] SWI2C already initialized\r\n"); return; } /* TWI 라인 완전 해제 후 SW 비트뱅 모드 진입 */ // 실제 SW 초기화 twi_uninitialize(); // TWI 라인 해제 nrf_delay_ms(1); /* 해제 후 안정화 대기 (1ms) */ /* 모드 플래그 갱신: SW 활성, HW 비활성 */ SW_I2C_FRQ = true; HW_I2C_FRQ = false; // DBG_PRINTF("[I2C] SW I2C Mode set!\r\n"); } /* -------------------------------------------------------------------------- */ /* 전체 리셋 */ /* -------------------------------------------------------------------------- */ /* * 모든 I2C 모드 플래그를 초기화하는 함수. * HW/SW 모두 비활성 상태로 만들어, 다음 init 호출 시 강제로 재초기화되도록 한다. * 주로 시스템 리셋이나 에러 복구 시 사용. */ void i2c_reset_state(void) { HW_I2C_FRQ = false; /* HW 모드 플래그 초기화 */ SW_I2C_FRQ = false; /* SW 모드 플래그 초기화 */ DBG_PRINTF("Flags reset\r\n"); }