이 문서는 STM32 마이크로컨트롤러에서 I2C 인터페이스를 통해 PGA302 센서 신호 컨디셔너를 제어하는 드라이버 구현 방법을 설명합니다. PGA302는 압력 및 온도 센서 신호를 처리하기 위한 고정밀 아날로그 프론트엔드(AFE) 장치로,STM32Cube HAL 라이브러리를 사용하여 I2C를 통해 레지스터 설정 및 데이터 읽기가 가능합니다.
키워드 (Keywords): PGA302 STM32 I2C Driver, STM32Cube HAL I2C Communication, PGA302 Register Configuration Example,Sensor Signal Conditioner (Pressure & Temperature)
PGA302 사양
PGA302는 Texas Instruments에서 제공하는 저드리프트, 저소음의 프로그래머블 센서 신호 컨디셔너로, 다양한 저항성 브릿지 센서 애플리케이션(압력, 온도, 레벨 감지 등)을 위해 설계되었습니다 . 다음은 PGA302의 주요 사양을 데이터시트를 기반으로 정리한 내용입니다
주요 특징 (Key Features)
- 기능 (Functionality): 저항성 브릿지 센서(압력, 온도, 레벨 감지) 및 기타 애플리케이션(유량계, 중량계, 힘 감지, 가속도계, 습도 센서, 전류 감지)을 위한 신호 컨디셔닝
- 입력 (Input):
- 두 개의 동일한 아날로그 프론트엔드(AFE) 채널 제공
- 각 AFE 채널은 최대 200V/V의 프로그래머블 게인 증폭기(PGA) 포함
- 한 채널은 센서 오프셋 보상 기능, 다른 채널은 내부 온도 센서 통합
- 16비트 시그마-델타 ADC로 아날로그 입력을 디지털로 변환
- 출력 (Output):
- 1.25V, 14비트 DAC와 4V/V 게인의 레이티오메트릭 전압 출력 버퍼로 0~5V 출력
- 3차 온도 계수(TC) 및 비선형성(NL) 디지털 보상 알고리즘 구현
- 브릿지 여기 (Bridge Excitation):
- 2.5V 브릿지 여기 전압 제공
- 최대 1mA까지 프로그래머블 전류 출력 소스
- 인터페이스 (Interface):
- I2C 인터페이스(7비트 주소, 최대 속도 명시되지 않음, 일반적으로 100kHz 또는 400kHz 사용)
- One-Wire Interface(OWI)로 전원 라인을 통한 통신 및 최종 시스템 보정 지원
- 메모리 (Memory): 통합 EEPROM에 선형화 알고리즘 매개변수 및 사용자 데이터 저장
- 진단 (Diagnostics):
- 여기 출력 소스, AFE 입력, 전원 공급에 대한 진단 기능 inputs, and power supply
- 센서 오픈/쇼트와 같은 시스템 진단 지원
- 지원 센서 유형 (Supported Sensor Types): 피에조저항성, 세라믹 필름, 스트레인 게이지, 스틸 멤브레인 등
전기적 특성 (Electrical Characteristics)
- 동작 전압 (Operating Voltage): 2.7V ~ 5.5V (권장 동작 조건)
- 브릿지 여기 전압 (Bridge Excitation Voltage): 2.5V (고정)
- 전류 소스 (Current Source): 50μA, 100μA, 200μA, 1000μA 프로그래머블 출력
- ADC 해상도 (ADC Resolution): 16비트 (시그마-델타)
- DAC 해상도 (DAC Resolution): 14비트 (14-bit).
- 게인 범위 (Gain Range): 1.33V/V ~ 200V/V (8단계: 1.33, 2, 4, 10, 20, 40, 100, 200)
- 오프셋 보상 (Offset Compensation): 0mV ~ 54.75mV (16단계)
- 샘플링 속도 (Sampling Rate): 출력 샘플링 주기 약 96μs (샘플 주기 제어 비트 = 0b00, 디지털 필터 설정에 따라 변동 가능, 특정 레지스터 정보 미제공)
- ESD 등급 (ESD Rating): HBM ±2000V, CDM ±500V
- 동작 온도 (Operating Temperature): -40°C ~ +150°C
패키지 및 핀 구성 (Package and Pin Configuration)
- 패키지 (Package): TSSOP-16
- 핀 기능 (Pin Functions):
- VINP, VINN: 브릿지 입력 (압력/온도)
- VOUT: 0~5V rationmetric output.
- SDA, SCL: I2C 인터페이스
- VBRG: 2.5V 브릿지 여기 출력
- VDD, VSS: 전원 및 접지
- 기타: 온도 센서, 전류 소스 제어 등
애플리케이션 (Applications)
- 압력, 온도, 레벨 감지
- 유량계, 중량계, 힘 감지(스트레인 게이지 기반)
- 가속도계, 습도 센서, 전류 감지(shunt 기반)
STM32L432KC를 사용한 PGA302 I2C 드라이버 구현
하드웨어 요구사항
- 마이크로컨트롤러 (Microcontroller): STM32L432KC
- I2C 인터페이스 (I2C Interface): I2C1 (SCL: PB6, SDA: PB7)
- 선택적 아날로그 입력 (Optional Analog Input): PA0 (GPIO 입력, 선택 사항)
- PGA302 장치 (PGA302 Device): I2C 슬레이브 주소 0x42 (기본)
- 개발 환경 (Development Environment): STM32CubeMX, STM32CubeIDE 또는 유사한 툴
- 클럭 설정 (Clock Configuration): 48MHz 시스템 클럭 (I2C 타이밍 값 기준)
소프트웨어 요구사항
- STM32Cube HAL 라이브러리 (stm32l4xx_hal.h)
- pga302.h 및 pga302.c 파일
- STM32CubeMX로 생성된 I2C 및 GPIO 초기화 코드
드라이버 설계 개요
드라이버는 다음과 같은 기능을 제공합니다
- I2C를 통한 PGA302 레지스터 읽기/쓰기
- 압력 및 온도 게인 설정
- 온도 모드 및 MUX 제어
- 오프셋 조정
- 압력 및 온도 ADC 데이터 읽기
- EEPROM 및 테스트 페이지 액세스
드라이버는 모든 함수에서 I2C_HandleTypeDef *hi2c와 uint8_t slave_address를 인자로 받아 전역 변수 없이 동작합니다. 설정 간 지연은 pga302_Config 내에서 HAL_Delay(100)로 처리되며, 호출자가 필요 시 추가 지연을 관리할 수 있습니다 . 함수 반환 값은 int 타입으로, 성공 시 0, 오류 시 -1을 반환합니다 .
코드 구현
1. 헤더 파일: pga302.h
PGA302 레지스터, 설정 값, 함수 프로토타입을 정의하며, 상세한 주석을 추가
#ifndef PGA302_H
#define PGA302_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32l4xx_hal.h"
// PGA302 드라이버 API 정의
// PGA302 센서 신호 컨디셔너의 I2C 통신 및 설정을 위한 함수 제공
// 저항성 브릿지 센서(압력, 온도 등) 신호 처리 및 0~5V 레이티오메트릭 출력 지원
// 레지스터 정의
#define PGA302_REG_TEST_MICRO_INTERFACE_CONTROL 0x0C // 마이크로 인터페이스 제어 레지스터 (소프트 리셋, 인터페이스 선택)
#define PGA302_REG_TEST_PADC_DATA_1 0x10 // 압력 ADC 데이터 LSB
#define PGA302_REG_TEST_PADC_DATA_2 0x11 // 압력 ADC 데이터 MSB
#define PGA302_REG_TEST_TADC_DATA_1 0x14 // 온도 ADC 데이터 LSB
#define PGA302_REG_TEST_TADC_DATA_2 0x15 // 온도 ADC 데이터 MSB
#define PGA302_REG_CTRL_STATUS_PSMON_1 0x58 // 전원 상태 모니터링 레지스터
#define PGA302_REG_CTRL_STATUS_AFEDIAG 0x5A // 아날로그 프론트엔드 진단 레지스터
#define PGA302_REG_CTRL_STATUS_P_GAIN_SELECT 0x47 // 압력 게인 선택 레지스터
#define PGA302_REG_CTRL_STATUS_T_GAIN_SELECT 0x48 // 온도 게인 선택 및 온도 모드/MUX 제어 레지스터
#define PGA302_REG_CTRL_STATUS_TEMP_CTRL 0x4C // 온도 전류 제어 및 오프셋 조정 레지스터
#define PGA302_REG_CTRL_STATUS_OFFSET_CANCEL 0x4E // 오프셋 캔슬 레지스터
#define PGA302_REG_CTRL_STATUS_DAC_REG0_1 0x30 // DAC 레지스터 0-1 (출력 설정)
#define PGA302_REG_CTRL_STATUS_DAC_REG0_2 0x31 // DAC 레지스터 0-2 (출력 설정)
#define PGA302_REG_CTRL_STATUS_OP_STAGE_CTRL 0x3B // 출력 스테이지 제어 레지스터
#define PGA302_REG_EEPROM_ARRAY_START 0x00 // EEPROM 배열 시작 주소
#define PGA302_REG_EEPROM_ARRAY_END 0x7F // EEPROM 배열 끝 주소
#define PGA302_REG_EEPROM_CACHE_BYTE_0 0x80 // EEPROM 캐시 바이트 0
#define PGA302_REG_EEPROM_CACHE_BYTE_1 0x81 // EEPROM 캐시 바이트 1
#define PGA302_REG_EEPROM_PAGE_ADDRESS 0x82 // EEPROM 페이지 주소
#define PGA302_REG_EEPROM_CTRL 0x83 // EEPROM 제어 레지스터
#define PGA302_REG_EEPROM_CRC 0x84 // EEPROM CRC 레지스터
#define PGA302_REG_EEPROM_STATUS 0x85 // EEPROM 상태 레지스터
#define PGA302_REG_EEPROM_CRC_STATUS 0x86 // EEPROM CRC 상태 레지스터
#define PGA302_REG_EEPROM_CRC_VALUE 0x87 // EEPROM CRC 값 레지스터
// 설정 값 정의
#define PGA302_SET_IF_SEL_ACCESSES_CONTROLLER 0x00 // 컨트롤러 액세스 (마이크로 인터페이스 제어)
#define PGA302_SET_IF_SEL_ACCESSES_DIGITAL_INTERFACE 0x01 // 디지털 인터페이스 액세스 (I2C/OWI)
#define PGA302_SET_TSEM_MODE_SINGLE_ENDED 0x00 // 단일 입력 온도 모드
#define PGA302_SET_TSEM_MODE_DIFFERENTIAL 0x01 // 차동 입력 온도 모드
#define PGA302_SET_T_MUX_CTRL_EXT_TEMPE 0x00 // 외부 온도 센서 선택
#define PGA302_SET_T_MUX_CTRL_TEST 0x01 // 테스트 모드 선택
#define PGA302_SET_T_MUX_CTRL_INT_TEMPE 0x02 // 내부 온도 센서 선택
#define PGA302_SET_T_MUX_CTRL_BRIDGE_CURRENT 0x03 // 브릿지 전류 측정
#define PGA302_SET_T_MUX_CTRL_ITEMP 0x04 // 내부 전류 측정
#define PGA302_SET_GAIN_1_33 0x00 // 게인 1.33V/V
#define PGA302_SET_GAIN_2 0x01 // 게인 2V/V
#define PGA302_SET_GAIN_4 0x02 // 게인 4V/V
#define PGA302_SET_GAIN_10 0x03 // 게인 10V/V
#define PGA302_SET_GAIN_20 0x04 // 게인 20V/V
#define PGA302_SET_GAIN_40 0x05 // 게인 40V/V
#define PGA302_SET_GAIN_100 0x06 // 게인 100V/V
#define PGA302_SET_GAIN_200 0x07 // 게인 200V/V
#define PGA302_SET_ITEMP_CTRL_50_mA 0x00 // 50μA 전류 제어
#define PGA302_SET_ITEMP_CTRL_100_mA 0x01 // 100μA 전류 제어
#define PGA302_SET_ITEMP_CTRL_200_mA 0x02 // 200μA 전류 제어
#define PGA302_SET_ITEMP_CTRL_1000_mA 0x03 // 1000μA 전류 제어
#define PGA302_SET_ITEMP_CTRL_OFF 0x04 // 전류 제어 끄기
#define PGA302_SET_OFFSET_CANCEL_0_mV 0x00 // 오프셋 0mV
#define PGA302_SET_OFFSET_CANCEL_3_65_mV 0x01 // 오프셋 3.65mV
#define PGA302_SET_OFFSET_CANCEL_7_3_mV 0x02 // 오프셋 7.3mV
#define PGA302_SET_OFFSET_CANCEL_10_95_mV 0x03 // 오프셋 10.95mV
#define PGA302_SET_OFFSET_CANCEL_14_6_mV 0x04 // 오프셋 14.6mV
#define PGA302_SET_OFFSET_CANCEL_18_28_mV 0x05 // 오프셋 18.28mV
#define PGA302_SET_OFFSET_CANCEL_21_9_mV 0x06 // 오프셋 21.9mV
#define PGA302_SET_OFFSET_CANCEL_25_55_mV 0x07 // 오프셋 25.55mV
#define PGA302_SET_OFFSET_CANCEL_29_2_mV 0x08 // 오프셋 29.2mV
#define PGA302_SET_OFFSET_CANCEL_32_85_mV 0x09 // 오프셋 32.85mV
#define PGA302_SET_OFFSET_CANCEL_36_5_mV 0x0A // 오프셋 36.5mV
#define PGA302_SET_OFFSET_CANCEL_40_15_mV 0x0B // 오프셋 40.15mV
#define PGA302_SET_OFFSET_CANCEL_43_8_mV 0x0C // 오프셋 43.8mV
#define PGA302_SET_OFFSET_CANCEL_47_45_mV 0x0D // 오프셋 47.45mV
#define PGA302_SET_OFFSET_CANCEL_51_1_mV 0x0E // 오프셋 51.1mV
#define PGA302_SET_OFFSET_CANCEL_54_75_mV 0x0F // 오프셋 54.75mV
#define PGA302_SET_OFFSET_CURRENT_VINPN 0x00 // VINP-N 오프셋 전류
#define PGA302_SET_OFFSET_CURRENT_VINPP 0x01 // VINP-P 오프셋 전류
#define PGA302_SET_DEV_ADDR 0x42 // 기본 I2C 슬레이브 주소
#define PGA302_SET_MEMORY_PAGE_TEST_REG 0x40 // 테스트 레지스터 페이지 주소
#define PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG 0x42 // 제어 및 상태 레지스터 페이지 주소
#define PGA302_SET_MEMORY_PAGE_EEPROM_CACHE_CELLS 0x45 // EEPROM 캐시 페이지 주소
#define PGA302_SET_MEMORY_PAGE_CTRL_AND_STATUS_REG 0x47 // 제어 및 상태 레지스터 페이지 주소(대체)
// 비트 마스크 정의
#define PGA302_SOFT_RESET 0x02 // 소프트 리셋 비트
#define PGA302_P_GAIN_BIT_MASK 0xF8 // 압력 게인 선택 비트 마스크
#define PGA302_T_GAIN_BIT_MASK 0xF8 // 온도 게인 선택 비트 마스크
#define PGA302_TEMP_MODE_BIT_MASK 0xF7 // 온도 모드 선택 비트 마스크
#define PGA302_T_MUX_CTRL_BIT_MASK 0x8F // 온도 MUX 제어 비트 마스크
#define PGA302_ITEMP_CTRL_BIT_MASK 0x8F // 전류 제어 비트 마스크
#define PGA302_OFFSET_BIT_MASK 0x1F // 오프셋 조정 비트 마스크
// 함수 프로토타입
// I2C 및 선택적 아날로그 핀 초기화
// hi2c: I2C 핸들, i2c_speed: I2C 속도(100kHz 또는 400kHz), i2c_address: PGA302 슬레이브 주소,
// an_port: 아날로그 입력 GPIO 포트, an_pin: 아날로그 입력 핀
// 반환: 0(성공), -1(오류)
int pga302_init(I2C_HandleTypeDef *hi2c, uint32_t i2c_speed, uint8_t i2c_address, GPIO_TypeDef *an_port, uint16_t an_pin);
// 기본 설정 적용 (소프트 리셋, 디지털 인터페이스, 게인, 온도 모드, MUX 설정)
// hi2c: I2C 핸들, slave_address: PGA302 슬레이브 주소
// 반환: 0(성공), -1(오류)
int pga302_Config(I2C_HandleTypeDef *hi2c, uint8_t slave_address);
// 범용 레지스터 쓰기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, reg: 대상 레지스터, tx_buf: 전송 데이터, tx_len: 데이터 길이
// 반환: 0(성공), -1(오류)
int pga302_generic_write(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *tx_buf, uint8_t tx_len);
// 범용 레지스터 읽기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, reg: 대상 레지스터, rx_buf: 수신 데이터, rx_len: 데이터 길이
// 반환: 0(성공), -1(오류)
int pga302_generic_read(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *rx_buf, uint8_t rx_len);
// EEPROM 쓰기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, reg: 대상 레지스터, tx_buf: 전송 데이터, tx_len: 데이터 길이
// 반환: 0(성공), -1(오류)
int pga302_generic_eeprom_write(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *tx_buf, uint8_t tx_len);
// EEPROM 읽기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, reg: 대상 레지스터, rx_buf: 수신 데이터, rx_len: 데이터 길이
// 반환: 0(성공), -1(오류)
int pga302_generic_eeprom_read(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *rx_buf, uint8_t rx_len);
// 테스트 페이지 쓰기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, reg: 대상 레지스터, tx_buf: 전송 데이터, tx_len: 데이터 길이
// 반환: 0(성공), -1(오류)
int pga302_generic_test_page_write(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *tx_buf, uint8_t tx_len);
// 테스트 페이지 읽기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, reg: 대상 레지스터, rx_buf: 수신 데이터, rx_len: 데이터 길이
// 반환: 0(성공), -1(오류)
int pga302_generic_test_page_read(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *rx_buf, uint8_t rx_len);
// 메모리 페이지 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소 포인터, memory_page: 메모리 페이지 값
// 반환: 0(성공), -1(오류)
int pga302_set_memory_page_slave_addr(I2C_HandleTypeDef *hi2c, uint8_t *slave_address, uint8_t memory_page);
// 컨트롤러 액세스 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소
// 반환: 0(성공), -1(오류)
int pga302_accesses_controller(I2C_HandleTypeDef *hi2c, uint8_t slave_address);
// 디지털 인터페이스 액세스 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소
// 반환: 0(성공), -1(오류)
int pga302_accesses_digital_interface_control(I2C_HandleTypeDef *hi2c, uint8_t slave_address);
// 소프트 리셋
// hi2c: I2C 핸들, slave_address: 슬레이브 주소
// 반환: 0(성공), -1(오류)
int pga302_soft_reset(I2C_HandleTypeDef *hi2c, uint8_t slave_address);
// 압력 게인 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, p_gain: 게인 값 (0~7)
// 반환: 0(성공), -1(오류)
int pga302_set_p_gain(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t p_gain);
// 온도 게인 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, t_gain: 게인 값 (0~7)
// 반환: 0(성공), -1(오류)
int pga302_set_t_gain(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t t_gain);
// 온도 모드 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, t_mode: 온도 모드 (단일/차동)
// 반환: 0(성공), -1(오류)
int pga302_set_temp_mode(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t t_mode);
// 온도 MUX 제어 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, t_mux_ctrl: MUX 제어 값
// 반환: 0(성공), -1(오류)
int pga302_set_t_mux_ctrl(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t t_mux_ctrl);
// 전류 제어 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, itemp_ctrl: 전류 제어 값
// 반환: 0(성공), -1(오류)
int pga302_itemp_ctrl(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t itemp_ctrl);
// 오프셋 설정
// hi2c: I2C 핸들, slave_address: 슬레이브 주소, offset_cancel_val: 오프셋 값, offset_cancel_sel: 오프셋 선택
// 반환: 0(성공), -1(오류)
int pga302_set_offset(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t offset_cancel_val, uint8_t offset_cancel_sel);
// 압력 ADC 데이터 읽기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소
// 반환: 16비트 ADC 데이터 (오류 시 0)
int16_t pga302_get_p_adc_data(I2C_HandleTypeDef *hi2c, uint8_t slave_address);
// 온도 ADC 데이터 읽기
// hi2c: I2C 핸들, slave_address: 슬레이브 주소
// 반환: 16비트 ADC 데이터 (오류 시 0)
int16_t pga302_get_t_adc_data(I2C_HandleTypeDef *hi2c, uint8_t slave_address);
#ifdef __cplusplus
}
#endif
#endif // PGA302_H
2. 소스 파일: pga302.c
드라이버의 핵심 로직을 구현하며, 상세한 주석을 추가했습니다.
#include "pga302.h"
// pga302_init: PGA302의 I2C 인터페이스 및 선택적 아날로그 입력 핀 초기화
// 매개변수:
// - hi2c: I2C 핸들 (STM32 HAL I2C 구조체)
// - i2c_speed: I2C 통신 속도 (100kHz 또는 400kHz)
// - i2c_address: PGA302의 I2C 슬레이브 주소 (기본: 0x42)
// - an_port: 아날로그 입력 GPIO 포트 (NULL 가능)
// - an_pin: 아날로그 입력 GPIO 핀 (GPIO_PIN_RESET 가능)
// 반환값: 0 (성공), -1 (I2C 초기화 실패)
int pga302_init(I2C_HandleTypeDef *hi2c, uint32_t i2c_speed, uint8_t i2c_address, GPIO_TypeDef *an_port, uint16_t an_pin)
{
// I2C 설정: I2C1 사용, 7비트 주소 모드, 클럭 스트레칭 비활성화
hi2c->Instance = I2C1; // I2C1 포트 설정
hi2c->Init.Timing = (i2c_speed == 100000) ? 0x10808BDF : 0x00D07BFF; // 100kHz 또는 400kHz 타이밍 (48MHz 기준)
hi2c->Init.OwnAddress1 = 0; // 마스터 모드이므로 자신의 주소 사용 안 함
hi2c->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7비트 주소 모드
hi2c->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 듀얼 주소 비활성화
hi2c->Init.OwnAddress2 = 0; // 두 번째 주소 사용 안 함
hi2c->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 일반 호출 비활성화
hi2c->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 클럭 스트레칭 활성화
// I2C 초기화
if (HAL_I2C_Init(hi2c) != HAL_OK) {
return -1; // 초기화 실패 시 오류 반환
}
// 아날로그 핀 설정 (선택적)
if (an_port != NULL && an_pin != GPIO_PIN_RESET) {
GPIO_InitTypeDef GPIO_InitStruct = {0}; // GPIO 설정 구조체 초기화
GPIO_InitStruct.Pin = an_pin; // 핀 번호 설정 (예: PA0)
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 입력 모드
GPIO_InitStruct.Pull = GPIO_NOPULL; // 풀업/풀다운 없음
HAL_GPIO_Init(an_port, &GPIO_InitStruct); // GPIO 초기화
}
return 0; // 성공
}
// pga302_Config: PGA302의 기본 설정 적용 (소프트 리셋, 디지털 인터페이스, 게인, 온도 모드, MUX 설정)
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: PGA302 슬레이브 주소
// 반환값: 0 (성공), -1 (설정 실패)
int pga302_Config(I2C_HandleTypeDef *hi2c, uint8_t slave_address)
{
// 1. 소프트 리셋 수행
if (pga302_soft_reset(hi2c, slave_address) != 0) return -1;
HAL_Delay(100); // 리셋 후 안정화 대기 (100ms)
// 2. 디지털 인터페이스(I2C/OWI) 활성화
if (pga302_accesses_digital_interface_control(hi2c, slave_address) != 0) return -1;
HAL_Delay(100); // 설정 적용 대기
// 3. 압력 게인 설정 (200V/V)
if (pga302_set_p_gain(hi2c, slave_address, PGA302_SET_GAIN_200) != 0) return -1;
HAL_Delay(100); // 설정 적용 대기
// 4. 온도 게인 설정 (200V/V)
if (pga302_set_t_gain(hi2c, slave_address, PGA302_SET_GAIN_200) != 0) return -1;
HAL_Delay(100); // 설정 적용 대기
// 5. 차동 온도 모드 설정
if (pga302_set_temp_mode(hi2c, slave_address, PGA302_SET_TSEM_MODE_DIFFERENTIAL) != 0) return -1;
HAL_Delay(100); // 설정 적용 대기
// 6. 내부 온도 센서 선택
if (pga302_set_t_mux_ctrl(hi2c, slave_address, PGA302_SET_T_MUX_CTRL_INT_TEMPE) != 0) return -1;
HAL_Delay(100); // 설정 적용 대기
return 0; // 모든 설정 성공
}
// pga302_generic_write: PGA302 레지스터에 데이터 쓰기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - reg: 대상 레지스터 주소
// - tx_buf: 전송할 데이터 버퍼
// - tx_len: 전송 데이터 길이
// 반환값: 0 (성공), -1 (I2C 전송 실패)
int pga302_generic_write(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *tx_buf, uint8_t tx_len)
{
uint8_t data_buf[257]; // 레지스터 주소 + 데이터 (최대 256바이트 데이터 + 1바이트 주소)
data_buf[0] = reg; // 첫 바이트는 레지스터 주소
for (uint8_t cnt = 0; cnt < tx_len; cnt++) {
data_buf[cnt + 1] = tx_buf[cnt]; // 데이터 복사
}
// I2C 마스터 전송 (슬레이브 주소는 7비트로 왼쪽 시프트)
if (HAL_I2C_Master_Transmit(hi2c, slave_address << 1, data_buf, tx_len + 1, HAL_MAX_DELAY) != HAL_OK) {
return -1; // 전송 실패
}
return 0; // 성공
}
// pga302_generic_read: PGA302 레지스터에서 데이터 읽기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - reg: 대상 레지스터 주소
// - rx_buf: 수신 데이터 저장 버퍼
// - rx_len: 수신 데이터 길이
// 반환값: 0 (성공), -1 (I2C 전송/수신 실패)
int pga302_generic_read(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *rx_buf, uint8_t rx_len)
{
// 1. 레지스터 주소 전송
if (HAL_I2C_Master_Transmit(hi2c, slave_address << 1, ®, 1, HAL_MAX_DELAY) != HAL_OK) {
return -1; // 주소 전송 실패
}
// 2. 데이터 수신
if (HAL_I2C_Master_Receive(hi2c, slave_address << 1, rx_buf, rx_len, HAL_MAX_DELAY) != HAL_OK) {
return -1; // 데이터 수신 실패
}
return 0; // 성공
}
// pga302_generic_eeprom_write: EEPROM에 데이터 쓰기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - reg: 대상 EEPROM 레지스터
// - tx_buf: 전송 데이터
// - tx_len: 데이터 길이
// 반환값: 0 (성공), -1 (오류)
int pga302_generic_eeprom_write(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *tx_buf, uint8_t tx_len)
{
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// EEPROM 캐시 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_EEPROM_CACHE_CELLS) != 0) return -1;
// 데이터 쓰기
return pga302_generic_write(hi2c, temp_slave_address, reg, tx_buf, tx_len);
}
// pga302_generic_eeprom_read: EEPROM에서 데이터 읽기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - reg: 대상 EEPROM 레지스터
// - rx_buf: 수신 데이터 저장 버퍼
// - rx_len: 데이터 길이
// 반환값: 0 (성공), -1 (오류)
int pga302_generic_eeprom_read(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *rx_buf, uint8_t rx_len)
{
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// EEPROM 캐시 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_EEPROM_CACHE_CELLS) != 0) return -1;
// 데이터 읽기
return pga302_generic_read(hi2c, temp_slave_address, reg, rx_buf, rx_len);
}
// pga302_generic_test_page_write: 테스트 페이지에 데이터 쓰기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - reg: 대상 테스트 페이지 레지스터
// - tx_buf: 전송 데이터
// - tx_len: 데이터 길이
// 반환값: 0 (성공), -1 (오류)
int pga302_generic_test_page_write(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *tx_buf, uint8_t tx_len)
{
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 테스트 레지스터 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_TEST_REG) != 0) return -1;
// 데이터 쓰기
return pga302_generic_write(hi2c, temp_slave_address, reg, tx_buf, tx_len);
}
// pga302_generic_test_page_read: 테스트 페이지에서 데이터 읽기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - reg: 대상 테스트 페이지 레지스터
// - rx_buf: 수신 데이터 저장 버퍼
// - rx_len: 데이터 길이
// 반환값: 0 (성공), -1 (오류)
int pga302_generic_test_page_read(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t reg, uint8_t *rx_buf, uint8_t rx_len)
{
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 테스트 레지스터 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_TEST_REG) != 0) return -1;
// 데이터 읽기
return pga302_generic_read(hi2c, temp_slave_address, reg, rx_buf, rx_len);
}
// pga302_set_memory_page_slave_addr: 메모리 페이지 설정 및 슬레이브 주소 업데이트
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소 포인터 (업데이트됨)
// - memory_page: 설정할 메모리 페이지 (테스트, 제어/상태, EEPROM 등)
// 반환값: 0 (성공), -1 (잘못된 페이지)
int pga302_set_memory_page_slave_addr(I2C_HandleTypeDef *hi2c, uint8_t *slave_address, uint8_t memory_page)
{
// 유효한 메모리 페이지인지 확인
if ((memory_page == PGA302_SET_MEMORY_PAGE_TEST_REG) ||
(memory_page == PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG) ||
(memory_page == PGA302_SET_MEMORY_PAGE_EEPROM_CACHE_CELLS) ||
(memory_page == PGA302_SET_MEMORY_PAGE_CTRL_AND_STATUS_REG)) {
*slave_address = memory_page; // 슬레이브 주소를 메모리 페이지로 업데이트
return 0; // 성공
}
return -1; // 잘못된 페이지
}
// pga302_accesses_controller: 컨트롤러 액세스 설정
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// 반환값: 0 (성공), -1 (오류)
int pga302_accesses_controller(I2C_HandleTypeDef *hi2c, uint8_t slave_address)
{
uint8_t tx_buf[1] = {PGA302_SET_IF_SEL_ACCESSES_CONTROLLER}; // 컨트롤러 액세스 설정값
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 테스트 레지스터 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_TEST_REG) != 0) return -1;
// 인터페이스 제어 레지스터에 쓰기
return pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_TEST_MICRO_INTERFACE_CONTROL, tx_buf, 1);
}
// pga302_accesses_digital_interface_control: 디지털 인터페이스(I2C/OWI) 액세스 설정
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// 반환값: 0 (성공), -1 (오류)
int pga302_accesses_digital_interface_control(I2C_HandleTypeDef *hi2c, uint8_t slave_address)
{
uint8_t tx_buf[1] = {PGA302_SET_IF_SEL_ACCESSES_DIGITAL_INTERFACE}; // 디지털 인터페이스 설정값
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 테스트 레지스터 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_TEST_REG) != 0) return -1;
// 인터페이스 제어 레지스터에 쓰기
return pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_TEST_MICRO_INTERFACE_CONTROL, tx_buf, 1);
}
// pga302_soft_reset: PGA302 소프트 리셋 수행
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// 반환값: 0 (성공), -1 (오류)
int pga302_soft_reset(I2C_HandleTypeDef *hi2c, uint8_t slave_address)
{
uint8_t tx_buf[1] = {PGA302_SOFT_RESET}; // 소프트 리셋 명령
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 테스트 레지스터 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_TEST_REG) != 0) return -1;
// 인터페이스 제어 레지스터에 리셋 명령 쓰기
return pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_TEST_MICRO_INTERFACE_CONTROL, tx_buf, 1);
}
// pga302_set_p_gain: 압력 게인 설정
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - p_gain: 압력 게인 값 (0~7, 1.33~200V/V)
// 반환값: 0 (성공), -1 (잘못된 게인 또는 I2C 오류)
int pga302_set_p_gain(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t p_gain)
{
if (p_gain < 8) { // 유효한 게인 값인지 확인
uint8_t rx_buf; // 현재 레지스터 값 저장
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 제어/상태 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG) != 0) return -1;
// 현재 압력 게인 레지스터 읽기
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_P_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
rx_buf &= PGA302_P_GAIN_BIT_MASK; // 기존 비트 마스크 적용
rx_buf |= p_gain; // 새로운 게인 값 적용
// 업데이트된 값 쓰기
if (pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_P_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
return 0; // 성공
}
return -1; // 잘못된 게인 값
}
// pga302_set_t_gain: 온도 게인 설정
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - t_gain: 온도 게인 값 (0~7, 1.33~200V/V)
// 반환값: 0 (성공), -1 (잘못된 게인 또는 I2C 오류)
int pga302_set_t_gain(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t t_gain)
{
if (t_gain < 8) { // 유효한 게인 값인지 확인
uint8_t rx_buf; // 현재 레지스터 값 저장
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 제어/상태 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG) != 0) return -1;
// 현재 온도 게인 레지스터 읽기
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_T_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
rx_buf &= PGA302_T_GAIN_BIT_MASK; // 기존 비트 마스크 적용
rx_buf |= t_gain; // 새로운 게인 값 적용
// 업데이트된 값 쓰기
if (pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_T_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
return 0; // 성공
}
return -1; // 잘못된 게인 값
}
// pga302_set_temp_mode: 온도 모드 설정 (단일/차동)
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - t_mode: 온도 모드 (0: 단일, 1: 차동)
// 반환값: 0 (성공), -1 (잘못된 모드 또는 I2C 오류)
int pga302_set_temp_mode(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t t_mode)
{
if (t_mode == PGA302_SET_TSEM_MODE_SINGLE_ENDED || t_mode == PGA302_SET_TSEM_MODE_DIFFERENTIAL) {
uint8_t rx_buf; // 현재 레지스터 값 저장
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 제어/상태 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG) != 0) return -1;
// 현재 온도 게인 레지스터 읽기 (온도 모드는 동일 레지스터에 저장)
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_T_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
rx_buf &= PGA302_TEMP_MODE_BIT_MASK; // 기존 비트 마스크 적용
t_mode <<= 3; // 비트 위치 조정
rx_buf |= t_mode; // 새로운 모드 적용
// 업데이트된 값 쓰기
if (pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_T_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
return 0; // 성공
}
return -1; // 잘못된 모드
}
// pga302_set_t_mux_ctrl: 온도 MUX 제어 설정
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - t_mux_ctrl: MUX 제어 값 (외부/내부 온도, 테스트 등)
// 반환값: 0 (성공), -1 (잘못된 MUX 값 또는 I2C 오류)
int pga302_set_t_mux_ctrl(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t t_mux_ctrl)
{
if (t_mux_ctrl <= PGA302_SET_T_MUX_CTRL_ITEMP) { // 유효한 MUX 값인지 확인
uint8_t rx_buf; // 현재 레지스터 값 저장
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 제어/상태 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG) != 0) return -1;
// 현재 온도 게인 레지스터 읽기 (MUX 제어는 동일 레지스터에 저장)
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_T_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
rx_buf &= PGA302_T_MUX_CTRL_BIT_MASK; // 기존 비트 마스크 적용
t_mux_ctrl <<= 4; // 비트 위치 조정
rx_buf |= t_mux_ctrl; // 새로운 MUX 값 적용
// 업데이트된 값 쓰기
if (pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_T_GAIN_SELECT, &rx_buf, 1) != 0) return -1;
return 0; // 성공
}
return -1; // 잘못된 MUX 값
}
// pga302_itemp_ctrl: 온도 센서 전류 제어 설정
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - itemp_ctrl: 전류 제어 값 (50μA~1000μA 또는 끄기)
// 반환값: 0 (성공), -1 (잘못된 전류 값 또는 I2C 오류)
int pga302_itemp_ctrl(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t itemp_ctrl)
{
if (itemp_ctrl < 5) { // 유효한 전류 제어 값인지 확인
uint8_t rx_buf; // 현재 레지스터 값 저장
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 제어/상태 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG) != 0) return -1;
// 현재 온도 제어 레지스터 읽기
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_TEMP_CTRL, &rx_buf, 1) != 0) return -1;
rx_buf &= PGA302_ITEMP_CTRL_BIT_MASK; // 기존 비트 마스크 적용
itemp_ctrl <<= 4; // 비트 위치 조정
rx_buf |= itemp_ctrl; // 새로운 전류 값 적용
// 업데이트된 값 쓰기
if (pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_TEMP_CTRL, &rx_buf, 1) != 0) return -1;
return 0; // 성공
}
return -1; // 잘못된 전류 값
}
// pga302_set_offset: 오프셋 보상 설정
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// - offset_cancel_val: 오프셋 값 (0~54.75mV, 16단계)
// - offset_cancel_sel: 오프셋 선택 (VINP-N 또는 VINP-P)
// 반환값: 0 (성공), -1 (잘못된 오프셋 값 또는 I2C 오류)
int pga302_set_offset(I2C_HandleTypeDef *hi2c, uint8_t slave_address, uint8_t offset_cancel_val, uint8_t offset_cancel_sel)
{
if (offset_cancel_val < 16 && offset_cancel_sel < 2) { // 유효한 오프셋 값과 선택인지 확인
uint8_t rx_buf; // 현재 레지스터 값 저장
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 제어/상태 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_CONTROL_AND_STATUS_REG) != 0) return -1;
// 현재 온도 제어 레지스터 읽기 (오프셋은 동일 레지스터에 저장)
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_TEMP_CTRL, &rx_buf, 1) != 0) return -1;
rx_buf &= PGA302_OFFSET_BIT_MASK; // 기존 비트 마스크 적용
offset_cancel_sel <<= 4; // 오프셋 선택 비트 위치 조정
rx_buf |= offset_cancel_sel; // 오프셋 선택 적용
rx_buf |= offset_cancel_val; // 오프셋 값 적용
// 업데이트된 값 쓰기
if (pga302_generic_write(hi2c, temp_slave_address, PGA302_REG_CTRL_STATUS_TEMP_CTRL, &rx_buf, 1) != 0) return -1;
return 0; // 성공
}
return -1; // 잘못된 오프셋 값 또는 선택
}
// pga302_get_p_adc_data: 압력 ADC 데이터 읽기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// 반환값: 16비트 압력 ADC 데이터 (오류 시 0)
int16_t pga302_get_p_adc_data(I2C_HandleTypeDef *hi2c, uint8_t slave_address)
{
uint8_t lsb, msb; // LSB와 MSB 데이터
int16_t result; // 최종 16비트 데이터
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 테스트 레지스터 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_TEST_REG) != 0) return 0;
// 압력 ADC 데이터 LSB 읽기
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_TEST_PADC_DATA_1, &lsb, 1) != 0) return 0;
// 압력 ADC 데이터 MSB 읽기
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_TEST_PADC_DATA_2, &msb, 1) != 0) return 0;
result = msb; // MSB를 상위 8비트로 설정
result <<= 8; // 8비트 왼쪽 시프트
result |= lsb; // LSB를 하위 8비트로 결합
return result; // 16비트 데이터 반환
}
// pga302_get_t_adc_data: 온도 ADC 데이터 읽기
// 매개변수:
// - hi2c: I2C 핸들
// - slave_address: 슬레이브 주소
// 반환값: 16비트 온도 ADC 데이터 (오류 시 0)
int16_t pga302_get_t_adc_data(I2C_HandleTypeDef *hi2c, uint8_t slave_address)
{
uint8_t lsb, msb; // LSB와 MSB 데이터
int16_t result; // 최종 16비트 데이터
uint8_t temp_slave_address = slave_address; // 임시 슬레이브 주소
// 테스트 레지스터 페이지 설정
if (pga302_set_memory_page_slave_addr(hi2c, &temp_slave_address, PGA302_SET_MEMORY_PAGE_TEST_REG) != 0) return 0;
// 온도 ADC 데이터 LSB 읽기
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_TEST_TADC_DATA_1, &lsb, 1) != 0) return 0;
// 온도 ADC 데이터 MSB 읽기
if (pga302_generic_read(hi2c, temp_slave_address, PGA302_REG_TEST_TADC_DATA_2, &msb, 1) != 0) return 0;
result = msb; // MSB를 상위 8비트로 설정
result <<= 8; // 8비트 왼쪽 시프트
result |= lsb; // LSB를 하위 8비트로 결합
return result; // 16비트 데이터 반환
}
STM32CubeMX 설정
I2C 설정 (I2C Configuration):
- I2C1 활성화 (SCL: PB6, SDA: PB7) (Enable I2C1 (SCL: PB6, SDA: PB7)).
- 속도: 100kHz (타이밍 값: 0x10808BDF, 48MHz 클럭 기준) 또는 400kHz (0x00D07BFF)
- 주소 모드: 7비트, 나머지 설정은 기본값
GPIO 설정 (선택적) (GPIO Configuration (Optional)):
- PA0을 입력 모드로 설정 (풀업/풀다운 없음)
- 사용하지 않을 경우 pga302_init 호출 시 an_port=NULL, an_pin=GPIO_PIN_RESET으로 설정
클럭 설정 (Clock Configuration):
- 시스템 클럭: 48MHz (I2C 타이밍 값 기준)
- I2C 클럭 활성화: __HAL_RCC_I2C1_CLK_ENABLE()
프로젝트 설정 (Project Configuration):
- STM32CubeMX로 프로젝트 생성 후 stm32l4xx_hal.h 포함
- pga302.h와 pga302.c를 프로젝트에 추가
사용 예제
다음은 드라이버를 사용하여 PGA302를 초기화하고 압력 및 온도 ADC 데이터를 읽는 예제 코드
#include "pga302.h"
I2C_HandleTypeDef hi2c1; // 전역 I2C 핸들 선언
// 시스템 클럭 설정 함수 (STM32CubeMX에서 생성)
void SystemClock_Config(void); // 사용자 정의 필요
int main(void)
{
HAL_Init(); // HAL 라이브러리 초기화
SystemClock_Config(); // 시스템 클럭 설정 (48MHz 기준)
// I2C 초기화
hi2c1.Instance = I2C1; // I2C1 포트 사용
hi2c1.Init.Timing = 0x10808BDF; // 100kHz, 48MHz 클럭 기준
hi2c1.Init.OwnAddress1 = 0; // 마스터 모드
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7비트 주소
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; // 듀얼 주소 비활성화
hi2c1.Init.OwnAddress2 = 0; // 두 번째 주소 사용 안 함
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; // 일반 호출 비활성화
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // 클럭 스트레칭 활성화
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
while (1); // I2C 초기화 실패 시 무한 루프
}
// PGA302 초기화 (PA0 사용)
if (pga302_init(&hi2c1, 100000, PGA302_SET_DEV_ADDR, GPIOA, GPIO_PIN_0) != 0) {
while (1); // 초기화 실패 시 무한 루프
}
// PGA302 기본 설정 적용
if (pga302_Config(&hi2c1, PGA302_SET_DEV_ADDR) != 0) {
while (1); // 설정 실패 시 무한 루프
}
// 메인 루프
while (1) {
// 압력 ADC 데이터 읽기
int16_t p_adc = pga302_get_p_adc_data(&hi2c1, PGA302_SET_DEV_ADDR);
// 온도 ADC 데이터 읽기
int16_t t_adc = pga302_get_t_adc_data(&hi2c1, PGA302_SET_DEV_ADDR);
// 데이터 처리 (예: 시리얼 출력, 디스플레이 등)
HAL_Delay(1000); // 1초 대기
}
}
코드 구현 상세 설명
- 초기화 (pga302_init) :
- I2C1을 설정하고, 선택적 아날로그 핀(PA0)을 초기화.
- I2C 속도는 100kHz(0x10808BDF) 또는 400kHz(0x00D07BFF)로 설정.
- 성공 시 0, 실패 시 -1을 반환.
- 기본 설정 (pga302_Config) :
- 소프트 리셋, 디지털 인터페이스 액세스, 압력/온도 게인(200V/V), 차동 온도 모드, 내부 온도 센서 설정을 순차적으로 적용.
- 각 설정 사이에 HAL_Delay(100)로 100ms 지연을 추가.
- hi2c와 slave_address를 인자로 받아 전역 변수 없이 동작.
- 성공 시 0, 실패 시 -1을 반환.
- I2C 읽기/쓰기 (pga302_generic_read, pga302_generic_write) :
- HAL 라이브러리의 HAL_I2C_Master_Transmit와 HAL_I2C_Master_Receive를 사용.
- 슬레이브 주소는 7비트로 왼쪽 시프트(<< 1) 처리.
- 성공 시 0, 실패 시 -1을 반환.
- EEPROM 및 테스트 페이지 접근 :
- pga302_generic_eeprom_read/write와 pga302_generic_test_page_read/write는 메모리 페이지 설정 후 읽기/쓰기를 수행 .
- 페이지 설정은 pga302_set_memory_page_slave_addr로 처리.
- 설정 함수:
- pga302_set_p_gain, pga302_set_t_gain: 압력 및 온도 게인 설정(1.33~200V/V).
- pga302_set_temp_mode: 단일/차동 온도 모드 설정 .
- pga302_set_t_mux_ctrl: 온도 MUX 제어(외부/내부 센서 등) .
- pga302_itemp_ctrl: 전류 제어(50μA~1000 μA 또는 off).
- pga302_set_offset: 오프셋 조정(05~4.75mV).
- 모든 함수는 성공 시 0, 실패 시 -1을 반환.
- 데이터 읽기 :
- pga302_get_p_adc_data, pga302_get_t_adc_data: 16비트 압력 및 온도 ADC 데이터를 읽어 반환.
- 오류 발생 시 0을 반환 (데이터 무효).
주의사항 (Precautions)
- I2C 타이밍 (I2C Timing): 0x10808BDF(100kHz)와 0x00D07BFF(400kHz)는 48MHz 클럭 기준입니다. STM32CubeMX로 시스템 클럭에 맞게 조정.
- 아날로그 핀 (Analog Pin): 선택적이며, 사용하지 않을 경우 pga302_init 호출 시 an_port=NULL, an_pin=GPIO_PIN_RESET으로 설정
- 타임아웃 (Timeout): HAL_MAX_DELAY는 단순화를 위해 사용됩니다. 실제 프로젝트에서는 적절한 타임아웃 값(예: 100ms)을 지정하는 것이 권장.
- 다중 장치 (Multiple Devices): 여러 PGA302 장치를 사용할 경우, 각 함수 호출 시 적절한 slave_address를 전달.
- 에러 처리 (Error Handling): 반환 값(0 = 성공, -1 = 오류)을 확인하여 I2C 통신 오류 처리
- 지연 관리 (Delay Management): pga302_Config는 내부적으로 HAL_Delay(100)을 사용합니다. 추가 지연이 필요한 경우 호출자가 HAL_Delay()로 관리.
디버깅 팁 (Debugging Tips)
- I2C 통신 실패 시, STM32CubeMX에서 I2C 핀과 클럭 설정을 확인
- pga302_generic_read/write의 반환 값을 로깅하여 오류 원인을 파악
- PGA302 데이터시트와 레지스터 맵을 참조하여 설정 값을 검증
- 아날로그 입력(PA0) 사용 시, GPIO 상태를 모니터링하여 올바른 입력을 확인
참고 (References)
- 데이터시트: Texas Instruments PGA302 데이터시트 (665KB, 74페이지)
- 평가 모듈: PGA302EVM-037 (단종) .
'아날로그회로(Analog Circuit) > ADC관련' 카테고리의 다른 글
ADS124S08 24비트 ADC STM32 HAL 기반 디바이스 드라이버 구현 (1) | 2025.08.28 |
---|---|
ZSC31015 Sensor Signal Conditioner IC 드라이버 구현: STM32를 활용한 Zacwire 인터페이싱 (4) | 2025.08.25 |
ADS114S08 16비트 ADC STM32 HAL 기반 디바이스 드라이버 구현 (0) | 2025.08.24 |
PT100/PT1000 RTD 센서용 MAX31865 온도 변환 IC STM32 디바이스 드라이버 구현 (3) | 2025.08.24 |
ZSC31050 Sensor Signal Conditioner IC STM32용 I2C 드라이버 구현 (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 측정 설정 절차 및 I2C 코드 (0) | 2025.08.15 |