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

ZSSC3241 Sensor Signal Conditioner IC OWI 통신 절차 및 코드 구현

by linuxgo 2025. 8. 10.

이 문서는 Renesas의 ZSSC3241 센서 신호 컨디셔너 IC의 OWI(One-Wire Interface) 통신 절차를 데이터시트(REN_zssc3241-datasheet_DST_20240202.pdf) 기반으로 상세히 설명하고, 명령 모드(Command Mode)의 모든 명령을 STM32L432KC 마이크로컨트롤러를 사용해 코드를 구현하였습니다. 데이터시트 섹션 6.4.3(OWI 통신) 및 6.6.1, Table 34(명령 모드)를 참조하여 내용을 작성하였습니다.

ZSSC3241 OWI 통신 

ZSSC3241의 OWI는 단일 와이어를 통해 양방향 통신을 지원하는 저속 인터페이스로, 최대 100kBit/s 속도를 제공합니다. 데이터시트 섹션 6.4.3에 따르면, OWI는 주로 AOUT/OWI1 핀(핀 16)을 사용하며, current-loop 애플리케이션에서 옵션으로 OWI2in 핀(핀 15)을 사용할 수 있습니다. OWI는 I²C/SPI와 조합 가능하지만, AOUT/OWI1이 아날로그 출력과 공유될 경우 동시 사용은 선택적 extra activation pulse(tOWI_ACT ≥100µs low pulse, Figure 16)를 통해 활성화 가능하며,인터페이스 선택(I²C, SPI, OWI)은 전원 인가 후 첫 번째 유효 신호로 결정됩니다.

OWI interface

OWI 통신 절차 (OWI Communication Procedure)

데이터시트 섹션 6.4.3, Figure 14~18, Table 23,24를 기반으로 OWI 통신 절차를 단계별로 정리했습니다: 

OWI protocol Timimg

  1. 초기화 (Initialization):
  • AOUT/OWI1 핀(핀 16)을 오픈드레인(Open-Drain) 모드로 설정하고, 1.8kΩ~10 kΩ 풀업 저항을 VDD에 연결(Table23 권장 예시).
  • Current-loop 시 OWI2in(핀 15) 사용 가능. 
  • STM32L432KC GPIO(예: PA0)를 AOUT/OWI1에 연결, 오픈드레인 출력으로 설정. 
  • 타이밍 정확도를 위해 타이머 또는 시스템 클럭 기반 지연 함수 준비. 
  • 아날로그 출력과 OWI 동시 사용 시, 선택적으로 extra activation pulse(tOWI_ACT ≥100µs low pulse, Figure 16) 적용. 

 

 

 

프레임 전송 (Frame Transmission)

  • 시작 비트 (Start Bit): OWI 핀을 tOWI_START(최소 10µs) 동안 로우로 설정 후 하이로 복귀(Figure 15). 
  • 데이터 비트 (Data Bits): 8비트 데이터를 MSB부터 전송, 각 비트는 tOWI_BIT(최소 10µs) 동안 유지. 로우 펄스 후 듀티 사이클로 0(1/8~3/8)또는 1(5/8~7/8) 설정(Figure 15).
  • 정지 비트 (Stop Bit): OWI 핀을 tOWI_STOP(1~10us)동안 Low로 설정 후 , High로 복귀,포레임간 tOWI, IDLE( ≥ 10µs)유지

데이터 수신 (Data Reception)

  • 수신 프로세스: 마스터가 시작 비트를 전송한 후, 슬레이브 주소(7비트) + 읽기 비트(1)를 포함한 요청을 보냅니다(Figure 17/18). 슬레이브는 마스터의 읽기 요청에 응답하여 8비트 데이터를 전송하며, 마스터가 정지 비트를 생성하여 통신을 종료합니다. 
  • 샘플링: 비트 중간(tOWI_BIT/2)에서 OWI 핀 상태를 샘플링하여 슬레이브 응답 읽기.
  • 오류 처리:  타임아웃 또는 비정상 신호로 오류 처리. 

명령 처리 (Command Processing)

  • 명령 전송 후 상태 바이트 확인(NOP 명령, 0xFF). 
  • Busy 비트(상태 바이트 비트 5)가 0이 될 때까지 대기. 

오류 처리 (Error Handling)

  • 타임아웃, 비지 상태 지속 시 오류 처리 루틴 실행. 
  • OWI 타이밍 파라미터 (OWI Timing Parameters)데이터시트 Table 24 및 Figure 15 기반: 
