본문 바로가기
MCU/C2000

TMS320F28377D DSP DMA 사용법 : Bitfield 구조 활용 예제 코드(수정)

by linuxgo 2025. 8. 18.

TI의 TMS320F28377D는 C2000 Delfino 시리즈의 32비트 마이크로컨트롤러로, 고성능 데이터 처리 및 전송에 최적화된 DMA(Direct Memory Access) 모듈을 제공합니다. DMA는 CPU 개입 없이 메모리 간 데이터 전송을 가능하게 하여 모터 제어, 데이터 로깅, 고속 데이터 수집과 같은 애플리케이션에서 효율적인 데이터 처리를 지원합니다. 이 문서에서는 TMS320F28377D의 DMA 모듈 설정 방법, Bitfield 구조를 활용한 레지스터 설정, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두가 쉽게 활용할 수 있도록 돕겠습니다.

1. TMS320F28377D DMA 모듈 개요

TMS320F28377D는 최대 6개의 독립적인 DMA 채널(CH1~CH6)을 포함하며, 각 채널은 고속 데이터 전송을 지원합니다. 아래는 주요 사양입니다:

  • 클럭 소스: 시스템 클럭(SYSCLK, 최대 200MHz)
  • 전송 모드:
    • 기본 모드: 단일 데이터 블록 전송
    • 버스트 모드: 고정 크기 데이터 버스트 전송
    • 연속 모드: 반복 전송
  • 소스/대상: RAM, 외부 메모리, 주변 장치(ADC, ePWM, SPI, McBSP 등)
  • 트리거 소스: 소프트웨어, ADC, ePWM, 외부 인터럽트(XINT), 타이머 등
  • 주요 기능:
    • 워드 크기: 16비트 또는 32비트
    • 인터럽트 지원: 전송 완료, 에러 발생 시
    • 채널 우선순위 설정
    • 동기화 지원: 다중 채널 간 동기화
  • 인터럽트: 전송 완료, 오버런, 에러 이벤트
  • 주소 지정 모드:
    • 고정 주소
    • 증가/감소 주소
    • 순환 버퍼 지원

2. DMA Bitfield 설정

TMS320F28377D의 DMA 레지스터는 Bitfield 구조로 정의되어 있으며, F2837xD_dma.h 헤더 파일을 통해 접근합니다. Bitfield는 레지스터의 개별 비트를 명확히 설정하여 코드 가독성과 유지보수성을 높입니다. 주요 레지스터와 Bitfield는 다음과 같습니다:

2.1 DMACTRL (DMA 제어 레지스터)

  • bit.HARDRESET: DMA 모듈 리셋 (1: 리셋, 0: 리셋 해제)
  • bit.PRIORITYRESET: 우선순위 설정 리셋 (1: 리셋)
  • 참고: 채널 우선순위는 PRIORITYCTRL1.bit.CH1PRIORITY로 설정 (0: 고정 우선순위, 1: 라운드 로빈).

2.2 MODE (채널 모드 레지스터)

  • bit.PERINTSEL: 주변 장치 인터럽트 소스 선택 (예: DMA_ADCAINT1, DMA_EPWM1A)
  • bit.OVRINTE: 오버플로우 인터럽트 활성화 (0: 비활성화, 1: 활성화)
  • bit.PERINTE: 주변 장치 인터럽트 활성화 (0: 비활성화, 1: 활성화)
  • bit.CHINTMODE: 채널 인터럽트 타이밍 (0: 전송 시작 시, 1: 전송 완료 시)
  • bit.ONESHOT: 단일 전송 모드 (0: 연속, 1: 단일)
  • bit.CONTINUOUS: 연속 전송 모드 (0: 비활성화, 1: 활성화)
  • bit.DATASIZE: 데이터 크기 (0: 16비트, 1: 32비트)
  • bit.CHINTE: 채널 인터럽트 활성화 (0: 비활성화, 1: 활성화)

