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

[ZSSC3241]OWI 통신 절차 및 코드 구현 (ZSSC3241 OWI Communication Procedure and Code Implementation)

by linuxgo 2025. 8. 10.
반응형

이 가이드는 Renesas의 ZSSC3241 센서 신호 컨디셔너 IC의 OWI(One-Wire Interface) 통신 절차를 데이터시트(REN_zssc3241-datasheet_DST_20240202.pdf) 기반으로 상세히 설명하고, 명령 모드(Command Mode)의 모든 명령을 STM32L432KC 마이크로컨트롤러를 사용해 구현한 코드를 제공합니다. (This guide details the OWI communication procedure for Renesas' ZSSC3241 sensor signal conditioner IC based on the datasheet and provides code implementing all Command Mode commands using the STM32L432KC microcontroller.) 데이터시트 섹션 6.4.3(OWI 통신) 및 6.6.1, Table 34(명령 모드)를 참조하여, 초보자도 이해할 수 있도록 단계별로 설명하였습니다.(Referencing datasheet sections 6.4.3 (OWI communication) and 6.6.1, Table 34 (Command Mode), it’s explained step-by-step for beginners)

ZSSC3241 OWI 통신 절차 (ZSSC3241 OWI Communication Procedure)

ZSSC3241의 OWI는 단일 와이어를 통해 양방향 통신을 지원하는 저속 인터페이스로, 최대 100kBit/s 속도를 제공합니다. (The ZSSC3241’s OWI is a low-speed interface supporting bidirectional communication over a single wire, offering up to 100kBit/s.) 데이터시트 섹션 6.4.3에 따르면, OWI는 SDA 핀(핀 9)을 사용하며, I2C/SPI와 동시에 사용할 수 없습니다. (According to datasheet section 6.4.3, OWI uses the SDA pin (pin 9) and cannot be used simultaneously with I2C/SPI.) 인터페이스 선택은 전원 인가 후 첫 번째 유효 신호로 결정됩니다. (Interface selection is determined by the first valid signal after power-on.)

OWI 통신 절차 (OWI Communication Procedure)

데이터시트 섹션 6.4.3, Figure 13, Table 22를 기반으로 OWI 통신 절차를 단계별로 정리했습니다: (The OWI communication procedure is outlined step-by-step based on datasheet section 6.4.3, Figure 13, and Table 22:)

  1. 초기화 (Initialization):
    •    SDA 핀(핀 9)을 오픈드레인(Open-Drain) 모드로 설정하고, 10kΩ 풀업 저항 연결(데이터시트 권장). (Configure SDA pin (pin 9) in open-drain mode with a 10kΩ pull-up resistor (datasheet recommendation).)
    •    STM32L432KC의 GPIO(예: PB7)를 오픈드레인 출력으로 설정. (Configure STM32L432KC GPIO (e.g., PB7) as open-drain output.)
    •    타이밍 정확도를 위해 타이머 또는 시스템 클럭 기반 지연 함수 준비. (Prepare a timer or system clock-based delay function for timing accuracy.)
  2. 프레임 전송 (Frame Transmission):
    •    시작 비트 (Start Bit): SDA를 tOWI_START(최소 20µs) 동안 로우로 설정 후 하이로 복귀. (Set SDA low for tOWI_START (minimum 20µs), then return to high.)
    •    데이터 비트 (Data Bits): 8비트 데이터를 MSB부터 전송, 각 비트는 tOWI_BIT(최소 10µs) 동안 유지. 로우 펄스(tOWI_LOW, 최소 1µs) 후 데이터 값(0/1) 설정. (Send 8-bit data starting from MSB, each bit held for tOWI_BIT (minimum 10µs). Set low pulse (tOWI_LOW, minimum 1µs), then set data value (0/1).)
    •    패리티 비트 (Parity Bit): 데이터 비트의 XOR로 계산된 홀수 패리티 전송. (Send odd parity bit calculated as XOR of data bits.)
    •    정지 비트 (Stop Bit): SDA를 tOWI_STOP(최소 20µs) 동안 로우로 설정 후 하이로 복귀, 프레임 간 간격 tOWI_FRAME(최소 40µs) 유지. (Set SDA low for tOWI_STOP (minimum 20µs), return to high, maintain inter-frame gap tOWI_FRAME (minimum 40µs).)
  3. 데이터 수신 (Data Reception):
    •    마스터가 시작 비트를 감지한 후, 슬레이브로부터 8비트 데이터, 패리티 비트, 정지 비트를 수신. (After detecting the start bit, receive 8-bit data, parity bit, and stop bit from the slave.)
    •    비트 중간(tOWI_BIT/2)에서 SDA 상태 샘플링. (Sample SDA state at bit midpoint (tOWI_BIT/2).)
    •    패리티 검증 후 오류 처리. (Verify parity and handle errors.)
  4. 명령 처리 (Command Processing):
    •    명령 전송 후 상태 바이트 확인(NOP 명령, 0xFF). (Check status byte after sending command using NOP command (0xFF).)
    •    Busy 비트(상태 바이트 비트 5)가 0이 될 때까지 대기. (Wait until Busy bit (status byte bit 5) is 0.)
  5. 오류 처리 (Error Handling):
    •    패리티 오류, 타임아웃, 비지 상태 지속 시 오류 처리 루틴 실행. (Execute error handling routine for parity errors, timeouts, or persistent busy state.)

OWI 타이밍 파라미터 (OWI Timing Parameters)

데이터시트 Table 22 및 Figure 13을 기반으로 주요 타이밍 파라미터는 다음과 같습니다: (Key timing parameters based on datasheet Table 22 and Figure 13 are as follows:)

파라미터 (Parameter) 설명 (Description) 값 (Value)
tOWI_BIT 비트 전송 시간 (Bit Transmission Time) 최소 10µs (100kBit/s)
tOWI_START 시작 비트 지속 시간 (Start Bit Duration) 최소 2 × tOWI_BIT (20µs)
tOWI_STOP 정지 비트 지속 시간 (Stop Bit Duration) 최소 2 × tOWI_BIT (20µs)
tOWI_LOW 로우 펄스 지속 시간 (Low Pulse Duration) 최소 1µs
tOWI_FRAME 프레임 간 간격 (Inter-Frame Gap) 최소 4 × tOWI_BIT (40µs)

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

데이터시트 섹션 6.6.1 및 Table 34에 따르면, 명령 모드에서 지원하는 명령은 다음과 같습니다: (According to datasheet section 6.6.1 and Table 34, the commands supported in Command Mode are as follows:)

명령 (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로 구현한 것입니다. (The code below implements all ZSSC3241 Command Mode commands using STM32L432KC and OWI.) OWI는 하드웨어 모듈이 없으므로 비트 뱅잉(Bit-Banging) 기법을 사용하며, PB7을 SDA로, PB8을 RESO 핀으로 설정했습니다. (Since OWI lacks a dedicated hardware module, it uses bit-banging, with PB7 as SDA and PB8 as RESO pin.) 타이밍은 데이터시트 Table 22를 준수하며, 명령 처리는 Table 34를 기반으로 합니다. (Timing adheres to datasheet Table 22, and command processing is based on Table 34.)


// ZSSC3241 OWI 명령 모드 전부 구현 - STM32L432KC (Complete ZSSC3241 OWI Command Mode Implementation - STM32L432KC)
// 데이터시트 섹션 6.4.3, 6.6.1, Table 34 기반 (Based on Datasheet Sections 6.4.3, 6.6.1, Table 34)
// 상세 주석 포함 (Detailed Comments Included)

#include "stm32l4xx_hal.h"

// OWI 핀 설정 (SDA: PB7, RESO: PB8) - 데이터시트 핀 9, 7 (OWI Pin Settings (SDA: PB7, RESO: PB8) - Datasheet Pins 9, 7)
#define OWI_SDA_PIN GPIO_PIN_7
#define OWI_SDA_PORT GPIOB
#define RESO_PIN GPIO_PIN_8
#define RESO_PORT GPIOB

// OWI 타이밍 상수 (µs 단위) - 데이터시트 Table 22 (OWI Timing Constants (in µs) - Datasheet Table 22)
#define T_OWI_BIT 10    // 비트 전송 시간 (Bit Transmission Time)
#define T_OWI_START 20  // 시작 비트 지속 시간 (Start Bit Duration)
#define T_OWI_STOP 20   // 정지 비트 지속 시간 (Stop Bit Duration)
#define T_OWI_LOW 1     // 로우 펄스 지속 시간 (Low Pulse Duration)
#define T_OWI_FRAME 40  // 프레임 간 간격 (Inter-Frame Gap)

// 데이터 유형 정의 - 센서/온도 구분 (Data Type Definition - Sensor/Temperature Distinction)
typedef enum { SENSOR, TEMPERATURE } DataType;

// 오류 처리 함수 (Error Handling Function)
void Error_Handler(void) {
    while (1); // 무한 루프, 실제 프로젝트에서 디버깅 추가 (Infinite Loop, Add Debugging in Actual Projects)
}

// OWI 핀 초기화 (Initialize OWI Pin)
void OWI_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE(); // GPIO 클럭 활성화 (Enable GPIO Clock)
    
    // SDA 핀 설정 (SDA Pin Configuration)
    GPIO_InitStruct.Pin = OWI_SDA_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;
    HAL_GPIO_Init(OWI_SDA_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_SET); // 기본 상태: 하이 (Default State: High)
    
    // RESO 핀 설정 (RESO Pin Configuration)
    GPIO_InitStruct.Pin = RESO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(RESO_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(RESO_PORT, RESO_PIN, GPIO_PIN_SET); // 기본 상태: 하이 (Default State: High)
}

// OWI 타이밍 지연 (OWI Timing Delay)
void OWI_Delay(uint32_t us) {
    uint32_t ticks = (us * (SystemCoreClock / 1000000)) / 8; // 시스템 클럭 기반 지연 (System Clock-Based Delay)
    while (ticks--) {
        __NOP(); // 바쁜 대기 (Busy Wait)
    }
}

// OWI 시작 비트 전송 (Send OWI Start Bit)
void OWI_SendStart(void) {
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_RESET); // 로우로 설정 (Set Low)
    OWI_Delay(T_OWI_START); // 시작 비트 지속 시간 (Start Bit Duration)
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to High)
    OWI_Delay(T_OWI_BIT); // 비트 간 간격 (Inter-Bit Gap)
}

