이 문서에서는 Texas Instruments의 TMS320F28388D 마이크로컨트롤러에서 **ADC(아날로그-디지털 컨버터)**를 DriverLib API를 사용하여 설정하고 사용하는 방법을 상세히 다룹니다. C2000 시리즈의 고성능 마이크로컨트롤러인 TMS320F28388D의 ADC 모듈을 활용하여 아날로그 신호를 디지털로 변환하는 방법을 배우고, 다양한 독립적인 예제 코드를 통해 실제 구현 방법을 익힐 수 있습니다. 각 코드에는 상세한 주석이 포함되어 있으며, Code Composer Studio(CCS) 환경에서 실행 가능합니다.
1. TMS320F28388D ADC 개요
TMS320F28388D는 Texas Instruments의 C2000 시리즈에 속하는 고성능 32비트 마이크로컨트롤러로, 최대 4개의 ADC 모듈(ADC-A, ADC-B, ADC-C, ADC-D)을 제공합니다. 각 모듈은 최대 16비트 해상도로 아날로그 신호를 디지털로 변환할 수 있으며, 실시간 제어 애플리케이션에 최적화되어 있습니다. ADC 모듈의 주요 특징은 다음과 같습니다:
- ADC 채널: 최대 24개의 외부 아날로그 입력 핀(ADCINx)과 내부 온도 센서 연결.
- 해상도: 12비트 또는 16비트 모드 지원.
- 샘플링 속도: 12비트 모드에서 최대 3.5 MSPS, 16비트 모드에서 1.1 MSPS.
- SOC (Start of Conversion): 각 ADC 모듈은 최대 16개의 SOC 트리거를 지원하여 다양한 입력 채널과 트리거 소스를 설정 가능.
- 트리거 소스: 소프트웨어, ePWM, 외부 핀, 타이머 등 다양한 트리거 소스 지원.
- S/H (Sample and Hold): Acquisition Window를 통해 아날로그 입력의 안정적인 샘플링 가능.
DriverLib API는 하드웨어 레지스터를 직접 조작하는 대신 추상화된 함수를 제공하여 ADC 설정과 제어를 간소화합니다. 이 포스트에서는 DriverLib API를 중심으로 ADC의 설정, 동작 원리, 주요 기능에 대해 체계적으로 설명합니다.
2. 주요 ADC DriverLib API 함수
TMS320F28388D의 ADC를 제어하기 위해 자주 사용되는 DriverLib API 함수와 그 사용 방법을 아래에 정리했습니다. 각 함수는 ADC 설정, 인터럽트 처리, 결과 읽기 등 특정 작업에 최적화되어 있습니다.
2.1. ADC 설정 관련 함수
- ADC_setPrescaler(base, clkPrescale)
- 설명: ADC 클럭 프리스케일러를 설정하여 ADC 동작 주파수를 조정합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- clkPrescale: 클럭 분주 값 (예: ADC_CLK_DIV_2_0, ADC_CLK_DIV_4_0 등).
- 사용 예: 시스템 클럭을 4로 분주하여 ADC 클럭 설정.
- ADC_setupSOC(base, socNumber, trigger, channel, sampleWindow)
- 설명: 특정 SOC(Start of Conversion)를 설정하여 트리거 소스, 입력 채널, 샘플링 윈도우를 지정합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- socNumber: 설정할 SOC 번호 (0~15).
- trigger: 트리거 소스 (예: ADC_TRIGGER_SW_ONLY, ADC_TRIGGER_EPWM1_SOCA 등).
- channel: 입력 채널 (예: ADC_CH_ADCIN0, ADC_CH_ADCIN1 등).
- sampleWindow: 샘플링 윈도우 시간 (클럭 사이클 단위, 최소 15 사이클 권장).
- 사용 예: ADC-A의 SOC0을 소프트웨어 트리거로 설정하여 ADCIN0 채널 샘플링.
- ADC_enableConverter(base)
- 설명: ADC 모듈을 활성화하여 변환 준비를 합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- 사용 예: ADC 모듈을 동작 시작.
- ADC_disableConverter(base)
- 설명: ADC 모듈을 비활성화합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
2.2. 인터럽트 관련 함수
- ADC_enableInterrupt(base, intNumber)
- 설명: 특정 ADC 인터럽트를 활성화합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- intNumber: 인터럽트 번호 (예: ADC_INT_NUMBER1, ADC_INT_NUMBER2 등).
- 사용 예: ADC-A의 인터럽트 1 활성화.
- ADC_clearInterruptStatus(base, intNumber)
- 설명: ADC 인터럽트 플래그를 지웁니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- intNumber: 인터럽트 번호.
- registerInterrupt(intNumber, handler)
- 설명: ADC 인터럽트 핸들러를 등록합니다.
- 매개변수:
- intNumber: 인터럽트 번호 (예: INT_ADCA1).
- handler: 인터럽트 서비스 루틴(ISR) 함수 포인터.
- 사용 예: ADC-A 인터럽트 1에 ISR 등록.
2.3. 변환 결과 읽기 관련 함수
- ADC_readResult(base, socNumber)
- 설명: 지정된 SOC의 변환 결과를 읽습니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- socNumber: 읽을 SOC 번호 (0~15).
- 반환값: 12비트 또는 16비트 변환 결과 (uint16_t).
- 사용 예: ADC-A SOC0의 변환 결과 읽기.
2.4. 트리거 및 동기화 관련 함수
- ADC_forceSOC(base, socNumber)
- 설명: 소프트웨어로 특정 SOC 변환을 강제로 시작합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- socNumber: 트리거할 SOC 번호.
- 사용 예: 소프트웨어로 ADC-A SOC0 변환 시작.
- ADC_setInterruptSOCTrigger(base, socNumber, intNumber)
- 설명: 특정 SOC가 완료될 때 인터럽트를 발생시키도록 설정합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- socNumber: 인터럽트를 발생시킬 SOC 번호.
- intNumber: 사용할 인터럽트 번호.
2.5. 기타 유용한 함수
- ADC_setMode(base, resolution, signalMode)
- 설명: ADC의 해상도와 신호 모드(싱글엔드/차동)를 설정합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소.
- resolution: 해상도 (ADC_RESOLUTION_12BIT 또는 ADC_RESOLUTION_16BIT).
- signalMode: 신호 모드 (ADC_MODE_SINGLE_ENDED 또는 ADC_MODE_DIFFERENTIAL).
- 사용 예: 12비트 싱글엔드 모드 설정.
- ADC_getTemperatureC(base, socNumber)
- 설명: 내부 온도 센서의 ADC 변환 결과를 섭씨 온도로 변환합니다.
- 매개변수:
- base: ADC 모듈의 베이스 주소 (ADC-A만 온도 센서 지원).
- socNumber: 온도 센서에 연결된 SOC 번호.
- 반환값: 섭씨 온도 (float).
3. ADC 설정 및 동작 원리
TMS320F28388D의 ADC 모듈을 설정하고 동작시키는 일반적인 절차는 다음과 같습니다:
- 시스템 초기화:
- 시스템 클럭과 GPIO 초기화를 수행합니다 (Device_init(), Device_initGPIO()).
- 인터럽트 모듈을 초기화합니다 (Interrupt_initModule(), Interrupt_initVectorTable()).
- ADC 모듈 설정:
- ADC 클럭 프리스케일러 설정 (ADC_setPrescaler).
- 해상도 및 신호 모드 설정 (ADC_setMode).
- SOC 설정: 트리거 소스, 입력 채널, 샘플링 윈도우 지정 (ADC_setupSOC).
- 인터럽트 설정 (선택):
- 인터럽트 활성화 및 ISR 등록 (ADC_enableInterrupt, ADC_registerInterrupt).
- SOC와 인터럽트 연결 (ADC_setInterruptSOCTrigger).
- ADC 활성화 및 변환 시작:
- ADC 모듈 활성화 (ADC_enableConverter).
- 소프트웨어 트리거로 변환 시작 (ADC_forceSOC) 또는 하드웨어 트리거 설정.
- 결과 처리:
- 변환 완료 후 결과 읽기 (ADC_readResult) 또는 인터럽트를 통해 결과 처리.
4. ADC 예제 코드
아래는 TMS320F28388D의 ADC를 다양한 방식으로 사용하는 독립적인 예제 코드입니다. 각 예제는 독립적으로 실행 가능하며, C2000Ware의 DriverLib를 기반으로 작성되었습니다. 코드에는 상세한 주석이 포함되어 있어 초보자도 쉽게 이해할 수 있습니다.
4.1. 예제 1: 소프트웨어 트리거를 사용한 단일 채널 ADC 변환
이 예제는 ADC-A의 ADCIN0 채널을 소프트웨어 트리거로 샘플링하여 변환 결과를 읽습니다.
#include "driverlib.h"
#include "device.h"
#include "f2838x_device.h" // INT_ADCA1 정의 포함
// ADC 결과 저장 변수
volatile uint16_t adcResult;
// 인터럽트 서비스 루틴 (ISR) 선언
__interrupt void adcA1ISR(void);
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 핀 락 해제 및 내부 풀업 활성화
Device_initGPIO();
// 인터럽트 모듈 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// ADC 클럭 프리스케일러 설정 (시스템 클럭 200MHz / 4 = 50MHz)
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
// ADC 해상도 및 신호 모드 설정 (12비트, 싱글엔드, 내부 3.3V 기준)
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
// ADC 오프셋 트림 로드
ADC_setOffsetTrim(ADCA_BASE);
// SOC0 설정: 소프트웨어 트리거, ADCIN0 채널, 샘플링 윈도우 15 사이클
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN0, 15);
// PPB1 설정: SOC0과 연결, 오프셋 보정
ADC_setupPPB(ADCA_BASE, ADC_PPB_NUMBER1, ADC_SOC_NUMBER0);
ADC_setPPBCalibrationOffset(ADCA_BASE, ADC_PPB_NUMBER1, 0); // 기본 오프셋 0
// 인터럽트 소스 설정: SOC0 -> ADC_INT1
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
// 인터럽트 펄스 모드 설정: 변환 종료 시 펄스 발생
ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
// ADC 인터럽트 활성화
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
// 인터럽트 등록
Interrupt_register(INT_ADCA1, &adcA1ISR);
// ADC 모듈 활성화
ADC_enableConverter(ADCA_BASE);
// ADC 안정화를 위해 1ms 지연
DEVICE_DELAY_US(1000);
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프
for(;;)
{
// Watchdog 서비스 (리셋 방지)
SysCtl_serviceWatchdog();
// ADC가 바쁘지 않은 경우 SOC0 변환 강제 시작
if (!ADC_isBusy(ADCA_BASE))
{
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
}
// 100ms 대기 (인터럽트 처리로 CPU 부하 감소)
DEVICE_DELAY_US(100000);
}
}
// ADC 인터럽트 서비스 루틴
__interrupt void adcA1ISR(void)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 변환 결과 읽기 (0~4095 범위, 12비트)
adcResult = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
// PPB 결과 읽기 (오프셋 보정 적용, 32비트 signed)
int32_t ppbResult = ADC_readPPBResult(ADCARESULT_BASE, ADC_PPB_NUMBER1);
// 인터럽트 플래그 지우기
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
// 인터럽트 확인
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}
설명:
- 기능: ADC-A의 ADCIN0 채널을 소프트웨어 트리거로 샘플링.
- 설정: 12비트 해상도, 내부 3.3V 기준 전압, 50MHz ADC 클럭.
- 결과: 변환 결과는 adcResult 변수에 저장되며, 0~4095 범위의 값을 가짐.
- 주기: 100ms마다 변환 수행.
4.2. 예제 2: 인터럽트를 사용한 ADC 변환
이 예제는 ADC-A의 ADCIN0 채널을 인터럽트를 사용하여 샘플링하고, 변환 결과를 ISR에서 처리합니다.
#include "driverlib.h"
#include "device.h"
#include "f2838x_device.h" // INT_ADCA1 정의 포함
// ADC 결과 저장 변수
volatile uint16_t adcResult;
// 인터럽트 서비스 루틴 (ISR) 선언
__interrupt void adcA1ISR(void);
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 핀 락 해제 및 내부 풀업 활성화
Device_initGPIO();
// 인터럽트 모듈 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// ADC 클럭 프리스케일러 설정 (시스템 클럭 200MHz / 4 = 50MHz)
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
// ADC 해상도 및 신호 모드 설정 (12비트, 싱글엔드, 내부 3.3V 기준)
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
// ADC 오프셋 트림 로드
ADC_setOffsetTrim(ADCA_BASE);
// SOC0 설정: 소프트웨어 트리거, ADCIN0 채널, 샘플링 윈도우 15 사이클
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN0, 15);
// PPB1 설정: SOC0과 연결, 오프셋 보정
ADC_setupPPB(ADCA_BASE, ADC_PPB_NUMBER1, ADC_SOC_NUMBER0);
ADC_setPPBCalibrationOffset(ADCA_BASE, ADC_PPB_NUMBER1, 0); // 기본 오프셋 0
// 인터럽트 소스 설정: SOC0의 EOC -> ADC_INT1
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
// 인터럽트 펄스 모드 설정: 변환 종료 시 펄스 발생
ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
// ADC 인터럽트 활성화
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
// 인터럽트 등록 (ADC-A 인터럽트 1)
Interrupt_register(INT_ADCA1, &adcA1ISR);
// ADC 모듈 활성화
ADC_enableConverter(ADCA_BASE);
// ADC 안정화를 위해 1ms 지연
DEVICE_DELAY_US(1000);
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프
for(;;)
{
// Watchdog 서비스 (리셋 방지)
SysCtl_serviceWatchdog();
// ADC가 바쁘지 않은 경우 SOC0 변환 강제 시작
if (!ADC_isBusy(ADCA_BASE))
{
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
}
// 100ms 대기 (인터럽트 처리로 CPU 부하 감소)
DEVICE_DELAY_US(100000);
}
}
// ADC 인터럽트 서비스 루틴
__interrupt void adcA1ISR(void)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 변환 결과 읽기 (0~4095 범위, 12비트)
adcResult = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
// PPB 결과 읽기 (오프셋 보정 적용, 32비트 signed)
int32_t ppbResult = ADC_readPPBResult(ADCARESULT_BASE, ADC_PPB_NUMBER1);
// 인터럽트 플래그 지우기
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
// 인터럽트 확인
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}
설명:
- 기능: ADC-A의 ADCIN0 채널을 소프트웨어 트리거로 샘플링하고 인터럽트로 결과 처리.
- 인터럽트: 변환 완료 시 adcA1ISR에서 결과 읽기 및 플래그 정리.
- 결과: adcResult 변수에 ISR에서 업데이트.
- 주기: 100ms마다 변환 트리거.
4.3. 예제 3: ePWM 트리거를 사용한 ADC 변환
이 예제는 ePWM1의 SOCA 신호를 트리거로 사용하여 ADC-A의 ADCIN0 채널을 샘플링합니다.
#include "driverlib.h"
#include "device.h"
#include "f2838x_device.h" // INT_ADCA1 정의 포함
#include "epwm.h" // ePWM 함수 및 상수 정의 포함
// ADC 결과 저장 버퍼
#define RESULTS_BUFFER_SIZE 256
uint16_t adcResults[RESULTS_BUFFER_SIZE];
volatile uint16_t index = 0;
volatile uint16_t bufferFull = 0; // 버퍼 가득 참 플래그
// ePWM 초기화 함수
void initEPWM(void)
{
// ePWM1 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
// SOCA 비활성화
EPWM_disableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
// SOCA 트리거 설정 (카운터가 CMPA에 도달할 때 트리거)
EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPA);
EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_SOC_A, 1);
// 비교 값 및 주기 설정 (50kHz PWM, 200MHz / 4000 = 50kHz)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 2000);
EPWM_setTimeBasePeriod(EPWM1_BASE, 3999);
// 클럭 분주 설정 (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
// 카운터 모드 설정 (상향 카운트)
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
}
// 인터럽트 서비스 루틴
__interrupt void adcA1ISR(void)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// ADC 변환 결과 읽기 (SOC0의 결과, 0~4095)
adcResults[index] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
// PPB 결과 읽기 (오프셋 보정 적용, 32비트 signed)
int32_t ppbResult = ADC_readPPBResult(ADCARESULT_BASE, ADC_PPB_NUMBER1);
// 인덱스 증가 및 버퍼 오버플로우 방지
index++;
if (index >= RESULTS_BUFFER_SIZE)
{
index = 0;
bufferFull = 1;
}
// 인터럽트 플래그 지우기
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
// 인터럽트 오버플로우 확인 및 처리
if (ADC_getInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1))
{
ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
}
// PIE 인터럽트 ACK
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 핀 락 해제 및 내부 풀업 활성화
Device_initGPIO();
// 인터럽트 모듈 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// ADC 인터럽트 ISR 등록
Interrupt_register(INT_ADCA1, &adcA1ISR);
// ADC 클럭 프리스케일러 설정 (200MHz / 4 = 50MHz)
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
// ADC 해상도 및 신호 모드 설정 (12비트, 싱글엔드, 내부 3.3V 기준)
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
// ADC 오프셋 트림 로드
ADC_setOffsetTrim(ADCA_BASE);
// SOC0 설정: ePWM1 SOCA 트리거, ADCIN0 채널, 샘플링 윈도우 15 사이클
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN0, 15);
// PPB1 설정: SOC0과 연결, 오프셋 보정
ADC_setupPPB(ADCA_BASE, ADC_PPB_NUMBER1, ADC_SOC_NUMBER0);
ADC_setPPBCalibrationOffset(ADCA_BASE, ADC_PPB_NUMBER1, 0); // 기본 오프셋 0
// 인터럽트 소스 설정: SOC0의 EOC -> ADC_INT1
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
// 인터럽트 펄스 모드 설정: 변환 종료 시 펄스 발생
ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
// ADC 인터럽트 1 활성화
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
// ADC 모듈 활성화
ADC_enableConverter(ADCA_BASE);
// ADC 안정화를 위해 1ms 지연
DEVICE_DELAY_US(1000);
// 결과 버퍼 초기화
for(index = 0; index < RESULTS_BUFFER_SIZE; index++)
{
adcResults[index] = 0;
}
index = 0;
bufferFull = 0;
// ePWM1 초기화
initEPWM();
// 글로벌 인터럽트 및 실시간 인터럽트 활성화
EINT;
ERTM;
// 무한 루프 (ePWM 트리거에 의해 ADC 자동 실행)
while(1)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// ePWM1 SOCA 활성화 및 카운터 시작
EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// 버퍼가 가득 찰 때까지 대기
while(bufferFull == 0)
{
SysCtl_serviceWatchdog();
}
bufferFull = 0; // 플래그 초기화
// ePWM1 SOCA 비활성화 및 카운터 정지
EPWM_disableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_STOP_FREEZE);
// 디버깅용 소프트웨어 브레이크포인트
ESTOP0;
}
}
설명:
- 기능: ePWM1의 SOCA 신호를 트리거로 사용하여 ADC-A의 ADCIN0 채널 샘플링.
- ePWM 설정: 100kHz 주기로 SOCA 트리거 생성.
- 결과: adcResults 버퍼에 저장, 인터럽트로 처리.
- 버퍼 관리: 오버플로우 방지를 위해 인덱스 순환.
4.4. 예제 4: 내부 온도 센서 읽기
이 예제는 ADC-A의 내부 온도 센서를 사용하여 칩 온도를 섭씨 단위로 읽습니다.
#include "driverlib.h"
#include "device.h"
#include "f2838x_device.h" // INT_ADCA1 정의 포함
// 온도 저장 변수
volatile float temperatureC;
// 인터럽트 서비스 루틴
__interrupt void adcA1ISR(void)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 온도 센서 결과 읽기 및 섭씨로 변환
temperatureC = ADC_getTemperatureC(ADCA_BASE, ADC_SOC_NUMBER0);
// PPB 결과 읽기 (오프셋 보정 적용, 32비트 signed)
int32_t ppbResult = ADC_readPPBResult(ADCARESULT_BASE, ADC_PPB_NUMBER1);
// 인터럽트 플래그 지우기
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
// 인터럽트 오버플로우 확인 및 처리
if (ADC_getInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1))
{
ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
}
// PIE 인터럽트 ACK
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 핀 락 해제 및 내부 풀업 활성화
Device_initGPIO();
// 인터럽트 모듈 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// ADC 인터럽트 ISR 등록
Interrupt_register(INT_ADCA1, &adcA1ISR);
// ADC 클럭 프리스케일러 설정 (200MHz / 4 = 50MHz)
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
// ADC 해상도 및 신호 모드 설정 (12비트, 싱글엔드, 내부 3.3V 기준)
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
// ADC 오프셋 트림 로드
ADC_setOffsetTrim(ADCA_BASE);
// SOC0 설정: 소프트웨어 트리거, 내부 온도 센서 채널 (ADCIN14), 샘플링 윈도우 140 사이클
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN14, 140);
// PPB1 설정: SOC0과 연결, 오프셋 보정
ADC_setupPPB(ADCA_BASE, ADC_PPB_NUMBER1, ADC_SOC_NUMBER0);
ADC_setPPBCalibrationOffset(ADCA_BASE, ADC_PPB_NUMBER1, 0); // 기본 오프셋 0
// 인터럽트 소스 설정: SOC0의 EOC -> ADC_INT1
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
// 인터럽트 펄스 모드 설정: 변환 종료 시 펄스 발생
ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
// ADC 인터럽트 1 활성화
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
// ADC 모듈 활성화
ADC_enableConverter(ADCA_BASE);
// ADC 안정화를 위해 1ms 지연
DEVICE_DELAY_US(1000);
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프
for(;;)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// ADC가 바쁘지 않은 경우 SOC0 변환 강제 시작
if (!ADC_isBusy(ADCA_BASE))
{
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
}
// 1초 대기 (인터럽트 처리로 CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ADC-A의 내부 온도 센서(ADCIN14 채널)에 연결하여 온도 측정.
- 결과 처리: ADC_getTemperatureC 함수로 섭씨 온도 변환.
- 주기: 1초마다 온도 측정, temperatureC 변수에 저장.
5. 추가 고려 사항
- 샘플링 윈도우(S/H 시간): 데이터시트에 따르면, 12비트 모드에서는 최소 75ns, 16비트 모드에서는 320ns의 S/H 시간이 필요합니다. 샘플링 윈도우는 ADC_setupSOC의 sampleWindow 매개변수로 설정하며, ADC 클럭 주기에 따라 계산됩니다 (예: 50MHz ADC 클럭에서 15 사이클 = 300ns).
- 동기화: 다중 ADC 모듈을 사용할 경우, 트리거 소스와 S/H 시간을 통일하여 비동기 변환으로 인한 노이즈를 최소화해야 합니다.
- C2000Ware: 예제 코드는 C2000Ware의 DriverLib를 기반으로 작성되었습니다. C2000Ware는 C:\ti\c2000에 설치되며, 다양한 예제와 문서를 제공합니다.
- 디버깅: **Code Composer Studio(CCS)**에서 .syscfg GUI 툴을 사용하면 ADC 설정을 시각적으로 구성할 수 있어 편리합니다.
키워드: TMS320F28388D, ADC, DriverLib, C2000, 아날로그-디지털 변환, 마이크로컨트롤러, Code Composer Studio, ePWM 트리거, 온도 센서
'MCU > C2000' 카테고리의 다른 글
TMS320F28388D DSP EMIF 사용법: DriverLib API로 EMIF 설정 및 코드(수정) (0) | 2025.08.17 |
---|---|
TMS320F28388D DSP eQEP 사용법: DriverLib API로 eQEP 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP eCAP 사용법: DriverLib API로 eCAP 설정 및 코드(수정) (3) | 2025.08.17 |
TMS320F28388D DSP ePWM 사용법: DriverLib API로 ePWM 설정 및 코드(수정본) (0) | 2025.08.16 |
TMS320F28388D DSP CPU 타이머 사용법 : Driverlib API로 CPU 타이머 설정과 예제(수정본) (0) | 2025.08.08 |
TMS320F28388D DSP SCI 사용법: Driverlib API로 UART 설정 및 예제(수정본) (0) | 2025.08.08 |
TMS320F28388D DSP Driverlib 기반 프로젝트 설정 및 기본 프로그램 작성 절차 (0) | 2025.08.08 |
TMS320F28335 DSP ePWM SPWM 생성 (0) | 2025.08.07 |