파라미터 (Parameter) 설명 (Description) 값 (Value)
tOWI_BIT 비트 전송 시간 (Bit Transmission Time) 최소 10µs (100kBit/s)
tOWI_START 시작 비트 지속 시간 (Start Bit Duration) 최소 10µs
tOWI_STOP 정지 비트 지속 시간 (Stop Bit Duration) 1~10µs
tOWI_LOW 로우 펄스 지속 시간 (Low Pulse Duration) 최소 1µs (명시 없음)
tOWI_IDLE 프레임 간 간격 (Inter-Frame Gap) 최소 10µs
tOWI_ACT Concurrent OWI/아날로그 출력 활성화 펄스
(Activation Pulse for Concurrent OWI/Analog)
최소 100µs (Figure 16)

ZSSC3241 명령 모드 개요 (ZSSC3241 Command Mode Overview)

데이터시트 섹션 6.6.1 및 Table 34에 따르면, 명령 모드에서 지원하는 명령은 다음과 같습니다: 

명령 (Command) 코드 (Code) 설명 (Description)
START_CM 0xA9 명령 모드 시작 (Start Command Mode)
START_CYC 0xAB 사이클릭 모드 시작 (Start Cyclic Mode)
START_SLEEP 0xA8 슬립 모드 시작 (Start Sleep Mode)
MEASURE 0xAA SSC 보정 데이터 측정 (Measure SSC Corrected Data)
READ_RAW_SENSOR 0xA2 원시 센서 데이터 읽기 (Read Raw Sensor Data)
READ_RAW_TEMP 0xA4 원시 온도 데이터 읽기 (Read Raw Temperature Data)
UPDATE_DIAG 0xB2 진단 갱신 (Update Diagnostics)
CHECK_DIAG 0xB0 진단 결과 읽기 (Read Diagnostic Results)
RESET_DIAG 0xB1 진단 리셋 (Reset Diagnostics)
CALCULATE_NVM_CHECKSUM 0x90 NVM 체크섬 계산 (Calculate NVM Checksum)
READ_NVM 0x00~0x3F NVM 데이터 읽기 (Read NVM Data)
WRITE_NVM 0x40~0x75 NVM 데이터 쓰기 (Write NVM Data)

코드 (Code)

아래 코드는 ZSSC3241의 모든 명령 모드 명령을 STM32L432KC와 OWI로 구현한 것입니다. OWI는 하드웨어 모듈이 없으므로 비트 뱅잉(Bit-Banging) 기법을 사용하며, PA0을 AOUT/OWI1 로, PB8을 RESO 핀으로 설정했습니다. 타이밍은 데이터시트 Table 22를 준수하며, 명령 처리는 Table 34를 기반으로 합니다.

코드 설명 및 데이터시트 연계 

이 코드는 ZSSC3241의 모든 명령 모드 명령을 OWI로 구현하며, 각 함수는 데이터시트와 다음과 같이 연계됩니다: 

함수 (Function) 명령 (Command) 데이터시트 섹션 (Datasheet Section) 설명 (Description)
OWI_EnterCommandMode START_CM (0xA9) 6.6.1, Table 34 명령 모드 진입 
OWI_EnterCyclicMode START_CYC (0xAB) 6.6.1, Table 34 사이클릭 모드 진입
OWI_EnterSleepMode START_SLEEP (0xA8) 6.6.1, Table 34 슬립 모드 진입 
OWI_ReadSSCData MEASURE (0xAA) 6.5.1, Table 34 SSC 보정 데이터 읽기 
OWI_ReadRawData READ_RAW_SENSOR (0xA2), READ_RAW_TEMP (0xA4) 6.5.1, Table 34 원시 센서/온도 데이터 읽기 
OWI_UpdateDiagnostics UPDATE_DIAG (0xB2) 6.3, Table 34 진단 갱신 
OWI_CheckDiagnostics CHECK_DIAG (0xB0) 6.3, Table 34 진단 결과 읽기 
OWI_ResetDiagnostics RESET_DIAG (0xB1) 6.3, Table 34 진단 리셋 
OWI_CalculateNVMChecksum CALCULATE_NVM_CHECKSUM (0x90) 6.6.2, Table 34 NVM 체크섬 계산 
OWI_ReadNVMData READ_NVM (0x00~0x3F) Table 34 NVM 데이터 읽기 
OWI_WriteNVMData WRITE_NVM (0x40~0x75) Table 34 NVM 데이터 쓰기 

zssc3241_owi_driver.h

