본문 바로가기
MCU/C2000

[TMS320F28377D] 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: 리셋)
  • bit.PRIORITY: 채널 우선순위 (0: 고정, 1: 라운드 로빈)
  • bit.PRIORITYRESET: 우선순위 설정 리셋

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

  • bit.CHSEL: 채널 선택 (0~5)
  • bit.PERINTSEL: 주변 장치 인터럽트 소스 선택 (예: ADCINT1, EPWM1_INT)
  • bit.ONESHOT: 단일 전송 모드 (0: 연속, 1: 단일)
  • bit.CONTINUOUS: 연속 전송 모드 (1: 활성화)
  • bit.DATASIZE: 데이터 크기 (0: 16비트, 1: 32비트)
  • bit.BURSTSIZE: 버스트 크기 (0~31 워드)

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

  • bit.RUN: 전송 시작 (1: 시작)
  • bit.HALT: 전송 중지 (1: 중지)
  • bit.SOFTRESET: 소프트웨어 리셋 (1: 리셋)
  • bit.PERINTCLR: 인터럽트 플래그 클리어
  • bit.ERRCLR: 에러 플래그 클리어

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

  • bit.SRC_ADDR: 소스 시작 주소
  • bit.DST_ADDR: 대상 시작 주소
  • bit.SRC_BEG_ADDR: 소스 순환 버퍼 시작 주소
  • bit.DST_BEG_ADDR: 대상 순환 버퍼 시작 주소

2.5 BURST/TRANSFER SIZE

  • bit.BURST_SIZE: 버스트당 전송 워드 수
  • bit.TRANSFER_SIZE: 전체 전송 워드 수

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

  • bit.SRC_STEP: 소스 주소 증가/감소 값
  • bit.DST_STEP: 대상 주소 증가/감소 값

Bitfield 사용 이점:

  • 명확한 비트 단위 설정으로 실수 감소
  • 코드 가독성 및 유지보수성 향상
  • F2837xD_dma.h에서 제공하는 구조체로 직관적 접근

3. DMA 설정 절차

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

  1. 시스템 초기화:
    • InitSysCtrl()를 호출하여 시스템 클럭과 PLL을 초기화합니다.
    • 인터럽트를 비활성화하고 PIE를 초기화합니다 (DINT, InitPieCtrl, InitPieVectTable).
  2. DMA 클럭 활성화:
    • CpuSysRegs.PCLKCR0.bit.DMA = 1을 설정하여 DMA 모듈 클럭을 활성화합니다.
    • 보호된 레지스터 접근을 위해 EALLOW와 EDIS 사용.
  3. DMA 채널 설정:
    • MODE.bit.CHSEL로 채널 선택 (CH1~CH6).
    • MODE.bit.PERINTSEL로 트리거 소스 선택 (예: ADCINT1).
    • MODE.bit.DATASIZE로 데이터 크기 설정 (16/32비트).
    • MODE.bit.ONESHOT 또는 MODE.bit.CONTINUOUS로 전송 모드 설정.
  4. 소스 및 대상 설정:
    • SRC_ADDR와 DST_ADDR로 소스/대상 메모리 주소 설정.
    • 순환 버퍼 사용 시 SRC_BEG_ADDR, DST_BEG_ADDR 설정.
    • SRC_STEP, DST_STEP으로 주소 증가/감소 설정.
  5. 버스트 및 전송 크기 설정:
    • BURST_SIZE로 버스트당 전송 워드 수 설정.
    • TRANSFER_SIZE로 전체 전송 워드 수 설정.
  6. 인터럽트 설정 (필요 시):
    • CONTROL.bit.PERINTSEL로 인터럽트 활성화.
    • PIE 벡터 테이블에 ISR(인터럽트 서비스 루틴) 등록.
  7. DMA 실행:
    • CONTROL.bit.RUN = 1로 전송 시작.
    • 필요 시 CONTROL.bit.HALT로 전송 중지.

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 환경에서 실행 가능합니다.

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

#include "F28x_Project.h"

volatile Uint16 adcBuffer[256]; // ADC 데이터 저장 버퍼

void main(void) {
    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭 및 PLL 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // GPIO 및 ADC 설정
    EALLOW;
    GpioCtrlRegs.GPBDIR.bit.GPIO31 = 1; // GPIO31을 출력(LED)으로 설정
    GpioDataRegs.GPBSET.bit.GPIO31 = 1; // LED 켜기
    AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE);
    AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // ADC 클럭 분주
    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // 인터럽트 펄스 위치
    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 전원 활성화
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADC 채널 A0
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 15; // 샘플링 윈도우
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // ePWM1 SOCA 트리거
    EDIS;

    // ePWM1 설정 (ADC 트리거용)
    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
    EPwm1Regs.TBPRD = 2000; // 주기 = 2000 TBCLK (100kHz)
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; // SOCA 활성화
    EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; // TBCTR=0일 때 SOCA 발생
    EPwm1Regs.ETPS.bit.SOCAPRD = 1; // 첫 번째 이벤트에서 SOCA 발생
    EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; // Free run 모드
    EDIS;

    // DMA 클럭 활성화
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 클럭 활성화
    EDIS;

    // DMA 채널 1 설정 (Bitfield 사용)
    DMAInitialize(); // DMA 초기화
    DMACH1AddrConfig(&adcBuffer[0], &AdcaResultRegs.ADCRESULT0); // 소스: ADC, 대상: RAM
    DMACH1BurstConfig(0, 1, 1); // 버스트 크기: 1 워드, 소스/대상 스텝: 1
    DMACH1TransferConfig(255, 1, 1); // 전송 크기: 256 워드
    DMACH1WrapConfig(0xFFFF, 0, 0xFFFF, 0); // 순환 버퍼 비활성화
    DMACH1ModeConfig(DMA_ADCAINT1, PERINT_ENABLE, ONESHOT_DISABLE, 
                     CONT_ENABLE, SYNC_DISABLE, SYNC_SRC, 
                     DATASIZE_16BIT, CH1_ENABLE); // ADCINT1 트리거, 16비트 데이터
    StartDMACH1(); // DMA 채널 1 시작

    for(;;); // 무한 루프
}