// OWI 정지 비트 전송 (Send OWI Stop Bit)
void OWI_SendStop(void) {
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_RESET); // 로우로 설정 (Set Low)
    OWI_Delay(T_OWI_STOP); // 정지 비트 지속 시간 (Stop Bit Duration)
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to High)
    OWI_Delay(T_OWI_FRAME); // 프레임 간 간격 (Inter-Frame Gap)
}

// OWI 비트 전송 (Send OWI Bit)
void OWI_SendBit(uint8_t bit) {
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_RESET); // 로우 펄스 시작 (Start Low Pulse)
    OWI_Delay(T_OWI_LOW); // 로우 펄스 지속 시간 (Low Pulse Duration)
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, bit ? GPIO_PIN_SET : GPIO_PIN_RESET); // 비트 값 설정 (Set Bit Value)
    OWI_Delay(T_OWI_BIT - T_OWI_LOW); // 비트 시간 완성 (Complete Bit Time)
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to High)
}

// OWI 바이트 전송 (패리티 포함) (Send OWI Byte with Parity)
void OWI_SendByte(uint8_t data) {
    OWI_SendStart(); // 시작 비트 (Start Bit)
    uint8_t parity = 0;
    for (uint8_t i = 0; i < 8; i++) {
        uint8_t bit = (data >> i) & 0x01;
        OWI_SendBit(bit); // 데이터 비트 전송 (Send Data Bit)
        parity ^= bit; // 패리티 계산 (Calculate Parity)
    }
    OWI_SendBit(parity); // 패리티 비트 전송 (Send Parity Bit)
    OWI_SendStop(); // 정지 비트 (Stop Bit)
}