// zssc3241_owi_driver.h - ZSSC3241 OWI 드라이버 헤더 파일 (zssc3241_owi_driver.h - ZSSC3241 OWI driver header file)
// ZSSC3241 OWI 통신을 위한 함수 및 자료형 정의 (Function and type definitions for ZSSC3241 OWI communication)

#ifndef ZSSC3241_OWI_DRIVER_H
#define ZSSC3241_OWI_DRIVER_H

#include "stm32l4xx_hal.h"

// 데이터 유형 열거형 (Data type enumeration)
typedef enum {
    SENSOR,       // 센서 데이터 (Sensor data)
    TEMPERATURE   // 온도 데이터 (Temperature data)
} DataType;

// 함수 프로토타입 (Function prototypes)
void OWI_Init(void);              // OWI 초기화 (Initialize OWI)
void OWI_Delay(uint32_t us);      // OWI 타이밍 지연 (OWI timing delay)
void OWI_SendStart(void);         // OWI 시작 조건 전송 (Transmit OWI start condition)
void OWI_SendStop(void);          // OWI 정지 조건 전송 (Transmit OWI stop condition)
void OWI_SendBit(uint8_t bit);    // OWI 비트 전송 (Transmit OWI bit)
void OWI_SendByte(uint8_t byte);  // OWI 바이트 전송 (Transmit OWI byte)
uint8_t OWI_ReceiveBit(void);     // OWI 비트 수신 (Receive OWI bit)
uint8_t OWI_ReceiveByte(void);    // OWI 바이트 수신 (Receive OWI byte)
uint8_t OWI_GetStatus(void);      // 상태 바이트 읽기 (Read status byte)
bool OWI_IsDeviceBusy(void);      // 장치 바쁜지 확인 (Check if device is busy)
void OWI_EnterCommandMode(void);  // 명령 모드 진입 (Enter Command Mode)
void OWI_EnterCyclicMode(void);   // 사이클릭 모드 진입 (Enter Cyclic Mode)
void OWI_EnterSleepMode(void);    // 슬립 모드 진입 (Enter Sleep Mode)
HAL_StatusTypeDef OWI_ReadSSCData(int32_t *sensor_data, int32_t *temp_data); // SSC 보정 데이터 읽기 (Read SSC calibrated data)
int32_t OWI_ReadRawData(DataType type); // 원시 데이터 읽기 (Read raw data)
HAL_StatusTypeDef OWI_UpdateDiagnostics(void); // 진단 갱신 (Update diagnostics)
HAL_StatusTypeDef OWI_CheckDiagnostics(uint16_t *diag_data); // 진단 결과 읽기 (Read diagnostics result)
HAL_StatusTypeDef OWI_ResetDiagnostics(void); // 진단 리셋 (Reset diagnostics)
HAL_StatusTypeDef OWI_CalculateNVMChecksum(void); // NVM 체크섬 계산 (Calculate NVM checksum)
bool OWI_IsNVMLocked(void); // NVM 잠금 상태 확인 (Check NVM lock status)
void OWI_UnlockNVM(void);   // NVM 잠금 해제 (Unlock NVM)
HAL_StatusTypeDef OWI_ReadNVMData(uint8_t address, uint8_t *data, uint8_t size); // NVM 데이터 읽기 (Read NVM data)
HAL_StatusTypeDef OWI_WriteNVMData(uint8_t address, uint8_t *data, uint8_t size); // NVM 데이터 쓰기 (Write NVM data)

#endif // ZSSC3241_OWI_DRIVER_H

zssc3241_owi_driver.c

// zssc3241_owi_driver.c - ZSSC3241 OWI 드라이버 구현 파일 (zssc3241_owi_driver.c - ZSSC3241 OWI driver implementation file)
// ZSSC3241의 OWI(One-Wire Interface) 통신을 위한 저수준 드라이버 (Low-level driver for ZSSC3241 OWI communication)
// 데이터시트 섹션 6.4.3, 6.6.1, Table 24, Figure 15~18 기반 (Based on Datasheet Sections 6.4.3, 6.6.1, Table 24, Figure 15~18)

#include "stm32l4xx_hal.h"
#include "zssc3241_owi_driver.h"

// OWI 핀 정의 (OWI pin definitions) - 데이터시트 핀 16(AOUT/OWI1), 7(RESO)
#define OWI_PIN GPIO_PIN_0 // AOUT/OWI1 핀, PA0으로 설정 (AOUT/OWI1 pin, set to PA0)
#define OWI_PORT GPIOA     // OWI 포트 (OWI port)
#define RESO_PIN GPIO_PIN_8 // RESO 핀, PB8으로 설정 (RESO pin, set to PB8)
#define RESO_PORT GPIOB    // RESO 포트 (RESO port)

