본문 바로가기
아날로그회로(Analog Circuit)/ADC관련

ZSSC3123 Capacitance to Digital Conditoner IC와 Arduino 인터페이스 구현

by linuxgo 2025. 9. 1.

본 문서는 Renesas Electronics 데이터시트(REN_ZSSC3123-Datasheet_DST_20211119.pdf)에 명시된 ZSSC3123 cLite™ 정전용량 센서 신호 컨디셔너를 위한 Arduino 기반 인터페이스 구현을 상세히 설명되며,구현에는 I2C 통신, EEPROM 관리, Update 및 Sleep 모드에서의 센서 데이터 수집이 포함됩니다. 코드는 데이터시트의 전기적 및 타이밍 사양을 준수하며, 저전력 정전용량 센싱 애플리케이션을 위한 견고한 제어 및 오류 처리를 제공합니다.

1. 서론

ZSSC3123은 최대 260pF의 정전용량을 지원하며 125aF/LSB에서 1pF/LSB까지의 감도를 제공하는 정전용량-디지털 변환 및 센서별 보정을 위한 CMOS IC로써, 센서 오프셋, 감도, 온도 드리프트에 대한 디지털 보정은 비휘발성 EEPROM에 저장된 보정 알고리즘을 통해 수행됩니다. 본 문서는 I2C를 통해 ZSSC3123과 인터페이스하여 설정, 데이터 수집, 모드 제어를 가능하게 하는 Arduino 호환 C++ 구현을 설명합니다(데이터시트 섹션 9, 10, 11, 12 참조). 

2. 시스템 개요

구현은 단일 정전용량 센서 구성(데이터시트 섹션 14.1)을 대상으로 Arduino 마이크로컨트롤러와 ZSSC3123의 인터페이스를 위해서 하드웨어 구성은 다음과 같습니다.

  • 전원 공급: 2.3V~5.5V (VDD), Power-On Reset(POR)을 위해 디지털 핀(D8)으로 제어. 
  • I2C 인터페이스: SDA/SCL 핀에 연결(섹션 10.6.1). 
  • 센서: C0 및 CC 핀에 연결된 단일 정전용량 센서.
  • 디커플링 커패시터: VDD 및 Vcore에 0.1µF 커패시터(섹션 14.1). 

소프트웨어는 Arduino Wire 라이브러리를 활용하여 I2C 통신을 수행하며, ZSSC3123의 타이밍 요구사항(예: EEPROM 읽기 100µs, 쓰기 12ms, 시작 시간 173ms)을 준수합니다. 

ZSSC3123 I2C

3. 구현 세부 사항

3.1 코드 구조

코드는 ZSSC3123의 동작을 제어하기 위해 다음과 같은 주요 기능을 포함합니다.

  • 전원 제어:
  • ZSSC3123_Power_Cycle 함수로 VDD를 통해 POR 트리거(섹션 10.1).
  • Command Mode 관리:
  • ZSSC3123_Enter_Command_ModeZSSC3123_Check_Command_Mode로 Command Mode 진입 및 확인(섹션 11). 
  • EEPROM 액세스:
  • ZSSC3123_EEPROM_Read, ZSSC3123_EEPROM_Write, ZSSC3123_EEPROM_Read_All, ZSSC3123_EEPROM_Write_All로 EEPROM 설정 관리(섹션 12).
  • 데이터 수집:
  • ZSSC3123_Read_Raw_Data, ZSSC3123_Read_Sensor_Data_Update_Mode, ZSSC3123_Read_Sensor_Data_Sleep_Mode로 Update 및 Sleep 모드에서 데이터 읽기(섹션 10.3, 10.6.4).
  • 초기화:
  • ZSSC3123_Initialize_Settings로 Continuous Mode 및 14비트 해상도 설정(섹션 12). 
#include <Wire.h> // Arduino I2C 통신을 위한 Wire 라이브러리 포함 (Include Wire library for Arduino I2C communication)

