본문 바로가기
MCU/C2000

TMS320F28388D DSP DMA 사용법: DriverLib API로 DMA 설정 및 코드(수정)

by linuxgo 2025. 8. 17.

1. TMS320F28388D DMA 개요

TMS320F28388D는 Texas Instruments의 C2000 시리즈 32비트 마이크로컨트롤러로, 최대 6개의 DMA(Direct Memory Access) 채널을 제공합니다. DMA 모듈은 CPU 개입 없이 메모리 간 데이터 전송을 처리하여 실시간 애플리케이션에서 효율적인 데이터 이동을 가능하게 합니다. 모터 제어, 데이터 로깅, ADC 결과 처리 등에 적합합니다.

DMA 모듈의 주요 특징

  • 채널: 6개의 독립적인 DMA 채널 제공.
  • 트리거 소스: ePWM, ADC, SPI, McBSP, 외부 인터럽트 등 다양한 트리거 소스 지원.
  • 전송 모드: 단일 전송, 블록 전송, 버스트 전송 지원.
  • 데이터 크기: 16비트 또는 32비트 단위 전송.
  • 메모리 액세스: RAM, Flash, 외부 메모리 등 다양한 메모리 공간 접근 가능.
  • 인터럽트: 전송 완료 또는 에러 시 인터럽트 발생 가능.

DriverLib API는 복잡한 레지스터 조작을 추상화하여 DMA 설정을 간소화합니다.

2. 주요 DMA DriverLib API 함수

아래는 TMS320F28388D의 DMA 모듈을 제어하기 위해 자주 사용되는 DriverLib API 함수와 그 사용 방법입니다.

2.1. DMA 기본 설정 관련 함수

DMA_initController()

  • 설명: DMA 컨트롤러를 초기화하여 모든 채널을 기본 상태로 설정합니다. 모든 레지스터를 리셋하고 DMA 모듈을 동작 가능한 상태로 준비합니다.
  • 매개변수: 없음.
  • 사용 예:
    // 시스템 시작 시 DMA 모듈 초기화
    DMA_initController();
    

DMA_configMode()

  • 설명: 특정 DMA 채널의 동작 모드와 트리거 소스를 설정합니다. 전송 모드(단일/연속), 데이터 크기(16비트/32비트), 트리거 소스(소프트웨어, ePWM 등)를 지정합니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소 (예: DMA_CH1_BASE).
    • trigger: 트리거 소스 (예: DMA_TRIGGER_SOFTWARE, DMA_TRIGGER_EPWM1_SOCA).
    • config: 동작 모드 플래그 (예: DMA_CFG_ONESHOT_DISABLE, DMA_CFG_CONTINUOUS_DISABLE, DMA_CFG_SIZE_16BIT).
  • 사용 예:
    // DMA 채널 1을 소프트웨어 트리거, 단일 전송, 16비트 모드로 설정
    DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SOFTWARE, 
                   (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT));
    

DMA_configAddresses()

  • 설명: DMA 전송의 소스 및 목적지 메모리 주소를 설정합니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소 (예: DMA_CH1_BASE).
    • dest: 목적지 메모리 주소 (포인터).
    • src: 소스 메모리 주소 (포인터).
  • 사용 예:
    // ADC 결과 레지스터에서 버퍼로 데이터 전송
    uint16_t adcBuffer[256];
    DMA_configAddresses(DMA_CH1_BASE, adcBuffer, (uint16_t *)ADCARESULT_BASE);
    

DMA_configBurst()

  • 설명: 버스트 전송의 크기와 소스/목적지 주소 증가 단위를 설정합니다. 버스트는 한 번의 트리거로 전송되는 데이터 단위입니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소.
    • size: 버스트당 전송 단위 수 (1~16).
    • srcStep: 소스 주소 증가 단위 (바이트 단위, 예: 2는 16비트 증가).
    • destStep: 목적지 주소 증가 단위 (바이트 단위).
  • 사용 예:
    // 1워드 버스트, 소스 고정, 목적지 2바이트 증가
    DMA_configBurst(DMA_CH1_BASE, 1, 0, 2);
    