// 슬레이브 주소 (Slave address) - 데이터시트 섹션 6.4.3, 기본값 0x28
#define ZSSC3241_ADDR 0x28

// OWI 타이밍 상수 (OWI timing constants) - 데이터시트 Table 24, Figure 15 기반
#define T_OWI_START 10   // 시작 펄스 지속 시간, 최소 10µs (Start pulse duration, minimum 10µs)
#define T_OWI_STOP 5     // 정지 펄스 지속 시간, 1~10µs (Stop pulse duration, 1~10µs)
#define T_OWI_IDLE 10    // 아이들 시간, 최소 10µs (Idle time, minimum 10µs)
#define T_OWI_BIT 10     // 비트 기간, 최소 10µs (하드웨어 튜닝 필요) (Bit duration, minimum 10µs, hardware tuning required)
#define T_OWI_DUTY_0 3   // 0 비트 고 펄스, 듀티 1/8~3/8 (0 bit high pulse, duty 1/8~3/8)
#define T_OWI_DUTY_1 7   // 1 비트 고 펄스, 듀티 5/8~7/8 (1 bit high pulse, duty 5/8~7/8)

// 오류 처리 함수 (Error handling function)
void Error_Handler(void) {
    while (1); // 무한 루프, 디버깅 추가 필요 (Infinite loop, add debugging in actual projects)
}

// OWI 초기화 함수 (OWI initialization function)
void OWI_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0}; // GPIO 초기화 구조체 선언 (Declare GPIO initialization structure)
    __HAL_RCC_GPIOA_CLK_ENABLE(); // GPIOA 클럭 활성화 (Enable GPIOA clock)
    __HAL_RCC_GPIOB_CLK_ENABLE(); // GPIOB 클럭 활성화 (Enable GPIOB clock)

    // OWI 핀 (PA0) 설정 - 오픈드레인 모드, 풀업 활성화
    GPIO_InitStruct.Pin = OWI_PIN; // OWI 핀 설정 (Set OWI pin)
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 오픈드레인 모드 (Open-drain mode)
    GPIO_InitStruct.Pull = GPIO_PULLUP; // 풀업 저항 활성화 (Enable pull-up resistor)
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 고속 모드 (High-speed mode)
    HAL_GPIO_Init(OWI_PORT, &GPIO_InitStruct); // GPIO 초기화 (Initialize GPIO)
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_SET); // 기본 상태: 하이 (Default state: High)

    // RESO 핀 (PB8) 설정 - 푸시풀 출력, 풀업 없음
    GPIO_InitStruct.Pin = RESO_PIN; // RESO 핀 설정 (Set RESO pin)
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 푸시풀 출력 (Push-pull mode)
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업 없음 (No pull-up)
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 저속 모드 (Low-speed mode)
    HAL_GPIO_Init(RESO_PORT, &GPIO_InitStruct); // GPIO 초기화 (Initialize GPIO)
    HAL_GPIO_WritePin(RESO_PORT, RESO_PIN, GPIO_PIN_SET); // 기본 상태: 하이 (Default state: High)
}

// OWI 타이밍 지연 함수 (OWI timing delay function)
void OWI_Delay(uint32_t us) {
    uint32_t ticks = us * (SystemCoreClock / 1000000) / 8; // 시스템 클럭 기반 지연 계산 (Calculate delay based on system clock)
    while (ticks--) __NOP(); // NOP 명령어로 바쁜 대기 (Busy wait with NOP instruction)
}

// OWI 시작 조건 전송 함수 (OWI start condition transmission function)
void OWI_SendStart(void) {
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_RESET); // OWI 라인을 로우로 설정 (Set OWI line low)
    OWI_Delay(T_OWI_START); // 시작 펄스 지속 시간 대기 (Wait for start pulse duration)
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to high)
    OWI_Delay(T_OWI_IDLE); // 아이들 시간 대기 (Wait for idle time)
}

// OWI 정지 조건 전송 함수 (OWI stop condition transmission function)
void OWI_SendStop(void) {
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_RESET); // OWI 라인을 로우로 설정 (Set OWI line low)
    OWI_Delay(T_OWI_STOP); // 정지 펄스 지속 시간 대기 (Wait for stop pulse duration)
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to high)
    OWI_Delay(T_OWI_IDLE); // 아이들 시간 대기 (Wait for idle time)
}