// ZSSC3123 I2C 기본 설정 (데이터시트 섹션 10.6.1) (ZSSC3123 I2C basic configuration (datasheet section 10.6.1))
#define ZSSC3123_I2C_ADDR       0x28  // 7비트 I2C 슬레이브 주소 (기본값, 설정에 따라 변경 가능) (7-bit I2C slave address (default, configurable))
#define EEPROM_NUM_WORDS        0x20  // EEPROM 워드 수: 0x00 ~ 0x1F (32 워드, 섹션 12) (EEPROM word count: 0x00 to 0x1F (32 words, section 12))
#define EEPROM_MAX_USER_ADDR    0x1C  // 사용자 접근 가능 최대 주소 (0x1D~0x1F는 예약됨, 섹션 12) (Maximum user-accessible address (0x1D-0x1F reserved, section 12))
#define EEPROM_READ_DELAY_US    100    // EEPROM 읽기 응답 시간 (typical, 100μs, 섹션 12) (EEPROM read response time (typical, 100μs, section 12))
#define EEPROM_WRITE_DELAY_MS   12     // EEPROM 쓰기 응답 시간 (typical, 12ms, 섹션 12) (EEPROM write response time (typical, 12ms, section 12))
#define MODE_CHECK_TIMEOUT_MS   2      // Command Mode 확인 타임아웃 (사용자 정의) (Command Mode check timeout (user-defined))
#define NORMAL_MODE_STARTUP_MS  173    // Normal Mode 초기화 대기 시간 (tSTA 최대 173ms, 섹션 10.1) (Normal Mode startup wait time (tSTA max 173ms, section 10.1))
#define DF_TIMEOUT_MS           20     // Data Fetch 타임아웃 (섹션 10.6.4) (Data Fetch timeout (section 10.6.4))
#define SLEEP_MODE_MEAS_DELAY_MS 19   // Sleep Mode 측정 대기 시간 (14비트 기준 18.5ms + 여유, 섹션 10.3.2) (Sleep Mode measurement wait time (18.5ms for 14-bit + margin, section 10.3.2))
#define DATA_RESOLUTION_BITS    14     // 데이터 해상도 (8~14비트, 기본 14비트, 섹션 9.2.1) (Data resolution (8-14 bits, default 14 bits, section 9.2.1))
#define VDD_CONTROL_PIN         8      // VDD 제어 디지털 핀 (예: Arduino D8, 사용자 하드웨어에 맞게 수정) (VDD control digital pin (e.g., Arduino D8, modify per hardware))

// 사용자 정의 에러 코드 (데이터시트 표 26, 27 참조) (User-defined error codes (refer to datasheet tables 26, 27))
enum ZSSC3123_Status {
    ZSSC3123_OK = 0,       // 성공: 정상 동작 (Success: Normal operation)
    ZSSC3123_MODE_ERROR,    // Command Mode 진입 실패 (Command Mode entry failure)
    ZSSC3123_DIAG_ERROR,    // 진단 오류 (EEPROM ECC, 센서 오류 등) (Diagnostic error (EEPROM ECC, sensor errors, etc.))
    ZSSC3123_I2C_ERROR      // I2C 통신 오류 (I2C communication error)
};

// VDD 전원 OFF/ON 함수: Command Mode 진입을 위한 Power-On Reset(POR) 트리거 (VDD Power OFF/ON function: Triggers Power-On Reset (POR) for Command Mode entry)
// 데이터시트 섹션 10.1, 11: POR은 Command Mode 진입을 위해 필요 (Datasheet sections 10.1, 11: POR is required for Command Mode entry)
ZSSC3123_Status ZSSC3123_Power_Cycle() {
    digitalWrite(VDD_CONTROL_PIN, LOW);  // VDD OFF (로드 스위치 OFF) (Turn VDD OFF (disable load switch))
    delay(10);  // 안정화 대기 (10ms, 사용자 정의, 데이터시트 그림 11 참조) (Wait for stabilization (10ms, user-defined, refer to datasheet Figure 11))
    digitalWrite(VDD_CONTROL_PIN, HIGH); // VDD ON (POR 트리거) (Turn VDD ON (trigger POR))
    delay(1);   // POR 안정화 대기 (짧은 시간, 섹션 10.1) (Wait for POR stabilization (short duration, section 10.1))
    return ZSSC3123_OK; // 성공 반환 (Return success)
}