2.3 CONTROL (채널 제어 레지스터)

  • bit.RUN: 전송 시작 (1: 시작)
  • bit.HALT: 전송 중지 (1: 중지)
  • bit.SOFTRESET: 소프트웨어 리셋 (1: 리셋)
  • bit.PERINTFRC: 인터럽트 강제 발생 (1: 강제)
  • bit.PERINTCLR: 인터럽트 플래그 클리어 (1: 클리어)
  • bit.ERRCLR: 에러 플래그 클리어 (1: 클리어)
  • bit.PERINTFLG: 인터럽트 플래그 상태 (1: 인터럽트 발생)
  • bit.TRANSFERSTS: 전송 상태 (1: 전송 중)
  • bit.BURSTSTS: 버스트 상태 (1: 버스트 중)
  • bit.OVRFLG: 오버플로우 플래그 (1: 오버플로우 발생)

2.4 SRC/DST ADDR (소스/대상 주소 레지스터)

  • SRC_BEG_ADDR_SHADOW: 소스 순환 버퍼 시작 주소 (Shadow)
  • SRC_ADDR_SHADOW: 소스 현재 주소 (Shadow)
  • DST_BEG_ADDR_SHADOW: 대상 순환 버퍼 시작 주소 (Shadow)
  • DST_ADDR_SHADOW: 대상 현재 주소 (Shadow)
  • 참고: Active 주소 레지스터(SRC_ADDR_ACTIVE, DST_ADDR_ACTIVE)는 하드웨어에서 관리.

2.5 BURST/TRANSFER SIZE

  • BURST_SIZE.bit.BURSTSIZE: 버스트당 전송 워드 수 (0~31, 실제 워드 수는 값+1)
  • TRANSFER_SIZE: 버스트 수 (0~65535, 실제 버스트 수는 값+1)
  • 참고: 전체 전송 워드 수 = (BURSTSIZE + 1) × (TRANSFER_SIZE + 1)

2.6 SRC/DST STEP (주소 스텝 레지스터)

  • SRC_BURST_STEP: 버스트 간 소스 주소 증가/감소 값
  • DST_BURST_STEP: 버스트 간 대상 주소 증가/감소 값
  • SRC_TRANSFER_STEP: 전송 간 소스 주소 증가/감소 값
  • DST_TRANSFER_STEP: 전송 간 대상 주소 증가/감소 값
  • SRC_WRAP_STEP: 소스 순환 버퍼 스텝
  • DST_WRAP_STEP: 대상 순환 버퍼 스텝

3. DMA 설정 절차

DMA 모듈을 효과적으로 설정하려면 다음 단계를 따라야 합니다:

시스템 초기화

  • InitSysCtrl()를 호출하여 시스템 클럭(예: 200MHz)과 PLL을 초기화.
  • 인터럽트를 비활성화하고 PIE를 초기화:
    DINT; // 글로벌 인터럽트 비활성화
    InitPieCtrl(); // PIE 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 클리어
    InitPieVectTable(); // PIE 벡터 테이블 초기화
    
  • ERTM 호출로 실시간 모드 활성화 (디버깅용, 선택 사항):
    ERTM; // 실시간 모드 활성화
    

DMA 클럭 활성화

  • CpuSysRegs.PCLKCR0.bit.DMA = 1로 DMA 모듈 클럭 활성화:
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 클럭 활성화
    EDIS; // 보호된 레지스터 접근 차단
    

DMA 채널 설정

  • DmaRegs.CHx.MODE.bit.PERINTSEL로 트리거 소스 선택 (예: DMA_ADCAINT1 for ADCINT1).
  • MODE.bit.DATASIZE로 데이터 크기 설정 (0: 16비트, 1: 32비트).
  • MODE.bit.ONESHOT 또는 MODE.bit.CONTINUOUS로 전송 모드 설정.
  • MODE.bit.PERINTE와 MODE.bit.CHINTE로 인터럽트 활성화 설정.
  • 예:
    DmaRegs.CH1.MODE.bit.PERINTSEL = DMA_ADCAINT1; // ADCINT1 트리거
    DmaRegs.CH1.MODE.bit.DATASIZE = SIXTEEN_BIT; // 16비트 데이터
    DmaRegs.CH1.MODE.bit.ONESHOT = ONESHOT_DISABLE; // 연속 전송
    DmaRegs.CH1.MODE.bit.CONTINUOUS = CONT_ENABLE; // 연속 모드 활성화
    DmaRegs.CH1.MODE.bit.PERINTE = PERINT_ENABLE; // 인터럽트 활성화
    DmaRegs.CH1.MODE.bit.CHINTE = CHINT_ENABLE; // 채널 인터럽트 활성화
    
  • 또는 C2000Ware 함수 사용:
    DMACH1ModeConfig(DMA_ADCAINT1, PERINT_ENABLE, ONESHOT_DISABLE, CONT_ENABLE,
                     SYNC_DISABLE, SYNC_SRC, OVRFLOW_DISABLE, SIXTEEN_BIT,
                     CHINT_END, CHINT_ENABLE);
    