// OWI 비트 전송 함수 (OWI bit transmission function)
void OWI_SendBit(uint8_t bit) {
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_RESET); // 로우 펄스 시작 (Start low pulse)
    OWI_Delay(bit ? T_OWI_DUTY_1 : T_OWI_DUTY_0); // 고 펄스 지속 시간 (High pulse duration based on bit value)
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to high)
    OWI_Delay(T_OWI_BIT - (bit ? T_OWI_DUTY_1 : T_OWI_DUTY_0)); // 나머지 비트 기간 대기 (Wait for remaining bit duration)
}

// OWI 바이트 전송 함수 (OWI byte transmission function)
void OWI_SendByte(uint8_t byte) {
    for (int i = 7; i >= 0; i--) OWI_SendBit((byte >> i) & 1); // MSB부터 비트 전송 (Transmit bits from MSB)
}

// OWI 비트 수신 함수 (OWI bit reception function)
uint8_t OWI_ReceiveBit(void) {
    uint8_t bit = 0; // 비트 변수 초기화 (Initialize bit variable)
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_RESET); // 로우 펄스 시작 (Start low pulse)
    OWI_Delay(2); // 짧은 로우 펄스 (Short low pulse, arbitrary 2µs)
    HAL_GPIO_WritePin(OWI_PORT, OWI_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to high)
    OWI_Delay(T_OWI_BIT / 2); // 중간 샘플링 지점 대기 (Wait for midpoint sampling)
    bit = HAL_GPIO_ReadPin(OWI_PORT, OWI_PIN); // 슬레이브 응답 읽기 (Read slave response)
    OWI_Delay(T_OWI_BIT / 2); // 비트 기간 완성 (Complete bit duration)
    return bit;
}

// OWI 바이트 수신 함수 (OWI byte reception function)
uint8_t OWI_ReceiveByte(void) {
    uint8_t byte = 0; // 바이트 변수 초기화 (Initialize byte variable)
    for (int i = 7; i >= 0; i--) {
        byte |= (OWI_ReceiveBit() << i); // MSB부터 조합 (Combine from MSB)
    }
    // 슬레이브 응답 타임아웃 체크 필요 (Timeout check for slave response recommended)
    return byte;
}

// 상태 바이트 읽기 함수 (Status byte reading function)
uint8_t OWI_GetStatus(void) {
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte((ZSSC3241_ADDR << 1) | 1); // 읽기 주소 전송 (Transmit read address)
    uint8_t status = OWI_ReceiveByte(); // 상태 바이트 수신 (Receive status byte)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)
    return status;
}

// 장치 바쁜지 확인 함수 (Check if device is busy function)
bool OWI_IsDeviceBusy(void) {
    return (OWI_GetStatus() & (1 << 5)) != 0; // Busy 비트 확인 (Check Busy bit)
}

// 명령 모드로 전환 함수 (Enter Command Mode function)
void OWI_EnterCommandMode(void) {
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0xA9); // START_CM 명령 전송 (Transmit START_CM command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)
    HAL_Delay(10); // 안정화 대기 (Stabilization delay, 10ms)
}

// 사이클릭 모드로 전환 함수 (Enter Cyclic Mode function)
void OWI_EnterCyclicMode(void) {
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0xAB); // START_CYC 명령 전송 (Transmit START_CYC command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)
    HAL_Delay(10); // 안정화 대기 (Stabilization delay, 10ms)
}

// 슬립 모드로 전환 함수 (Enter Sleep Mode function)
void OWI_EnterSleepMode(void) {
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0xA8); // START_SLEEP 명령 전송 (Transmit START_SLEEP command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)
    HAL_Delay(10); // 안정화 대기 (Stabilization delay, 10ms)
}

