이 글에서는 Renesas(구 IDT)의 ZSC31015 RBicdLite™ Analog Output Sensor Signal Conditioner를 STM32L432KC 마이크로컨트롤러와 함께 사용하는 드라이버 구현을 다룹니다. ZSC31015는 압저항성 브리지 센서(압력, 힘 등)의 신호를 보정하여 디지털(ZACwire) 또는 아날로그 출력(레일-투-레일 0.5~4.5V 또는 절대 전압)을 제공하는 고정밀 IC입니다. 이 글은 두 부분으로 나뉩니다:
- ZSC31015 사양 상세 분석: 데이터시트(Rev 1.40, 2016년 11월 14일, 53페이지)를 기반으로 IC의 기능, 전기적 특성, 회로 구성, 동작 모드, 아날로그 출력 설정 등을 체계적으로 정리합니다.
- ZACwire 통신 및 아날로그 출력 코드 구현: STM32 HAL 라이브러리를 사용한 ZACwire 프로토콜 구현, 보정 계수 프로그래밍, 최종 EEPROM 설정, 아날로그 출력(VOUT)을 읽는 ADC 코드를 포함한 완전한 드라이버를 제공합니다.
코드 구현은 STM32CubeIDE에서 테스트되었으며, ZACwire의 맨체스터 인코딩과 타이밍 요구사항(50μs ±10%)을 준수합니다. 아날로그 출력은 ADC1(채널 6, PA1)을 사용해 VOUT(0.5~4.5V)을 측정하며, 2:1 분압기로 03.3V로 조정합니다. UART2(PA2, 115200bps)를 통해 디버깅 정보를 출력하고 오류 처리와 검증 로직도 포함됩니다. 데이터시트를 처음부터 끝까지 분석하여 핵심 내용을 반영하였으며, 실제 구현 시 데이터시트 전체를 참조하기 바랍니다.
1. ZSC31015 사양 분석
ZSC31015는 저비용, 고정밀 센서 신호 컨디셔너로, 브리지 센서의 오프셋, 감도, 온도 드리프트, 비선형성을 디지털로 보정합니다. 주요 특징은 ZACwire(단일 와이어 시리얼 인터페이스)를 통한 캘리브레이션, 진단 기능(EEPROM 무결성, 센서 연결/단락 검사), 아날로그 출력(12비트 DAC)입니다. 아래에서 데이터시트의 주요 섹션을 기반으로 사양을 상세히 분석한 내용입니다.
1.1. 개요 및 기능 (데이터시트 섹션 1, 페이지 1-2)
- 제품명: ZSC31015 RBicdLite™ Analog Output Sensor Signal Conditioner with Diagnostic Features.
- 주요 기능:
- 센서 보정: 브리지 센서의 오프셋, 감도, 온도 드리프트, 2차 비선형성 보정 (수식 1~5, 섹션 3.6).
- 출력 옵션:
-
- 아날로그: 레일-투-레일 비례 출력(0.5~
4.5V, Output_Mode=0/1) 또는 절대 전압 출력(0VDD, Output_Mode=3), 12비트 DAC (섹션 3.5, 테이블 2.3). - 디지털: ZACwire를 통한 16비트 브리지 및 8비트 온도 데이터 (Output_Mode=2).
- 아날로그: 레일-투-레일 비례 출력(0.5~
- 진단 기능 (테이블 2.3): EEPROM CRC, 브리지 연결/단락 검사 (INP/INN 핀), 전력 손실 감지 (VBR 핀).
- 온도 보정: 내부 PTAT 또는 외부 다이오드(ExtTemp 핀).
- 전력 소비: 업데이트 속도에 따라 0.25~1.4mA (Bsink로 절감, 섹션 2.3.4).
- 정확도: -25~
85°C에서 ±0.1% FSO, -50~150°C에서 ±0.25% FSO.
- 애플리케이션: 산업(압력/레벨), 빌딩 자동화(HVAC), 자동차(비 AEC-Q100), 백색 가전.
- 패키지: SOP8 (150mil), 동작 온도 -50~150°C.
- 블록 다이어그램 (그림 1.1): 아날로그 프론트엔드(PREAMP, 14비트 ADC, PTAT), 디지털 코어(DSP, 106비트 EEPROM), 출력(DAC, ZACwire).
1.2. 전기적 특성 (섹션 2, 페이지 7-12)
- 절대 최대 정격 (테이블 2.1):
- VDD: -0.3~6V.
- 저장 온도: -50~150°C (170°C, 10시간 이내).
- 권장 동작 조건 (테이블 2.2):
- VDD: 2.7~
5.5V (JFET로 5.5~30V 확장). - 주변 온도: -50~150°C.
- 브리지 저항: 0.3~100kΩ (VBR 핀).
- VDD: 2.7~
- 전기 파라미터 (테이블 2.3~2.7):
- 공급 전류: 0.25mA(저속) ~ 1.4mA(고속).
- ADC: 14비트, INL ±4 LSB, DNL ±1 LSB, 변환 시간 1ms.
- DAC: 12비트, 절대 오류 ±0.2% VDD, 부하 5kΩ/15nF, VOUT 클리핑(0.5~4.5V).
- ZACwire: 라인 저항 3.9kΩ, 커패시턴스 15nF, 로직 레벨 0.2/0.8 VDD.
- 응답 시간: 1~2ms (1kHz 샘플링).
- 정확도: 디지털 ±0.1% FSO (-25~85°C), 아날로그 ±0.25% FSO.
- 입력 vs 출력 해상도 (테이블 1.1~1.4):
- PREAMP 게인 6: 입력 스팬 57.8~105.8mV/V, 해상도 12.4비트.
- PREAMP 게인 96: 입력 스팬 4.3~7.9mV/V, 해상도 12.7비트.
- 높은 게인에서 오프셋 범위 감소 (ADC 포화 방지).
1.3. 회로 설명 (섹션 2, 페이지 13-22)
- 신호 흐름 (그림 2.1):
- 아날로그 프론트엔드: PREAMP(게인 6/24/48/96), 14비트 ADC, PTAT 또는 ExtTemp.
- 디지털 코어: DSP(보정 공식 적용), 106비트 EEPROM.
- 출력 스테이지: 12비트 DAC(VOUT), ZACwire(디지털).
- PREAMP: 브리지 입력(INP/INN) 증폭, 극성 반전 가능, 게인 선택 (EEPROM [97:96]).
- ADC: 1ms 변환, 14비트 해상도, 브리지/온도 데이터 디지털화.
- EEPROM: 106비트, 쓰기 시간 6ms, 100k 사이클 내구성 (85°C 이하).
- 진단: EEPROM CRC, 브리지 단락/연결 검사, 전력 손실 감지.
- 출력: DAC 클리핑 한계(Upper/Lower Clip, [15:8], [23:16]), 버퍼 오프셋 <1mV.
1.4. 기능 설명 (섹션 3, 페이지 23-41)
- 동작 모드 (섹션 3.2.5):
- Normal Operation Mode (NOM): 보정된 데이터 출력 (1kHz 기본).
- Command Mode (CM): EEPROM 프로그래밍 및 설정.
- Raw Mode (RM): 비보정 데이터 수집 (16비트 브리지, 8비트 온도).
- ZACwire 인터페이스 (섹션 3.2):
- 인코딩: 맨체스터 (0=로우-하이, 1=하이-로우, 그림 3.2).
- 타이밍: 비트 기간 50μs ±10% (20kHz), 스타트/스톱 비트 100μs.
- 쓰기 프레임: 19비트 (스타트 + 8비트 명령 + 8비트 데이터 + 패리티 + 스톱, 그림 3.3).
- 읽기: ACK(로우 펄스) 후 데이터 패킷 (그림 3.5~3.8).
- EEPROM 비트 (테이블 3.5):
- 보정 계수: Gain_B [13:0], Offset_B [13:0], Gain_T [7:0], Offset_T [7:0], Tco [7:0], Tcg [7:0], SOT [7:0], T_SETL [7:0].
- 설정 비트: Output_Mode [93:92], Update_Rate [95:94], Pamp_Gain [97:96], ExtTemp [105], EEPROM_Lock [104].
- 명령어 인코딩 (테이블 3.4):
- CM 진입: 0x50 | 0x90.
- NOM 시작: 0x40 | 0x00.
- 계수 프로그래밍: 0x60~0xF0 (예: Gain_B 상위 0x80, 하위 0x90).
- 캘리브레이션 시퀀스 (섹션 3.4):
- RM으로 Raw 데이터 수집.
- 외부에서 보정 계수 계산 (섹션 3.6).
- CM에서 EEPROM에 계수/설정 기록.
- NOM으로 전환, 아날로그 출력 활성화.
- 보정 수학 (섹션 3.6): 2차 보정 공식, 예: Gain_B = (Vout_max - Vout_min) / (Bridge_max - Bridge_min).
1.5. 아날로그 출력 관련 사양 (섹션 3.5, 테이블 2.3, 그림 4.1~4.3)
- 출력 모드 (EEPROM [93:92], CMD_TRIM_CONFIG, W=0x3):
- 0: 비례 출력 (0.5~4.5V, VDD 비례).
- 1: 비례 역출력 (4.5~0.5V, VDD 비례).
- 3: 절대 전압 출력 (0~VDD, VDD 독립).
- DAC 사양:
- 해상도: 12비트 (4096 레벨).
- 출력 범위: 0.5
4.5V (ratiometric), 0VDD (absolute). - 부하: 5kΩ 저항, 15nF 커패시턴스.
- 절대 오류: ±0.2% VDD.
- 클리핑 한계:
- Upper Clip ([15:8], CMD_PROG_UP_CLIP, MSB=0).
- Lower Clip ([23:16], CMD_PROG_LO_CLIP, MSB=0).
- 회로 구성 (그림 4.1~4.3):
- VOUT 핀(핀 7)을 STM32 ADC 입력(PA1)에 연결, 2:1 분압기 사용.
- JFET(선택 사항)로 5.5~30V 확장 가능.
- 응답 시간: 1~2ms (1kHz 샘플링, Update_Rate [95:94] 설정).
1.6. 애플리케이션 및 기타 (섹션 46, 페이지 42~53)
- 회로 예시 (그림 4.1~4.3): 레일-투-레일 출력, 절대 출력, 과전압 보호(JFET).
- EEPROM 복원 (섹션 5): 기본값 복원 절차 (그림 5.1).
- 핀 구성 (섹션 6): SOP8, 핀 1(Bsink) ~ 8(Vgate), VOUT=핀 7.
- ESD/신뢰성: ESD 보호, AEC-Q100 미인증.
1.7. 사양 분석 요약
- 강점: 저전력(0.25~1.4mA), 고정밀(±0.1% FSO), ZACwire로 간단한 캘리브레이션, 아날로그 출력, 다기능 진단.
- 제한사항: EEPROM 쓰기 85°C 이하, 브리지 저항 0.3~100kΩ, AEC-Q100 미인증.
- 드라이버 구현 고려사항:
- ZACwire 타이밍: 50μs 비트 기간, 맨체스터 인코딩.
- GPIO: PA0(ZACwire), PA1(ADC), PA2(UART TX).
- TIM2: μs 단위 딜레이 (1MHz 클럭).
- ADC: 12비트, 0~
3.3V 범위, VOUT(0.5~4.5V)을 2:1 분압기로 조정. - UART: 디버깅 출력 (115200bps).
- 오류 처리: 타임아웃, 패리티, ACK, ADC 변환 오류.
2. ZACwire 통신 및 아날로그 출력 코드 구현
ZACwire는 단일 와이어 시리얼 프로토콜로, 맨체스터 인코딩을 사용합니다. STM32L432KC의 GPIO(PA0)와 TIM2(1MHz 클럭)를 활용해 ZACwire를 구현하며, HAL 라이브러리로 GPIO, 타이머, ADC, UART를 제어합니다. 드라이버는 초기화, 쓰기/읽기, 모드 전환, Trim/Configure, 보정 계수 프로그래밍, 최종 EEPROM 설정, 아날로그 출력(VOUT) 읽기 함수로 구성됩니다. 아날로그 출력은 ADC1(채널 6, PA1)을 사용해 VOUT(0.5~4.5V)을 측정하며, 2:1 분압기로 0~3.3V로 조정합니다. UART2(PA2, 115200bps)로 디버깅 정보를 출력합니다. 각 함수는 데이터시트(섹션 3.2, 3.4, 3.5, 테이블 3.4)를 기반으로 작성되었습니다.
2.1. 드라이버 코드 구조
- zacwire.h: 상수, 명령어, 함수 선언 (ZACwire, ADC, UART).
- zacwire.c: 초기화, ZACwire 쓰기/읽기, 모드 전환, 설정/프로그래밍, ADC 읽기 함수.
- main.c: 시스템 초기화, Raw 데이터 수집, 보정 계수 프로그래밍, 최종 설정, EEPROM 검증, 아날로그 출력 읽기, UART 출력.
- 주요 기능:
- 초기화: GPIO(PA0=ZACwire, PA1=ADC, PA2=UART TX), TIM2, ADC1, UART2 설정.
- 쓰기: 19비트 프레임 (스타트 + 명령 + 데이터 + 패리티 + 스톱).
- 읽기: ACK 후 데이터 패킷 수신 (EEPROM 또는 Raw 데이터).
- 모드 전환: CM, NOM, RM 전환.
- 설정: Output_Mode(0/1/3), Update_Rate, Pamp_Gain, ExtTemp, EEPROM_Lock.
- 프로그래밍: Gain_B, Offset_B, Gain_T, Upper/Lower Clip 등.
- 아날로그 출력: ADC로 VOUT(0.5~4.5V) 측정, 2:1 분압기 사용.
- 최종 설정: NOM에서 아날로그 출력 활성화.
- 디버깅: UART로 Raw 데이터, EEPROM, VOUT 전압 출력.
2.2. 코드
이 코드는 zacwire.h, zacwire.c, main.c로 나누어져 있으며, STM32CubeIDE에서 실행 가능하도록 작성되었습니다. 각 함수는 데이터시트의 타이밍과 설정을 준수하며, 오류 처리를 포함합니다.
zacwire.h
// zacwire.h
#ifndef ZACWIRE_H
#define ZACWIRE_H
#include "stm32l4xx_hal.h"
// ZACwire 핀 설정: PA0을 ZACwire 통신에 사용 (ZACwire pin configuration: PA0 for communication)
#define ZACWIRE_GPIO_PORT GPIOA
#define ZACWIRE_GPIO_PIN GPIO_PIN_0
// ADC 핀 설정: PA1, ADC1 채널 6, VOUT 읽기 (ADC pin configuration: PA1, ADC1 channel 6 for VOUT)
#define ADC_GPIO_PORT GPIOA
#define ADC_GPIO_PIN GPIO_PIN_1
#define ADC_CHANNEL ADC_CHANNEL_6
// UART 핀 설정: PA2, UART2 TX, 디버깅 출력 (UART pin configuration: PA2, UART2 TX for debugging)
#define UART_GPIO_PORT GPIOA
#define UART_GPIO_PIN GPIO_PIN_2
// 타이밍 상수: μs 단위, 데이터시트 섹션 3.2.1 (Timing constants: μs, datasheet section 3.2.1)
#define BIT_PERIOD_US 50 // 비트 기간: 50μs ±10% (20kHz) (Bit period: 50μs ±10%)
#define HALF_BIT_US 25 // 반 비트 기간: 맨체스터 인코딩 (Half bit period: Manchester encoding)
#define START_BIT_US 100 // 스타트 비트: 로우 100μs (Start bit: Low for 100μs)
#define STOP_BIT_US 100 // 스톱 비트: 하이 100μs (Stop bit: High for 100μs)
#define TIMEOUT_US 5000 // 타임아웃 시간: 읽기 대기 등 (Timeout: For read operations)
// 커맨드 정의: 데이터시트 테이블 3.4 기반, 8비트 커맨드 + 데이터로 19비트 프레임 (Command definitions: Based on datasheet table 3.4, 8-bit command + data for 19-bit frame)
#define CMD_READ_EEPROM 0x00 // EEPROM 전체 읽기, 더미 데이터 (Read entire EEPROM, dummy data)
#define CMD_DAC_RAMP_TEST 0x20 // DAC 램프 테스트 모드, 데이터 5X HEX (DAC ramp test mode, data 5X HEX)
#define CMD_TRIM_CONFIG 0x30 // Trim/Configure, 데이터 WD HEX (Trim/Configure, data WD HEX)
#define CMD_START_NOM 0x40 // NOM 시작, 데이터 0x00 (Start NOM, data 0x00)
#define CMD_START_RM 0x40 // RM 시작, 데이터 0x10 (Start RM, data 0x10)
#define CMD_START_CM 0x50 // CM 시작, 데이터 0x90 (Start CM, data 0x90)
#define CMD_PROG_SOT 0x60 // SOT 프로그래밍, 데이터 YY HEX (Program SOT, data YY HEX)
#define CMD_PROG_T_SETL 0x70 // T_SETL 프로그래밍, MSB=0 (Program T_SETL, MSB=0)
#define CMD_PROG_GAIN_B_UP 0x80 // Gain_B 상위 7비트, MSB=0 (Program Gain_B upper 7 bits, MSB=0)
#define CMD_PROG_GAIN_B_LO 0x90 // Gain_B 하위 8비트 (Program Gain_B lower 8 bits)
#define CMD_PROG_OFFSET_B_UP 0xA0 // Offset_B 상위 6비트, 두 MSB=0 (Program Offset_B upper 6 bits, two MSBs=0)
#define CMD_PROG_OFFSET_B_LO 0xB0 // Offset_B 하위 8비트 (Program Offset_B lower 8 bits)
#define CMD_PROG_GAIN_T 0xC0 // Gain_T 프로그래밍 (Program Gain_T)
#define CMD_PROG_OFFSET_T 0xD0 // Offset_T 프로그래밍 (Program Offset_T)
#define CMD_PROG_TCO 0xE0 // Tco 프로그래밍 (Program Tco)
#define CMD_PROG_TCG 0xF0 // Tcg 프로그래밍 (Program Tcg)
#define CMD_PROG_UP_CLIP 0x08 // 상한 클리핑, MSB=0 (Program Upper Clipping, MSB=0)
#define CMD_PROG_LO_CLIP 0x18 // 하한 클리핑, MSB=0 (Program Lower Clipping, MSB=0)
#define CMD_PROG_CUST_ID0 0x28 // Cust_ID0 프로그래밍 (Program Cust_ID0)
#define CMD_PROG_CUST_ID1 0x38 // Cust_ID1 프로그래밍 (Program Cust_ID1)
#define CMD_PROG_CUST_ID2 0x48 // Cust_ID2 프로그래밍 (Program Cust_ID2)
// Trim/Configure 서브 옵션: CMD_TRIM_CONFIG 데이터의 상위 nibble W (Trim/Configure sub-options: Upper nibble W of data)
#define TRIM_OSC 0x0 // 오실레이터 트림, D=0~7 (Oscillator trim, D=0~7)
#define TRIM_1V_REF 0x1 // 1V 참조 트림, D=0~F (1V reference trim, D=0~F)
#define TRIM_OFFSET_MODE 0x2 // 오프셋 모드, D=0~F (Offset mode, D=0~F)
#define TRIM_OUTPUT_MODE 0x3 // 출력 모드, D=0~3 (Output mode, D=0~3)
#define TRIM_UPDATE_RATE 0x4 // 업데이트 속도, D=0~3 (Update rate, D=0~3)
#define TRIM_JFET_REG 0x5 // JFET 규제 구성, D=0~F (JFET regulation, D=0~F)
#define TRIM_TC_CFG 0x6 // Tc_cfg [99:96], D=0~7 (Tc_cfg [99:96], D=0~7)
#define TRIM_EEPROM_BITS 0x7 // EEPROM 비트 [99:96], SOT_cfg, Pamp_Gain (EEPROM bits [99:96], SOT_cfg, Pamp_Gain)
#define TRIM_EEPROM_LOCK 0xD // EEPROM 락/온도 소스 [105:103], D=0/1/2/4/5/6/7 (EEPROM lock/temperature source [105:103])
#define TRIM_DIAG_CFG 0xE // 진단 구성 [102:100], D=0~7 (Diagnostic configuration [102:100])
// 함수 선언 (Function declarations)
// 초기화 및 기본 쓰기/읽기 함수 (Initialization and basic read/write functions)
void ZACwire_Init(void); // ZACwire 인터페이스 초기화 (Initialize ZACwire interface)
HAL_StatusTypeDef ZACwire_Write(uint8_t command, uint8_t data); // 19비트 프레임 쓰기 (Write 19-bit frame)
// 모드 전환 함수: 섹션 3.2.5 (Mode switching functions: Section 3.2.5)
HAL_StatusTypeDef ZACwire_Start_CM(void); // Command Mode 시작 (Start Command Mode)
HAL_StatusTypeDef ZACwire_Start_NOM(void); // Normal Operation Mode 시작 (Start Normal Operation Mode)
HAL_StatusTypeDef ZACwire_Start_RM(void); // Raw Mode 시작 (Start Raw Mode)
// 읽기 함수: 섹션 3.2.4 (Read functions: Section 3.2.4)
HAL_StatusTypeDef ZACwire_Read_Raw(uint16_t* bridge_raw, uint8_t* temp_raw); // Raw 데이터 읽기: 브리지(16비트)/온도(8비트) (Read raw data: 16-bit bridge, 8-bit temperature)
HAL_StatusTypeDef ZACwire_Read_EEPROM(uint8_t* eeprom_data, uint8_t length); // EEPROM 읽기 (Read EEPROM)
// DAC 램프 테스트 (DAC ramp test)
HAL_StatusTypeDef ZACwire_DAC_Ramp_Test(uint8_t x); // DAC 램프 테스트 (DAC ramp test)
// Trim/Configure 함수: CMD_TRIM_CONFIG, 섹션 3.4 (Trim/Configure functions: CMD_TRIM_CONFIG, section 3.4)
HAL_StatusTypeDef ZACwire_Trim_Oscillator(uint8_t trim_val); // 오실레이터 트림 (Oscillator trim)
HAL_StatusTypeDef ZACwire_Trim_1V_Reference(uint8_t trim_val); // 1V 참조 트림 (1V reference trim)
HAL_StatusTypeDef ZACwire_Trim_Offset_Mode(uint8_t mode_val); // 오프셋 모드 (Offset mode)
HAL_StatusTypeDef ZACwire_Trim_Output_Mode(uint8_t mode_val); // 출력 모드 (Output mode)
HAL_StatusTypeDef ZACwire_Trim_Update_Rate(uint8_t rate_val); // 업데이트 속도 (Update rate)
HAL_StatusTypeDef ZACwire_Trim_JFET_Reg(uint8_t reg_val); // JFET 규제 (JFET regulation)
HAL_StatusTypeDef ZACwire_Trim_TC_Cfg(uint8_t cfg_val); // Tc_cfg (Tc configuration)
HAL_StatusTypeDef ZACwire_Trim_EEPROM_Bits(uint8_t bits_val); // EEPROM 비트 [99:96] (EEPROM bits [99:96])
HAL_StatusTypeDef ZACwire_Trim_EEPROM_Lock(uint8_t lock_val); // EEPROM 락/온도 소스 (EEPROM lock/temperature source)
HAL_StatusTypeDef ZACwire_Trim_Diag_Cfg(uint8_t diag_val); // 진단 구성 (Diagnostic configuration)
// 프로그래밍 함수: 보정 계수 및 클리핑/ID, 섹션 3.5 (Programming functions: Calibration coefficients and clipping/ID, section 3.5)
HAL_StatusTypeDef ZACwire_Prog_SOT(uint8_t sot_val); // SOT 프로그래밍 (Program SOT)
HAL_StatusTypeDef ZACwire_Prog_T_SETL(uint8_t t_setl_val); // T_SETL 프로그래밍 (Program T_SETL)
HAL_StatusTypeDef ZACwire_Prog_Gain_B_Upper(uint8_t upper_val); // Gain_B 상위 7비트 (Program Gain_B upper 7 bits)
HAL_StatusTypeDef ZACwire_Prog_Gain_B_Lower(uint8_t lower_val); // Gain_B 하위 8비트 (Program Gain_B lower 8 bits)
HAL_StatusTypeDef ZACwire_Prog_Offset_B_Upper(uint8_t upper_val); // Offset_B 상위 6비트 (Program Offset_B upper 6 bits)
HAL_StatusTypeDef ZACwire_Prog_Offset_B_Lower(uint8_t lower_val); // Offset_B 하위 8비트 (Program Offset_B lower 8 bits)
HAL_StatusTypeDef ZACwire_Prog_Gain_T(uint8_t gain_t_val); // Gain_T 프로그래밍 (Program Gain_T)
HAL_StatusTypeDef ZACwire_Prog_Offset_T(uint8_t offset_t_val); // Offset_T 프로그래밍 (Program Offset_T)
HAL_StatusTypeDef ZACwire_Prog_Tco(uint8_t tco_val); // Tco 프로그래밍 (Program Tco)
HAL_StatusTypeDef ZACwire_Prog_Tcg(uint8_t tcg_val); // Tcg 프로그래밍 (Program Tcg)
HAL_StatusTypeDef ZACwire_Prog_Upper_Clip(uint8_t clip_val); // 상한 클리핑 (Program Upper Clipping)
HAL_StatusTypeDef ZACwire_Prog_Lower_Clip(uint8_t clip_val); // 하한 클리핑 (Program Lower Clipping)
HAL_StatusTypeDef ZACwire_Prog_Cust_ID0(uint8_t id_val); // Cust_ID0 프로그래밍 (Program Cust_ID0)
HAL_StatusTypeDef ZACwire_Prog_Cust_ID1(uint8_t id_val); // Cust_ID1 프로그래밍 (Program Cust_ID1)
HAL_StatusTypeDef ZACwire_Prog_Cust_ID2(uint8_t id_val); // Cust_ID2 프로그래밍 (Program Cust_ID2)
// 통합 함수 (Integrated functions)
HAL_StatusTypeDef ZACwire_Setup_Raw_Mode(
uint8_t output_mode, uint8_t update_rate, uint8_t temp_source,
uint8_t pamp_gain, uint16_t gain_b, uint8_t gain_t); // Raw Mode 설정 (Setup Raw Mode)
HAL_StatusTypeDef ZACwire_Program_Calibration_Coefficients(
uint8_t sot, uint8_t t_setl, uint16_t gain_b, uint16_t offset_b,
uint8_t gain_t, uint8_t offset_t, uint8_t tco, uint8_t tcg); // 보정 계수 프로그래밍 (Program calibration coefficients)
HAL_StatusTypeDef ZACwire_Finalize_EEPROM_Settings(
uint8_t output_mode, uint8_t update_rate, uint8_t temp_source,
uint8_t pamp_gain, uint8_t lock_enable, uint8_t upper_clip, uint8_t lower_clip); // 최종 EEPROM 설정 (Finalize EEPROM settings)
HAL_StatusTypeDef ZACwire_Calibration_Sequence(
uint8_t osc_trim, uint8_t ref_trim, uint8_t offset_mode, uint8_t output_mode,
uint8_t update_rate, uint8_t jfet_reg, uint8_t tc_cfg, uint8_t eeprom_bits,
uint8_t eeprom_lock, uint8_t diag_cfg, uint8_t sot, uint8_t t_setl,
uint16_t gain_b, uint16_t offset_b, uint8_t gain_t, uint8_t offset_t,
uint8_t tco, uint8_t tcg, uint8_t up_clip, uint8_t lo_clip,
uint8_t cust_id0, uint8_t cust_id1, uint8_t cust_id2); // 전체 캘리브레이션 시퀀스 (Full calibration sequence)
uint8_t ZACwire_CalculateParity(uint16_t value); // 패리티 계산: 커맨드 + 데이터 (Calculate parity: command + data)
// ADC 관련 함수: 아날로그 출력 읽기 (ADC functions: Read analog output)
void ZACwire_Init_ADC(void); // ADC 초기화: ADC1, 채널 6, PA1 (Initialize ADC: ADC1, channel 6, PA1)
HAL_StatusTypeDef ZACwire_Read_Analog_Output(float* voltage); // VOUT 전압 읽기 (V) (Read VOUT voltage in volts)
#endif /* ZACWIRE_H */
zacwire.c
// zacwire.c
#include "zacwire.h"
// 외부 선언: TIM2, ADC1, UART2 핸들러, STM32CubeMX에서 설정 (External declarations: TIM2, ADC1, UART2 handlers, configured in STM32CubeMX)
extern TIM_HandleTypeDef htim2;
extern ADC_HandleTypeDef hadc1;
extern UART_HandleTypeDef huart2;
// 내부 헬퍼 함수: μs 단위 딜레이 (Internal helper: Microsecond delay)
static void delay_us(uint32_t us) {
__HAL_TIM_SET_COUNTER(&htim2, 0); // 카운터 초기화 (Reset counter)
HAL_TIM_Base_Start(&htim2); // 타이머 시작 (Start timer)
while (__HAL_TIM_GET_COUNTER(&htim2) < us); // 지정된 μs 대기 (Wait for specified μs)
HAL_TIM_Base_Stop(&htim2); // 타이머 중지 (Stop timer)
}
// 내부 헬퍼 함수: GPIO 핀을 하이로 설정 (Internal helper: Set GPIO pin high)
static void set_pin_high(void) {
HAL_GPIO_WritePin(ZACWIRE_GPIO_PORT, ZACWIRE_GPIO_PIN, GPIO_PIN_SET);
}
// 내부 헬퍼 함수: GPIO 핀을 로우로 설정 (Internal helper: Set GPIO pin low)
static void set_pin_low(void) {
HAL_GPIO_WritePin(ZACWIRE_GPIO_PORT, ZACWIRE_GPIO_PIN, GPIO_PIN_RESET);
}
// 내부 헬퍼 함수: GPIO 핀 상태 읽기 (Internal helper: Read GPIO pin state)
static uint8_t read_pin(void) {
return HAL_GPIO_ReadPin(ZACWIRE_GPIO_PORT, ZACWIRE_GPIO_PIN);
}
// 내부 헬퍼 함수: 맨체스터 인코딩으로 비트 전송 (Internal helper: Send bit with Manchester encoding)
// 0: 로우(25μs) → 하이(25μs), 1: 하이(25μs) → 로우(25μs) (0: low→high, 1: high→low)
static void send_bit(uint8_t bit) {
if (bit == 0) {
set_pin_low();
delay_us(HALF_BIT_US);
set_pin_high();
delay_us(HALF_BIT_US);
} else {
set_pin_high();
delay_us(HALF_BIT_US);
set_pin_low();
delay_us(HALF_BIT_US);
}
}
// 내부 헬퍼 함수: 맨체스터 인코딩으로 비트 수신 (Internal helper: Receive bit with Manchester encoding)
// 상태 전환 감지 후 반 비트 대기, 초기 상태(하이=1, 로우=0) 반환 (Detect state transition, wait half bit, return initial state)
static int8_t receive_bit(void) {
uint32_t timeout = TIMEOUT_US / HALF_BIT_US; // 타임아웃 카운트 (Timeout count)
uint8_t state = read_pin(); // 초기 핀 상태 (Initial pin state)
while (timeout--) {
uint8_t new_state = read_pin();
if (new_state != state) { // 상태 전환 감지 (Detect state transition)
delay_us(HALF_BIT_US); // 반 비트 대기 (Wait half bit)
return (state == 1) ? 1 : 0; // 초기 상태 기반 비트 반환 (Return bit based on initial state)
}
delay_us(HALF_BIT_US);
}
return -1; // 타임아웃 시 오류 (Error on timeout)
}
// ZACwire 인터페이스 초기화: GPIO(PA0)를 출력 모드, 풀업 저항으로 설정 (Initialize ZACwire interface: GPIO PA0 as output with pull-up)
void ZACwire_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = ZACWIRE_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 푸시-풀 출력 (Push-pull output)
GPIO_InitStruct.Pull = GPIO_PULLUP; // 풀업 저항 (Pull-up resistor)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 고속 동작 (High-speed operation)
HAL_GPIO_Init(ZACWIRE_GPIO_PORT, &GPIO_InitStruct);
set_pin_high(); // 초기 상태: 하이 (ZACwire 대기 상태) (Initial state: High, ZACwire idle)
}
// ADC 초기화: ADC1, 채널 6 (PA1), 12비트, 단일 변환 (Initialize ADC: ADC1, channel 6 (PA1), 12-bit, single conversion)
void ZACwire_Init_ADC(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = ADC_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; // 아날로그 입력 (Analog input)
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 없음 (No pull-up/pull-down)
HAL_GPIO_Init(ADC_GPIO_PORT, &GPIO_InitStruct);
ADC_ChannelConfTypeDef sConfig = {0};
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // 클럭 분주 (Clock prescaler)
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 12비트 해상도 (12-bit resolution)
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 데이터 정렬 (Right-aligned data)
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; // 단일 채널 (Single channel)
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 단일 변환 완료 (Single conversion EOC)
hadc1.Init.ContinuousConvMode = DISABLE; // 비연속 변환 (Non-continuous conversion)
HAL_ADC_Init(&hadc1);
sConfig.Channel = ADC_CHANNEL;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; // 높은 샘플링 시간 (High sampling time)
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// 아날로그 출력(VOUT) 읽기: ADC로 전압 측정 (V) (Read analog output (VOUT): Measure voltage with ADC)
// 2:1 분압기 가정 (4.5V → 3V 이하, STM32 ADC 범위 0~3.3V) (Assumes 2:1 voltage divider, 4.5V to ≤3V, ADC range 0~3.3V)
HAL_StatusTypeDef ZACwire_Read_Analog_Output(float* voltage) {
HAL_ADC_Start(&hadc1); // ADC 변환 시작 (Start ADC conversion)
if (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK) return HAL_TIMEOUT; // 변환 대기 (Wait for conversion)
uint32_t adc_value = HAL_ADC_GetValue(&hadc1); // 12비트 ADC 값 (12-bit ADC value)
HAL_ADC_Stop(&hadc1); // ADC 중지 (Stop ADC)
// ADC 값을 전압으로 변환: Vref=3.3V, 12비트, 2:1 분압기 (Convert ADC value to voltage: Vref=3.3V, 12-bit, 2:1 divider)
*voltage = (adc_value * 3.3f / 4096.0f) * 2.0f; // 실제 전압 (V) (Actual voltage in volts)
return HAL_OK;
}
// ZACwire 쓰기: 19비트 프레임 전송 (Write ZACwire: Send 19-bit frame)
// 프레임: 스타트 비트(100μs 로우) + 8비트 커맨드 + 8비트 데이터 + 패리티 + 스톱 비트(100μs 하이) (Frame: Start bit, 8-bit command, 8-bit data, parity, stop bit)
HAL_StatusTypeDef ZACwire_Write(uint8_t command, uint8_t data) {
uint16_t frame = (command << 8) | data; // 16비트 프레임: 커맨드 + 데이터 (16-bit frame: command + data)
uint8_t parity = ZACwire_CalculateParity(frame); // 패리티 계산 (Calculate parity)
// GPIO를 출력 모드로 설정 (Set GPIO to output mode)
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = ZACWIRE_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(ZACWIRE_GPIO_PORT, &GPIO_InitStruct);
set_pin_low(); // 스타트 비트: 100μs 로우 (Start bit: 100μs low)
delay_us(START_BIT_US);
for (int i = 7; i >= 0; i--) send_bit((command >> i) & 1); // 8비트 커맨드 전송 (Send 8-bit command)
for (int i = 7; i >= 0; i--) send_bit((data >> i) & 1); // 8비트 데이터 전송 (Send 8-bit data)
send_bit(parity); // 패리티 비트 전송 (Send parity bit)
set_pin_high(); // 스톱 비트: 100μs 하이 (Stop bit: 100μs high)
delay_us(STOP_BIT_US);
return HAL_OK;
}
// Command Mode 시작: 0x50 | 0x90 (Start Command Mode: 0x50 | 0x90)
HAL_StatusTypeDef ZACwire_Start_CM(void) {
return ZACwire_Write(CMD_START_CM, 0x90);
}
// Normal Operation Mode 시작: 0x40 | 0x00 (Start Normal Operation Mode: 0x40 | 0x00)
HAL_StatusTypeDef ZACwire_Start_NOM(void) {
return ZACwire_Write(CMD_START_NOM, 0x00);
}
// Raw Mode 시작: 0x40 | 0x10 (Start Raw Mode: 0x40 | 0x10)
HAL_StatusTypeDef ZACwire_Start_RM(void) {
return ZACwire_Write(CMD_START_RM, 0x10);
}
// Raw 데이터 읽기: 브리지(16비트) + 온도(8비트) (Read raw data: 16-bit bridge + 8-bit temperature)
// RM에서 ACK 후 24비트 데이터 패킷 수신, 그림 3.6 (Receive 24-bit data packet after ACK in RM, figure 3.6)
HAL_StatusTypeDef ZACwire_Read_Raw(uint16_t* bridge_raw, uint8_t* temp_raw) {
if (ZACwire_Start_RM() != HAL_OK) return HAL_ERROR; // RM 시작 (Start RM)
// GPIO를 입력 모드로 전환 (Switch GPIO to input mode)
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = ZACWIRE_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(ZACWIRE_GPIO_PORT, &GPIO_InitStruct);
// ACK 대기: 로우 펄스 (Wait for ACK: Low pulse)
uint32_t timeout = TIMEOUT_US;
while (read_pin() == 1 && timeout--) delay_us(1);
if (timeout == 0) return HAL_TIMEOUT;
// 브리지 데이터 (16비트) 수신 (Receive 16-bit bridge data)
*bridge_raw = 0;
for (int i = 15; i >= 0; i--) {
int8_t bit = receive_bit();
if (bit < 0) return HAL_TIMEOUT;
*bridge_raw |= (bit << i);
}
// 온도 데이터 (8비트) 수신 (Receive 8-bit temperature data)
*temp_raw = 0;
for (int i = 7; i >= 0; i--) {
int8_t bit = receive_bit();
if (bit < 0) return HAL_TIMEOUT;
*temp_raw |= (bit << i);
}
ZACwire_Start_NOM(); // RM 종료 후 NOM 복귀 (Return to NOM after RM)
return HAL_OK;
}
// EEPROM 읽기: 106비트 데이터 덤프, 최대 length 바이트 (Read EEPROM: 106-bit data dump, max length bytes)
// CMD_READ_EEPROM (0x00 | 0x00) 후 ACK 및 데이터 수신, 그림 3.8 (Send CMD_READ_EEPROM, receive data after ACK, figure 3.8)
HAL_StatusTypeDef ZACwire_Read_EEPROM(uint8_t* eeprom_data, uint8_t length) {
if (ZACwire_Write(CMD_READ_EEPROM, 0x00) != HAL_OK) return HAL_ERROR;
// GPIO를 입력 모드로 전환 (Switch GPIO to input mode)
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = ZACWIRE_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(ZACWIRE_GPIO_PORT, &GPIO_InitStruct);
// ACK 대기 (Wait for ACK)
uint32_t timeout = TIMEOUT_US;
while (read_pin() == 1 && timeout--) delay_us(1);
if (timeout == 0) return HAL_TIMEOUT;
// 최대 length 바이트 수신 (Receive up to length bytes)
for (uint8_t byte = 0; byte < length; byte++) {
eeprom_data[byte] = 0;
for (int i = 7; i >= 0; i--) {
int8_t bit = receive_bit();
if (bit < 0) return HAL_TIMEOUT;
eeprom_data[byte] |= (bit << i);
}
}
return HAL_OK;
}
// DAC 램프 테스트: 0x20 | 5X (DAC ramp test: 0x20 | 5X)
HAL_StatusTypeDef ZACwire_DAC_Ramp_Test(uint8_t x) {
return ZACwire_Write(CMD_DAC_RAMP_TEST, (0x50 | (x & 0x0F)));
}
// Trim/Configure 함수: EEPROM 설정, CMD_TRIM_CONFIG (Trim/Configure functions: EEPROM configuration, CMD_TRIM_CONFIG)
HAL_StatusTypeDef ZACwire_Trim_Oscillator(uint8_t trim_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_OSC << 4) | (trim_val & 0x07));
}
HAL_StatusTypeDef ZACwire_Trim_1V_Reference(uint8_t trim_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_1V_REF << 4) | (trim_val & 0x0F));
}
HAL_StatusTypeDef ZACwire_Trim_Offset_Mode(uint8_t mode_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_OFFSET_MODE << 4) | (mode_val & 0x0F));
}
HAL_StatusTypeDef ZACwire_Trim_Output_Mode(uint8_t mode_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_OUTPUT_MODE << 4) | (mode_val & 0x03));
}
HAL_StatusTypeDef ZACwire_Trim_Update_Rate(uint8_t rate_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_UPDATE_RATE << 4) | (rate_val & 0x03));
}
HAL_StatusTypeDef ZACwire_Trim_JFET_Reg(uint8_t reg_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_JFET_REG << 4) | (reg_val & 0x0F));
}
HAL_StatusTypeDef ZACwire_Trim_TC_Cfg(uint8_t cfg_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_TC_CFG << 4) | (cfg_val & 0x07));
}
HAL_StatusTypeDef ZACwire_Trim_EEPROM_Bits(uint8_t bits_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_EEPROM_BITS << 4) | (bits_val & 0x0F));
}
HAL_StatusTypeDef ZACwire_Trim_EEPROM_Lock(uint8_t lock_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_EEPROM_LOCK << 4) | (lock_val & 0x07));
}
HAL_StatusTypeDef ZACwire_Trim_Diag_Cfg(uint8_t diag_val) {
return ZACwire_Write(CMD_TRIM_CONFIG, (TRIM_DIAG_CFG << 4) | (diag_val & 0x07));
}
// 프로그래밍 함수: 보정 계수 및 클리핑/ID (Programming functions: Calibration coefficients and clipping/ID)
HAL_StatusTypeDef ZACwire_Prog_SOT(uint8_t sot_val) {
return ZACwire_Write(CMD_PROG_SOT, sot_val);
}
HAL_StatusTypeDef ZACwire_Prog_T_SETL(uint8_t t_setl_val) {
return ZACwire_Write(CMD_PROG_T_SETL, t_setl_val & 0x7F); // MSB=0
}
HAL_StatusTypeDef ZACwire_Prog_Gain_B_Upper(uint8_t upper_val) {
return ZACwire_Write(CMD_PROG_GAIN_B_UP, upper_val & 0x7F); // MSB=0
}
HAL_StatusTypeDef ZACwire_Prog_Gain_B_Lower(uint8_t lower_val) {
return ZACwire_Write(CMD_PROG_GAIN_B_LO, lower_val);
}
HAL_StatusTypeDef ZACwire_Prog_Offset_B_Upper(uint8_t upper_val) {
return ZACwire_Write(CMD_PROG_OFFSET_B_UP, upper_val & 0x3F); // 두 MSB=0 (Two MSBs=0)
}
HAL_StatusTypeDef ZACwire_Prog_Offset_B_Lower(uint8_t lower_val) {
return ZACwire_Write(CMD_PROG_OFFSET_B_LO, lower_val);
}
HAL_StatusTypeDef ZACwire_Prog_Gain_T(uint8_t gain_t_val) {
return ZACwire_Write(CMD_PROG_GAIN_T, gain_t_val);
}
HAL_StatusTypeDef ZACwire_Prog_Offset_T(uint8_t offset_t_val) {
return ZACwire_Write(CMD_PROG_OFFSET_T, offset_t_val);
}
HAL_StatusTypeDef ZACwire_Prog_Tco(uint8_t tco_val) {
return ZACwire_Write(CMD_PROG_TCO, tco_val);
}
HAL_StatusTypeDef ZACwire_Prog_Tcg(uint8_t tcg_val) {
return ZACwire_Write(CMD_PROG_TCG, tcg_val);
}
HAL_StatusTypeDef ZACwire_Prog_Upper_Clip(uint8_t clip_val) {
return ZACwire_Write(CMD_PROG_UP_CLIP, clip_val & 0x7F); // MSB=0
}
HAL_StatusTypeDef ZACwire_Prog_Lower_Clip(uint8_t clip_val) {
return ZACwire_Write(CMD_PROG_LO_CLIP, clip_val & 0x7F); // MSB=0
}
HAL_StatusTypeDef ZACwire_Prog_Cust_ID0(uint8_t id_val) {
return ZACwire_Write(CMD_PROG_CUST_ID0, id_val);
}
HAL_StatusTypeDef ZACwire_Prog_Cust_ID1(uint8_t id_val) {
return ZACwire_Write(CMD_PROG_CUST_ID1, id_val);
}
HAL_StatusTypeDef ZACwire_Prog_Cust_ID2(uint8_t id_val) {
return ZACwire_Write(CMD_PROG_CUST_ID2, id_val);
}
// Raw Mode 설정: 캘리브레이션 전 Raw 데이터 수집 (Setup Raw Mode: Collect raw data before calibration)
HAL_StatusTypeDef ZACwire_Setup_Raw_Mode(
uint8_t output_mode, uint8_t update_rate, uint8_t temp_source,
uint8_t pamp_gain, uint16_t gain_b, uint8_t gain_t) {
if (ZACwire_Start_CM() != HAL_OK) return HAL_ERROR; // CM 진입 (Enter CM)
if (ZACwire_Trim_Output_Mode(output_mode & 0x03) != HAL_OK) return HAL_ERROR; // 출력 모드 설정 (Set output mode)
if (ZACwire_Trim_Update_Rate(update_rate & 0x03) != HAL_OK) return HAL_ERROR; // 업데이트 속도 설정 (Set update rate)
uint8_t lock_val = (temp_source & 0x01); // 온도 소스 설정, ExtTemp [105] (Set temperature source, ExtTemp [105])
if (ZACwire_Trim_EEPROM_Lock(lock_val) != HAL_OK) return HAL_ERROR;
uint8_t bits_val = (pamp_gain & 0x03); // 프리앰프 게인 설정, [97:96] (Set preamp gain, [97:96])
if (ZACwire_Trim_EEPROM_Bits(bits_val) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Gain_B_Upper((gain_b >> 8) & 0x7F) != HAL_OK) return HAL_ERROR; // Gain_B 상위 (Gain_B upper)
if (ZACwire_Prog_Gain_B_Lower(gain_b & 0xFF) != HAL_OK) return HAL_ERROR; // Gain_B 하위 (Gain_B lower)
if (ZACwire_Prog_Gain_T(gain_t) != HAL_OK) return HAL_ERROR; // Gain_T
return HAL_OK;
}
// 보정 계수 프로그래밍: 외부 계산된 계수 EEPROM에 기록 (Program calibration coefficients: Write calculated coefficients to EEPROM)
HAL_StatusTypeDef ZACwire_Program_Calibration_Coefficients(
uint8_t sot, uint8_t t_setl, uint16_t gain_b, uint16_t offset_b,
uint8_t gain_t, uint8_t offset_t, uint8_t tco, uint8_t tcg) {
if (ZACwire_Start_CM() != HAL_OK) return HAL_ERROR; // CM 진입 (Enter CM)
if (ZACwire_Prog_SOT(sot) != HAL_OK) return HAL_ERROR; // SOT 프로그래밍 (Program SOT)
if (ZACwire_Prog_T_SETL(t_setl & 0x7F) != HAL_OK) return HAL_ERROR; // T_SETL, MSB=0 (Program T_SETL, MSB=0)
if (ZACwire_Prog_Gain_B_Upper((gain_b >> 8) & 0x7F) != HAL_OK) return HAL_ERROR; // Gain_B 상위 (Program Gain_B upper)
if (ZACwire_Prog_Gain_B_Lower(gain_b & 0xFF) != HAL_OK) return HAL_ERROR; // Gain_B 하위 (Program Gain_B lower)
if (ZACwire_Prog_Offset_B_Upper((offset_b >> 8) & 0x3F) != HAL_OK) return HAL_ERROR; // Offset_B 상위 (Program Offset_B upper)
if (ZACwire_Prog_Offset_B_Lower(offset_b & 0xFF) != HAL_OK) return HAL_ERROR; // Offset_B 하위 (Program Offset_B lower)
if (ZACwire_Prog_Gain_T(gain_t) != HAL_OK) return HAL_ERROR; // Gain_T
if (ZACwire_Prog_Offset_T(offset_t) != HAL_OK) return HAL_ERROR; // Offset_T
if (ZACwire_Prog_Tco(tco) != HAL_OK) return HAL_ERROR; // Tco
if (ZACwire_Prog_Tcg(tcg) != HAL_OK) return HAL_ERROR; // Tcg
if (ZACwire_Start_NOM() != HAL_OK) return HAL_ERROR; // NOM 전환 (Switch to NOM)
return HAL_OK;
}
// 최종 EEPROM 설정: NOM 데이터 출력 준비, 아날로그 출력 포함 (Finalize EEPROM settings: Prepare NOM data output, including analog)
HAL_StatusTypeDef ZACwire_Finalize_EEPROM_Settings(
uint8_t output_mode, uint8_t update_rate, uint8_t temp_source,
uint8_t pamp_gain, uint8_t lock_enable, uint8_t upper_clip, uint8_t lower_clip) {
if (ZACwire_Start_CM() != HAL_OK) return HAL_ERROR; // CM 진입 (Enter CM)
if (ZACwire_Trim_Output_Mode(output_mode & 0x03) != HAL_OK) return HAL_ERROR; // 출력 모드, [93:92] (Set output mode, [93:92])
if (ZACwire_Trim_Update_Rate(update_rate & 0x03) != HAL_OK) return HAL_ERROR; // 업데이트 속도, [95:94] (Set update rate, [95:94])
uint8_t lock_val = (temp_source & 0x01); // 온도 소스, [105] (Temperature source, [105])
if (lock_enable) lock_val |= 0x01; // 락 활성화, [104] (Enable lock, [104])
if (ZACwire_Trim_EEPROM_Lock(lock_val) != HAL_OK) return HAL_ERROR;
uint8_t bits_val = (pamp_gain & 0x03); // 프리앰프 게인, [97:96] (Preamp gain, [97:96])
if (ZACwire_Trim_EEPROM_Bits(bits_val) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Upper_Clip(upper_clip & 0x7F) != HAL_OK) return HAL_ERROR; // 상한 클리핑, [15:8] (Upper clipping, [15:8])
if (ZACwire_Prog_Lower_Clip(lower_clip & 0x7F) != HAL_OK) return HAL_ERROR; // 하한 클리핑, [23:16] (Lower clipping, [23:16])
if (ZACwire_Start_NOM() != HAL_OK) return HAL_ERROR; // NOM 전환 (Switch to NOM)
return HAL_OK;
}
// 전체 캘리브레이션 시퀀스: 모든 설정 및 계수 프로그래밍, 아날로그 출력 포함 (Full calibration sequence: All settings and coefficients, including analog)
HAL_StatusTypeDef ZACwire_Calibration_Sequence(
uint8_t osc_trim, uint8_t ref_trim, uint8_t offset_mode, uint8_t output_mode,
uint8_t update_rate, uint8_t jfet_reg, uint8_t tc_cfg, uint8_t eeprom_bits,
uint8_t eeprom_lock, uint8_t diag_cfg, uint8_t sot, uint8_t t_setl,
uint16_t gain_b, uint16_t offset_b, uint8_t gain_t, uint8_t offset_t,
uint8_t tco, uint8_t tcg, uint8_t up_clip, uint8_t lo_clip,
uint8_t cust_id0, uint8_t cust_id1, uint8_t cust_id2) {
if (ZACwire_Start_CM() != HAL_OK) return HAL_ERROR; // CM 진입 (Enter CM)
if (ZACwire_Trim_Oscillator(osc_trim) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_1V_Reference(ref_trim) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_Offset_Mode(offset_mode) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_Output_Mode(output_mode) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_Update_Rate(update_rate) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_JFET_Reg(jfet_reg) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_TC_Cfg(tc_cfg) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_EEPROM_Bits(eeprom_bits) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_EEPROM_Lock(eeprom_lock) != HAL_OK) return HAL_ERROR;
if (ZACwire_Trim_Diag_Cfg(diag_cfg) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_SOT(sot) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_T_SETL(t_setl) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Gain_B_Upper((gain_b >> 8) & 0x7F) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Gain_B_Lower(gain_b & 0xFF) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Offset_B_Upper((offset_b >> 8) & 0x3F) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Offset_B_Lower(offset_b & 0xFF) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Gain_T(gain_t) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Offset_T(offset_t) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Tco(tco) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Tcg(tcg) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Upper_Clip(up_clip) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Lower_Clip(lo_clip) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Cust_ID0(cust_id0) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Cust_ID1(cust_id1) != HAL_OK) return HAL_ERROR;
if (ZACwire_Prog_Cust_ID2(cust_id2) != HAL_OK) return HAL_ERROR;
if (ZACwire_Start_NOM() != HAL_OK) return HAL_ERROR; // NOM 전환 (Switch to NOM)
return HAL_OK;
}
// 패리티 계산: 커맨드 + 데이터 (16비트) 홀수 패리티 (Calculate parity: Odd parity for 16-bit command + data)
uint8_t ZACwire_CalculateParity(uint16_t value) {
uint8_t count = 0;
while (value) {
count += value & 1;
value >>= 1;
}
return (count % 2 == 0) ? 0 : 1; // 홀수 패리티: 1의 개수 홀수 → 1 (Odd parity: 1 if odd number of 1s)
}
main.c
// main.c
#include "zacwire.h"
#include <stdio.h>
#include <string.h>
// HAL 핸들러 선언 (HAL handler declarations)
TIM_HandleTypeDef htim2; // TIM2: 1MHz 클럭, μs 딜레이 (TIM2: 1MHz clock for μs delays)
ADC_HandleTypeDef hadc1; // ADC1: 채널 6, VOUT 읽기 (ADC1: Channel 6 for VOUT reading)
UART_HandleTypeDef huart2; // UART2: 디버깅 출력, 115200bps (UART2: Debugging output, 115200bps)
// 시스템 클럭 설정: STM32L432KC, HSI 80MHz (System clock configuration: STM32L432KC, HSI 80MHz)
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// HSI 활성화, 16MHz 기본 (Enable HSI, 16MHz default)
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1; // PLL 입력 분주 (PLL input divider)
RCC_OscInitStruct.PLL.PLLN = 10; // PLL 배수 (PLL multiplier)
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; // ADC용 (For ADC)
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // 사용 안 함 (Not used)
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // 시스템 클럭용, 80MHz (For system clock, 80MHz)
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
while (1); // 오류 처리 (Error handling)
}
// 시스템 클럭: 80MHz, APB1/APB2: 80MHz (System clock: 80MHz, APB1/APB2: 80MHz)
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
while (1); // 오류 처리 (Error handling)
}
// 주변 장치 클럭 활성화: GPIO, TIM2, ADC1, UART2 (Enable peripheral clocks: GPIO, TIM2, ADC1, UART2)
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_ADC_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
}
// TIM2 초기화: 1MHz 클럭, μs 단위 딜레이 (Initialize TIM2: 1MHz clock for μs delays)
void TIM2_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 79; // 80MHz / (79+1) = 1MHz (1μs 틱) (80MHz / (79+1) = 1MHz, 1μs tick)
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFF;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK) {
while (1); // 오류 처리 (Error handling)
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) {
while (1); // 오류 처리 (Error handling)
}
}
// UART2 초기화: PA2(TX), 115200bps (Initialize UART2: PA2(TX), 115200bps)
void UART2_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = UART_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 대체 기능, 푸시-풀 (Alternate function, push-pull)
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2; // USART2용 AF7 (AF7 for USART2)
HAL_GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct);
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK) {
while (1); // 오류 처리 (Error handling)
}
}
// UART로 데이터 전송: 디버깅 출력 (Transmit data via UART: Debugging output)
void UART_Transmit(const char* msg) {
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 1000);
}
// 메인 함수 (Main function)
int main(void) {
// HAL 및 시스템 초기화 (HAL and system initialization)
HAL_Init();
SystemClock_Config();
TIM2_Init();
UART2_Init();
ZACwire_Init();
ZACwire_Init_ADC();
// 디버깅 메시지 출력 (Print debug message)
char msg[128];
snprintf(msg, sizeof(msg), "ZSC31015 드라이버 초기화 완료\r\n");
UART_Transmit(msg);
// Raw Mode 설정 및 데이터 읽기 테스트 (Setup Raw Mode and test data reading)
if (ZACwire_Setup_Raw_Mode(0, 0, 0, 0, 0x1000, 0x80) == HAL_OK) {
uint16_t bridge_raw;
uint8_t temp_raw;
if (ZACwire_Read_Raw(&bridge_raw, &temp_raw) == HAL_OK) {
snprintf(msg, sizeof(msg), "Raw 데이터 - 브리지: 0x%04X, 온도: 0x%02X\r\n", bridge_raw, temp_raw);
UART_Transmit(msg);
} else {
UART_Transmit("Raw 데이터 읽기 실패\r\n");
}
} else {
UART_Transmit("Raw Mode 설정 실패\r\n");
}
// 보정 계수 프로그래밍 예시 (Example: Program calibration coefficients)
if (ZACwire_Program_Calibration_Coefficients(0x80, 0x40, 0x1000, 0x0800, 0x80, 0x40, 0x20, 0x10) == HAL_OK) {
UART_Transmit("보정 계수 프로그래밍 완료\r\n");
} else
상세한 내용은 ZSC31014 데이트시트를 참조 바랍니다.
'아날로그회로(Analog Circuit) > ADC관련' 카테고리의 다른 글
STM32 HAL 기반 ADS114S08 ADC 드라이버 구현 (0) | 2025.08.24 |
---|---|
STM32에서 PT100/PT1000 RTD 센서용 MAX31865 온도 변환 IC 드라이버 구현 (2) | 2025.08.24 |
PGA302 Sensor Signal Conditioner IC STM32 I2C 드라이버 구현 | 압력 센서 보정 및 통신 예제(PGA302 I2C Driver Implementation Using STM32) (0) | 2025.08.20 |
ZSC31050 Sensor Signal Conditioner IC I²C 인터페이스 설정 및 데이터 처리 코드 구현 (0) | 2025.08.16 |
ZSSC3230 Sensor Signal Conditioner IC 보정 절차 및 Calibration Math 분석 (1) | 2025.08.15 |
ZSSC3230 Sensor Signal Conditioner IC STM32을 사용한 I2C 코드 구현 (0) | 2025.08.15 |
ZSSC3230 Sensor Signal Conditioner IC 센서 Raw Data 측정 설정 절차 (0) | 2025.08.15 |
ZSSC3230 Sensor Signal Conditioner IC 전체 측정 전 NVM 설정 절차 (0) | 2025.08.15 |