소스 및 대상 설정

  • DmaRegs.CHx.SRC_BEG_ADDR_SHADOW와 DST_BEG_ADDR_SHADOW로 소스/대상 메모리 주소 설정.
  • 순환 버퍼 사용 시 SRC_WRAP_SIZE, DST_WRAP_SIZE 설정.
  • SRC_BURST_STEP, DST_BURST_STEP, SRC_TRANSFER_STEP, DST_TRANSFER_STEP으로 주소 증가/감소 설정.
  • 예:
    DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32)&AdcaResultRegs.ADCRESULT0; // 소스 주소
    DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32)&adcBuffer[0]; // 대상 주소
    DmaRegs.CH1.SRC_BURST_STEP = 1; // 소스 스텝: 1 워드
    DmaRegs.CH1.DST_BURST_STEP = 1; // 대상 스텝: 1 워드
    
  • 또는 C2000Ware 함수 사용:
    DMACH1AddrConfig(&adcBuffer[0], &AdcaResultRegs.ADCRESULT0);
    

버스트 및 전송 크기 설정

  • DmaRegs.CHx.BURST_SIZE.bit.BURSTSIZE로 버스트당 전송 워드 수 설정 (0~31).
  • DmaRegs.CHx.TRANSFER_SIZE로 버스트 수 설정 (0~65535).
  • 예:
    DmaRegs.CH1.BURST_SIZE.bit.BURSTSIZE = 7; // 버스트당 8 워드
    DmaRegs.CH1.TRANSFER_SIZE = 31; // 32 버스트 (총 256 워드)
    
  • 또는 C2000Ware 함수 사용:
    DMACH1BurstConfig(7, 1, 1); // 버스트 크기: 8 워드, 스텝: 1
    DMACH1TransferConfig(31, 1, 1); // 32 버스트, 스텝: 1
    

인터럽트 설정 (필요 시)

  • MODE.bit.PERINTE와 MODE.bit.CHINTE로 인터럽트 활성화.
  • PieVectTable.DMA_CHx_INT에 ISR 등록.
  • PIE 그룹 7과 CPU 인터럽트 활성화:
    EALLOW;
    PieVectTable.DMA_CH1_INT = &dma_ch1_isr; // DMA 채널 1 ISR
    PieCtrlRegs.PIEIER7.bit.INTx1 = 1; // PIE 그룹 7, DMA CH1 활성화
    IER |= M_INT7; // CPU 인터럽트 7 활성화
    EDIS;
    

DMA 실행

  • DmaRegs.CHx.CONTROL.bit.RUN = 1로 전송 시작.
  • 또는 C2000Ware 함수 사용:
    StartDMACH1(); // DMA 채널 1 전송 시작
    
  • 필요 시 CONTROL.bit.HALT로 전송 중지 또는 CONTROL.bit.ERRCLR로 에러 클리어:
    DmaRegs.CH1.CONTROL.bit.HALT = 1; // 전송 중지
    DmaRegs.CH1.CONTROL.bit.ERRCLR = 1; // 에러 플래그 클리어
    
  1.  