// OWI 비트 수신 (Receive OWI Bit)
uint8_t OWI_ReceiveBit(void) {
    uint8_t bit = 0;
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_RESET); // 로우 펄스 시작 (Start Low Pulse)
    OWI_Delay(T_OWI_LOW); // 로우 펄스 지속 시간 (Low Pulse Duration)
    HAL_GPIO_WritePin(OWI_SDA_PORT, OWI_SDA_PIN, GPIO_PIN_SET); // 하이로 복귀 (Return to High)
    OWI_Delay(T_OWI_BIT / 2); // 비트 중간에서 샘플링 (Sample at Bit Midpoint)
    bit = HAL_GPIO_ReadPin(OWI_SDA_PORT, OWI_SDA_PIN); // 비트 읽기 (Read Bit)
    OWI_Delay(T_OWI_BIT / 2); // 비트 시간 완성 (Complete Bit Time)
    return bit;
}

// OWI 바이트 수신 (패리티 포함) (Receive OWI Byte with Parity)
uint8_t OWI_ReceiveByte(void) {
    uint8_t data = 0, parity = 0;
    while (HAL_GPIO_ReadPin(OWI_SDA_PORT, OWI_SDA_PIN) == GPIO_PIN_SET); // 시작 비트 대기 (Wait for Start Bit)
    OWI_Delay(T_OWI_START); // 시작 비트 스킵 (Skip Start Bit)
    for (uint8_t i = 0; i < 8; i++) {
        uint8_t bit = OWI_ReceiveBit();
        data |= (bit << i); // 데이터 비트 조합 (Combine Data Bits)
        parity ^= bit; // 패리티 계산 (Calculate Parity)
    }
    uint8_t received_parity = OWI_ReceiveBit();
    if (received_parity != parity) {
        Error_Handler(); // 패리티 오류 (Parity Error)
    }
    while (HAL_GPIO_ReadPin(OWI_SDA_PORT, OWI_SDA_PIN) == GPIO_PIN_RESET); // 정지 비트 대기 (Wait for Stop Bit)
    OWI_Delay(T_OWI_FRAME); // 프레임 간 간격 (Inter-Frame Gap)
    return data;
}

