이 문서는 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 통신 절차 (OWI Communication Procedure)
데이터시트 섹션 6.4.3, Figure 14~18, Table 23,24를 기반으로 OWI 통신 절차를 단계별로 정리했습니다:
- 초기화 (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는 저속이므로 실시간 데이터 전송보다는 캘리브레이션 및 설정에 적합합니다. **실제 프로젝트에서는 타이머 인터럽트를 사용하여 타이밍 정확도를 높이는 것이 좋습니다.