4. DMA 설정 고려사항

  • 트리거 소스: 트리거 소스는 애플리케이션에 맞게 선택 (예: ADC 변환 완료, ePWM 이벤트).
  • 메모리 정렬: 소스/대상 주소는 16비트 또는 32비트 정렬 필요.
  • 우선순위: 다중 채널 사용 시 DMACTRL.bit.PRIORITY로 우선순위 설정.
  • 인터럽트: 전송 완료 시 ISR에서 플래그 클리어 (CONTROL.bit.PERINTCLR).
  • 에러 처리: 오버런 또는 에러 발생 시 CONTROL.bit.ERRCLR로 플래그 클리어.
  • 성능 최적화: 버스트 크기를 최적화하여 CPU 부하 감소.

5. DMA 예제 코드 (Bitfield 구조)

아래는 TMS320F28377D DMA 모듈을 Bitfield 구조로 설정한 3개의 실용적인 예제 코드입니다. 각 예제는 Code Composer Studio(CCS)와 C2000Ware 환경에서 실행 가능합니다.

TMS320F28377D DMA

5.1 예제 1: ADC 데이터를 RAM으로 전송

#include "F28x_Project.h"
#include "F2837xD_Dma_defines.h"

// GPIO 매크로 정의
#define BLINKY_LED_GPIO 31 // GPIO31을 LED 출력 핀으로 사용

// ADC 데이터 저장을 위한 전역 버퍼
volatile Uint16 adcBuffer[256]; // 256 워드(16비트) 크기의 RAM 버퍼

// GPIO 설정 함수: LED용 GPIO31을 초기화
void setupGpio(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    GPIO_SetupPinMux(BLINKY_LED_GPIO, GPIO_MUX_CPU1, 0); // GPIO31을 CPU1의 일반 GPIO로 설정 (멀티플렉싱 기능 없음)
    GPIO_SetupPinOptions(BLINKY_LED_GPIO, GPIO_OUTPUT, GPIO_PUSHPULL); // GPIO31을 출력, 푸시-풀 모드로 설정
    GPIO_WritePin(BLINKY_LED_GPIO, 1); // LED 초기 상태: 켜짐
    EDIS; // 보호된 레지스터 접근 차단
}

// DMA 채널 1 인터럽트 서비스 루틴: 전송 완료 시 호출
__interrupt void dma_ch1_isr(void) {
    DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1; // DMA 채널 1 인터럽트 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹 7 인터럽트 ACK (승인)
}