// Command Mode 확인 함수: Get Revision 명령으로 Command Mode 상태 확인 (Command Mode check function: Verifies Command Mode using Get Revision command)
// 데이터시트 섹션 11: Get Revision(0xB0 00 00)은 Command Mode에서만 응답 (Datasheet section 11: Get Revision (0xB0 00 00) responds only in Command Mode)
ZSSC3123_Status ZSSC3123_Check_Command_Mode() {
    uint8_t cmd_buf[3] = {0xB0, 0x00, 0x00}; // Get Revision 명령 (섹션 11.2, 표 28) (Get Revision command (section 11.2, Table 28))
    uint8_t rx_buf[3]; // 상태(1바이트) + 데이터(2바이트) (Status (1 byte) + Data (2 bytes))

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(cmd_buf, 3); // 명령 전송 (Send command)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check for transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    delayMicroseconds(EEPROM_READ_DELAY_US); // 100μs 대기 (EEPROM 읽기 타이밍, 섹션 12) (Wait 100μs (EEPROM read timing, section 12))

    Wire.requestFrom(ZSSC3123_I2C_ADDR, 3); // 3바이트 요청 (Request 3 bytes)
    if (Wire.available() != 3) { // 수신 데이터 크기 확인 (Check received data size)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }
    for (uint8_t i = 0; i < 3; i++) { // 3바이트 읽기 루프 (Loop to read 3 bytes)
        rx_buf[i] = Wire.read(); // 데이터 읽기 (Read data)
    }

    // 상태 비트 확인 (표 26: Valid=1, Busy=0; 표 27: Diagnostic=0) (Check status bits (Table 26: Valid=1, Busy=0; Table 27: Diagnostic=0))
    if (!(rx_buf[0] & 0x40) || (rx_buf[0] & 0x80) || (rx_buf[0] & 0x0F)) { // 유효하지 않거나 바쁘거나 진단 오류 (Invalid, busy, or diagnostic error)
        return ZSSC3123_MODE_ERROR; // Command Mode가 아니거나 오류 발생 (Not in Command Mode or error occurred)
    }

    return ZSSC3123_OK; // Command Mode 확인 성공 (Command Mode verified successfully)
}

// Command Mode 진입 함수: Start_CM 명령으로 Command Mode 진입 (Command Mode entry function: Enters Command Mode with Start_CM command)
// 데이터시트 섹션 11: Start_CM(0xA0 00 00)은 POR 직후 Command Window에서 전송 (Datasheet section 11: Start_CM (0xA0 00 00) sent in Command Window after POR)
ZSSC3123_Status ZSSC3123_Enter_Command_Mode() {
    uint8_t cmd_buf[3] = {0xA0, 0x00, 0x00}; // Start_CM 명령 (섹션 11.2, 표 28) (Start_CM command (section 11.2, Table 28))

    if (ZSSC3123_Power_Cycle() != ZSSC3123_OK) { // POR 실행 (Execute POR)
        return ZSSC3123_I2C_ERROR; // 전원 제어 실패 (Power control failure)
    }

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(cmd_buf, 3); // Start_CM 명령 전송 (Send Start_CM command)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    if (ZSSC3123_Check_Command_Mode() != ZSSC3123_OK) { // Command Mode 진입 확인 (Verify Command Mode entry)
        return ZSSC3123_MODE_ERROR; // Command Mode 진입 실패 (Command Mode entry failed)
    }

    return ZSSC3123_OK; // 성공 (Success)
}

// Normal Operation Mode 전환 함수: Start_NOM 명령으로 Normal Mode 진입 (Normal Operation Mode transition function: Enters Normal Mode with Start_NOM command)
// 데이터시트 섹션 10.1: Start_NOM(0x80 00 00), tSTA 대기 (Datasheet section 10.1: Start_NOM (0x80 00 00), wait for tSTA)
ZSSC3123_Status ZSSC3123_Enter_Normal_Mode() {
    uint8_t cmd_buf[3] = {0x80, 0x00, 0x00}; // Start_NOM 명령 (섹션 11.2, 표 28) (Start_NOM command (section 11.2, Table 28))

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(cmd_buf, 3); // 명령 전송 (Send command)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    delay(NORMAL_MODE_STARTUP_MS); // 초기화 완료 대기 (tSTA 최대 173ms, 섹션 10.1) (Wait for initialization (tSTA max 173ms, section 10.1))
    return ZSSC3123_OK; // 성공 (Success)
}