DMA_configTransfer()

  • 설명: 전체 전송 크기와 주소 증가 단위를 설정합니다. 전체 전송은 여러 버스트로 구성됩니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소.
    • size: 전체 전송 단위 수 (버스트 횟수).
    • srcStep: 소스 주소 증가 단위 (버스트 간, 바이트 단위).
    • destStep: 목적지 주소 증가 단위 (버스트 간, 바이트 단위).
  • 사용 예:
    // 256번 전송, 소스 고정, 목적지 2바이트 증가
    DMA_configTransfer(DMA_CH1_BASE, 256, 0, 2);
    

DMA_enableTrigger()

  • 설명: DMA 채널의 트리거를 활성화하여 트리거 신호를 수신할 준비를 합니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소.
  • 사용 예:
    // DMA 채널 1 트리거 활성화
    DMA_enableTrigger(DMA_CH1_BASE);
    

DMA_startChannel()

  • 설명: DMA 채널을 시작하여 데이터 전송을 개시합니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소.
  • 사용 예:
    // DMA 채널 1 전송 시작
    DMA_startChannel(DMA_CH1_BASE);
    

2.2. 인터럽트 관련 함수

DMA_enableInterrupt()

  • 설명: DMA 채널의 인터럽트를 활성화하여 전송 완료 또는 오류 시 인터럽트를 발생시킵니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소.
  • 사용 예:
    // DMA 채널 1 인터럽트 활성화
    DMA_enableInterrupt(DMA_CH1_BASE);
    

DMA_setInterruptMode()

  • 설명: 인터럽트 발생 조건을 설정합니다 (예: 전송 완료 시).
  • 매개변수:
    • base: DMA 채널의 베이스 주소.
    • mode: 인터럽트 모드 (예: DMA_INT_AT_END).
  • 사용 예:
    // 전송 완료 시 인터럽트 설정
    DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END);
    

DMA_clearInterruptFlag()

  • 설명: DMA 인터럽트 플래그를 지워 추가 인터럽트를 수신할 수 있도록 합니다.
  • 매개변수:
    • base: DMA 채널의 베이스 주소.
  • 사용 예:
    // DMA 채널 1 인터럽트 플래그 지우기
    DMA_clearInterruptFlag(DMA_CH1_BASE);
    

Interrupt_register()

  • 설명: 인터럽트 서비스 루틴(ISR)을 특정 인터럽트 번호에 등록합니다.
  • 매개변수:
    • intNumber: 인터럽트 번호 (예: INT_DMA_CH1).
    • handler: ISR 함수 포인터.
  • 사용 예:
    // DMA 채널 1 ISR 등록
    Interrupt_register(INT_DMA_CH1, &dmaCh1ISR);
    

3. DMA 설정 및 동작 원리

  1. 시스템 초기화: 시스템 클럭, GPIO, 인터럽트 벡터 테이블을 초기화합니다.
Device_init(); // 시스템 클럭 및 주변 장치 초기화 
Device_initGPIO(); // GPIO 초기화 
Interrupt_initModule(); // 인터럽트 모듈 초기화 
Interrupt_initVectorTable(); // 인터럽트 벡터 테이블 초기화
  1. DMA 컨트롤러 초기화: DMA 모듈을 기본 상태로 설정합니다.
DMA_initController(); // DMA 컨트롤러 초기화
  1. DMA 채널 설정: 소스/목적지 주소, 버스트/전송 크기, 트리거 소스를 설정합니다.
DMA_configAddresses(DMA_CH1_BASE, destBuffer, srcBuffer); 
DMA_configBurst(DMA_CH1_BASE, 8, 2, 2); 
DMA_configTransfer(DMA_CH1_BASE, 16, 16, 16); 
DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SOFTWARE, (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT));
  1. 트리거 및 인터럽트 설정: 트리거 활성화 및 인터럽트를 설정하여 전송 완료를 감지합니다.