void main(void) {
    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭(200MHz) 및 PLL 초기화, C2000Ware 제공 함수
    DINT; // 모든 인터럽트 비활성화 (글로벌 인터럽트 마스크)
    InitPieCtrl(); // PIE(Peripheral Interrupt Expansion) 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 레지스터 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 클리어
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // DMA 채널 1 인터럽트 벡터 설정
    EALLOW; // 보호된 레지스터 접근 허용
    PieVectTable.DMA_CH1_INT = &dma_ch1_isr; // DMA 채널 1 인터럽트 벡터를 ISR에 연결
    PieCtrlRegs.PIEIER7.bit.INTx1 = 1; // PIE 그룹 7, DMA 채널 1 인터럽트 활성화
    IER |= M_INT7; // CPU 레벨에서 인터럽트 7 활성화 (DMA 관련)
    EDIS; // 보호된 레지스터 접근 차단

    // GPIO 설정 호출
    setupGpio(); // LED용 GPIO31 설정

    // ADC 설정: ADC A 모듈을 12비트, 단일 입력 모드로 설정
    EALLOW; // 보호된 레지스터 접근 허용
    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); // ADC A, 12비트 해상도, 단일 입력
    AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // ADC 클럭 분주: SYSCLK/12 (200MHz/12 ≈ 16.67MHz)
    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // 인터럽트 펄스를 변환 완료 시점에 발생
    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 전원 활성화
    DELAY_US(1000); // ADC 안정화를 위한 1ms 대기
    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // ADCINT1을 SOC0에서 트리거
    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // ADCINT1 인터럽트 활성화 (DMA 트리거용)
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADC 채널 A0 선택
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 15; // 샘플링 윈도우: 16 사이클 (12비트 ADC에 적합)
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // 트리거 소스: ePWM1 SOCA
    EDIS; // 보호된 레지스터 접근 차단

    // ePWM1 설정: ADC 트리거를 위한 100kHz PWM 신호 생성
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR2.bit.EPWM1 = 1; // ePWM1 모듈 클럭 활성화
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // 타이머 업 카운트 모드
    EPwm1Regs.TBCTL.bit.CLKDIV = 0; // 클럭 분주비 1/1
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 1; // 고속 클럭 분주비 1/1 (TBCLK = 200MHz/2 = 100MHz)
    EPwm1Regs.TBPRD = 2000; // 주기 설정: 100MHz/2000 = 100kHz
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; // SOCA 이벤트 활성화
    EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; // 타이머가 0일 때 SOCA 발생
    EPwm1Regs.ETPS.bit.SOCAPRD = 1; // 매 주기마다 SOCA 발생
    EPwm1Regs.ETCLR.bit.SOCA = 1; // SOCA 플래그 클리어
    EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; // Free Run 모드 (지속 동작)
    EDIS; // 보호된 레지스터 접근 차단

    // DMA 클럭 활성화
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 모듈 클럭 활성화
    EDIS; // 보호된 레지스터 접근 차단

    // DMA 채널 1 설정: ADC 데이터를 RAM으로 전송
    DMAInitialize(); // DMA 모듈 초기화 (C2000Ware 제공)
    DMACH1AddrConfig(&adcBuffer[0], &AdcaResultRegs.ADCRESULT0); // 소스: ADC 결과 레지스터, 대상: adcBuffer
    DMACH1BurstConfig(0, 1, 1); // 버스트 크기: 1 워드, 소스/대상 스텝: 1 (1워드씩 증가)
    DMACH1TransferConfig(255, 1, 1); // 전송 크기: 256 워드, 소스/대상 스텝: 1
    DMACH1WrapConfig(0xFFFF, 0, 0xFFFF, 0); // 순환 버퍼 비활성화 (0xFFFF는 무효 값)
    DMACH1ModeConfig(
        DMA_ADCAINT1,      // 트리거 소스: ADCINT1
        PERINT_ENABLE,     // 주변 장치 인터럽트 활성화
        ONESHOT_DISABLE,   // 단일 전송 비활성화 (연속 전송)
        CONT_ENABLE,       // 연속 모드 활성화
        SYNC_DISABLE,      // 동기화 비활성화
        SYNC_SRC,          // 동기화 소스 (동기화 비활성화 시 무관)
        OVRFLOW_DISABLE,   // 오버플로우 인터럽트 비활성화
        SIXTEEN_BIT,       // 데이터 크기: 16비트
        CHINT_END,         // 인터럽트 타이밍: 전송 완료 시
        CHINT_ENABLE       // 채널 인터럽트 활성화
    );
    StartDMACH1(); // DMA 채널 1 전송 시작

    EINT; // 글로벌 인터럽트 활성화

설명:

  • 기능: ADC 채널 A0의 데이터를 DMA 채널 1을 통해 RAM 버퍼(adcBuffer)로 전송.
  • 설정: ADC는 ePWM1 SOCA로 트리거, 100kHz 샘플링, DMA는 256 워드 전송, 16비트 데이터.
  • GPIO: GPIO31(LED).
  • 출력: ADC 데이터가 adcBuffer에 저장, 정상 동작 시 LED ON.

5.2 예제 2: RAM 간 데이터 전송 (소프트웨어 트리거)

#include "F28x_Project.h"
#include "F2837xD_Dma_defines.h"

// GPIO 매크로 정의
#define BLINKY_LED_GPIO 31 // GPIO31을 LED 출력 핀으로 사용

// RAM 데이터 전송을 위한 전역 버퍼
volatile Uint16 srcBuffer[256]; // 소스 버퍼: 전송할 데이터 저장 (256 워드, 16비트)
volatile Uint16 dstBuffer[256]; // 대상 버퍼: 전송된 데이터 저장 (256 워드, 16비트)

