Texas Instruments의 ADS114S08은 저전력, 고정밀 16비트 Delta-Sigma ADC로, 센서 데이터 수집, 의료 기기, 산업용 계측에 이상적입니다. 이 블로그에서는 STM32L432KC 마이크로컨트롤러와 STM32 HAL을 기반으로 ADS114S08 드라이버를 구현하는 방법을 상세히 다룹니다.데이터시트 기반으로 전체 기능을 다 활용할 수 있는 상세 주석이 포함된 완전한 소스 코드, STM32CubeMX 설정 가이드를 제공하며, 초보자부터 숙련된 개발자까지 활용 가능한 실용적인 내용을 담았습니다.
키워드: ADS114S08, STM32, ADC 드라이버, 고정밀 데이터 수집, STM32CubeMX, SPI 인터페이스, Delta-Sigma ADC
ADS114S08 사양
ADS114S08은 저전력 고정밀 애플리케이션에 최적화된 16비트 Delta-Sigma ADC입니다. Texas Instruments 데이터시트(Rev. A, 2017)에 기반한 주요 사양은 다음과 같습니다:
ADC 성능
- 해상도: 16비트 (No Missing Codes).
- 데이터 레이트: 2.5 SPS ~ 4000 SPS (프로그래머블, DATARATE 레지스터).
- 입력 채널: 12개 아날로그 입력(AIN0~AIN11), 싱글 엔드 또는 디퍼런셜 구성.
- 입력 범위: ±VREF/게인 (VREF=참조 전압, 게인=1~128).
- 잡음 성능: 0.75 μV RMS (20 SPS, 게인=1, 저지연 필터).
- CMRR: 105 dB (typ), PSRR: 100 dB (typ).
입력 멀티플렉서 (INPMUX)
- 12개 입력 핀(AIN0~AIN11) 및 AINCOM, 플로팅 입력(Open), (AVDD-AVSS)/4, 온도 센서 선택 가능.
- 디퍼런셜 또는 싱글 엔드 구성 지원.
프로그래머블 게인 앰프 (PGA)
- 게인: 1, 2, 4, 8, 16, 32, 64, 128 (PGA 레지스터).
- 옵션: PGA 바이패스(게인=1), 입력 버퍼 활성화.
- 레일 감지: 입력 및 출력 레일링 플래그(STATUS 레지스터).
참조 전압 (REF)
- 선택: 외부(REF0, REF1), 내부 2.5V(±0.5%).
- 내부 참조 제어: 항상 켜짐, 변환 중 켜짐, 꺼짐 (REF 레지스터).
- 모니터링: 저전압 감지 레벨 1/2 (STATUS 레지스터).
디지털 필터 (DATARATE)
- 타입: sinc^3 (높은 잡음 억제) 또는 저지연 필터 (빠른 응답).
- 글로벌 초핑: 오프셋 감소.
IDAC (전류 소스, IDACMAG/IDACMUX)
- 2개 독립 IDAC: 10 μA, 50 μA, 100 μA, 250 μA, 500 μA, 750 μA, 1000 μA, 1500 μA, 2000 μA.
- 라우팅: AIN0~AIN11, AINCOM, 또는 비연결.
VBIAS
- 바이어스 전압: (AVDD+AVSS)/2 또는 (REFP+REFN)/2.
- AIN0~AIN6, AINCOM에 개별 적용.
GPIO (GPIODAT/GPIOCON)
- 4개 핀(AIN8~AIN11): 아날로그 입력 또는 GPIO로 구성.
- 방향: 입력/출력, 데이터 읽기/쓰기 지원.
캘리브레이션 (OFCAL/FSCAL)
- 시스템 오프셋/게인, 셀프 오프셋 캘리브레이션.
- 샘플 수: 1, 4, 8, 16 (SYS 레지스터).
- 24비트 캘리브레이션 레지스터 (16비트 ADC에 맞게 하위 16비트 사용).
SPI 인터페이스
- 모드: SPI Mode 1 (CPOL=0, CPHA=1).
- 최대 클럭: 10 MHz.
- 명령어: WAKEUP, POWERDOWN, RESET, START/SYNC, STOP, RDATA, SY_OCAL, SY_GCAL, SF_OCAL, RREG, WREG.
- 데이터 읽기: 16비트 ADC 데이터, 옵션 상태 바이트(1), CRC(2).
상태 및 진단 (STATUS)
- 플래그: POR, 데이터 준비(RDY), PGA 레일링, 참조 저전압.
- SPI 타임아웃, 레지스터 CRC 옵션 (SYS 레지스터).
전원 및 소비
- 아날로그 전원: AVDD 2.7V~5.25V, AVSS (그라운드 또는 -2.5V).
- 디지털 전원: DVDD 2.7V~3.6V.
- 소비 전류: 280 μA (typ, 내부 참조/PGA 활성), 1 μA (power-down).
기타
- 내부 온도 센서: ±2°C 정확도.
- 클럭: 내부 4.096 MHz(±2%) 또는 외부 입력.
- 패키지: TQFP-32, VQFN-32.
- 동작 온도: -50°C ~ +125°C.
코드 구현 개요
이 드라이버는 STM32L432KC (Nucleo-32 보드 가정)를 기반으로 ADS114S08의 모든 기능을 지원합니다:
- 환경:
- STM32CubeMX로 프로젝트 생성: SPI1, UART2, GPIO, EXTI 설정.
- SPI1: PA5(SCLK), PA6(MISO), PA7(MOSI), Mode 1, ~1 MHz.
- CS: PA4 (GPIO 출력, active low).
- DRDY: PB0 (GPIO 인터럽트, falling edge).
- UART2: PA2(TX)/PA3(RX), 115200 baud (디버깅 출력).
- 클럭: 80 MHz.
- 기능:
- 전체 명령어 지원: WAKEUP, POWERDOWN, RESET, START/SYNC, STOP, RDATA, 캘리브레이션(SY_OCAL, SY_GCAL, SF_OCAL).
- 레지스터(0x00~0x11) 읽기/쓰기, 비트 필드 정의.
- 초기화: POR 대기, 리셋, ID 확인, 기본 구성(AIN0-AIN1, 게인1, 20 SPS, 내부 참조, IDAC/VBIAS/GPIO off).
- 데이터 읽기: 동적 버퍼 크기(상태/CRC 옵션), DRDY 인터럽트 기반.
- 캘리브레이션: 시스템/셀프, 샘플 수 및 대기 시간 계산.
- IDAC, VBIAS, GPIO 설정 및 제어.
- 상태 점검: STATUS 플래그 확인(POR, RDY, 오류).
- 타이밍:
- RESET: 4096 tCLK (~1 ms @4.096 MHz).
- 내부 참조 안정화: ~5.9 ms (1 μF 기준).
- 캘리브레이션: 데이터 레이트 및 샴플 수에 따라 동적 대기.
- VBIAS 안정화: ~1 ms (예상 부하 기준).
- 에러 처리:
- ID 확인, STATUS 오류 플래그 점검.
- HAL 상태 반환 및 타임아웃 처리.
- main.c:
- 초기화, 셀프 오프셋 캘리브레이션, IDAC/VBIAS/GPIO 예시 구성.
- DRDY 인터럽트로 데이터 읽기, UART로 출력.
사용 사례
- 산업용 센서: 온도, 압력, 스트레인 게이지 데이터를 고정밀으로 수집.
- 의료 기기: 바이오 센서 신호 측정.
- IoT 디바이스: 저전력 환경에서 배터리 효율적 데이터 로깅.
코드
ads114s08.h
#ifndef ADS114S08_H
#define ADS114S08_H
#include "stm32l4xx_hal.h" // STM32L4 HAL 헤더 (L432KC 대상)
// ADS114S08 명령어 opcode 정의 (데이터시트 Section 9.5.3)
// 명령어는 SPI를 통해 ADS114S08 제어에 사용
#define ADS_NOP 0x00 // No operation, 패딩 또는 타임아웃 방지
#define ADS_WAKEUP 0x00 // Power-down에서 깨우기 (0x02도 동일)
#define ADS_POWERDOWN 0x02 // 저전력 모드 진입 (~1uA 소비)
#define ADS_RESET 0x06 // 소프트웨어 리셋, 레지스터 기본값 복원
#define ADS_START 0x08 // 변환 시작 또는 동기화 (0x0A도 동일)
#define ADS_STOP 0x0A // 변환 중지
#define ADS_RDATA 0x12 // 변환 데이터 읽기 (16-bit, 상태/CRC 옵션)
#define ADS_SY_OCAL 0x16 // 시스템 오프셋 캘리브레이션 (입력 단락 필요)
#define ADS_SY_GCAL 0x18 // 시스템 게인 캘리브레이션 (풀 스케일 입력 필요)
#define ADS_SF_OCAL 0x1A // 셀프 오프셋 캘리브레이션 (내부 단락)
#define ADS_RREG 0x20 // 레지스터 읽기: 0x20 + (addr << 2) + (num-1)
#define ADS_WREG 0x40 // 레지스터 쓰기: 0x40 + (addr << 2) + (num-1)
// 레지스터 주소 정의 (데이터시트 Table 19, 0x00~0x11)
// ADS114S08의 설정 및 상태를 제어/읽기 위한 레지스터
#define ADS_REG_ID 0x00 // 읽기 전용, 장치 ID (ADS114S08=0x4X)
#define ADS_REG_STATUS 0x01 // 상태 (POR, RDY, 오류 플래그)
#define ADS_REG_INPMUX 0x02 // 입력 멀티플렉서 (MUXP/MUXN)
#define ADS_REG_PGA 0x03 // PGA 설정 (게인, 바이패스, 지연)
#define ADS_REG_DATARATE 0x04 // 데이터 레이트 및 필터 설정
#define ADS_REG_REF 0x05 // 참조 전압 제어
#define ADS_REG_IDACMAG 0x06 // IDAC 크기
#define ADS_REG_IDACMUX 0x07 // IDAC 라우팅
#define ADS_REG_VBIAS 0x08 // VBIAS 설정
#define ADS_REG_SYS 0x09 // 시스템 제어 (CRC, 상태, 타임아웃 등)
#define ADS_REG_OFCAL0 0x0A // 오프셋 캘리브레이션 LSB
#define ADS_REG_OFCAL1 0x0B // 오프셋 캘리브레이션 MSB
#define ADS_REG_OFCAL2 0x0C // 오프셋 캘리브레이션 상위 (16-bit ADC에서는 사용 안 함)
#define ADS_REG_FSCAL0 0x0D // 풀 스케일 캘리브레이션 LSB
#define ADS_REG_FSCAL1 0x0E // 풀 스케일 캘리브레이션
#define ADS_REG_FSCAL2 0x0F // 풀 스케일 캘리브레이션 MSB (기본 0x00400000=1.0)
#define ADS_REG_GPIODAT 0x10 // GPIO 데이터 (방향 및 값)
#define ADS_REG_GPIOCON 0x11 // GPIO 설정 (아날로그 또는 GPIO)
// 비트 필드 정의 (데이터시트 Table 20~36)
// 각 레지스터의 비트별 기능 정의
#define ADS_ID_DEV_ID_MASK 0x07 // Bits 2:0: 장치 ID (0x04=ADS114S08)
#define ADS_STATUS_FL_POR (1 << 7) // Bit 7: POR 발생 플래그 (1=발생, 0으로 클리어)
#define ADS_STATUS_RDY (1 << 6) // Bit 6: 데이터 준비 (0=준비됨)
#define ADS_STATUS_FL_P_RAILP (1 << 5) // Bit 5: PGA 긍정 입력 상한 레일링
#define ADS_STATUS_FL_P_RAILN (1 << 4) // Bit 4: PGA 긍정 입력 하한 레일링
#define ADS_STATUS_FL_N_RAILP (1 << 3) // Bit 3: PGA 부정 입력 상한 레일링
#define ADS_STATUS_FL_N_RAILN (1 << 2) // Bit 2: PGA 부정 입력 하한 레일링
#define ADS_STATUS_FL_REF_L1 (1 << 1) // Bit 1: 참조 전압 저전압 레벨 1
#define ADS_STATUS_FL_REF_L0 (1 << 0) // Bit 0: 참조 전압 저전압 레벨 0
#define ADS_INPMUX_MUXP_SHIFT 4 // Bits 7:4: 긍정 입력 (0x0=AIN0, 0xC=AINCOM, 0xD=Open, 0xE=(AVDD-AVSS)/4, 0xF=온도 센서)
#define ADS_INPMUX_MUXN_MASK 0x0F // Bits 3:0: 부정 입력 (유사)
#define ADS_PGA_DELAY_MASK (7 << 5) // Bits 7:5: 변환 지연 (000=14 tMOD, 111=2048 tMOD)
#define ADS_PGA_GAIN_MASK (7 << 2) // Bits 4:2: 게인 (000=1, 001=2, ..., 111=128)
#define ADS_PGA_EN_MASK 0x03 // Bits 1:0: PGA 활성화 (00=바이패스, 01=활성, 10=버퍼 포함)
#define ADS_DATARATE_GLOBCHOP (1 << 7) // Bit 7: 글로벌 초핑 활성화 (오프셋 감소)
#define ADS_DATARATE_CLKSEL (1 << 6) // Bit 6: 클럭 소스 (0=내부 4.096MHz, 1=외부)
#define ADS_DATARATE_MODE (1 << 5) // Bit 5: 변환 모드 (0=싱글 샷, 1=연속)
#define ADS_DATARATE_FILTER (1 << 4) // Bit 4: 필터 타입 (0=sinc3, 1=저지연)
#define ADS_DATARATE_DR_MASK 0x0F // Bits 3:0: 데이터 레이트 (0000=2.5SPS, 1111=4000SPS)
#define ADS_REF_FL_REF_EN_MASK (3 << 6) // Bits 7:6: 참조 모니터링 (00=꺼짐, 11=레벨 1+2)
#define ADS_REF_REFSEL_MASK (3 << 3) // Bits 4:3: 참조 선택 (00=REF0, 01=REF1, 10=내부, 11=IDAC용 내부)
#define ADS_REF_REFCON_MASK 0x03 // Bits 1:0: 내부 참조 제어 (00=꺼짐, 01=항상 켜짐, 10=변환 중 켜짐)
#define ADS_IDACMAG_FL_POR_STAT (1 << 7) // Bit 7: POR 상태 (읽기 전용)
#define ADS_IDACMAG_IMAG_MASK 0x0F // Bits 3:0: IDAC 크기 (0000=꺼짐, 0001=10uA, ..., 1100=2000uA)
#define ADS_IDACMUX_IDAC2_MASK (0xF << 4) // Bits 7:4: IDAC2 라우팅 (0x0=AIN0, ..., 0xF=비연결)
#define ADS_IDACMUX_IDAC1_MASK 0x0F // Bits 3:0: IDAC1 라우팅 (유사)
#define ADS_VBIAS_VB_LEVEL (1 << 7) // Bit 7: VBIAS 레벨 (0=중앙 공급, 1=중앙 참조)
#define ADS_VBIAS_VB_MASK 0x7F // Bits 6:0: VBIAS 활성화 (AIN0~6, AINCOM)
#define ADS_SYS_CAL_SAMP_MASK (3 << 6) // Bits 7:6: 캘리브레이션 샘플 수 (00=1, 01=4, 10=8, 11=16)
#define ADS_SYS_CRC (1 << 5) // Bit 5: 데이터 읽기 CRC 활성화
#define ADS_SYS_STATUS (1 << 4) // Bit 4: 데이터 읽기 상태 바이트 포함
#define ADS_SYS_TIMEOUT (1 << 3) // Bit 3: SPI 타임아웃 활성화
#define ADS_SYS_REG_CRC (1 << 2) // Bit 2: 레지스터 맵 CRC 활성화
#define ADS_SYS_RESERVED 0x03 // Bits 1:0: 예약됨 (0)
#define ADS_GPIODAT_DIR_MASK (0xF << 4) // Bits 7:4: GPIO 방향 (1=출력, 0=입력)
#define ADS_GPIODAT_DAT_MASK 0x0F // Bits 3:0: GPIO 데이터
#define ADS_GPIOCON_CON_MASK 0x0F // Bits 3:0: GPIO 활성화 (1=GPIO, 0=아날로그 입력)
// 데이터 읽기 버퍼 크기 (SYS 레지스터에 따라 동적)
#define ADS_DATA_BYTES_BASE 2 // 기본: 16-bit 데이터
#define ADS_DATA_BYTES_MAX 5 // 최대: 상태(1) + 데이터(2) + CRC(2)
// 함수 선언
// 초기화: 기본 구성 및 인터럽트 설정
void ADS114S08_Init(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, GPIO_TypeDef *drdy_port, uint16_t drdy_pin);
// 단일 명령어 전송 (예: RESET, START)
void ADS114S08_SendCommand(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t cmd);
// 레지스터 읽기
HAL_StatusTypeDef ADS114S08_ReadRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t reg_addr, uint8_t *data, uint8_t num_bytes);
// 레지스터 쓰기
HAL_StatusTypeDef ADS114S08_WriteRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t reg_addr, uint8_t *data, uint8_t num_bytes);
// 데이터 읽기: 16-bit ADC 값, 옵션 상태/CRC
int32_t ADS114S08_ReadData(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t *status_out, uint16_t *crc_out);
// 변환 시작
void ADS114S08_StartConversion(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin);
// 변환 중지
void ADS114S08_StopConversion(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin);
// 소프트웨어 리셋
void ADS114S08_Reset(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin);
// Wakeup 명령
void ADS114S08_Wakeup(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin);
// Power-down 명령
void ADS114S08_PowerDown(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin);
// 캘리브레이션 수행 (시스템/셀프)
HAL_StatusTypeDef ADS114S08_PerformCalibration(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t cal_type);
// 상태 점검
uint8_t ADS114S08_CheckStatus(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin);
// IDAC 구성 (크기 및 라우팅)
void ADS114S08_ConfigIDAC(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t mag, uint8_t mux1, uint8_t mux2);
// VBIAS 구성
void ADS114S08_ConfigVBIAS(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t level, uint8_t enable_mask);
// GPIO 구성 (AIN8~11)
void ADS114S08_ConfigGPIO(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t con, uint8_t dir, uint8_t dat);
// GPIO 데이터 읽기
uint8_t ADS114S08_ReadGPIO(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin);
// DRDY 인터럽트 콜백 (main에서 재정의)
extern void ADS114S08_DataReadyCallback(void);
#endif /* ADS114S08_H */
ads114s08.c
#include "ads114s08.h"
// CS 핀 제어 매크로 (active low)
// SPI 통신 시 칩 선택(CS)을 활성화/비활성화
#define CS_LOW(cs_port, cs_pin) HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_RESET)
#define CS_HIGH(cs_port, cs_pin) HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_SET)
/**
* @brief ADS114S08 초기화
* - 데이터시트 Section 9.5.1 Pseudo Code 기반.
* - POR 후 2.2ms 대기 (HAL_Init에서 처리 가정).
* - SPI Mode 1 (CPOL=0, CPHA=1), CubeMX에서 설정.
* - 소프트웨어 리셋 후 POR 플래그 클리어.
* - ID 확인 (0x4X for ADS114S08).
* - 기본 구성:
* - 입력: AIN0(긍정)-AIN1(부정).
* - PGA: 바이패스, 게인=1, 지연=14 tMOD.
* - 데이터 레이트: 20 SPS, 저지연 필터, 연속 모드.
* - 참조: 내부 2.5V, 항상 켜짐.
* - IDAC: 꺼짐.
* - VBIAS: 꺼짐.
* - 시스템: CRC/상태 바이트 꺼짐, 타임아웃 꺼짐.
* - 캘리브레이션: OFCAL=0, FSCAL=1.0.
* - GPIO: 모두 아날로그 입력 (AIN8~11).
* @param hspi SPI 핸들러 (STM32 SPI 인스턴스)
* @param cs_port CS GPIO 포트
* @param cs_pin CS GPIO 핀
* @param drdy_port DRDY GPIO 포트 (인터럽트)
* @param drdy_pin DRDY GPIO 핀
*/
void ADS114S08_Init(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, GPIO_TypeDef *drdy_port, uint16_t drdy_pin) {
// DRDY 인터럽트는 CubeMX에서 설정 (EXTI, falling edge, pull-up)
// 리셋 명령 전송
ADS114S08_Reset(hspi, cs_port, cs_pin);
HAL_Delay(1); // RESET 후 4096 tCLK (~1ms @4.096MHz) 대기, 데이터시트 Figure 67
// STATUS: POR 플래그 클리어 (데이터시트 Table 20)
uint8_t status = 0x00; // FL_POR=0
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_STATUS, &status, 1);
// ID 확인 (0x40~0x4F 예상, 데이터시트 Table 20)
uint8_t id;
ADS114S08_ReadRegister(hspi, cs_port, cs_pin, ADS_REG_ID, &id, 1);
if ((id & ADS_ID_DEV_ID_MASK) != 0x04) {
// 에러: 잘못된 장치 ID, 디버깅용 무한 루프
while(1);
}
// INPMUX: MUXP=AIN0 (0x0), MUXN=AIN1 (0x1), 데이터시트 Table 21
uint8_t reg_data = (0x0 << ADS_INPMUX_MUXP_SHIFT) | 0x1;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_INPMUX, ®_data, 1);
// PGA: DELAY=000 (14 tMOD), GAIN=000 (1), PGA_EN=00 (바이패스), 데이터시트 Table 22
reg_data = 0x00;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_PGA, ®_data, 1);
// DATARATE: GLOBCHOP=0, CLKSEL=0 (내부), MODE=1 (연속), FILTER=1 (저지연), DR=0100 (20SPS), 데이터시트 Table 23
reg_data = (0 << 7) | (0 << 6) | (1 << 5) | (1 << 4) | 0x04;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_DATARATE, ®_data, 1);
// REF: FL_REF_EN=00 (꺼짐), REFSEL=10 (내부 2.5V), REFCON=01 (항상 켜짐), 데이터시트 Table 24
reg_data = (0 << 6) | (2 << 3) | 0x01;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_REF, ®_data, 1);
// IDACMAG: IMAG=0000 (꺼짐), 데이터시트 Table 25
reg_data = 0x00;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_IDACMAG, ®_data, 1);
// IDACMUX: IDAC1/2=1111 (비연결), 데이터시트 Table 26
reg_data = 0xFF;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_IDACMUX, ®_data, 1);
// VBIAS: VB_LEVEL=0, VB=0000000 (모두 꺼짐), 데이터시트 Table 27
reg_data = 0x00;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_VBIAS, ®_data, 1);
// SYS: CAL_SAMP=00 (1 샘플), CRC=0, STATUS=0, TIMEOUT=0, REG_CRC=0, 데이터시트 Table 28
reg_data = 0x00;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_SYS, ®_data, 1);
// 캘리브레이션: OFCAL=0, FSCAL=0x00400000 (1.0), 데이터시트 Table 29~34
uint8_t cal_data[6] = {0x00, 0x00, 0x00, 0x00, 0x40, 0x00};
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_OFCAL0, cal_data, 6);
// GPIO: CON=0000 (모두 아날로그), DIR=0, DAT=0, 데이터시트 Table 35~36
reg_data = 0x00;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_GPIOCON, ®_data, 1);
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_GPIODAT, ®_data, 1);
// 내부 참조 안정화 대기 (5.9ms for 1uF capacitor, 데이터시트 Section 9.4.6)
HAL_Delay(6);
}
/**
* @brief 단일 명령어 전송
* - 데이터시트 Figure 71: CS low -> 명령어 전송 -> CS high.
* - SPI 통신의 기본 단위로, ADS114S08 제어 명령 전송.
* @param cmd 명령어 opcode (예: ADS_RESET, ADS_START)
*/
void ADS114S08_SendCommand(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t cmd) {
CS_LOW(cs_port, cs_pin);
HAL_SPI_Transmit(hspi, &cmd, 1, HAL_MAX_DELAY);
CS_HIGH(cs_port, cs_pin);
}
/**
* @brief 레지스터 읽기
* - 데이터시트 Figure 73: RREG 명령 = 0x20 | (addr << 2) | (num-1).
* - 2바이트 명령어 전송 후 지정된 바이트 수만큼 데이터 수신.
* @param reg_addr 시작 레지스터 주소 (0x00~0x11)
* @param data 읽은 데이터 저장 버퍼
* @param num_bytes 읽을 바이트 수 (1~18)
* @return HAL 상태 (HAL_OK, HAL_ERROR 등)
*/
HAL_StatusTypeDef ADS114S08_ReadRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t reg_addr, uint8_t *data, uint8_t num_bytes) {
uint8_t tx_buf[2] = {ADS_RREG | (reg_addr << 2), num_bytes - 1};
CS_LOW(cs_port, cs_pin);
HAL_SPI_Transmit(hspi, tx_buf, 2, HAL_MAX_DELAY);
HAL_StatusTypeDef status = HAL_SPI_Receive(hspi, data, num_bytes, HAL_MAX_DELAY);
CS_HIGH(cs_port, cs_pin);
return status;
}
/**
* @brief 레지스터 쓰기
* - 데이터시트 Figure 72: WREG 명령 = 0x40 | (addr << 2) | (num-1).
* - 2바이트 명령어 후 지정된 바이트 수만큼 데이터 전송.
* @param reg_addr 시작 레지스터 주소
* @param data 쓸 데이터 버퍼
* @param num_bytes 쓸 바이트 수
* @return HAL 상태
*/
HAL_StatusTypeDef ADS114S08_WriteRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t reg_addr, uint8_t *data, uint8_t num_bytes) {
uint8_t tx_buf[2] = {ADS_WREG | (reg_addr << 2), num_bytes - 1};
CS_LOW(cs_port, cs_pin);
HAL_SPI_Transmit(hspi, tx_buf, 2, HAL_MAX_DELAY);
HAL_StatusTypeDef status = HAL_SPI_Transmit(hspi, data, num_bytes, HAL_MAX_DELAY);
CS_HIGH(cs_port, cs_pin);
return status;
}
/**
* @brief 변환 데이터 읽기
* - 데이터시트 Section 9.5.3.7, Figure 74: RDATA 명령.
* - SYS 레지스터 설정에 따라 출력: 상태(1바이트) + 데이터(2바이트) + CRC(2바이트).
* - 16-bit 데이터 sign-extended로 반환, 상태/CRC은 포인터로 옵션 출력.
* - DRDY 핀 또는 STATUS RDY=0 확인 후 호출 권장.
* @param status_out 상태 바이트 출력 (NULL 가능)
* @param crc_out CRC 출력 (NULL 가능)
* @return ADC 값 (-32768 ~ 32767, int32_t로 확장)
*/
int32_t ADS114S08_ReadData(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t *status_out, uint16_t *crc_out) {
// SYS 레지스터 읽어 출력 포맷 확인 (데이터시트 Table 28)
uint8_t sys_reg;
ADS114S08_ReadRegister(hspi, cs_port, cs_pin, ADS_REG_SYS, &sys_reg, 1);
uint8_t send_status = (sys_reg & ADS_SYS_STATUS) ? 1 : 0;
uint8_t send_crc = (sys_reg & ADS_SYS_CRC) ? 1 : 0;
uint8_t rx_bytes = ADS_DATA_BYTES_BASE + send_status + (send_crc * 2); // 2~5바이트
uint8_t rx_buf[5] = {0};
// RDATA 명령 전송 및 데이터 수신
uint8_t cmd = ADS_RDATA;
CS_LOW(cs_port, cs_pin);
HAL_SPI_Transmit(hspi, &cmd, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(hspi, rx_buf, rx_bytes, HAL_MAX_DELAY);
CS_HIGH(cs_port, cs_pin);
// 상태 바이트 처리
uint8_t offset = 0;
if (send_status) {
if (status_out) *status_out = rx_buf[0];
offset++;
}
// 16-bit 데이터 추출 (MSB first, sign extend)
int16_t adc_data = (int16_t)((rx_buf[offset] << 8) | rx_buf[offset + 1]);
offset += 2;
// CRC 처리 (옵션, 데이터시트 Section 9.5.3.7.1)
if (send_crc && crc_out) {
*crc_out = (rx_buf[offset] << 8) | rx_buf[offset + 1];
// CRC 검증은 사용자 애플리케이션에서 구현 (polynomial 0x07)
}
return (int32_t)adc_data;
}
/**
* @brief 변환 시작
* - 데이터시트 Section 9.5.3.4: START 또는 SYNC 명령.
* - 연속 또는 싱글 샷 모드 시작 (DATARATE MODE 비트).
*/
void ADS114S08_StartConversion(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) {
ADS114S08_SendCommand(hspi, cs_port, cs_pin, ADS_START);
}
/**
* @brief 변환 중지
* - 데이터시트 Section 9.5.3.5: STOP 명령.
*/
void ADS114S08_StopConversion(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) {
ADS114S08_SendCommand(hspi, cs_port, cs_pin, ADS_STOP);
}
/**
* @brief 소프트웨어 리셋
* - 데이터시트 Section 9.5.3.3: RESET 명령.
* - 모든 레지스터 기본값 복원, STATUS FL_POR=1 설정.
*/
void ADS114S08_Reset(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) {
ADS114S08_SendCommand(hspi, cs_port, cs_pin, ADS_RESET);
}
/**
* @brief Wakeup from power-down
* - 데이터시트 Section 9.5.3.1: WAKEUP 명령.
* - 저전력 모드에서 정상 모드로 복귀.
*/
void ADS114S08_Wakeup(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) {
ADS114S08_SendCommand(hspi, cs_port, cs_pin, ADS_WAKEUP);
}
/**
* @brief Power-down 모드 진입
* - 데이터시트 Section 9.5.3.2: POWERDOWN 명령.
* - 소비 전류 ~1uA로 감소.
*/
void ADS114S08_PowerDown(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) {
ADS114S08_SendCommand(hspi, cs_port, cs_pin, ADS_POWERDOWN);
}
/**
* @brief 캘리브레이션 수행
* - 데이터시트 Section 9.4.12: SY_OCAL, SY_GCAL, SF_OCAL.
* - SYS CAL_SAMP(1,4,8,16)에 따라 대기 시간 계산.
* - 완료 확인: STATUS RDY=0.
* - SY_OCAL/SY_GCAL은 외부 입력 준비 필요.
* @param cal_type 캘리브레이션 타입 (ADS_SY_OCAL, ADS_SY_GCAL, ADS_SF_OCAL)
* @return HAL_OK (성공), HAL_ERROR (실패)
*/
HAL_StatusTypeDef ADS114S08_PerformCalibration(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t cal_type) {
ADS114S08_SendCommand(hspi, cs_port, cs_pin, cal_type);
// 대기 시간 계산 (데이터 레이트 및 샘플 수 기반, 데이터시트 Table 7)
uint8_t sys_reg, datarate_reg;
ADS114S08_ReadRegister(hspi, cs_port, cs_pin, ADS_REG_SYS, &sys_reg, 1);
ADS114S08_ReadRegister(hspi, cs_port, cs_pin, ADS_REG_DATARATE, &datarate_reg, 1);
uint8_t samples = 1 << ((sys_reg >> 6) & 0x03); // 1, 4, 8, 16
uint16_t dr_code = datarate_reg & ADS_DATARATE_DR_MASK;
uint32_t dr_hz = (dr_code == 0) ? 3 : (1 << dr_code); // 근사 데이터 레이트 (Hz)
uint32_t delay_ms = (samples * 1000 / dr_hz) + 100; // 여유 마진
HAL_Delay(delay_ms);
// 완료 확인 (STATUS RDY 비트 체크)
uint8_t status = ADS114S08_CheckStatus(hspi, cs_port, cs_pin);
if (status & ADS_STATUS_RDY) return HAL_ERROR;
return HAL_OK;
}
/**
* @brief 상태 레지스터 점검
* - 데이터시트 Table 20: RDY, POR, 레일링, 참조 오류 확인.
* @return STATUS 레지스터 값
*/
uint8_t ADS114S08_CheckStatus(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) {
uint8_t status;
ADS114S08_ReadRegister(hspi, cs_port, cs_pin, ADS_REG_STATUS, &status, 1);
return status;
}
/**
* @brief IDAC 구성
* - 데이터시트 Section 9.4.7: 크기 및 출력 핀 설정.
* - mag: 0x0=꺼짐 ~ 0xC=2000uA.
* - mux1/mux2: 0x0=AIN0 ~ 0xF=비연결.
*/
void ADS114S08_ConfigIDAC(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t mag, uint8_t mux1, uint8_t mux2) {
uint8_t reg_data = mag & ADS_IDACMAG_IMAG_MASK;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_IDACMAG, ®_data, 1);
reg_data = ((mux2 & 0x0F) << 4) | (mux1 & 0x0F);
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_IDACMUX, ®_data, 1);
}
/**
* @brief VBIAS 구성
* - 데이터시트 Section 9.4.8: 바이어스 전압 활성화.
* - level: 0=(AVDD+AVSS)/2, 1=(REFP+REFN)/2.
* - enable_mask: AIN0~AIN6, AINCOM 비트 (0x7F).
*/
void ADS114S08_ConfigVBIAS(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t level, uint8_t enable_mask) {
uint8_t reg_data = ((level & 0x01) << 7) | (enable_mask & 0x7F);
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_VBIAS, ®_data, 1);
HAL_Delay(1); // VBIAS 안정화 (~280us~28ms, 데이터시트 Section 9.4.8)
}
/**
* @brief GPIO 구성 (AIN8~AIN11)
* - 데이터시트 Section 9.4.11: 모드, 방향, 데이터 설정.
* - con: 1=GPIO, 0=아날로그 (bit per AIN8~11).
* - dir: 1=출력, 0=입력.
* - dat: 출력 값 (입력 시 무시).
*/
void ADS114S08_ConfigGPIO(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, uint8_t con, uint8_t dir, uint8_t dat) {
uint8_t reg_data = con & ADS_GPIOCON_CON_MASK;
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_GPIOCON, ®_data, 1);
reg_data = ((dir & 0x0F) << 4) | (dat & 0x0F);
ADS114S08_WriteRegister(hspi, cs_port, cs_pin, ADS_REG_GPIODAT, ®_data, 1);
}
/**
* @brief GPIO 데이터 읽기
* - 입력 모드에서 AIN8~AIN11 상태 반환.
* @return GPIO 데이터 (하위 4비트)
*/
uint8_t ADS114S08_ReadGPIO(SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin) {
uint8_t reg_data;
ADS114S08_ReadRegister(hspi, cs_port, cs_pin, ADS_REG_GPIODAT, ®_data, 1);
return reg_data & ADS_GPIODAT_DAT_MASK;
}
// DRDY 콜백 (main.c에서 재정의)
__weak void ADS114S08_DataReadyCallback(void) {
// 기본 구현: 사용자 코드에서 데이터 처리
}
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : STM32L432KC 기반 ADS114S08 드라이버 테스트 (80MHz 클럭)
* - STM32CubeMX로 생성: SPI1, UART2, GPIO, EXTI.
* - ADS114S08 초기화, 셀프 오프셋 캘리브레이션, IDAC/VBIAS/GPIO 예시.
* - DRDY 인터럽트로 데이터 읽기, UART 출력.
* - 핀 구성:
* - SPI1: PA5(SCLK), PA6(MISO), PA7(MOSI).
* - CS: PA4 (GPIO 출력).
* - DRDY: PB0 (EXTI, falling edge).
* - UART2: PA2(TX), PA3(RX), 115200 baud.
* - 클럭: PLL 기반 80MHz (MSI 4MHz 소스, PLL M=1, N=40, R=2).
* - SPI 클럭: ~10MHz (80MHz/8).
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "ads114s08.h"
#include <string.h>
#include <stdio.h>
/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart2;
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART2_UART_Init(void);
/* ADS114S08 핀 정의 */
#define ADS_CS_PORT GPIOA
#define ADS_CS_PIN GPIO_PIN_4
#define ADS_DRDY_PORT GPIOB
#define ADS_DRDY_PIN GPIO_PIN_0
/* 글로벌 변수 */
volatile uint8_t data_ready = 0; // DRDY 인터럽트 플래그
/**
* @brief 메인 함수
* - HAL 초기화, 시스템 클럭(80MHz), 주변장치 초기화.
* - ADS114S08 초기화 및 설정 (셀프 캘리브레이션, IDAC, VBIAS, GPIO).
* - DRDY 인터럽트로 데이터 읽고 UART로 출력.
*/
int main(void)
{
/* MCU 초기화 */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART2_UART_Init();
/* ADS114S08 초기화 (기본 설정 적용) */
ADS114S08_Init(&hspi1, ADS_CS_PORT, ADS_CS_PIN, ADS_DRDY_PORT, ADS_DRDY_PIN);
/* 셀프 오프셋 캘리브레이션 (입력 단락 불필요, 데이터시트 Section 9.4.12) */
if (ADS114S08_PerformCalibration(&hspi1, ADS_CS_PORT, ADS_CS_PIN, ADS_SF_OCAL) != HAL_OK) {
char msg[] = "Calibration Failed\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
while(1); // 캘리브레이션 실패 시 디버깅용 무한 루프
}
/* IDAC 설정 예시: 500uA, IDAC1=AIN0, IDAC2=AIN1, 데이터시트 Section 9.4.7 */
ADS114S08_ConfigIDAC(&hspi1, ADS_CS_PORT, ADS_CS_PIN, 0x05, 0x0, 0x1); // 0x05=500uA
/* VBIAS 설정 예시: (AVDD+AVSS)/2, AIN0 활성화, 데이터시트 Section 9.4.8 */
ADS114S08_ConfigVBIAS(&hspi1, ADS_CS_PORT, ADS_CS_PIN, 0, 0x01);
/* GPIO 설정 예시: AIN8=GPIO 입력, 나머지 아날로그, 데이터시트 Section 9.4.11 */
ADS114S08_ConfigGPIO(&hspi1, ADS_CS_PORT, ADS_CS_PIN, 0x01, 0x00, 0x00);
/* 변환 시작 (연속 모드, 데이터시트 Section 9.5.3.4) */
ADS114S08_StartConversion(&hspi1, ADS_CS_PORT, ADS_CS_PIN);
/* 메인 루프: DRDY 인터럽트로 데이터 처리 */
while (1)
{
if (data_ready) {
data_ready = 0; // 플래그 리셋
uint8_t status;
uint16_t crc;
int32_t adc_value = ADS114S08_ReadData(&hspi1, ADS_CS_PORT, ADS_CS_PIN, &status, &crc);
// ADC 값 UART 출력
char buf[50];
sprintf(buf, "ADC: %ld, Status: 0x%02X\r\n", adc_value, status);
HAL_UART_Transmit(&huart2, (uint8_t*)buf, strlen(buf), HAL_MAX_DELAY);
// GPIO 데이터 읽기 및 출력
uint8_t gpio_dat = ADS114S08_ReadGPIO(&hspi1, ADS_CS_PORT, ADS_CS_PIN);
sprintf(buf, "GPIO: 0x%02X\r\n", gpio_dat);
HAL_UART_Transmit(&huart2, (uint8_t*)buf, strlen(buf), HAL_MAX_DELAY);
// 상태 점검: 오류 플래그 출력 (데이터시트 Table 20)
if (status & (ADS_STATUS_FL_P_RAILP | ADS_STATUS_FL_P_RAILN | ADS_STATUS_FL_N_RAILP | ADS_STATUS_FL_N_RAILN)) {
sprintf(buf, "Error: PGA Rail Violation\r\n");
HAL_UART_Transmit(&huart2, (uint8_t*)buf, strlen(buf), HAL_MAX_DELAY);
}
}
}
}
/**
* @brief DRDY 인터럽트 콜백
* - 데이터 준비 시 플래그 설정.
* - DRDY 핀 falling edge에서 호출 (데이터시트 Section 9.5.3.7).
*/
void ADS114S08_DataReadyCallback(void) {
data_ready = 1;
}
/**
* @brief EXTI 인터럽트 핸들러
* - PB0(DRDY) falling edge에서 호출.
* - ADS114S08_DataReadyCallback 호출.
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == ADS_DRDY_PIN) {
ADS114S08_DataReadyCallback();
}
}
/**
* @brief 시스템 클럭 설정
* - PLL 기반 80MHz SYSCLK 설정.
* - MSI 4MHz를 소스로 사용, PLL 설정: M=1, N=40, R=2.
* - HCLK, PCLK1, PCLK2 = 80MHz (1분주).
* - STM32L432KC 데이터시트 및 참조 매뉴얼(RM0394) 참고.
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* MSI 오실레이터 활성화 (4MHz) */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = 0;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; // 4MHz
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLM = 1; // M=1 (4MHz 입력)
RCC_OscInitStruct.PLL.PLLN = 40; // N=40 (4MHz * 40 = 160MHz)
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // R=2 (160MHz / 2 = 80MHz)
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; // 사용 안 함
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; // 사용 안 함
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* SYSCLK, HCLK, PCLK1, PCLK2 설정 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // PLL을 시스템 클럭 소스로 사용
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // HCLK = 80MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // PCLK1 = 80MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // PCLK2 = 80MHz
/* 플래시 레이턴시 설정 (80MHz에서 4 WS 필요, STM32L432KC 데이터시트 Table 12) */
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief SPI1 초기화
* - Mode 1 (CPOL=0, CPHA=1), 8-bit, ~10MHz (80MHz/8).
* - ADS114S08 SPI 요구사항에 맞춘 설정 (데이터시트 Section 9.5.2, 최대 10MHz).
*/
static void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE; // Mode 1
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 80MHz/8 = 10MHz
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief USART2 초기화
* - 115200 baud, 8N1, 하드웨어 플로우 제어 없음.
* - 디버깅용 UART 설정.
*/
static void MX_USART2_UART_Init(void)
{
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_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLING_DISABLED;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief GPIO 초기화
* - PA4: CS 출력 (기본 high).
* - PB0: DRDY 입력 (EXTI, falling edge, pull-up).
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_GPIO_WritePin(ADS_CS_PORT, ADS_CS_PIN, GPIO_PIN_SET);
GPIO_InitStruct.Pin = ADS_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(ADS_CS_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = ADS_DRDY_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(ADS_DRDY_PORT, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
/**
* @brief 에러 핸들러
* - 무한 루프 진입 (디버깅용).
*/
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Assert 에러 보고
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* 사용자 디버깅 코드 추가 가능 */
}
#endif /* USE_FULL_ASSERT */
사용법 및 테스트
STM32CubeMX 설정
- SPI1:
- 핀: PA5(SCLK), PA6(MISO), PA7(MOSI).
- 모드: Mode 1 (CPOL=0, CPHA=1).
- Baudrate Prescaler: 8 (~125kHz).
- GPIO:
- PA4: CS 출력, 초기값 high.
- PB0: DRDY 입력, EXTI falling edge, pull-up.
- UART2:
- 핀: PA2(TX), PA3(RX).
- 설정: 115200 baud, 8N1.
- 클럭: 80MHz.
하드웨어 연결
- ADS114S08 전원: AVDD/DVDD=3.3V, AVSS=0V.
- SPI 연결: STM32의 SPI1 핀과 연결.
- 입력 신호: AIN0/AIN1에 테스트 입력(예: 전압 분배기, 센서).
- DRDY: PB0에 연결, 풀업 저항 권장.
빌드 및 실행
- STM32CubeIDE에서 프로젝트 생성 및 코드 추가.
- 빌드 후 Nucleo-32 보드에 업로드.
- UART 터미널(예: Tera Term, PuTTY)로 ADC 값, GPIO 상태, 오류 메시지 확인.
확장
- CRC 검증: SYS 레지스터의 CRC 비트 활성화 후 polynomial 0x07로 검증.
- 다른 설정 테스트: 데이터 레이트(2.5
4000 SPS), 게인(1128), 다른 입력 채널. - 외부 참조/클럭: REFSEL=00/01, CLKSEL=1로 변경.
디버깅 팁
- 데이터 읽기 오류: DRDY 핀이 올바르게 설정되었는지, SPI 클럭이 10MHz 이하인지 확인.
- 캘리브레이션 실패: 입력 신호가 올바른지, STATUS 레지스터의 RDY 비트 확인.
- UART 출력 없음: UART2 핀 연결 및 baud rate(115200) 점검.
- PGA 레일링 오류: 입력 전압이 ±VREF/게인 범위 내인지 확인 (데이터시트 Section 9.4.4).
- IDAC 문제: IDAC 출력 핀과 외부 부하 저항이 적절한지 확인 (데이터시트 Section 9.4.7).
결론
이 문서는 STM32와 ADS114S08을 활용한 고정밀 ADC 드라이버 구현 방법을 다뤘습니다. 사양서 기반으로 작성한 전체 기능을 활용할 수 있는 소스 코드 및 사용법과 디버깅 팁을 통해 초보자와 전문가 모두 쉽게 시작할 수 있습니다.
관련 리소스: Texas Instruments ADS114S08 데이터시트, STM32CubeMX
ADS114S08 data sheet, product information and support | TI.com
Download options Latest version Version: 01.00.00.0B Release date: 12 Mar 2023 Precision ADCs The design resource accessed as www.ti.com/lit/zip/sbar021 or www.ti.com/lit/xx/sbar021b/sbar021b.zip has been migrated to a new user experience at www.ti.com/too
www.ti.com
STM32CubeMX | Software - STMicroelectronics
STM32CubeMX is a graphical tool that allows a very easy configuration of STM32 microcontrollers and microprocessors, as well as the generation of the...
www.st.com
키워드: ADS114S08, STM32, ADC 드라이버, 고정밀 데이터 수집, STM32CubeMX, SPI 인터페이스, Delta-Sigma ADC