// 상태 바이트 읽기 (NOP 명령) - 데이터시트 Table 19, 섹션 6.4.1 (Read Status Byte (NOP Command) - Datasheet Table 19, Section 6.4.1)
uint8_t OWI_GetStatus(void) {
    OWI_SendByte(0xFF); // NOP 명령 (NOP Command)
    return OWI_ReceiveByte(); // 상태 바이트 수신 (Receive Status Byte)
}

// 장치가 바쁜지 확인 - 상태 바이트 비트 5 (Busy?) 확인 (Check if Device is Busy - Status Byte Bit 5 (Busy?))
bool OWI_IsDeviceBusy(void) {
    return (OWI_GetStatus() & 0x20) != 0; // Busy 비트(비트 5) 확인 (Check Busy Bit (Bit 5))
}

// 명령 모드로 전환 - START_CM (0xA9), 데이터시트 섹션 6.6.1 (Switch to Command Mode - START_CM (0xA9), Datasheet Section 6.6.1)
void OWI_EnterCommandMode(void) {
    OWI_SendByte(0xA9); // START_CM 명령 (START_CM Command)
    OWI_Delay(10000); // 모드 전환 후 안정화 대기 (10ms) (Stabilization Delay After Mode Switch (10ms))
}

// 사이클릭 모드로 전환 - START_CYC (0xAB), 데이터시트 섹션 6.6.1 (Switch to Cyclic Mode - START_CYC (0xAB), Datasheet Section 6.6.1)
void OWI_EnterCyclicMode(void) {
    OWI_SendByte(0xAB); // START_CYC 명령 (START_CYC Command)
    OWI_Delay(10000); // 모드 전환 후 안정화 대기 (10ms) (Stabilization Delay After Mode Switch (10ms))
}