// SSC 보정 데이터 읽기 함수 (Read SSC calibrated data function)
HAL_StatusTypeDef OWI_ReadSSCData(int32_t *sensor_data, int32_t *temp_data) {
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0xAA); // MEASURE 명령 전송 (Transmit MEASURE command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    uint32_t timeout = HAL_GetTick() + 100; // 100ms 타임아웃 설정 (Set 100ms timeout)
    while (OWI_IsDeviceBusy() && HAL_GetTick() < timeout); // Busy 해제 대기 (Wait for Busy to clear)

    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte((ZSSC3241_ADDR << 1) | 1); // 읽기 주소 전송 (Transmit read address)
    uint8_t data[6]; // 6바이트 데이터 버퍼 (6-byte data buffer)
    for (uint8_t i = 0; i < 6; i++) data[i] = OWI_ReceiveByte(); // 데이터 수신 (Receive data)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    *sensor_data = (data[0] << 16) | (data[1] << 8) | data[2]; // 센서 데이터 조합, 빅엔디안 (Combine sensor data, big-endian)
    *temp_data = (data[3] << 16) | (data[4] << 8) | data[5];   // 온도 데이터 조합, 빅엔디안 (Combine temperature data, big-endian)
    if (*sensor_data & 0x800000) *sensor_data |= 0xFF000000; // 부호 확장 (Sign extension)
    if (*temp_data & 0x800000) *temp_data |= 0xFF000000;     // 부호 확장 (Sign extension)
    return HAL_OK;
}

// 원시 데이터 읽기 함수 (Read raw data function)
int32_t OWI_ReadRawData(DataType type) {
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(type == SENSOR ? 0xA2 : 0xA4); // 명령 전송 (Transmit command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    uint32_t timeout = HAL_GetTick() + 100; // 100ms 타임아웃 설정 (Set 100ms timeout)
    while (OWI_IsDeviceBusy() && HAL_GetTick() < timeout); // Busy 해제 대기 (Wait for Busy to clear)

    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte((ZSSC3241_ADDR << 1) | 1); // 읽기 주소 전송 (Transmit read address)
    uint8_t data[3]; // 24비트 데이터 버퍼 (24-bit data buffer)
    for (uint8_t i = 0; i < 3; i++) data[i] = OWI_ReceiveByte(); // 데이터 수신 (Receive data)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    int32_t raw_value = (data[0] << 16) | (data[1] << 8) | data[2]; // 데이터 조합, 빅엔디안 (Combine data, big-endian)
    if (raw_value & 0x800000) raw_value |= 0xFF000000; // 부호 확장 (Sign extension)
    return raw_value;
}

// 진단 갱신 함수 (Update diagnostics function)
HAL_StatusTypeDef OWI_UpdateDiagnostics(void) {
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0xB2); // UPDATE_DIAG 명령 전송 (Transmit UPDATE_DIAG command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    uint32_t timeout = HAL_GetTick() + 100; // 100ms 타임아웃 설정 (Set 100ms timeout)
    while (OWI_IsDeviceBusy() && HAL_GetTick() < timeout); // Busy 해제 대기 (Wait for Busy to clear)
    return HAL_OK;
}

// 진단 결과 읽기 함수 (Read diagnostics result function)
HAL_StatusTypeDef OWI_CheckDiagnostics(uint16_t *diag_data) {
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0xB0); // CHECK_DIAG 명령 전송 (Transmit CHECK_DIAG command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    uint32_t timeout = HAL_GetTick() + 100; // 100ms 타임아웃 설정 (Set 100ms timeout)
    while (OWI_IsDeviceBusy() && HAL_GetTick() < timeout); // Busy 해제 대기 (Wait for Busy to clear)

    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte((ZSSC3241_ADDR << 1) | 1); // 읽기 주소 전송 (Transmit read address)
    uint8_t data[2]; // 16비트 데이터 버퍼 (16-bit data buffer)
    for (uint8_t i = 0; i < 2; i++) data[i] = OWI_ReceiveByte(); // 데이터 수신 (Receive data)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    *diag_data = (data[0] << 8) | data[1]; // 데이터 조합 (Combine data)
    return HAL_OK;
}

// 진단 리셋 함수 (Reset diagnostics function)
HAL_StatusTypeDef OWI_ResetDiagnostics(void) {
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0xB1); // RESET_DIAG 명령 전송 (Transmit RESET_DIAG command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)
    return HAL_OK;
}

// NVM 체크섬 계산 함수 (Calculate NVM checksum function)
HAL_StatusTypeDef OWI_CalculateNVMChecksum(void) {
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0x90); // CHECKSUM 명령 전송 (Transmit CHECKSUM command)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    uint32_t timeout = HAL_GetTick() + 100; // 100ms 타임아웃 설정 (Set 100ms timeout)
    while (OWI_IsDeviceBusy() && HAL_GetTick() < timeout); // Busy 해제 대기 (Wait for Busy to clear)
    return HAL_OK;
}