// GPIO 설정 함수: LED용 GPIO31을 초기화
void setupGpio(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    GPIO_SetupPinMux(BLINKY_LED_GPIO, GPIO_MUX_CPU1, 0); // GPIO31을 CPU1의 일반 GPIO로 설정 (멀티플렉싱 기능 없음)
    GPIO_SetupPinOptions(BLINKY_LED_GPIO, GPIO_OUTPUT, GPIO_PUSHPULL); // GPIO31을 출력, 푸시-풀 모드로 설정
    GPIO_WritePin(BLINKY_LED_GPIO, 1); // LED 초기 상태: 켜짐
    EDIS; // 보호된 레지스터 접근 차단
}

void main(void) {
    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭(200MHz) 및 PLL 초기화, C2000Ware 제공 함수
    DINT; // 모든 인터럽트 비활성화 (글로벌 인터럽트 마스크)
    InitPieCtrl(); // PIE(Peripheral Interrupt Expansion) 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 레지스터 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 클리어
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // GPIO 설정 호출
    setupGpio(); // LED용 GPIO31 설정

    // 소스 버퍼 초기화
    Uint16 i;
    for (i = 0; i < 256; i++) {
        srcBuffer[i] = i; // 테스트 데이터: srcBuffer에 0~255 값 저장
    }

    // DMA 클럭 활성화
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 모듈 클럭 활성화
    EDIS; // 보호된 레지스터 접근 차단

    // DMA 채널 1 설정: srcBuffer에서 dstBuffer로 데이터 전송
    DMAInitialize(); // DMA 모듈 초기화 (C2000Ware 제공)
    DMACH1AddrConfig(&dstBuffer[0], &srcBuffer[0]); // 소스: srcBuffer, 대상: dstBuffer
    DMACH1BurstConfig(7, 1, 1); // 버스트 크기: 8 워드 (7+1), 소스/대상 스텝: 1 (1워드씩 증가)
    DMACH1TransferConfig(31, 1, 1); // 전송 크기: 32 버스트 (31+1, 총 256 워드), 소스/대상 스텝: 1
    DMACH1WrapConfig(0xFFFF, 0, 0xFFFF, 0); // 순환 버퍼 비활성화 (0xFFFF는 무효 값)
    DMACH1ModeConfig(
        0,                 // 트리거 소스: 소프트웨어 트리거 (0)
        PERINT_DISABLE,    // 주변 장치 인터럽트 비활성화
        ONESHOT_ENABLE,    // 단일 전송 활성화 (1회 전송 후 종료)
        CONT_DISABLE,      // 연속 모드 비활성화
        SYNC_DISABLE,      // 동기화 비활성화
        SYNC_SRC,          // 동기화 소스 (동기화 비활성화 시 무관)
        OVRFLOW_DISABLE,   // 오버플로우 인터럽트 비활성화
        SIXTEEN_BIT,       // 데이터 크기: 16비트
        CHINT_END,         // 인터럽트 타이밍: 전송 완료 시 (사용 안 함)
        CHINT_DISABLE      // 채널 인터럽트 비활성화
    );
    StartDMACH1(); // DMA 채널 1 전송 시작

    for(;;) {
        // 무한 루프: 데이터는 dstBuffer에 저장됨
        // 디버깅 시 CCS Expressions 창에서 dstBuffer 확인 가능
    }
}

설명:

  • 기능: RAM 내 srcBuffer의 데이터를 DMA 채널 1을 통해 dstBuffer로 전송 (소프트웨어 트리거).
  • 설정: 256 워드 전송, 16비트 데이터, 버스트 크기 8 워드, 총 32 버스트.
  • GPIO: GPIO31(LED).
  • 출력: srcBuffer 데이터가 dstBuffer로 복사, 정상 동작 시 LED ON.

5.3 예제 3: DMA 인터럽트 기반 데이터 전송

#include "F28x_Project.h"
#include "F2837xD_Dma_defines.h"

// GPIO 매크로 정의
#define BLINKY_LED_GPIO 31 // GPIO31을 LED 출력 핀으로 사용