// 슬립 모드로 전환 - START_SLEEP (0xA8), 데이터시트 섹션 6.6.1 (Switch to Sleep Mode - START_SLEEP (0xA8), Datasheet Section 6.6.1)
void OWI_EnterSleepMode(void) {
    OWI_SendByte(0xA8); // START_SLEEP 명령 (START_SLEEP Command)
    OWI_Delay(10000); // 모드 전환 후 안정화 대기 (10ms) (Stabilization Delay After Mode Switch (10ms))
}

// SSC 보정 데이터 읽기 - MEASURE (0xAA), 데이터시트 섹션 6.5.1 (Read SSC Corrected Data - MEASURE (0xAA), Datasheet Section 6.5.1)
HAL_StatusTypeDef OWI_ReadSSCData(int32_t *sensor_data, int32_t *temp_data) {
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(0xAA); // MEASURE 명령 (MEASURE Command)
    
    while (OWI_IsDeviceBusy()) {
        OWI_Delay(10000); // 변환 완료 대기 (10ms) (Wait for Conversion Completion (10ms))
    }
    
    uint8_t data[6];
    for (uint8_t i = 0; i < 6; i++) {
        data[i] = OWI_ReceiveByte(); // 6바이트 데이터 수신 (Receive 6 Bytes of Data)
    }
    
    *sensor_data = (data[0] << 16) | (data[1] << 8) | data[2]; // 센서 데이터 조합 (Combine Sensor Data)
    if (*sensor_data & 0x800000) *sensor_data |= 0xFF000000; // 부호 확장 (Sign Extension)
    
    *temp_data = (data[3] << 16) | (data[4] << 8) | data[5]; // 온도 데이터 조합 (Combine Temperature Data)
    if (*temp_data & 0x800000) *temp_data |= 0xFF000000; // 부호 확장 (Sign Extension)
    
    return HAL_OK;
}

// 원시 데이터 읽기 - READ_RAW_SENSOR (0xA2) / READ_RAW_TEMP (0xA4), 데이터시트 섹션 6.5.1 (Read Raw Data - READ_RAW_SENSOR (0xA2) / READ_RAW_TEMP (0xA4), Datasheet Section 6.5.1)
int32_t OWI_ReadRawData(DataType type) {
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(type == SENSOR ? 0xA2 : 0xA4); // 명령 전송 (Send Command)
    
    while (OWI_IsDeviceBusy()) {
        OWI_Delay(10000); // 변환 완료 대기 (10ms) (Wait for Conversion Completion (10ms))
    }
    
    uint8_t data[3];
    for (uint8_t i = 0; i < 3; i++) {
        data[i] = OWI_ReceiveByte(); // 24비트 데이터 수신 (Receive 24-bit Data)
    }
    
    int32_t raw_value = (data[0] << 16) | (data[1] << 8) | data[2]; // 데이터 조합 (Combine Data)
    if (raw_value & 0x800000) {
        raw_value |= 0xFF000000; // 부호 확장 (Sign Extension)
    }
    return raw_value;
}

// 진단 갱신 - UPDATE_DIAG (0xB2), 데이터시트 섹션 6.3 (Update Diagnostics - UPDATE_DIAG (0xB2), Datasheet Section 6.3)
HAL_StatusTypeDef OWI_UpdateDiagnostics(void) {
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(0xB2); // UPDATE_DIAG 명령 (UPDATE_DIAG Command)
    
    while (OWI_IsDeviceBusy()) {
        OWI_Delay(10000); // 진단 완료 대기 (10ms) (Wait for Diagnostics Completion (10ms))
    }
    return HAL_OK;
}

// 진단 결과 읽기 - CHECK_DIAG (0xB0), 데이터시트 섹션 6.3 (Read Diagnostic Results - CHECK_DIAG (0xB0), Datasheet Section 6.3)
HAL_StatusTypeDef OWI_CheckDiagnostics(uint16_t *diag_data) {
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(0xB0); // CHECK_DIAG 명령 (CHECK_DIAG Command)
    
    uint8_t data[2];
    for (uint8_t i = 0; i < 2; i++) {
        data[i] = OWI_ReceiveByte(); // 16비트 진단 데이터 수신 (Receive 16-bit Diagnostic Data)
    }
    
    *diag_data = (data[0] << 8) | data[1]; // 데이터 조합 (Combine Data)
    return HAL_OK;
}