설명:

  • 기능: 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"

volatile Uint16 srcBuffer[256]; // 소스 버퍼
volatile Uint16 dstBuffer[256]; // 대상 버퍼

void main(void) {
    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭 및 PLL 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // GPIO 설정
    EALLOW;
    GpioCtrlRegs.GPBDIR.bit.GPIO31 = 1; // GPIO31을 출력(LED)으로 설정
    GpioDataRegs.GPBSET.bit.GPIO31 = 1; // LED 켜기
    EDIS;

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

    // DMA 클럭 활성화
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 클럭 활성화
    EDIS;

    // DMA 채널 1 설정 (Bitfield 사용)
    DMAInitialize(); // DMA 초기화
    DMACH1AddrConfig(&dstBuffer[0], &srcBuffer[0]); // 소스: srcBuffer, 대상: dstBuffer
    DMACH1BurstConfig(7, 1, 1); // 버스트 크기: 8 워드
    DMACH1TransferConfig(31, 1, 1); // 전송 크기: 32 버스트 (256 워드)
    DMACH1WrapConfig(0xFFFF, 0, 0xFFFF, 0); // 순환 버퍼 비활성화
    DMACH1ModeConfig(0, PERINT_DISABLE, ONESHOT_ENABLE, 
                     CONT_DISABLE, SYNC_DISABLE, SYNC_SRC, 
                     DATASIZE_16BIT, CH1_ENABLE); // 소프트웨어 트리거, 16비트 데이터
    StartDMACH1(); // DMA 채널 1 시작

    for(;;); // 무한 루프
}

설명:

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

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

#include "F28x_Project.h"

volatile Uint16 srcBuffer[256]; // 소스 버퍼
volatile Uint16 dstBuffer[256]; // 대상 버퍼
volatile Uint16 transferComplete = 0; // 전송 완료 플래그

__interrupt void dma_ch1_isr(void) {
    DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1; // 인터럽트 플래그 클리어
    transferComplete = 1; // 전송 완료 표시
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹 7 ACK
}

void main(void) {
    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭 및 PLL 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // 인터럽트 벡터 설정
    EALLOW;
    PieVectTable.DMA_CH1_INT = &dma_ch1_isr; // DMA 채널 1 인터럽트 벡터
    EDIS;

    // GPIO 설정
    EALLOW;
    GpioCtrlRegs.GPBDIR.bit.GPIO31 = 1; // GPIO31을 출력(LED)으로 설정
    GpioDataRegs.GPBSET.bit.GPIO31 = 1; // LED 켜기
    EDIS;

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

    // DMA 클럭 활성화
    EALLOW;
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 클럭 활성화
    EDIS;

    // DMA 채널 1 설정 (Bitfield 사용)
    DMAInitialize(); // DMA 초기화
    DMACH1AddrConfig(&dstBuffer[0], &srcBuffer[0]); // 소스: srcBuffer, 대상: dstBuffer
    DMACH1BurstConfig(7, 1, 1); // 버스트 크기: 8 워드
    DMACH1TransferConfig(31, 1, 1); // 전송 크기: 32 버스트 (256 워드)
    DMACH1WrapConfig(0xFFFF, 0, 0xFFFF, 0); // 순환 버퍼 비활성화
    DMACH1ModeConfig(0, PERINT_ENABLE, ONESHOT_ENABLE, 
                     CONT_DISABLE, SYNC_DISABLE, SYNC_SRC, 
                     DATASIZE_16BIT, CH1_ENABLE); // 소프트웨어 트리거, 인터럽트 활성화
    PieCtrlRegs.PIEIER7.bit.INTx1 = 1; // PIE 그룹 7, DMA CH1 인터럽트 활성화
    IER |= M_INT7; // CPU 인터럽트 7 활성화
    EINT; // 글로벌 인터럽트 활성화

    StartDMACH1(); // DMA 채널 1 시작

    // 전송 완료 대기
    while (!transferComplete); // 전송 완료까지 대기
    GpioDataRegs.GPBTOGGLE.bit.GPIO31 = 1; // LED 토글 (완료 표시)

    for(;;); // 무한 루프
}

설명:

  • 기능: 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 전송, 인터럽트, 버스트 모드, 순환 버퍼

반응형