DMA_enableTrigger(DMA_CH1_BASE); 
DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END); 
DMA_enableInterrupt(DMA_CH1_BASE); 
Interrupt_register(INT_DMA_CH1, &dmaCh1ISR); 
Interrupt_enable(INT_DMA_CH1);
  1. DMA 시작: DMA 채널을 시작하여 데이터 전송을 개시합니다.
DMA_startChannel(DMA_CH1_BASE);

4. DMA 예제 코드

아래는 C2000Ware의 DriverLib를 기반으로 작성된 DMA 예제 코드로, Code Composer Studio(CCS)에서 실행 가능합니다. 각 예제는 독립적이며 상세한 주석을 포함합니다.

TMS320F28388D DSP DMA

4.1. 예제 1: ADC 결과를 DMA로 버퍼에 저장

ADC 변환 결과를 DMA를 통해 메모리 버퍼로 전송합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: 0은 초기화 완료, 1은 DMA 전송 완료, 0xFFFF는 오류
volatile uint32_t dmaStatus = 0;
// DMA 전송 완료 플래그: 0은 미완료, 1은 완료
volatile uint16_t done = 0;

// ADC 결과 저장 버퍼 크기 정의 (1024 샘플, 16의 배수로 DMA 전송 최적화)
#define RESULTS_BUFFER_SIZE 1024
// ADC 결과 버퍼를 GS0 RAM에 배치 (고속 액세스 메모리)
#pragma DATA_SECTION(adcABuffer, "ramgs0");
#pragma DATA_SECTION(adcCBuffer, "ramgs0");
uint16_t adcABuffer[RESULTS_BUFFER_SIZE]; // ADCA (A3 채널) 결과 저장 버퍼
uint16_t adcCBuffer[RESULTS_BUFFER_SIZE]; // ADCC (C3 채널) 결과 저장 버퍼

// 함수 프로토타입 선언
__interrupt void adcA1ISR(void); // ADC 인터럽트 서비스 루틴
__interrupt void dmach1ISR(void); // DMA 인터럽트 서비스 루틴
void configureEPWM(uint32_t epwmBase); // ePWM 모듈 설정 함수
void initializeDMA(void); // DMA 초기화 함수
void configureDMAChannels(void); // DMA 채널 설정 함수

// GPIO 초기화 함수
// GPIO31을 디버깅용 LED로 설정 (LAUNCHXL-F2838x 기준)
void initGPIO(void)
{
    // GPIO31을 일반 GPIO로 설정
    GPIO_setPinConfig(GPIO_31_GPIO31);
    // GPIO31을 출력 모드로 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    // GPIO31에 내부 풀업 저항 활성화 (외부 회로 안정성 확보)
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    // 초기 상태: LED OFF (GPIO31 = 0)
    GPIO_writePin(31, 0);
}