// 진단 리셋 - RESET_DIAG (0xB1), 데이터시트 섹션 6.3 (Reset Diagnostics - RESET_DIAG (0xB1), Datasheet Section 6.3)
HAL_StatusTypeDef OWI_ResetDiagnostics(void) {
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(0xB1); // RESET_DIAG 명령 (RESET_DIAG Command)
    return HAL_OK;
}

// NVM 체크섬 계산 - CALCULATE_NVM_CHECKSUM (0x90), 데이터시트 섹션 6.6.2 (Calculate NVM Checksum - CALCULATE_NVM_CHECKSUM (0x90), Datasheet Section 6.6.2)
HAL_StatusTypeDef OWI_CalculateNVMChecksum(void) {
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(0x90); // CHECKSUM 명령 (CHECKSUM Command)
    
    while (OWI_IsDeviceBusy()) {
        OWI_Delay(10000); // 체크섬 계산 완료 대기 (10ms) (Wait for Checksum Calculation Completion (10ms))
    }
    return HAL_OK;
}

// NVM 잠금 상태 확인 - SSF1 (0x03) 레지스터 읽기 (Check NVM Lock Status - Read SSF1 (0x03) Register)
bool OWI_IsNVMLocked(void) {
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(0x03); // SSF1 레지스터 읽기 명령 (Read SSF1 Register Command)
    
    uint8_t data[2];
    for (uint8_t i = 0; i < 2; i++) {
        data[i] = OWI_ReceiveByte(); // 16비트 데이터 수신 (Receive 16-bit Data)
    }
    
    return (data[0] & 0x40) != 0; // 비트 14 (lock) 확인 (Check Bit 14 (lock))
}

// RESO 핀으로 NVM 잠금 해제 및 리셋 - 데이터시트 핀 7 (Unlock NVM and Reset with RESO Pin - Datasheet Pin 7)
void OWI_UnlockNVM(void) {
    HAL_GPIO_WritePin(RESO_PORT, RESO_PIN, GPIO_PIN_RESET); // 로우로 설정하여 리셋 (Set Low for Reset)
    OWI_Delay(10000); // 리셋 유지 시간 (10ms) (Reset Hold Time (10ms))
    HAL_GPIO_WritePin(RESO_PORT, RESO_PIN, GPIO_PIN_SET); // 리셋 해제 (Release Reset)
    OWI_Delay(10000); // 안정화 대기 시간 (10ms) (Stabilization Delay (10ms))
}

// NVM 데이터 읽기 - READ_NVM (0x00~0x3F), 데이터시트 Table 34 (Read NVM Data - READ_NVM (0x00~0x3F), Datasheet Table 34)
HAL_StatusTypeDef OWI_ReadNVMData(uint8_t address, uint8_t *data, uint8_t size) {
    if (address > 0x3F) {
        return HAL_ERROR; // 주소 범위 초과 (Address Out of Range)
    }
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(address); // 주소 전송 (Send Address)
    
    for (uint8_t i = 0; i < size; i++) {
        data[i] = OWI_ReceiveByte(); // 데이터 수신 (Receive Data)
    }
    return HAL_OK;
}

// NVM 데이터 쓰기 - WRITE_NVM (0x40~0x75), 데이터시트 Table 34 (Write NVM Data - WRITE_NVM (0x40~0x75), Datasheet Table 34)
HAL_StatusTypeDef OWI_WriteNVMData(uint8_t address, uint8_t *data, uint8_t size) {
    if (address > 0x35) {
        return HAL_ERROR; // 주소 범위 초과 (Address Out of Range)
    }
    if (OWI_IsNVMLocked()) {
        OWI_UnlockNVM(); // NVM 잠금 해제 (Unlock NVM)
        if (OWI_IsNVMLocked()) {
            return HAL_ERROR; // 여전히 잠겨 있으면 실패 (Fail if Still Locked)
        }
    }
    OWI_EnterCommandMode(); // 명령 모드 진입 (Enter Command Mode)
    OWI_SendByte(address + 0x40); // 쓰기 주소 = NVM 주소 + 0x40 (Write Address = NVM Address + 0x40)
    
    for (uint8_t i = 0; i < size; i++) {
        OWI_SendByte(data[i]); // 데이터 전송 (Send Data)
    }
    
    return OWI_CalculateNVMChecksum(); // 체크섬 갱신 (Update Checksum)
}