// NVM 잠금 상태 확인 함수 (Check NVM lock status function)
bool OWI_IsNVMLocked(void) {
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(0x03); // SSF1 레지스터 읽기 (Read SSF1 register)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte((ZSSC3241_ADDR << 1) | 1); // 읽기 주소 전송 (Transmit read address)
    uint8_t data[2]; // 16비트 데이터 버퍼 (16-bit data buffer)
    for (uint8_t i = 0; i < 2; i++) data[i] = OWI_ReceiveByte(); // 데이터 수신 (Receive data)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    return (data[0] & (1 << 6)) != 0; // 비트 14(lock) 확인 (Check bit 14 (lock))
}

// NVM 잠금 해제 함수 (Unlock NVM function)
void OWI_UnlockNVM(void) {
    HAL_GPIO_WritePin(RESO_PORT, RESO_PIN, GPIO_PIN_RESET); // 로우로 설정하여 리셋 (Set low to reset)
    OWI_Delay(10); // 리셋 유지 시간 (Hold reset for 10ms)
    HAL_GPIO_WritePin(RESO_PORT, RESO_PIN, GPIO_PIN_SET); // 리셋 해제 (Release reset)
    OWI_Delay(10); // 안정화 대기 (Stabilization delay)
    if (OWI_IsNVMLocked()) OWI_UnlockNVM(); // 잠금 해제 실패 시 재시도 (Retry if unlock fails)
}

// NVM 데이터 읽기 함수 (Read NVM data function)
HAL_StatusTypeDef OWI_ReadNVMData(uint8_t address, uint8_t *data, uint8_t size) {
    if (address > 0x3F) return HAL_ERROR; // 주소 범위 초과 시 오류 (Return error if address out of range)
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(address); // NVM 주소 전송 (Transmit NVM address)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte((ZSSC3241_ADDR << 1) | 1); // 읽기 주소 전송 (Transmit read address)
    for (uint8_t i = 0; i < size; i++) data[i] = OWI_ReceiveByte(); // 데이터 수신 (Receive data)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)
    return HAL_OK;
}

// NVM 데이터 쓰기 함수 (Write NVM data function)
HAL_StatusTypeDef OWI_WriteNVMData(uint8_t address, uint8_t *data, uint8_t size) {
    if (address > 0x35) return HAL_ERROR; // 고객 영역 초과 시 오류 (Return error if customer area exceeded)
    if (OWI_IsNVMLocked()) { // NVM 잠금 상태 확인 (Check NVM lock status)
        OWI_UnlockNVM(); // 잠금 해제 시도 (Attempt to unlock)
        if (OWI_IsNVMLocked()) return HAL_ERROR; // 실패 시 오류 (Return error if failed)
    }
    OWI_EnterCommandMode(); // 명령 모드로 진입 (Enter Command Mode)
    OWI_SendStart(); // 시작 조건 전송 (Transmit start condition)
    OWI_SendByte(ZSSC3241_ADDR << 1); // 쓰기 주소 전송 (Transmit write address)
    OWI_SendByte(address + 0x40); // 쓰기 명령 주소 (Write command address)
    for (uint8_t i = 0; i < size; i++) OWI_SendByte(data[i]); // 데이터 전송 (Transmit data)
    OWI_SendStop(); // 정지 조건 전송 (Transmit stop condition)

    return OWI_CalculateNVMChecksum(); // 체크섬 갱신 (Update checksum)
}

main.c

// main.c - ZSSC3241 OWI 명령 모드 테스트 메인 파일 (main.c - Main file for ZSSC3241 OWI command mode testing)
// STM32L432KC에서 ZSSC3241의 모든 OWI 명령을 테스트하기 위한 메인 루틴 (Main routine to test all OWI commands of ZSSC3241 on STM32L432KC)
// 시스템 클럭 80MHz로 설정 (System clock set to 80MHz)
// 데이터시트 섹션 6.4.3, 6.6.1, Table 34 기반 (Based on Datasheet Sections 6.4.3, 6.6.1, Table 34)

#include "stm32l4xx_hal.h"
#include "zssc3241_owi_driver.h"

// 시스템 클럭 설정 구조체 (System clock configuration structure)
static void SystemClock_Config(void);