// RAM 데이터 전송을 위한 전역 버퍼 및 플래그
volatile Uint16 srcBuffer[256]; // 소스 버퍼: 전송할 데이터 저장 (256 워드, 16비트)
volatile Uint16 dstBuffer[256]; // 대상 버퍼: 전송된 데이터 저장 (256 워드, 16비트)
volatile Uint16 transferComplete = 0; // DMA 전송 완료 플래그

// GPIO 설정 함수: LED용 GPIO31을 초기화
void setupGpio(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    GPIO_SetupPinMux(BLINKY_LED_GPIO, GPIO_MUX_CPU1, 0); // GPIO31을 CPU1의 일반 GPIO로 설정 (멀티플렉싱 기능 없음)
    GPIO_SetupPinOptions(BLINKY_LED_GPIO, GPIO_OUTPUT, GPIO_PUSHPULL); // GPIO31을 출력, 푸시-풀 모드로 설정
    GPIO_WritePin(BLINKY_LED_GPIO, 1); // LED 초기 상태: 켜짐
    EDIS; // 보호된 레지스터 접근 차단
}

// DMA 채널 1 인터럽트 서비스 루틴: 전송 완료 시 호출
__interrupt void dma_ch1_isr(void) {
    DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1; // DMA 채널 1 인터럽트 플래그 클리어
    transferComplete = 1; // 전송 완료 플래그 설정
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹 7 인터럽트 ACK (승인)
}

void main(void) {
    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭(200MHz) 및 PLL 초기화, C2000Ware 제공 함수
    InitGpio(); // GPIO 모듈 초기화, 모든 GPIO를 기본 상태로 설정
    DINT; // 모든 인터럽트 비활성화 (글로벌 인터럽트 마스크)
    InitPieCtrl(); // PIE(Peripheral Interrupt Expansion) 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 레지스터 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 클리어
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // 인터럽트 벡터 설정
    EALLOW; // 보호된 레지스터 접근 허용
    PieVectTable.DMA_CH1_INT = &dma_ch1_isr; // DMA 채널 1 인터럽트 벡터를 ISR에 연결
    PieCtrlRegs.PIEIER7.bit.INTx1 = 1; // PIE 그룹 7, DMA 채널 1 인터럽트 활성화
    IER |= M_INT7; // CPU 레벨에서 인터럽트 7 활성화 (DMA 관련)
    EDIS; // 보호된 레지스터 접근 차단

    // GPIO 설정 호출
    setupGpio(); // LED용 GPIO31 설정

    // 소스 버퍼 초기화
    Uint16 i;
    for (i = 0; i < 256; i++) {
        srcBuffer[i] = i; // 테스트 데이터: srcBuffer에 0~255 값 저장
    }

    // DMA 클럭 활성화
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 모듈 클럭 활성화
    EDIS; // 보호된 레지스터 접근 차단

    // DMA 채널 1 설정: srcBuffer에서 dstBuffer로 데이터 전송
    DMAInitialize(); // DMA 모듈 초기화 (C2000Ware 제공)
    DMACH1AddrConfig(&dstBuffer[0], &srcBuffer[0]); // 소스: srcBuffer, 대상: dstBuffer
    DMACH1BurstConfig(7, 1, 1); // 버스트 크기: 8 워드 (7+1), 소스/대상 스텝: 1 (1워드씩 증가)
    DMACH1TransferConfig(31, 1, 1); // 전송 크기: 32 버스트 (31+1, 총 256 워드), 소스/대상 스텝: 1
    DMACH1WrapConfig(0xFFFF, 0, 0xFFFF, 0); // 순환 버퍼 비활성화 (0xFFFF는 무효 값)
    DMACH1ModeConfig(
        0,                 // 트리거 소스: 소프트웨어 트리거 (0)
        PERINT_ENABLE,     // 주변 장치 인터럽트 활성화 (전송 완료 인터럽트)
        ONESHOT_ENABLE,    // 단일 전송 활성화 (1회 전송 후 종료)
        CONT_DISABLE,      // 연속 모드 비활성화
        SYNC_DISABLE,      // 동기화 비활성화
        SYNC_SRC,          // 동기화 소스 (동기화 비활성화 시 무관)
        OVRFLOW_DISABLE,   // 오버플로우 인터럽트 비활성화
        SIXTEEN_BIT,       // 데이터 크기: 16비트
        CHINT_END,         // 인터럽트 타이밍: 전송 완료 시
        CHINT_ENABLE       // 채널 인터럽트 활성화
    );
    StartDMACH1(); // DMA 채널 1 전송 시작

    // 인터럽트 및 실시간 모드 활성화
    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화 (디버깅용)

    // 전송 완료 대기
    while (!transferComplete); // DMA 전송 완료까지 대기
    GpioDataRegs.GPBTOGGLE.all |= (1UL << 31); // GPIO31 LED 토글 (전송 완료 표시)

    for(;;) {
        // 무한 루프: 데이터는 dstBuffer에 저장됨
        // 디버깅 시 CCS Expressions 창에서 dstBuffer 확인 가능
    }
}