// 메인 함수 예시 - 모든 명령 테스트 (Main Function Example - Test All Commands)
int main(void) {
    HAL_Init();
    OWI_Init();
    
    // 명령 모드 진입 (Enter Command Mode)
    OWI_EnterCommandMode();
    
    // 원시 데이터 읽기 (Read Raw Data)
    int32_t sensor_data = OWI_ReadRawData(SENSOR);
    int32_t temp_data = OWI_ReadRawData(TEMPERATURE);
    
    // SSC 보정 데이터 읽기 (Read SSC Corrected Data)
    int32_t ssc_sensor, ssc_temp;
    OWI_ReadSSCData(&ssc_sensor, &ssc_temp);
    
    // 진단 갱신 및 결과 읽기 (Update and Read Diagnostics)
    OWI_UpdateDiagnostics();
    uint16_t diag_data;
    OWI_CheckDiagnostics(&diag_data);
    
    // 진단 리셋 (Reset Diagnostics)
    OWI_ResetDiagnostics();
    
    // NVM 읽기/쓰기 예시 (NVM Read/Write Example)
    uint8_t nvm_data[2] = {0x12, 0x34}; // 예시 데이터 (Example Data)
    OWI_WriteNVMData(0x03, nvm_data, 2); // SSF1 레지스터 쓰기 (Write SSF1 Register)
    OWI_ReadNVMData(0x03, nvm_data, 2); // SSF1 레지스터 읽기 (Read SSF1 Register)
    
    // NVM 체크섬 계산 (Calculate NVM Checksum)
    OWI_CalculateNVMChecksum();
    
    // 사이클릭 모드 전환 (Switch to Cyclic Mode)
    OWI_EnterCyclicMode();
    
    // 슬립 모드 전환 (Switch to Sleep Mode)
    OWI_EnterSleepMode();
    
    while (1) {
        // 메인 루프 - 실제 응용에서 데이터 처리 추가 (Main Loop - Add Data Processing in Actual Applications)
    }
}

코드 설명 및 데이터시트 연계 (Code Explanation and Datasheet Linkage)

위 코드는 ZSSC3241의 모든 명령 모드 명령을 OWI로 구현하며, 각 함수는 데이터시트와 다음과 같이 연계됩니다: (The above code implements all ZSSC3241 Command Mode commands via OWI, with each function linked to the datasheet as follows:)

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

참고: OWI는 저속이므로 실시간 데이터 전송보다는 캘리브레이션 및 설정에 적합합니다. (Note: OWI is low-speed and better suited for calibration and configuration than real-time data transfer.) 실제 프로젝트에서는 타이머 인터럽트를 사용하여 타이밍 정확도를 높이는 것이 좋습니다. (In real projects, use timer interrupts to improve timing accuracy.)

결론 (Conclusion)

이 가이드는 ZSSC3241의 OWI 통신 절차를 상세히 설명하고, 모든 명령 모드 명령을 STM32L432KC로 구현한 코드를 제공합니다. (This guide details the ZSSC3241 OWI communication procedure and provides code implementing all Command Mode commands with STM32L432KC.) 데이터시트 기반으로 빠진 부분 없이 완전한 구현을 보장하며, 실제 프로젝트에서 센서 연결 및 캘리브레이션 데이터를 추가하여 활용해 보세요. (Based on the datasheet, it ensures complete implementation with no missing parts; add sensor connections and calibration data for use in real projects.) 

참고: ZSSC3241 데이터시트 (Renesas), STM32L432KC 문서 (STMicroelectronics) (References: ZSSC3241 Datasheet (Renesas), STM32L432KC Documentation (STMicroelectronics))

반응형