// 메인 함수 - ZSSC3241 OWI 명령 테스트 (Main function - Test ZSSC3241 OWI commands)
int main(void) {
    // HAL 초기화 (Initialize HAL)
    HAL_Init();

    // 시스템 클럭 설정 (Configure system clock)
    SystemClock_Config();

    // OWI 드라이버 초기화 (Initialize OWI driver)
    OWI_Init();

    // 변수 선언 (Variable declarations)
    int32_t sensor_data, temp_data;       // 센서 및 온도 데이터 (Sensor and temperature data)
    int32_t ssc_sensor, ssc_temp;         // SSC 보정 데이터 (SSC calibrated data)
    uint16_t diag_data;                   // 진단 데이터 (Diagnostics data)
    uint8_t nvm_data[2] = {0x12, 0x34};   // NVM 테스트 데이터 (NVM test data)

    // 명령 모드로 진입 (Enter Command Mode)
    OWI_EnterCommandMode();

    // 원시 데이터 읽기 테스트 (Raw data reading test)
    sensor_data = OWI_ReadRawData(SENSOR);      // 센서 원시 데이터 읽기 (Read raw sensor data)
    temp_data = OWI_ReadRawData(TEMPERATURE);   // 온도 원시 데이터 읽기 (Read raw temperature data)

    // SSC 보정 데이터 읽기 테스트 (SSC calibrated data reading test)
    if (OWI_ReadSSCData(&ssc_sensor, &ssc_temp) == HAL_OK) {
        // 성공 시 데이터 사용 (Use data on success)
    } else {
        Error_Handler(); // 오류 처리 (Error handling)
    }

    // 진단 기능 테스트 (Diagnostics feature test)
    if (OWI_UpdateDiagnostics() == HAL_OK) {
        if (OWI_CheckDiagnostics(&diag_data) == HAL_OK) {
            // 진단 데이터 처리 (Process diagnostics data)
        } else {
            Error_Handler(); // 오류 처리 (Error handling)
        }
    }
    OWI_ResetDiagnostics(); // 진단 리셋 (Reset diagnostics)

    // NVM 데이터 테스트 (NVM data test)
    if (OWI_WriteNVMData(0x03, nvm_data, 2) == HAL_OK) {
        if (OWI_ReadNVMData(0x03, nvm_data, 2) == HAL_OK) {
            OWI_CalculateNVMChecksum(); // NVM 체크섬 계산 (Calculate NVM checksum)
        } else {
            Error_Handler(); // 오류 처리 (Error handling)
        }
    }

    // 모드 전환 테스트 (Mode switching test)
    OWI_EnterCyclicMode(); // 사이클릭 모드로 전환 (Switch to Cyclic Mode)
    HAL_Delay(100);        // 안정화 대기 (Stabilization delay, 100ms)
    OWI_EnterSleepMode();  // 슬립 모드로 전환 (Switch to Sleep Mode)

    // 무한 루프 - 실제 응용에서 데이터 처리 추가 (Infinite loop - Add data processing in actual application)
    while (1) {
        HAL_Delay(1000); // 1초 대기 (Wait for 1 second)
    }
}

// 시스템 클럭 설정 함수 (System clock configuration function)
// STM32L432KC를 80MHz로 설정 (Configure STM32L432KC to 80MHz)
static void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0}; // OSC 초기화 구조체 (OSC initialization structure)
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 클럭 초기화 구조체 (Clock initialization structure)

    // HSI OSC 활성화 및 설정 (Enable and configure HSI OSC)
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; // HSI 사용 (Use HSI)
    RCC_OscInitStruct.HSIState = RCC_HSI_ON; // HSI 켜기 (Turn on HSI)
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; // 기본 캘리브레이션 (Default calibration)
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // PLL 켜기 (Turn on PLL)
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; // HSI를 PLL 소스로 (HSI as PLL source)
    RCC_OscInitStruct.PLL.PLLM = 1; // PLL 입력 분주 (PLL input division)
    RCC_OscInitStruct.PLL.PLLN = 10; // PLL 승수 (PLL multiplication factor)
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; // PLL 출력 분주 (PLL output division)
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // PLL Q 출력 분주 (PLL Q output division)
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // PLL R 출력 분주 (PLL R output division)
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler(); // 오류 처리 (Error handling)
    }

    // 시스템 클럭 설정 (Configure system clock)
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // PLL 클럭 사용 (Use PLL clock)
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB 분주 없음 (No AHB division)
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // APB1 분주 없음 (No APB1 division)
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2 분주 없음 (No APB2 division)
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
        Error_Handler(); // 오류 처리 (Error handling)
    }

    // Systick 설정 - 1ms 단위 인터럽트 (Configure Systick for 1ms interrupt)
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);

    // Systick 인터럽트 우선순위 설정 (Set Systick interrupt priority)
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

참고: OWI는 저속이므로 실시간 데이터 전송보다는 캘리브레이션 및 설정에 적합합니다. **실제 프로젝트에서는 타이머 인터럽트를 사용하여 타이밍 정확도를 높이는 것이 좋습니다.