설명:

  • 기능: RAM 내 srcBuffer의 데이터를 DMA 채널 1을 통해 dstBuffer로 전송, 전송 완료 시 인터럽트 발생.
  • 설정: 256 워드 전송, 16비트 데이터, 버스트 크기 8 워드, 총 32 버스트, 인터럽트 활성화.
  • GPIO: GPIO31(LED).
  • 완료 동작: 전송 완료 시 transferComplete 플래그 설정, LED 토글.

6. 사용 방법

6.1 환경 설정

  • C2000Ware 설치: C:\ti\c2000\C2000Ware_x_xx_xx_xx에서 라이브러리 다운로드.
  • CCS 프로젝트: TMS320F28377D 타겟으로 프로젝트 생성, F28x_Project.h 포함.
  • 링커 파일: device_support\f2837xd 폴더에서 링커 파일 추가.

6.2 코드 실행

  • 각 예제를 별도의 .c 파일로 저장하거나, main.c에 복사.
  • 원하는 예제만 실행되도록 다른 코드 주석 처리.

6.3 하드웨어 준비

  • ADC 입력: 예제 1의 경우, ADC A0 핀에 아날로그 입력 연결.
  • LED: GPIO31에 LED 연결 (정상 동작 확인용).
  • 디버깅 장비: CCS와 JTAG 디버거로 변수 및 메모리 점검.

6.4 디버깅

  • CCS Expressions 창: adcBuffer, dstBuffer 확인.
  • 레지스터 점검: DmaRegs.CH1.CONTROL, DmaRegs.CH1.BURST_SIZE 모니터링.
  • 인터럽트 확인: DmaRegs.CH1.CONTROL.bit.PERINTFLG로 인터럽트 상태 점검.
  • 에러 확인: DmaRegs.CH1.CONTROL.bit.ERRFLG로 에러 상태 점검.

7. 추가 팁

  • 캘리브레이션: ADC 사용 시 Device_cal() 호출로 클럭 보정.
  • 노이즈 감소: ADC 입력에 저역통과 필터 사용.
  • C2000Ware 참고: C:\ti\c2000\C2000Ware_x_xx_xx_xx\device_support\f2837xd\examples\cpu1\dma.
  • 문제 해결:
    • 데이터 전송 실패: SRC_ADDR, DST_ADDR 정렬 확인.
    • 인터럽트 미발생: MODE.bit.PERINTSEL, PieCtrlRegs.PIEIER7 확인.
    • DMA 미작동: CpuSysRegs.PCLKCR0.bit.DMA 및 CONTROL.bit.RUN 확인.
  • TI 리소스: TI E2E 포럼, C2000Ware 예제.

8. 결론

이 문서는 TMS320F28377D DMA 모듈의 설정 방법과 Bitfield 구조를 활용한 예제 코드를 제공하여, 초보자부터 숙련된 개발자까지 쉽게 활용할 수 있도록 구성했습니다. ADC 데이터 전송, RAM 간 데이터 전송, 인터럽트 기반 전송 예제를 통해 다양한 애플리케이션에 적용 가능합니다.

키워드: TMS320F28377D, DMA, C2000, 데이터 전송, 마이크로컨트롤러, Code Composer Studio, ADC, RAM 전송, 인터럽트, 버스트 모드, 순환 버퍼