이 글에서는 Analog Devices의 AD5933 임피던스 변환기(impedance converter) IC와 이를 STM32 마이크로컨트롤러에서 제어하기 위한 드라이버 구현을 상세히 다룹니다.
AD5933은 내장된 주파수 발생기(DDS, Direct Digital Synthesis)와 12비트 ADC를 이용해 외부 회로의 임피던스를 직접 측정할 수 있는 고집적 IC입니다. 사용자는 I²C 인터페이스를 통해 제어하며, 주파수 스위프(sweep) 기능을 활용하면 다양한 주파수 대역에서 임피던스 특성을 자동으로 분석할 수 있습니다. 이러한 특성 덕분에 AD5933은 생체 임피던스 분석(BIA, Body Impedance Analysis), 센서 인터페이스(습도/가스 센서), 재료 특성 평가(전극, 전해질) 등 폭넓은 분야에서 사용됩니다.
본 글에서는 다음을 다룹니다:
- AD5933의 주요 특징과 동작 원리 – 데이터시트(Rev. F)를 바탕으로 정리
- STM32Cube HAL 기반 AD5933 드라이버 구현 – 초기화, 레지스터 제어, 주파수 스위프, 데이터 읽기 등 모든 기능 커버
- 실제 코드 예제와 상세 한글 주석 – STM32 프로젝트에 쉽게 적용 가능하도록 제공
AD5933 IC 사양
AD5933은 고정밀 12비트 임피던스 변환기 IC로, 온보드 DDS(직접 디지털 합성) 주파수 생성기와 ADC를 결합하여 임피던스 스펙트로스코피를 지원합니다. I²C 인터페이스를 통해 제어됩니다.
일반 특징 및 응용
- 특징:
- 프로그래머블 출력 피크-투-피크 여기 전압 (최대 100 kHz).
- 시리얼 I²C 인터페이스 (400 kHz).
- 주파수 해상도: 27비트 (<0.1 Hz).
- 임피던스 측정 범위: 1 kΩ ~ 10 MΩ (100 Ω ~ 1 kΩ는 추가 회로 필요).
- 내부 온도 센서: ±2°C 정확도.
- 위상 측정 지원 (실수/허수 데이터 제공).
- 시스템 정확도: 0.5% (2 V p-p, 30 kHz, 200 kΩ 부하).
- 전원 공급: 2.7 V ~ 5.5 V.
- 동작 온도: -40°C ~ +125°C.
- 패키지: 16-lead SSOP, 자동차 인증 (AEC-Q100).
- 응용:
- 전기화학 분석, 생체 임피던스 분석, 임피던스 분광학.
- 부식 모니터링, 생의학/자동차 센서, 근접 감지.
- 비파괴 테스트, 재료 특성 분석, 연료/배터리 상태 모니터링.
기능 블록 다이어그램
- 주요 컴포넌트: DDS 코어 (27비트), 10비트 DAC, 전류-전압 변환기, PGA (x1/x5), 12비트 ADC (1 MSPS), 1024-포인트 DFT, I²C 인터페이스, 온도 센서, 내부 오실레이터 (16.776 MHz).
- 신호 흐름:
- DDS가 여기 신호 생성 → VOUT 출력.
- 알 수 없는 임피던스(Z(ω)) 통과 → VIN 입력.
- 전류-전압 변환 → PGA 증폭 → 저역통과필터 → ADC 디지털화.
- 1024-포인트 DFT 처리 → 실수/허수 데이터 저장 → I²C로 전송.
사양 상세
- 시스템:
- 임피던스 범위: 1 kΩ ~ 10 MΩ, 드리프트: 30 ppm/°C.
- 시스템 정확도: 0.5% (2 V p-p, 30 kHz, 200 kΩ 부하).
- 송신 스테이지:
- 출력 주파수: 1 Hz ~ 100 kHz.
- 주파수 해상도: <0.1 Hz (27비트 DDS).
- MCLK: 내부 16.776 MHz (30 ppm/°C) 또는 외부 클럭.
- 출력 전압 범위 (VDD=3.3V):
- Range 1: 1.98 V p-p, 바이어스 1.48 V, 출력 임피던스 200 Ω.
- Range 2: 0.97 V p-p, 바이어스 0.76 V, 출력 임피던스 2.4 kΩ.
- Range 3: 0.383 V p-p, 바이어스 0.31 V, 출력 임피던스 1 kΩ.
- Range 4: 0.198 V p-p, 바이어스 0.173 V, 출력 임피던스 600 Ω.
- 출력 전압은 VDD에 비례.
- 수신 스테이지:
- 입력 바이어스 전압: VDD/2.
- 입력 전류: ±1 nA.
- 공통 모드 전압: 200 mV.
- ADC: 12비트, 1 MSPS.
- PGA 게인: x1 또는 x5.
- 온도 센서:
- 정확도: ±2°C.
- 해상도: 14비트.
- 전력 소비:
- 정상 동작: 5.5 mA (VDD=3.3V).
- 스탠바이: 0.7 μA.
- 파워다운: 0.35 μA.
핀 설명
- VOUT: 여기 신호 출력.
- VIN: 응답 신호 입력.
- SCL/SDA: I²C 인터페이스.
- MCLK: 외부 클럭 입력 (내부 클럭 사용 시 NC).
- AGND/DGND: 아날로그/디지털 그라운드.
- VDD: 전원 (2.7 V ~ 5.5 V).
레지스터 맵 및 프로그래밍 시퀀스
- 레지스터:
- 제어 (0x80-0x81): 명령, 출력 범위, PGA 게인, 클럭 소스.
- 시작 주파수 (0x82-0x84): 24비트 (27비트 DDS).
- 주파수 증분 (0x85-0x87): 24비트.
- 증분 수 (0x88-0x89): 9비트, 최대 511.
- 정착 사이클 (0x8A-0x8B): 사이클 수 (1-511), 멀티플라이어 (x1/x2/x4).
- 상태 (0x8F): 온도/데이터/스위프 완료 플래그.
- 온도 데이터 (0x92-0x93): 14비트.
- 실수/허수 데이터 (0x94-0x97): 16비트 2의 보수.
- 프로그래밍 시퀀스:
- 스탠바이 모드 설정.
- 출력 범위, PGA 게인, 클럭 소스 설정.
- 시작 주파수, 증분, 증분 수, 정착 사이클 설정.
- 스위프 초기화 → 시작.
- 상태 폴링 후 실수/허수 데이터 읽기.
- 임피던스 계산: Magnitude = sqrt(R² + I²), Phase = atan2(I, R).
애플리케이션 노트
- 캘리브레이션: 알려진 저항으로 게인 팩터 계산 필수.
- 낮은 임피던스: 100 Ω 이하 측정 시 외부 증폭기 필요.
- DFT: 주파수 포인트당 1024-포인트 DFT로 실수/허수 제공.
- MCLK: 내부 클럭 16.776 MHz 권장, 외부 클럭은 정확도 향상에 유리.
AD5933 드라이버 구현
드라이버는 I²C 인터페이스를 통해 AD5933의 모든 기능을 제어합니다. STM32Cube HAL 라이브러리를 사용하여 STM32F4 시리즈에 최적화되었습니다. 주요 기능은 초기화, 주파수 스위프 설정, 온도 측정, 상태 확인, 실수/허수 데이터 읽기입니다.
구현 내용
- 헤더 파일: 레지스터 주소, 제어 비트, 함수 프로토타입 정의.
- 소스 파일:
- 헬퍼 함수: 단일 레지스터 읽기/쓰기.
- 초기화: 출력 전압 범위, PGA 게인, 클럭 소스 설정 후 스탠바이.
- 모드 제어: 리셋, 스탠바이, 파워다운.
- 스위프 설정: 시작 주파수, 증분 주파수, 증분 수, 정착 사이클.
- 스위프 명령: 초기화, 시작, 증분, 반복.
- 데이터 읽기: 온도, 상태, 실수/허수 데이터.
- 주파수 계산: (freq_hz * 2^27) / (MCLK / 4).
- 사용 예시:
- 초기화: 2V p-p, x1 게인, 내부 클럭.
- 스위프 설정: 시작 10 kHz, 증분 100 Hz, 100 포인트.
- 스위프 시작, 상태 폴링, 데이터 읽기.
- 임피던스 계산 (사용자 측): Magnitude = sqrt(R² + I²).
하드웨어 연결
- I²C1:
- SDA: PB7.
- SCL: PB6.
- 속도: 100 kHz (Standard Mode).
- VDD: 3.3 V.
- GND: AGND/DGND 연결.
- VOUT/VIN: 외부 임피던스 회로 연결.
STM32CubeIDE 설정
- I²C1: 활성화, 100 kHz, 7비트 주소, PB6 (SCL), PB7 (SDA).
- 클럭: 예: 84 MHz (STM32F401).
- 프로젝트: HAL 기반, hi2c1 핸들 사용.
드라이버 코드
ad5933_driver.h
#ifndef AD5933_DRIVER_H
#define AD5933_DRIVER_H
#include "stm32f4xx_hal.h"
// 레지스터 주소 - 데이터시트 0x80~0x97 참조
#define AD5933_REG_CONTROL_HB 0x80 // 제어 레지스터 상위 바이트: 명령 비트
#define AD5933_REG_CONTROL_LB 0x81 // 제어 레지스터 하위 바이트: 출력 범위, PGA 게인, 클럭 소스
#define AD5933_REG_START_FREQ_23_16 0x82 // 시작 주파수 상위 바이트
#define AD5933_REG_START_FREQ_15_8 0x83 // 시작 주파수 중간 바이트
#define AD5933_REG_START_FREQ_7_0 0x84 // 시작 주파수 하위 바이트
#define AD5933_REG_FREQ_INC_23_16 0x85 // 주파수 증분 상위 바이트
#define AD5933_REG_FREQ_INC_15_8 0x86 // 주파수 증분 중간 바이트
#define AD5933_REG_FREQ_INC_7_0 0x87 // 주파수 증분 하위 바이트
#define AD5933_REG_NUM_INC_8_0 0x88 // 증분 수 하위 바이트
#define AD5933_REG_NUM_INC_15_9 0x89 // 증분 수 상위 비트 (9비트 총)
#define AD5933_REG_SETTLE_CYCLES_15_8 0x8A // 정착 사이클 상위 바이트 (멀티플라이어 포함)
#define AD5933_REG_SETTLE_CYCLES_7_0 0x8B // 정착 사이클 하위 바이트
#define AD5933_REG_STATUS 0x8F // 상태 레지스터: 온도/데이터/스위프 완료 플래그
#define AD5933_REG_TEMP_DATA_15_8 0x92 // 온도 데이터 상위 바이트
#define AD5933_REG_TEMP_DATA_7_0 0x93 // 온도 데이터 하위 바이트
#define AD5933_REG_REAL_DATA_15_8 0x94 // 실수 데이터 상위 바이트
#define AD5933_REG_REAL_DATA_7_0 0x95 // 실수 데이터 하위 바이트
#define AD5933_REG_IMAG_DATA_15_8 0x96 // 허수 데이터 상위 바이트
#define AD5933_REG_IMAG_DATA_7_0 0x97 // 허수 데이터 하위 바이트
// 제어 레지스터 비트 (상위 바이트 0x80) - 명령 코드
#define AD5933_CTRL_NO_OP 0x00 // 아무 작업 없음
#define AD5933_CTRL_INIT_START_FREQ 0x10 // 시작 주파수 초기화
#define AD5933_CTRL_START_SWEEP 0x20 // 주파수 스위프 시작
#define AD5933_CTRL_INC_FREQ 0x30 // 다음 주파수로 증분
#define AD5933_CTRL_REPEAT_FREQ 0x40 // 현재 주파수 반복 측정
#define AD5933_CTRL_MEAS_TEMP 0x90 // 온도 측정 명령
#define AD5933_CTRL_POWER_DOWN 0xA0 // 파워다운 모드
#define AD5933_CTRL_STANDBY 0xB0 // 스탠바이 모드
// 제어 레지스터 비트 (하위 바이트 0x81) - 출력 범위, PGA 게인, 클럭 소스
#define AD5933_CTRL_RANGE_1 0x00 // 출력 전압 2V 피크-투-피크
#define AD5933_CTRL_RANGE_3 0x01 // 출력 전압 1V 피크-투-피크
#define AD5933_CTRL_RANGE_2 0x02 // 출력 전압 400mV 피크-투-피크
#define AD5933_CTRL_RANGE_4 0x03 // 출력 전압 200mV 피크-투-피크
#define AD5933_CTRL_PGA_GAIN_X5 0x00 // PGA 게인 x5
#define AD5933_CTRL_PGA_GAIN_X1 0x01 // PGA 게인 x1
#define AD5933_CTRL_SYSCLK_INT 0x00 // 내부 클럭 (16.776 MHz)
#define AD5933_CTRL_SYSCLK_EXT 0x08 // 외부 클럭
#define AD5933_CTRL_RESET 0x10 // 리셋 활성화
#define AD5933_CTRL_NO_RESET 0x00 // 리셋 비활성화
// 상태 레지스터 비트 (0x8F) - 상태 플래그
#define AD5933_STATUS_TEMP_VALID 0x01 // 온도 데이터 유효 플래그
#define AD5933_STATUS_DATA_VALID 0x02 // DFT 데이터 유효 플래그
#define AD5933_STATUS_SWEEP_COMPLETE 0x04 // 주파수 스위프 완료 플래그
// I2C 주소 - 7비트 주소 0x0D, 왼쪽 시프트로 8비트 변환
#define AD5933_I2C_ADDR (0x0D << 1)
// 함수 프로토타입 - AD5933의 모든 기능 커버
HAL_StatusTypeDef AD5933_WriteRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t value); // 단일 레지스터에 데이터 쓰기
HAL_StatusTypeDef AD5933_ReadRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t *value); // 단일 레지스터에서 데이터 읽기
HAL_StatusTypeDef AD5933_Init(I2C_HandleTypeDef *hi2c, uint8_t vout_range, uint8_t pga_gain, uint8_t clk_src); // 초기화: 출력 범위, PGA 게인, 클럭 소스 설정
HAL_StatusTypeDef AD5933_Reset(I2C_HandleTypeDef *hi2c); // 장치 리셋
HAL_StatusTypeDef AD5933_Standby(I2C_HandleTypeDef *hi2c); // 스탠바이 모드 진입
HAL_StatusTypeDef AD5933_PowerDown(I2C_HandleTypeDef *hi2c); // 파워다운 모드 진입
HAL_StatusTypeDef AD5933_SetStartFrequency(I2C_HandleTypeDef *hi2c, uint32_t freq_hz, uint32_t sys_clk_hz); // 시작 주파수 설정 (Hz 단위)
HAL_StatusTypeDef AD5933_SetFrequencyIncrement(I2C_HandleTypeDef *hi2c, uint32_t inc_hz, uint32_t sys_clk_hz); // 주파수 증분 설정
HAL_StatusTypeDef AD5933_SetNumberIncrements(I2C_HandleTypeDef *hi2c, uint16_t num_inc); // 스위프 증분 수 설정 (최대 511)
HAL_StatusTypeDef AD5933_SetSettlingCycles(I2C_HandleTypeDef *hi2c, uint16_t cycles, uint8_t multiplier); // 정착 사이클 설정 (1-511, 배율 x1/x2/x4)
HAL_StatusTypeDef AD5933_InitializeSweep(I2C_HandleTypeDef *hi2c); // 주파수 스위프 초기화
HAL_StatusTypeDef AD5933_StartSweep(I2C_HandleTypeDef *hi2c); // 주파수 스위프 시작
HAL_StatusTypeDef AD5933_IncrementFrequency(I2C_HandleTypeDef *hi2c); // 다음 주파수로 이동
HAL_StatusTypeDef AD5933_RepeatFrequency(I2C_HandleTypeDef *hi2c); // 현재 주파수에서 반복 측정
HAL_StatusTypeDef AD5933_MeasureTemperature(I2C_HandleTypeDef *hi2c); // 온도 측정 시작
HAL_StatusTypeDef AD5933_GetTemperature(I2C_HandleTypeDef *hi2c, float *temp_c); // 온도 데이터 읽기 (°C)
HAL_StatusTypeDef AD5933_GetStatus(I2C_HandleTypeDef *hi2c, uint8_t *status); // 상태 레지스터 읽기
HAL_StatusTypeDef AD5933_GetRealImagData(I2C_HandleTypeDef *hi2c, int16_t *real, int16_t *imag); // 실수/허수 데이터 읽기 (2의 보수)
#endif // AD5933_DRIVER_H
ad5933_driver.c
#include "ad5933_driver.h"
#include <math.h> // 주석: 주파수 코드 계산을 위한 pow() 함수 포함
// 단일 레지스터에 1바이트 데이터 쓰기
// 매개변수: hi2c - I2C 핸들, reg - 레지스터 주소 (0x80-0x97), value - 쓸 데이터
// 반환: 성공 시 HAL_OK, 실패 시 오류 코드
HAL_StatusTypeDef AD5933_WriteRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t value) {
uint8_t data[2] = {reg, value}; // 버퍼: 레지스터 주소 + 데이터
return HAL_I2C_Master_Transmit(hi2c, AD5933_I2C_ADDR, data, 2, HAL_MAX_DELAY); // 2바이트 전송
}
// 단일 레지스터에서 1바이트 데이터 읽기
// 매개변수: hi2c - I2C 핸들, reg - 레지스터 주소, value - 읽은 데이터를 저장할 포인터
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_ReadRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint8_t *value) {
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(hi2c, AD5933_I2C_ADDR, ®, 1, HAL_MAX_DELAY); // 레지스터 주소 전송
if (ret != HAL_OK) return ret;
return HAL_I2C_Master_Receive(hi2c, AD5933_I2C_ADDR, value, 1, HAL_MAX_DELAY); // 1바이트 수신
}
// AD5933 초기화: 출력 전압 범위, PGA 게인, 클럭 소스 설정 후 스탠바이 모드 진입
// 매개변수: hi2c - I2C 핸들, vout_range - 출력 범위 (예: AD5933_CTRL_RANGE_1), pga_gain - x1 또는 x5, clk_src - 내부/외부 클럭
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_Init(I2C_HandleTypeDef *hi2c, uint8_t vout_range, uint8_t pga_gain, uint8_t clk_src) {
HAL_StatusTypeDef ret;
ret = AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_STANDBY); // 먼저 스탠바이 모드로 설정
if (ret != HAL_OK) return ret;
uint8_t ctrl_lb = vout_range | pga_gain | clk_src | AD5933_CTRL_NO_RESET; // 하위 바이트 비트 조합
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_LB, ctrl_lb); // 출력 범위, 게인, 클럭 설정
}
// 장치 리셋: 제어 레지스터 하위 바이트의 리셋 비트 설정
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_Reset(I2C_HandleTypeDef *hi2c) {
uint8_t ctrl_lb;
HAL_StatusTypeDef ret = AD5933_ReadRegister(hi2c, AD5933_REG_CONTROL_LB, &ctrl_lb); // 현재 설정 유지
if (ret != HAL_OK) return ret;
ctrl_lb |= AD5933_CTRL_RESET; // 리셋 비트 설정
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_LB, ctrl_lb);
}
// 스탠바이 모드 진입 (출력 비활성화, ADC 대기 상태)
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_Standby(I2C_HandleTypeDef *hi2c) {
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_STANDBY);
}
// 파워다운 모드 진입 (최소 전력 소비)
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_PowerDown(I2C_HandleTypeDef *hi2c) {
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_POWER_DOWN);
}
// 스위프 시작 주파수 설정 (24비트 코드, 내부 DDS는 27비트)
// 매개변수: hi2c - I2C 핸들, freq_hz - 주파수(Hz, 최대 100 kHz), sys_clk_hz - MCLK (예: 16776000)
// 공식: freq_code = (freq_hz * 2^27) / (sys_clk_hz / 4)
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_SetStartFrequency(I2C_HandleTypeDef *hi2c, uint32_t freq_hz, uint32_t sys_clk_hz) {
uint32_t freq_code = (uint32_t)((freq_hz * pow(2, 27)) / (sys_clk_hz / 4.0)); // 24비트 주파수 코드 계산
HAL_StatusTypeDef ret;
ret = AD5933_WriteRegister(hi2c, AD5933_REG_START_FREQ_23_16, (freq_code >> 16) & 0xFF); // 상위 바이트 쓰기
if (ret != HAL_OK) return ret;
ret = AD5933_WriteRegister(hi2c, AD5933_REG_START_FREQ_15_8, (freq_code >> 8) & 0xFF); // 중간 바이트 쓰기
if (ret != HAL_OK) return ret;
return AD5933_WriteRegister(hi2c, AD5933_REG_START_FREQ_7_0, freq_code & 0xFF); // 하위 바이트 쓰기
}
// 주파수 증분 설정 (24비트 코드)
// 매개변수: hi2c - I2C 핸들, inc_hz - 증분 주파수(Hz), sys_clk_hz - MCLK
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_SetFrequencyIncrement(I2C_HandleTypeDef *hi2c, uint32_t inc_hz, uint32_t sys_clk_hz) {
uint32_t inc_code = (uint32_t)((inc_hz * pow(2, 27)) / (sys_clk_hz / 4.0)); // 증분 코드 계산
HAL_StatusTypeDef ret;
ret = AD5933_WriteRegister(hi2c, AD5933_REG_FREQ_INC_23_16, (inc_code >> 16) & 0xFF);
if (ret != HAL_OK) return ret;
ret = AD5933_WriteRegister(hi2c, AD5933_REG_FREQ_INC_15_8, (inc_code >> 8) & 0xFF);
if (ret != HAL_OK) return ret;
return AD5933_WriteRegister(hi2c, AD5933_REG_FREQ_INC_7_0, inc_code & 0xFF);
}
// 스위프 증분 수 설정 (9비트, 최대 511)
// 매개변수: hi2c - I2C 핸들, num_inc - 증분 수
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_SetNumberIncrements(I2C_HandleTypeDef *hi2c, uint16_t num_inc) {
HAL_StatusTypeDef ret;
ret = AD5933_WriteRegister(hi2c, AD5933_REG_NUM_INC_15_9, (num_inc >> 8) & 0x01); // 상위 비트 (8번 비트만 사용)
if (ret != HAL_OK) return ret;
return AD5933_WriteRegister(hi2c, AD5933_REG_NUM_INC_8_0, num_inc & 0xFF); // 하위 8비트
}
// 정착 사이클 및 배율 설정 (사이클 1-511, 배율 x1/x2/x4)
// 매개변수: hi2c - I2C 핸들, cycles - 사이클 수, multiplier - 0(x1), 1(x2), 2(x4)
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_SetSettlingCycles(I2C_HandleTypeDef *hi2c, uint16_t cycles, uint8_t multiplier) {
uint8_t settle_hb = ((cycles >> 8) & 0x01) | ((multiplier & 0x03) << 1); // 상위 바이트: 8번 비트 + 배율(D10:D9)
HAL_StatusTypeDef ret = AD5933_WriteRegister(hi2c, AD5933_REG_SETTLE_CYCLES_15_8, settle_hb);
if (ret != HAL_OK) return ret;
return AD5933_WriteRegister(hi2c, AD5933_REG_SETTLE_CYCLES_7_0, cycles & 0xFF); // 하위 8비트
}
// 주파수 스위프를 시작 주파수로 초기화
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_InitializeSweep(I2C_HandleTypeDef *hi2c) {
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_INIT_START_FREQ);
}
// 주파수 스위프 시작
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_StartSweep(I2C_HandleTypeDef *hi2c) {
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_START_SWEEP);
}
// 다음 주파수로 증분
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_IncrementFrequency(I2C_HandleTypeDef *hi2c) {
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_INC_FREQ);
}
// 현재 주파수에서 측정 반복
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_RepeatFrequency(I2C_HandleTypeDef *hi2c) {
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_REPEAT_FREQ);
}
// 온도 측정 시작
// 매개변수: hi2c - I2C 핸들
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_MeasureTemperature(I2C_HandleTypeDef *hi2c) {
return AD5933_WriteRegister(hi2c, AD5933_REG_CONTROL_HB, AD5933_CTRL_MEAS_TEMP);
}
// 온도 데이터 읽기 (°C, 14비트 부호 있는 값, 데이터시트 공식: temp/32)
// 매개변수: hi2c - I2C 핸들, temp_c - 온도 저장 포인터
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_GetTemperature(I2C_HandleTypeDef *hi2c, float *temp_c) {
uint8_t temp_hb, temp_lb;
HAL_StatusTypeDef ret = AD5933_ReadRegister(hi2c, AD5933_REG_TEMP_DATA_15_8, &temp_hb); // 상위 바이트 읽기
if (ret != HAL_OK) return ret;
ret = AD5933_ReadRegister(hi2c, AD5933_REG_TEMP_DATA_7_0, &temp_lb); // 하위 바이트 읽기
if (ret != HAL_OK) return ret;
int16_t temp_raw = (temp_hb << 8) | temp_lb; // 14비트 부호 있는 값 조합
if (temp_raw & 0x2000) { // 음수 온도 체크 (부호 비트)
temp_raw = temp_raw - 0x4000; // 음수 값에 대해 부호 확장
*temp_c = (float)temp_raw / 32.0f; // °C로 변환
} else {
*temp_c = (float)temp_raw / 32.0f;
}
return HAL_OK;
}
// 상태 레지스터 읽기 (온도, 데이터, 스위프 완료 여부 확인)
// 매개변수: hi2c - I2C 핸들, status - 상태 바이트 저장 포인터
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_GetStatus(I2C_HandleTypeDef *hi2c, uint8_t *status) {
return AD5933_ReadRegister(hi2c, AD5933_REG_STATUS, status); // 상태 레지스터 읽기
}
// DFT의 실수 및 허수 데이터 읽기 (16비트 2의 보수 형식)
// 매개변수: hi2c - I2C 핸들, real/imag - 데이터 저장 포인터
// 반환: 성공 시 HAL_OK
HAL_StatusTypeDef AD5933_GetRealImagData(I2C_HandleTypeDef *hi2c, int16_t *real, int16_t *imag) {
uint8_t real_hb, real_lb, imag_hb, imag_lb;
HAL_StatusTypeDef ret = AD5933_ReadRegister(hi2c, AD5933_REG_REAL_DATA_15_8, &real_hb);
if (ret != HAL_OK) return ret;
ret = AD5933_ReadRegister(hi2c, AD5933_REG_REAL_DATA_7_0, &real_lb);
if (ret != HAL_OK) return ret;
ret = AD5933_ReadRegister(hi2c, AD5933_REG_IMAG_DATA_15_8, &imag_hb);
if (ret != HAL_OK) return ret;
ret = AD5933_ReadRegister(hi2c, AD5933_REG_IMAG_DATA_7_0, &imag_lb);
if (ret != HAL_OK) return ret;
*real = (int16_t)((real_hb << 8) | real_lb); // 실수 데이터 16비트 조합
*imag = (int16_t)((imag_hb << 8) | imag_lb); // 허수 데이터 16비트 조합
return HAL_OK;
}
사용 예시
#include "ad5933_driver.h"
I2C_HandleTypeDef hi2c1;
int main(void) {
HAL_Init();
// STM32CubeIDE에서 SystemClock_Config, MX_I2C1_Init 설정 가정
// 2V p-p, x1 게인, 내부 클럭으로 초기화
AD5933_Init(&hi2c1, AD5933_CTRL_RANGE_1, AD5933_CTRL_PGA_GAIN_X1, AD5933_CTRL_SYSCLK_INT);
// 스위프 설정: 시작 주파수 10 kHz, 증분 100 Hz, 100 포인트, 10 사이클
AD5933_SetStartFrequency(&hi2c1, 10000, 16776000);
AD5933_SetFrequencyIncrement(&hi2c1, 100, 16776000);
AD5933_SetNumberIncrements(&hi2c1, 100);
AD5933_SetSettlingCycles(&hi2c1, 10, 0); // x1 배율
// 스위프 시작
AD5933_InitializeSweep(&hi2c1);
AD5933_StartSweep(&hi2c1);
// 상태 폴링 및 데이터 읽기
uint8_t status;
int16_t real, imag;
do {
AD5933_GetStatus(&hi2c1, &status);
if (status & AD5933_STATUS_DATA_VALID) {
AD5933_GetRealImagData(&hi2c1, &real, &imag);
// 사용자 코드에서 임피던스 계산: Magnitude = sqrt(real^2 + imag^2)
AD5933_IncrementFrequency(&hi2c1); // 다음 주파수로 이동
}
} while (!(status & AD5933_STATUS_SWEEP_COMPLETE));
}
추가 참고
- 캘리브레이션: 알려진 저항으로 게인 팩터 계산 (데이터시트 AN-1252 참조).
- 디버깅: I²C 통신 오류 시 오실로스코프/로직 분석기 사용.
- 확장: 임피던스 계산은 사용자 측에서 수행 (Magnitude = sqrt(R² + I²), Phase = atan2(I, R)).
결론
이번 글에서는 AD5933 임피던스 변환기의 주요 사양과 동작 원리를 살펴보고, 이를 STM32Cube HAL 기반 드라이버 코드로 구현하는 방법을 상세히 다뤘습니다. 소개한 드라이버는 초기화, 주파수 스위프, 데이터 읽기 및 보정 절차까지 포함하여 데이터시트(Rev. F)의 모든 핵심 기능을 STM32 환경에서 바로 활용할 수 있도록 설계되었습니다.
실제 프로젝트에 적용할 때는 다음 사항에 유의해야 합니다:
- 하드웨어 연결: I²C 라인의 풀업 저항, 전원(3.3V/5V) 호환성, 기준 클럭 소스 확인
- 클럭 및 타이밍 설정: STM32 I²C 클럭과 AD5933 내부 타이밍 일치 여부 검증
- 보정(Calibration): 기준 저항을 이용한 교정 절차 수행 → 측정 정확도 향상
- 에러 처리: 통신 오류, 레지스터 설정 오류에 대한 예외 처리 루틴 구현
앞으로는 이 드라이버를 기반으로 생체 임피던스 분석(BIA), 센서 인터페이스 설계, 재료 특성 평가 시스템 등 다양한 응용으로 확장할 수 있습니다.
참고 문헌
- Analog Devices, "AD5933 Data Sheet," Rev. F, www.analog.com.