// ADC 및 DMA 초기화 함수
// ADCA와 ADCC를 설정하고, DMA를 통해 결과를 버퍼에 저장하도록 준비
void initADCandDMA(void)
{
    // ADC-A 및 ADC-C의 클럭 활성화 (SYSCTL을 통해 주변 장치 활성화)
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCC);

    // ADC 설정: 200MHz SYSCLK에서 50MHz ADCCLK 생성 (DIV_4_0)
    ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
    ADC_setPrescaler(ADCC_BASE, ADC_CLK_DIV_4_0);
    // ADC 모드 설정: 12비트 해상도, 단일 엔드 모드 (외부 3.3V VREF 가정)
    ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
    ADC_setMode(ADCC_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);

    // ADC SOC0 설정: ePWM2 SOCA로 트리거, A3/C3 채널, 샘플링 윈도우 15 사이클
    // - A3 (ADCA)와 C3 (ADCC) 채널 선택
    // - 샘플링 윈도우 15 사이클은 일반적인 입력 신호에 적합 (고임피던스 신호는 조정 필요)
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM2_SOCA, ADC_CH_ADCIN3, 15);
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM2_SOCA, ADC_CH_ADCIN3, 15);

    // ADC 인터럽트 설정: ADCINT2로 SOC0 재트리거 (연속 변환 활성화)
    // - ADCINT2가 SOC0을 재트리거하여 연속 변환 구현
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_ADCINT2);
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_ADCINT2);

    // ADC 컨버터 활성화 (아날로그 회로 전원 ON)
    ADC_enableConverter(ADCA_BASE);
    ADC_enableConverter(ADCC_BASE);

    // ADC 안정화를 위해 1ms 대기 (데이터시트: 최소 500us 필요)
    DEVICE_DELAY_US(1000);

    // 결과 버퍼 초기화: adcABuffer와 adcCBuffer를 0으로 초기화
    uint16_t resultsIndex;
    for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++)
    {
        adcABuffer[resultsIndex] = 0;
        adcCBuffer[resultsIndex] = 0;
    }

    // 인터럽트 플래그 초기화
    // - DMA 채널 1, 2의 트리거 플래그 초기화
    // - ADC 인터럽트 플래그 초기화 (ADCINT1, ADCINT2)
    // - ePWM2의 ADC 트리거 플래그 초기화
    DMA_clearTriggerFlag(DMA_CH1_BASE);
    DMA_clearTriggerFlag(DMA_CH2_BASE);
    HWREGH(ADCA_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCA의 ADCINT1, ADCINT2 플래그 초기화
    HWREGH(ADCC_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCC의 ADCINT1, ADCINT2 플래그 초기화
    EPWM_forceADCTriggerEventCountInit(EPWM2_BASE, EPWM_SOC_A);
    EPWM_clearADCTriggerFlag(EPWM2_BASE, EPWM_SOC_A);

    // ePWM2 클럭 활성화 및 설정
    // - TBCLKSYNC 비활성화 후 설정, 설정 완료 후 활성화
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    configureEPWM(EPWM2_BASE);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    // DMA 초기화 및 채널 설정
    initializeDMA();
    configureDMAChannels();
}

// ADC 인터럽트 서비스 루틴
// - ADCA의 ADCINT1 발생 시 호출
// - 첫 변환 후 ePWM 트리거 비활성화 및 인터럽트 비활성화
#pragma CODE_SECTION(adcA1ISR, ".TI.ramfunc");
__interrupt void adcA1ISR(void)
{
    // ePWM2의 ADC SOCA 트리거 비활성화 (추가 변환 방지)
    EPWM_disableADCTrigger(EPWM2_BASE, EPWM_SOC_A);

    // ADCA의 ADCINT1 인터럽트 비활성화 (단일 인터럽트 처리)
    Interrupt_disable(INT_ADCA1);

    // 인터럽트 그룹 1에 대한 ACK (ADCA 인터럽트 처리 완료)
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

// DMA 인터럽트 서비스 루틴
// - DMA 채널 1의 전송 완료 시 호출
// - ADC 트리거 제거 및 전송 완료 플래그 설정
#pragma CODE_SECTION(dmach1ISR, ".TI.ramfunc");
__interrupt void dmach1ISR(void)
{
    // ADC SOC0의 인터럽트 트리거 제거 (ADCA, ADCC 변환 중지)
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
    
    // DMA 전송 완료 플래그 설정
    done = 1;
    // DMA 동작 상태 업데이트 (1: 완료)
    dmaStatus = 1;

    // DMA 인터럽트 그룹 7에 대한 ACK (DMA 전송 완료 처리)
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
}

// ePWM 설정 함수
// - ePWM2를 40us 주기(50kHz)로 설정, ADC SOCA 트리거 생성
void configureEPWM(uint32_t epwmBase)
{
    // 타이머 베이스 초기화 (TBCTL 레지스터 초기화)
    HWREGH(epwmBase + EPWM_O_TBCTL) = 0x0000U;
    // 주기 설정: 200MHz / 4000 = 50kHz (40us 주기)
    EPWM_setTimeBasePeriod(epwmBase, 4000U);
    // AQ 설정: TBCTR=0에서 출력 HIGH
    EPWM_setActionQualifierAction(epwmBase, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    // AQ 설정: TBCTR=CMPA에서 출력 LOW (50% 듀티 사이클)
    EPWM_setActionQualifierAction(epwmBase, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    // CMPA 설정: 2000 (50% 듀티 사이클)
    EPWM_setCounterCompareValue(epwmBase, EPWM_COUNTER_COMPARE_A, 2000U);
    // ADC 트리거 소스: TBCTR=0에서 SOCA 발생
    EPWM_setADCTriggerSource(epwmBase, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
    // ADC 트리거 프리스케일: 1 (매 주기마다 트리거)
    EPWM_setADCTriggerEventPrescale(epwmBase, EPWM_SOC_A, 1U);
    // ADC 트리거 카운트 초기화 활성화
    EPWM_enableADCTriggerEventCountInit(epwmBase, EPWM_SOC_A);
}

// DMA 초기화 함수
// - DMA 컨트롤러 초기화 및 에뮬레이션 모드 설정
void initializeDMA(void)
{
    // DMA 컨트롤러 초기화
    DMA_initController();
    // 에뮬레이션 모드: 디버깅 중에도 DMA 동작 (자유 실행)
    DMA_setEmulationMode(DMA_EMULATION_FREE_RUN);
}

// DMA 채널 설정 함수
// - DMA 채널 1, 2를 설정하여 ADCA, ADCC 결과를 버퍼로 전송
void configureDMAChannels(void)
{
    // DMA 채널 1: ADCA (A3 채널) 결과 전송
    // - 소스: ADCARESULT_BASE, 목적지: adcABuffer
    DMA_configAddresses(DMA_CH1_BASE, (uint16_t *)&adcABuffer, (uint16_t *)ADCARESULT_BASE);
    // 버스트 설정: 16워드 단위, 소스/목적지 주소 2씩 증가
    DMA_configBurst(DMA_CH1_BASE, 16, 2, 2);
    // 전송 설정: (1024/16)번 전송, 소스 -14, 목적지 +2
    DMA_configTransfer(DMA_CH1_BASE, (RESULTS_BUFFER_SIZE >> 4), -14, 2);
    // 모드 설정: ADCINT2 트리거, 원샷/연속 비활성화, 32비트 전송
    DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_ADCA2, 
                   (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_32BIT));
    // DMA 채널 1 트리거 활성화
    DMA_enableTrigger(DMA_CH1_BASE);
    // 오버런 인터럽트 비활성화
    DMA_disableOverrunInterrupt(DMA_CH1_BASE);
    // 인터럽트 모드: 전송 완료 시 발생
    DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END);
    // DMA 채널 1 인터럽트 활성화
    DMA_enableInterrupt(DMA_CH1_BASE);

    // DMA 채널 2: ADCC (C3 채널) 결과 전송
    // - 소스: ADCCRESULT_BASE, 목적지: adcCBuffer
    DMA_configAddresses(DMA_CH2_BASE, (uint16_t *)&adcCBuffer, (uint16_t *)ADCCRESULT_BASE);
    // 버스트 설정: 16워드 단위, 소스/목적지 주소 2씩 증가
    DMA_configBurst(DMA_CH2_BASE, 16, 2, 2);
    // 전송 설정: (1024/16)번 전송, 소스 -14, 목적지 +2
    DMA_configTransfer(DMA_CH2_BASE, (RESULTS_BUFFER_SIZE >> 4), -14, 2);
    // 모드 설정: ADCINT2 트리거, 원샷/연속 비활성화, 32비트 전송
    DMA_configMode(DMA_CH2_BASE, DMA_TRIGGER_ADCA2, 
                   (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_32BIT));
    // DMA 채널 2 트리거 활성화
    DMA_enableTrigger(DMA_CH2_BASE);
    // 오버런 인터럽트 비활성화
    DMA_disableOverrunInterrupt(DMA_CH2_BASE);
    // 인터럽트 모드: 전송 완료 시 발생
    DMA_setInterruptMode(DMA_CH2_BASE, DMA_INT_AT_END);
    // DMA 채널 2 인터럽트 활성화
    DMA_enableInterrupt(DMA_CH2_BASE);
}

// 메인 함수
// - 시스템 초기화, ADC/DMA 설정, 데이터 수집 및 디버깅
void main(void)
{
    // 시스템 클럭, PLL, 주변 장치 초기화 (F2838x 디바이스 설정)
    Device_init();
    
    // GPIO 기본 초기화 (F2838x의 기본 GPIO 설정)
    Device_initGPIO();
    
    // 디버깅용 GPIO31 (LED) 설정
    initGPIO();
    
    // 인터럽트 모듈 및 벡터 테이블 초기화
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 인터럽트 서비스 루틴 등록
    // - DMA 채널 1 인터럽트: dmach1ISR
    // - ADCA 인터럽트 1: adcA1ISR
    Interrupt_register(INT_DMA_CH1, &dmach1ISR);
    Interrupt_register(INT_ADCA1, &adcA1ISR);
    
    // 시스템 클럭 확인: 200MHz 예상
    // - 클럭이 200MHz가 아니면 오류 처리
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        dmaStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0; // 디버깅용 정지
    }
    
    // ADC 및 DMA 초기화
    initADCandDMA();
    
    // 인터럽트 활성화
    // - DMA 채널 1 인터럽트
    // - ADCA 인터럽트 1
    Interrupt_enable(INT_DMA_CH1);
    Interrupt_enable(INT_ADCA1);
    
    // 글로벌 인터럽트 활성화
    EINT;
    // 실시간 디버깅 인터럽트 활성화
    ERTM;
    
    // DMA 채널 1, 2 시작
    DMA_startChannel(DMA_CH1_BASE);
    DMA_startChannel(DMA_CH2_BASE);
    
    // ePWM2의 ADC SOCA 트리거 활성화
    EPWM_enableADCTrigger(EPWM2_BASE, EPWM_SOC_A);
    
    // DMA 전송 완료 대기
    // - 100ms 주기로 GPIO31 상태 업데이트 (디버깅용 LED)
    while(done == 0)
    {
        GPIO_writePin(31, (dmaStatus == 1) ? 1 : 0); // 상태 표시: 완료 시 LED ON
        DEVICE_DELAY_US(100000); // 100ms 대기
    }
    
    // DMA 전송 완료 후 처리
    GPIO_writePin(31, 1); // LED ON으로 완료 표시
    ESTOP0; // 디버깅용 정지
}

설명:

  • 기능: ePWM1의 SOCA 트리거로 ADC 변환 결과를 DMA를 통해 메모리 버퍼로 전송.
  • 설정: ADC(12비트, 50MHz), ePWM1(100kHz, SOCA 트리거), DMA 채널 1(ADC 결과 → 버퍼).
  • GPIO: GPIO31(LED).
  • 출력: ADC 결과가 adcBuffer에 저장, 정상 동작 시 LED ON.
  • 용도: 실시간 데이터 수집, 모터 제어 피드백.

4.2. 예제 2: 메모리 간 데이터 전송

DMA를 사용하여 메모리 간 데이터를 전송합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: 0은 초기화 완료, 1은 DMA 전송 완료, 0xFFFF는 오류
volatile uint32_t dmaStatus = 0;
// DMA 전송 완료 플래그: 0은 미완료, 1은 완료
volatile uint16_t done = 0;

// 소스 및 목적지 버퍼 정의: 128개의 16비트 데이터
#define BUFFER_SIZE 128
#pragma DATA_SECTION(srcBuffer, "ramgs0");  // 소스 버퍼: RAMGS0 (고속 메모리)
#pragma DATA_SECTION(destBuffer, "ramgs1"); // 목적지 버퍼: RAMGS1 (고속 메모리)
uint16_t srcBuffer[BUFFER_SIZE];           // 소스 버퍼: 테스트 데이터
uint16_t destBuffer[BUFFER_SIZE];          // 목적지 버퍼: DMA 전송 결과

// 함수 프로토타입 선언
__interrupt void dmaCh1ISR(void); // DMA 채널 1 인터럽트 서비스 루틴
void initGPIO(void);              // GPIO 초기화 함수
void initDMA(void);               // DMA 초기화 및 설정 함수
void error(void);                 // 오류 처리 함수

// GPIO 초기화 함수
// - GPIO31을 디버깅용 LED로 설정 (LAUNCHXL-F28379D 기준)
void initGPIO(void)
{
    // GPIO31을 일반 GPIO로 설정
    GPIO_setPinConfig(GPIO_31_GPIO31);
    // GPIO31을 출력 모드로 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    // GPIO31에 내부 풀업 저항 활성화 (외부 회로 안정성 확보)
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    // 초기 상태: LED OFF (GPIO31 = 0)
    GPIO_writePin(31, 0);
}

// 오류 처리 함수
// - 데이터 무결성 실패 또는 기타 오류 시 호출
// - 디버거 정지 및 무한 루프
void error(void)
{
    dmaStatus = 0xFFFF; // 오류 상태 설정
    GPIO_writePin(31, 0); // LED OFF로 오류 표시
    ESTOP0; // 디버깅용 정지
    for(;;); // 무한 루프
}

// DMA 인터럽트 서비스 루틴
// - DMA 채널 1 전송 완료 시 호출, 데이터 무결성 검사
#pragma CODE_SECTION(dmaCh1ISR, ".TI.ramfunc");
__interrupt void dmaCh1ISR(void)
{
    uint16_t i;

    // DMA 채널 1 정지
    DMA_stopChannel(DMA_CH1_BASE);
    
    // DMA 트리거 플래그 지우기
    DMA_clearTriggerFlag(DMA_CH1_BASE);
    
    // 인터럽트 그룹 7에 대한 ACK (DMA 인터럽트 처리 완료)
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
    
    // 데이터 무결성 검사: destBuffer[i] == i 확인
    for (i = 0; i < BUFFER_SIZE; i++)
    {
        if (destBuffer[i] != i)
        {
            error(); // 데이터 불일치 시 오류 처리
        }
    }
    
    // DMA 동작 상태 업데이트: 전송 완료
    dmaStatus = 1;
    // 전송 완료 플래그 설정
    done = 1;
    // 디버깅용: LED ON
    GPIO_writePin(31, 1);
}

// DMA 초기화 및 설정 함수
// - DMA 컨트롤러와 채널 1을 설정하여 RAMGS0에서 RAMGS1으로 데이터 전송
void initDMA(void)
{
    uint16_t i;

    // 소스 버퍼 초기화: 0부터 127까지 값으로 채움 (테스트 데이터)
    for (i = 0; i < BUFFER_SIZE; i++)
    {
        srcBuffer[i] = i;
    }
    // 목적지 버퍼 초기화: 0으로 채움
    for (i = 0; i < BUFFER_SIZE; i++)
    {
        destBuffer[i] = 0;
    }
    
    // DMA 컨트롤러 초기화
    DMA_initController();
    // 에뮬레이션 모드: 디버깅 중에도 DMA 동작 (자유 실행)
    DMA_setEmulationMode(DMA_EMULATION_FREE_RUN);
    
    // DMA 채널 1 설정
    // - 소스: srcBuffer (RAMGS0), 목적지: destBuffer (RAMGS1)
    DMA_configAddresses(DMA_CH1_BASE, (uint16_t *)destBuffer, (uint16_t *)srcBuffer);
    // 버스트 설정: 8워드 단위, 소스/목적지 주소 2바이트 증가
    DMA_configBurst(DMA_CH1_BASE, 8, 2, 2);
    // 전송 설정: 16번 전송 (128/8), 소스/목적지 주소 16바이트 증가 (8*2)
    DMA_configTransfer(DMA_CH1_BASE, (BUFFER_SIZE / 8), 16, 16);
    // 모드 설정: 소프트웨어 트리거, 단일 전송, 16비트 데이터
    DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SOFTWARE, 
                   (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT));
    
    // DMA 인터럽트 설정: 전송 완료 시 발생
    DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END);
    DMA_enableInterrupt(DMA_CH1_BASE);
    
    // DMA 트리거 활성화
    DMA_enableTrigger(DMA_CH1_BASE);
    
    // 초기화 완료 상태 설정
    dmaStatus = 0;
}