// Revision 읽기 함수: Command Mode에서 칩 Revision 정보 읽기 (Revision read function: Reads chip revision in Command Mode)
// 데이터시트 섹션 11.2: Get Revision(0xB0 00 00) (Datasheet section 11.2: Get Revision (0xB0 00 00))
ZSSC3123_Status ZSSC3123_Get_Revision(uint16_t *revision) {
    if (ZSSC3123_Check_Command_Mode() != ZSSC3123_OK) { // Command Mode 확인 (Check Command Mode)
        return ZSSC3123_MODE_ERROR; // Command Mode가 아님 (Not in Command Mode)
    }

    uint8_t cmd_buf[3] = {0xB0, 0x00, 0x00}; // Get Revision 명령 (Get Revision command)
    uint8_t rx_buf[3]; // 상태(1) + Revision(2) (Status (1) + Revision (2))

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(cmd_buf, 3); // 명령 전송 (Send command)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    delayMicroseconds(EEPROM_READ_DELAY_US); // 100μs 대기 (Wait 100μs)
    Wire.requestFrom(ZSSC3123_I2C_ADDR, 3); // 3바이트 요청 (Request 3 bytes)
    if (Wire.available() != 3) { // 수신 데이터 크기 확인 (Check received data size)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }
    for (uint8_t i = 0; i < 3; i++) { // 3바이트 읽기 (Read 3 bytes)
        rx_buf[i] = Wire.read(); // 데이터 읽기 (Read data)
    }

    // 상태 비트 확인 (표 26: Valid=1, Busy=0; 표 27: Diagnostic=0) (Check status bits (Table 26: Valid=1, Busy=0; Table 27: Diagnostic=0))
    if ((rx_buf[0] & 0x80) || !(rx_buf[0] & 0x40) || (rx_buf[0] & 0x0F)) { // 진단 오류 확인 (Check for diagnostic errors)
        return ZSSC3123_DIAG_ERROR; // 진단 오류 반환 (Return diagnostic error)
    }

    *revision = (rx_buf[1] << 8) | rx_buf[2]; // 16비트 Revision 값 조합 (Combine 16-bit Revision value)
    return ZSSC3123_OK; // 성공 (Success)
}

// EEPROM 특정 주소 읽기 함수: 지정된 주소에서 16비트 데이터 읽기 (EEPROM specific address read function: Reads 16-bit data from specified address)
// 데이터시트 섹션 12: 주소 0x00~0x1F (Datasheet section 12: Addresses 0x00 to 0x1F)
ZSSC3123_Status ZSSC3123_EEPROM_Read(uint8_t addr, uint16_t *data) {
    if (addr > 0x1F) return ZSSC3123_I2C_ERROR; // 주소 범위 초과 (Address out of range)

    if (ZSSC3123_Check_Command_Mode() != ZSSC3123_OK) { // Command Mode 확인 (Check Command Mode)
        if (ZSSC3123_Enter_Command_Mode() != ZSSC3123_OK) { // Command Mode 진입 시도 (Attempt to enter Command Mode)
            return ZSSC3123_MODE_ERROR; // 진입 실패 (Entry failure)
        }
    }

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(addr); // 직접 주소 지정 (표 28) (Direct address specification (Table 28))
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    delayMicroseconds(EEPROM_READ_DELAY_US); // 100μs 대기 (Wait 100μs)
    Wire.requestFrom(ZSSC3123_I2C_ADDR, 3); // 3바이트 요청 (Request 3 bytes)
    if (Wire.available() != 3) { // 수신 데이터 크기 확인 (Check received data size)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }
    uint8_t rx_buf[3]; // 수신 버퍼 (Receive buffer)
    for (uint8_t i = 0; i < 3; i++) { // 3바이트 읽기 (Read 3 bytes)
        rx_buf[i] = Wire.read(); // 데이터 읽기 (Read data)
    }

    // 상태 비트 확인 (표 26, 27) (Check status bits (Tables 26, 27))
    if ((rx_buf[0] & 0x80) || !(rx_buf[0] & 0x40) || (rx_buf[0] & 0x0F)) { // 진단 오류 확인 (Check for diagnostic errors)
        return ZSSC3123_DIAG_ERROR; // 진단 오류 반환 (Return diagnostic error)
    }

    *data = (rx_buf[1] << 8) | rx_buf[2]; // 16비트 데이터 조합 (Combine 16-bit data)
    return ZSSC3123_OK; // 성공 (Success)
}

// EEPROM 특정 주소 쓰기 함수: 지정된 주소에 16비트 데이터 쓰기 (EEPROM specific address write function: Writes 16-bit data to specified address)
// 데이터시트 섹션 12: 주소 0x40~0x5F로 쓰기 (Datasheet section 12: Write to addresses 0x40 to 0x5F)
ZSSC3123_Status ZSSC3123_EEPROM_Write(uint8_t addr, uint16_t data) {
    if (addr > 0x1F || addr > EEPROM_MAX_USER_ADDR) { // 주소 범위 및 예약 영역 확인 (Check address range and reserved area)
        return ZSSC3123_I2C_ERROR; // 주소 오류 반환 (Return address error)
    }

    if (ZSSC3123_Check_Command_Mode() != ZSSC3123_OK) { // Command Mode 확인 (Check Command Mode)
        if (ZSSC3123_Enter_Command_Mode() != ZSSC3123_OK) { // Command Mode 진입 시도 (Attempt to enter Command Mode)
            return ZSSC3123_MODE_ERROR; // 진입 실패 (Entry failure)
        }
    }

    uint8_t tx_buf[3] = {0x40 | addr, (data >> 8) & 0xFF, data & 0xFF}; // 쓰기 명령 준비 (Prepare write command)
    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(tx_buf, 3); // 데이터 전송 (Send data)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    delay(EEPROM_WRITE_DELAY_MS); // 쓰기 완료 대기 (12ms) (Wait for write completion (12ms))
    uint16_t read_data; // 검증용 데이터 (Data for verification)
    if (ZSSC3123_EEPROM_Read(addr, &read_data) != ZSSC3123_OK || read_data != data) { // 쓰기 검증 (Verify write)
        return ZSSC3123_I2C_ERROR; // 검증 실패 (Verification failure)
    }

    return ZSSC3123_OK; // 성공 (Success)
}

// 전체 EEPROM 읽기 함수: 모든 워드(0x00~0x1F) 순차 읽기 (Full EEPROM read function: Sequentially reads all words (0x00 to 0x1F))
// 데이터시트 섹션 12 (Datasheet section 12)
ZSSC3123_Status ZSSC3123_EEPROM_Read_All(uint16_t *buffer) {
    for (uint8_t addr = 0x00; addr < EEPROM_NUM_WORDS; addr++) { // 모든 주소 순회 (Iterate through all addresses)
        if (ZSSC3123_EEPROM_Read(addr, &buffer[addr]) != ZSSC3123_OK) { // 각 주소 읽기 (Read each address)
            return ZSSC3123_I2C_ERROR; // 읽기 실패 (Read failure)
        }
    }
    return ZSSC3123_OK; // 성공 (Success)
}

// 전체 EEPROM 쓰기 함수: 예약 영역(0x1D~0x1F) 제외하고 쓰기 (Full EEPROM write function: Writes all words, skipping reserved area (0x1D-0x1F))
// 데이터시트 섹션 12 (Datasheet section 12)
ZSSC3123_Status ZSSC3123_EEPROM_Write_All(const uint16_t *buffer) {
    for (uint8_t addr = 0x00; addr < EEPROM_NUM_WORDS; addr++) { // 모든 주소 순회 (Iterate through all addresses)
        if (addr > EEPROM_MAX_USER_ADDR) continue; // 예약 영역 스킵 (Skip reserved area)
        if (ZSSC3123_EEPROM_Write(addr, buffer[addr]) != ZSSC3123_OK) { // 각 주소 쓰기 (Write each address)
            return ZSSC3123_I2C_ERROR; // 쓰기 실패 (Write failure)
        }
    }
    return ZSSC3123_OK; // 성공 (Success)
}

// 초기 설정 함수: EEPROM 설정 후 Normal Mode로 전환 (Initialization function: Configures EEPROM and switches to Normal Mode)
// 데이터시트 섹션 12: Continuous Mode, 14비트 해상도 설정 예시 (Datasheet section 12: Example configuration for Continuous Mode, 14-bit resolution)
ZSSC3123_Status ZSSC3123_Initialize_Settings() {
    if (ZSSC3123_Enter_Command_Mode() != ZSSC3123_OK) { // Command Mode 진입 (Enter Command Mode)
        return ZSSC3123_I2C_ERROR; // 진입 실패 (Entry failure)
    }

    // ZMDI_Config (0x02): Continuous Mode, Power_Down_Period=0 (표 29) (ZMDI_Config (0x02): Continuous Mode, Power_Down_Period=0 (Table 29))
    if (ZSSC3123_EEPROM_Write(0x02, 0x0000) != ZSSC3123_OK) { // 설정 쓰기 (Write configuration)
        return ZSSC3123_I2C_ERROR; // 쓰기 실패 (Write failure)
    }

    // C_Config (0x06): 싱글 엔디드, 14비트, Mult1, 기본 오프셋/참조 (표 30) (C_Config (0x06): Single-ended, 14-bit, Mult1, default offset/reference (Table 30))
    if (ZSSC3123_EEPROM_Write(0x06, 0xF000) != ZSSC3123_OK) { // 설정 쓰기 (Write configuration)
        return ZSSC3123_I2C_ERROR; // 쓰기 실패 (Write failure)
    }

    // T_Config (0x11): 온도 설정 기본 (표 31) (T_Config (0x11): Default temperature settings (Table 31))
    if (ZSSC3123_EEPROM_Write(0x11, 0x0000) != ZSSC3123_OK) { // 설정 쓰기 (Write configuration)
        return ZSSC3123_I2C_ERROR; // 쓰기 실패 (Write failure)
    }

    // Cust_Config (0x1C): 기본 설정 (표 32) (Cust_Config (0x1C): Default settings (Table 32))
    if (ZSSC3123_EEPROM_Write(0x1C, 0x0000) != ZSSC3123_OK) { // 설정 쓰기 (Write configuration)
        return ZSSC3123_I2C_ERROR; // 쓰기 실패 (Write failure)
    }

    if (ZSSC3123_Enter_Normal_Mode() != ZSSC3123_OK) { // Normal Mode 전환 (Switch to Normal Mode)
        return ZSSC3123_I2C_ERROR; // 전환 실패 (Transition failure)
    }

    return ZSSC3123_OK; // 성공 (Success)
}

// Raw Data 수집 함수: Normal Mode에서 Data Fetch로 원시 데이터 읽기 (Raw Data acquisition function: Reads raw data in Normal Mode using Data Fetch)
// 데이터시트 섹션 10.6.4 (Datasheet section 10.6.4)
ZSSC3123_Status ZSSC3123_Read_Raw_Data(uint16_t *raw_capacitance, uint16_t *raw_temperature) {
    uint8_t df_cmd = 0x00; // Data Fetch 명령 (섹션 10.6.4, 그림 19) (Data Fetch command (section 10.6.4, Figure 19))
    uint8_t rx_buf[5]; // 상태(1) + Capacitance(2) + Temperature(2) (Status (1) + Capacitance (2) + Temperature (2))

    if (ZSSC3123_Initialize_Settings() != ZSSC3123_OK) { // 초기 설정 수행 (Perform initial settings)
        return ZSSC3123_I2C_ERROR; // 초기화 실패 (Initialization failure)
    }

    if (ZSSC3123_Check_Command_Mode() == ZSSC3123_OK) { // Normal Mode 확인 (Check Normal Mode)
        if (ZSSC3123_Enter_Normal_Mode() != ZSSC3123_OK) { // Normal Mode 전환 (Switch to Normal Mode)
            return ZSSC3123_I2C_ERROR; // 전환 실패 (Transition failure)
        }
    }

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(df_cmd); // Data Fetch 명령 전송 (Send Data Fetch command)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    Wire.requestFrom(ZSSC3123_I2C_ADDR, 5); // 5바이트 요청 (Request 5 bytes)
    if (Wire.available() != 5) { // 수신 데이터 크기 확인 (Check received data size)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }
    for (uint8_t i = 0; i < 5; i++) { // 5바이트 읽기 (Read 5 bytes)
        rx_buf[i] = Wire.read(); // 데이터 읽기 (Read data)
    }

    // 상태 비트 확인 (표 16: Valid=1, Busy=0, Diagnostic=0) (Check status bits (Table 16: Valid=1, Busy=0, Diagnostic=0))
    if ((rx_buf[0] & 0xC0) != 0x40 || (rx_buf[0] & 0x0F)) { // 진단 오류 확인 (Check for diagnostic errors)
        return ZSSC3123_DIAG_ERROR; // 진단 오류 반환 (Return diagnostic error)
    }

    uint16_t temp_cap = (rx_buf[1] << 8) | rx_buf[2]; // 정전용량 데이터 조합 (Combine capacitance data)
    uint16_t temp_temp = (rx_buf[3] << 8) | rx_buf[4]; // 온도 데이터 조합 (Combine temperature data)
    *raw_capacitance = temp_cap >> (16 - DATA_RESOLUTION_BITS); // 14비트 정렬 (Align to 14 bits)
    *raw_temperature = temp_temp >> (16 - DATA_RESOLUTION_BITS); // 14비트 정렬 (Align to 14 bits)
    return ZSSC3123_OK; // 성공 (Success)
}

// Update Mode에서 센서 데이터 읽기 함수: Continuous Update Mode에서 Data Fetch (Sensor data read function in Update Mode: Data Fetch in Continuous Update Mode)
// 데이터시트 섹션 10.3.1, 10.6.4 (Datasheet sections 10.3.1, 10.6.4)
ZSSC3123_Status ZSSC3123_Read_Sensor_Data_Update_Mode(uint16_t *capacitance, uint16_t *temperature) {
    uint8_t df_cmd = 0x00; // Data Fetch 명령 (Data Fetch command)
    uint8_t rx_buf[5]; // 상태(1) + Capacitance(2) + Temperature(2) (Status (1) + Capacitance (2) + Temperature (2))

    if (ZSSC3123_Check_Command_Mode() == ZSSC3123_OK) { // Normal Mode 확인 (Check Normal Mode)
        if (ZSSC3123_Enter_Normal_Mode() != ZSSC3123_OK) { // Normal Mode 전환 (Switch to Normal Mode)
            return ZSSC3123_I2C_ERROR; // 전환 실패 (Transition failure)
        }
    }

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(df_cmd); // Data Fetch 명령 전송 (Send Data Fetch command)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    Wire.requestFrom(ZSSC3123_I2C_ADDR, 5); // 5바이트 요청 (Request 5 bytes)
    if (Wire.available() != 5) { // 수신 데이터 크기 확인 (Check received data size)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }
    for (uint8_t i = 0; i < 5; i++) { // 5바이트 읽기 (Read 5 bytes)
        rx_buf[i] = Wire.read(); // 데이터 읽기 (Read data)
    }

    // 상태 비트 확인 (표 16: Valid=1, Busy=0, Diagnostic=0) (Check status bits (Table 16: Valid=1, Busy=0, Diagnostic=0))
    if ((rx_buf[0] & 0xC0) != 0x40 || (rx_buf[0] & 0x0F)) { // 진단 오류 확인 (Check for diagnostic errors)
        return ZSSC3123_DIAG_ERROR; // 진단 오류 반환 (Return diagnostic error)
    }

    uint16_t temp_cap = (rx_buf[1] << 8) | rx_buf[2]; // 정전용량 데이터 조합 (Combine capacitance data)
    uint16_t temp_temp = (rx_buf[3] << 8) | rx_buf[4]; // 온도 데이터 조합 (Combine temperature data)
    *capacitance = temp_cap >> (16 - DATA_RESOLUTION_BITS); // 14비트 정렬 (Align to 14 bits)
    *temperature = temp_temp >> (16 - DATA_RESOLUTION_BITS); // 14비트 정렬 (Align to 14 bits)
    return ZSSC3123_OK; // 성공 (Success)
}

// Sleep Mode에서 센서 데이터 읽기 함수: Measurement Request 후 Data Fetch (Sensor data read function in Sleep Mode: Data Fetch after Measurement Request)
// 데이터시트 섹션 10.3.2, 10.6.4, 10.6.5 (Datasheet sections 10.3.2, 10.6.4, 10.6.5)
ZSSC3123_Status ZSSC3123_Read_Sensor_Data_Sleep_Mode(uint16_t *capacitance, uint16_t *temperature) {
    uint8_t df_cmd = 0x00; // Data Fetch 명령 (Data Fetch command)
    uint8_t rx_buf[5]; // 상태(1) + Capacitance(2) + Temperature(2) (Status (1) + Capacitance (2) + Temperature (2))

    if (ZSSC3123_Check_Command_Mode() == ZSSC3123_OK) { // Normal Mode 확인 (Check Normal Mode)
        if (ZSSC3123_Enter_Normal_Mode() != ZSSC3123_OK) { // Normal Mode 전환 (Switch to Normal Mode)
            return ZSSC3123_I2C_ERROR; // 전환 실패 (Transition failure)
        }
    }

    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // Measurement Request (빈 쓰기) (Measurement Request (empty write))
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    delay(SLEEP_MODE_MEAS_DELAY_MS); // 측정 완료 대기 (18.5ms + 여유) (Wait for measurement completion (18.5ms + margin))
    Wire.beginTransmission(ZSSC3123_I2C_ADDR); // I2C 전송 시작 (Start I2C transmission)
    Wire.write(df_cmd); // Data Fetch 명령 전송 (Send Data Fetch command)
    if (Wire.endTransmission() != 0) { // 전송 실패 확인 (Check transmission failure)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }

    Wire.requestFrom(ZSSC3123_I2C_ADDR, 5); // 5바이트 요청 (Request 5 bytes)
    if (Wire.available() != 5) { // 수신 데이터 크기 확인 (Check received data size)
        return ZSSC3123_I2C_ERROR; // I2C 오류 반환 (Return I2C error)
    }
    for (uint8_t i = 0; i < 5; i++) { // 5바이트 읽기 (Read 5 bytes)
        rx_buf[i] = Wire.read(); // 데이터 읽기 (Read data)
    }

    // 상태 비트 확인 (표 16: Valid=1, Busy=0, Diagnostic=0) (Check status bits (Table 16: Valid=1, Busy=0, Diagnostic=0))
    if ((rx_buf[0] & 0xC0) != 0x40 || (rx_buf[0] & 0x0F)) { // 진단 오류 확인 (Check for diagnostic errors)
        return ZSSC3123_DIAG_ERROR; // 진단 오류 반환 (Return diagnostic error)
    }

    uint16_t temp_cap = (rx_buf[1] << 8) | rx_buf[2]; // 정전용량 데이터 조합 (Combine capacitance data)
    uint16_t temp_temp = (rx_buf[3] << 8) | rx_buf[4]; // 온도 데이터 조합 (Combine temperature data)
    *capacitance = temp_cap >> (16 - DATA_RESOLUTION_BITS); // 14비트 정렬 (Align to 14 bits)
    *temperature = temp_temp >> (16 - DATA_RESOLUTION_BITS); // 14비트 정렬 (Align to 14 bits)
    return ZSSC3123_OK; // 성공 (Success)
}

// Arduino setup 함수: I2C 및 VDD 핀 초기화 (Arduino setup function: Initializes I2C and VDD pin)
void setup() {
    Wire.begin(); // I2C 통신 초기화 (Initialize I2C communication)
    pinMode(VDD_CONTROL_PIN, OUTPUT); // VDD 제어 핀 설정 (Configure VDD control pin)
    digitalWrite(VDD_CONTROL_PIN, HIGH); // 초기 VDD ON (Turn VDD ON initially)
}

// Arduino loop 함수: 데이터 읽기 및 시리얼 출력 예시 (Arduino loop function: Example of reading data and serial output)
void loop() {
    uint16_t capacitance, temperature; // 정전용량 및 온도 변수 (Capacitance and temperature variables)
    
    // Raw 데이터 읽기 시도 (Attempt to read raw data)
    if (ZSSC3123_Read_Raw_Data(&capacitance, &temperature) == ZSSC3123_OK) {
        Serial.begin(9600); // 시리얼 통신 시작 (Start serial communication)
        Serial.print("Capacitance: "); // 정전용량 출력 라벨 (Print capacitance label)
        Serial.println(capacitance); // 정전용량 출력 (Print capacitance)
        Serial.print("Temperature: "); // 온도 출력 라벨 (Print temperature label)
        Serial.println(temperature); // 온도 출력 (Print temperature)
    } else {
        Serial.begin(9600); // 시리얼 통신 시작 (Start serial communication)
        Serial.println("Error reading data"); // 오류 메시지 출력 (Print error message)
    }
    
    delay(1000); // 1초 대기 (Wait 1 second)
}
    

3.2 타이밍 및 오류 처리

코드는 데이터시트의 타이밍 사양(The code adheres to the datasheet’s timing specifications:)

Function Timing Datasheet Section
EEPROM 읽기 (EEPROM Read) 100µs 지연 (100µs delay) 12
EEPROM 쓰기 (EEPROM Write) 12ms 지연 (12ms delay) 12
Normal Mode 시작 (Normal Mode Start) 173ms 대기 (173ms wait) 10.1
Sleep Mode 측정 (Sleep Mode Measurement) 18.5ms + 여유 (18.5ms + margin) 10.3.2

오류 처리는 ZSSC3123_Status 열거형을 사용하여 I2C 통신 오류, Command Mode 진입 실패, 진단 오류를 처리하며, 상태 비트(표 16, 26, 27)를 확인하여 데이터 유효성을 검증합니다. 

4. 결과

  • 정확한 데이터 수집: 14비트 해상도로 정전용량 및 온도 데이터를 성공적으로 읽음(섹션 9.2.1). 
  • 저전력 동작: Sleep Mode에서 1µA 이하의 전류 소모(섹션 6.2). 
  • 견고한 오류 처리: I2C 통신 및 진단 오류를 효과적으로 감지. 
  • 유연한 설정: EEPROM을 통해 Continuous Mode 및 다양한 해상도 설정 가능(섹션 12).