// 메인 함수
// - 시스템 초기화, DMA 설정, 데이터 전송 및 디버깅
void main(void)
{
    // 시스템 클럭, PLL, 주변 장치 초기화 (F28379D 디바이스 설정)
    Device_init();
    
    // GPIO 기본 초기화
    Device_initGPIO();
    
    // 디버깅용 GPIO31 (LED) 설정
    initGPIO();
    
    // 인터럽트 모듈 및 벡터 테이블 초기화
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // DMA 채널 1 인터럽트 ISR 등록
    Interrupt_register(INT_DMA_CH1, &dmaCh1ISR);
    
    // 시스템 클럭 확인: 200MHz 예상
    // - 클럭이 200MHz가 아니면 오류 처리
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        dmaStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        error(); // 오류 처리
    }
    
    // DMA 초기화 및 설정
    initDMA();
    
    // DMA 인터럽트 활성화
    Interrupt_enable(INT_DMA_CH1);
    
    // 글로벌 인터럽트 활성화
    EINT;
    // 실시간 디버깅 인터럽트 활성화
    ERTM;
    
    // DMA 전송 시작 및 완료 대기
    // - 8워드 × 16 전송 완료까지 소프트웨어 트리거 반복
    done = 0;
    while (!done)
    {
        DMA_forceTrigger(DMA_CH1_BASE); // 소프트웨어 트리거 강제 실행
        asm(" RPT #255 || NOP"); // 대기 (참조 코드와 동일)
        GPIO_writePin(31, (dmaStatus == 1) ? 1 : 0); // 상태 표시
    }
    
    // 전송 완료 후 처리
    GPIO_writePin(31, 1); // LED ON으로 완료 표시
    ESTOP0; // 디버깅용 정지
}

설명:

  • 기능: 소스 버퍼에서 목적지 버퍼로 데이터를 DMA를 통해 전송.
  • 설정: DMA 채널 1, 소프트웨어 트리거, 16비트 데이터 전송.
  • GPIO: GPIO31(LED).
  • 출력: srcBuffer 데이터가 destBuffer로 복사, 정상 동작 시 LED ON.
  • 용도: 대량 데이터 처리, 메모리 초기화.

5. 추가 고려 사항

  • 트리거 선택: 애플리케이션 요구사항에 따라 적절한 트리거 소스(ePWM, ADC, 소프트웨어 등) 선택.
  • 메모리 정렬: DMA 전송 시 소스/목적지 주소는 16비트 또는 32비트 정렬 권장.
  • 인터럽트 관리: 전송 완료 인터럽트를 활용하여 동적 제어 가능.
  • C2000Ware: 예제 코드는 C2000Ware의 DriverLib 기반. C:\ti\c2000에 설치.
  • 디버깅: CCS의 .syscfg 툴로 DMA 설정 시각적 구성 가능.

키워드: TMS320F28388D, DMA, DriverLib, C2000, ADC, 메모리 전송, Code Composer Studio, 인터럽트, 실시간 제어