본문 바로가기
MCU/C2000

[TMS320F28335] DMA 사용법 : Bitfield 구조 활용 예제 코드

by linuxgo 2025. 8. 19.
반응형

1. TMS320F28335 DMA 모듈 개요

TI의 TMS320F28335는 C2000 Delfino 시리즈의 32비트 마이크로컨트롤러로, 고속 데이터 전송을 위한 DMA(Direct Memory Access) 모듈을 제공합니다. DMA 모듈은 CPU의 개입 없이 메모리 간 데이터 전송을 수행하여 ADC 데이터 처리, 메모리 복사, 외부 인터페이스 데이터 전송 등에 적합합니다. 이 문서에서는 TMS320F28335 DMA 모듈의 설정 방법, Bitfield 구조를 활용한 레지스터 설정, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두 쉽게 활용할 수 있도록 돕습니다.

주요 사양

  • 채널 수: 6개의 독립적인 DMA 채널 (채널 1~6)
  • 전송 모드:
    • 블록 전송: 고정된 데이터 블록 전송
    • 버스트 전송: 작은 데이터 단위 전송
  • 트리거 소스:
    • 소프트웨어 트리거
    • ADC, ePWM, McBSP, XINT 등 하드웨어 트리거
  • 데이터 크기: 16비트 또는 32비트 워드
  • 주소 모드: 증가, 감소, 고정
  • 인터럽트: 전송 완료, 에러 시 인터럽트 지원
  • 메모리 액세스: 내부 RAM, 외부 메모리, 주변 장치 레지스터
  • 클럭 소스: 시스템 클럭(SYSCLK, 최대 150MHz)

2. DMA Bitfield 설정 상세

TMS320F28335의 DMA 레지스터는 Bitfield 구조로 정의되어 있으며, F2833x_dma.h 헤더 파일을 통해 접근합니다. 주요 레지스터는 다음과 같습니다:

2.1 DMACTRL (DMA 제어 레지스터)

  • bit.HARDRESET: DMA 모듈 리셋 (1: 리셋)
  • bit.PRIORITY: 채널 우선순위 (0: 고정, 1: 라운드 로빈)
  • bit.PRIORITYRESET: 우선순위 리셋

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

  • bit.CHxEN: 채널 활성화 (1: 활성화, x=1~6)
  • bit.DATASIZE: 데이터 크기 (0: 16비트, 1: 32비트)
  • bit.CONTINUOUS: 연속 모드 (1: 활성화)
  • bit.ONESHOT: 원샷 모드 (1: 활성화)
  • bit.TRIGMODE: 트리거 모드 (0: 소프트웨어, 1: 하드웨어)
  • bit.SYNCE: 동기화 활성화 (1: 활성화)
  • bit.OVRINTE: 오버플로우 인터럽트 활성화

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

  • bit.RUN: 전송 시작 (1: 시작)
  • bit.STOP: 전송 정지 (1: 정지)
  • bit.SOFTRESET: 채널 소프트 리셋
  • bit.TRANSFERSTS: 전송 상태 플래그
  • bit.ERRCLR: 에러 플래그 클리어

2.4 BURST_SIZE (버스트 크기 레지스터)

  • bit.BURSTSIZE: 버스트당 전송 워드 수 (0~31)

2.5 SRC/DST_ADDR (소스/목적지 주소 레지스터)

  • bit.SRCADDR: 소스 메모리 주소
  • bit.DSTADDR: 목적지 메모리 주소

2.6 TRANSFER_SIZE (전송 크기 레지스터)

  • bit.TRANSFERSIZE: 전체 전송 워드 수

3. DMA 설정 절차

  1. 시스템 초기화:
    •   InitSysCtrl()로 시스템 클럭과 PLL 초기화
    •   인터럽트 비활성화 및 PIE 초기화 (DINT, InitPieCtrl, InitPieVectTable)
  2. DMA 클럭 활성화:
    •   CpuSysRegs.PCLKCR0.bit.DMA = 1로 DMA 모듈 클럭 활성화
    •   보호된 레지스터 접근을 위해 EALLOW와 EDIS 사용
  3. DMA 채널 설정:
    •   MODE.bit.CHxEN으로 채널 활성화
    •   MODE.bit.DATASIZE로 데이터 크기 설정 (16비트/32비트)
    •   MODE.bit.TRIGMODE로 트리거 소스 설정
  4. 소스 및 목적지 설정:
    •   SRC_ADDR와 DST_ADDR로 소스/목적지 메모리 주소 설정
    •   주소 모드 설정 (증가/감소/고정)
  5. 버스트 및 전송 크기 설정:
    •   BURST_SIZE.bit.BURSTSIZE로 버스트 크기 설정
    •   TRANSFER_SIZE.bit.TRANSFERSIZE로 전체 전송 크기 설정
  6. 인터럽트 설정 (필요 시):
    •   MODE.bit.OVRINTE로 오버플로우 인터럽트 활성화
    •   PieVectTable.DMAx_INT로 인터럽트 벡터 설정
  7. DMA 실행:
    • CONTROL.bit.RUN = 1로 전송 시작

4. DMA 설정 고려사항

  • 메모리 정렬: 소스/목적지 주소는 워드(16비트) 단위로 정렬
  • 트리거 선택: ADC, ePWM, McBSP 등 하드웨어 트리거와 동기화
  • 우선순위: 다중 채널 사용 시 우선순위 설정 필요
  • 인터럽트: 전송 완료 인터럽트로 데이터 처리 최적화
  • 에러 처리: 오버플로우, 주소 에러 확인 및 처리
  • 성능 최적화: 버스트 크기와 전송 크기 최적화로 대역폭 활용

5. 실용적인 DMA 예제 코드 (Bitfield 구조)

아래는 TMS320F28335 DMA 모듈을 Bitfield 구조로 설정한 예제 코드들입니다. GPIO와 DMA 설정은 별도의 함수로 분리되었으며, 각 라인에 상세한 주석이 추가되었습니다. Code Composer Studio(CCS)와 C2000Ware 환경에서 실행 가능합니다.

5.1 예제 1: ADC 데이터 DMA 전송

// File: dma_adc_transfer.c
// Description: TMS320F28335 DMA를 사용한 ADC 데이터 전송 예제
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28335

#include "F28x_Project.h"

volatile Uint16 AdcBuffer[256]; // DMA 목적지 버퍼: ADC 데이터 저장

// 인터럽트 서비스 루틴: DMA 채널 1 인터럽트 처리
__interrupt void dma_ch1_isr(void)
{
    DmaRegs.CH1.CONTROL.bit.TRANSFERSTS = 0; // 전송 상태 플래그 클리어
    DmaRegs.CH1.CONTROL.bit.ERRCLR = 1; // 에러 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹 7 인터럽트 ACK
}

// GPIO 설정 함수
void ConfigureGPIO(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // GPIO34를 출력으로 설정 (LED용)
    GpioDataRegs.GPBSET.bit.GPIO34 = 1; // GPIO34를 High로 설정하여 LED 켬
    EDIS; // 보호된 레지스터 접근 비허용
}

// ADC 설정 함수
void ConfigureADC(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; // ADC 인터럽트 펄스 위치: 변환 완료 시
    AdcRegs.ADCCTL1.bit.ADCENABLE = 1; // ADC 모듈 활성화
    AdcRegs.ADCCTL1.bit.ADCBGPWD = 1; // 백그라운드 전원 활성화
    AdcRegs.ADCCTL1.bit.ADCPWDN = 1; // ADC 전원 활성화
    AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADC 채널 A0 선택
    AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; // 샘플링 윈도우 설정 (7 사이클)
    AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // 트리거 소스: ePWM1 SOCA
    EDIS; // 보호된 레지스터 접근 비허용
}

// ePWM1 설정 함수 (ADC 트리거용)
void ConfigureEPWM1(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR1.bit.EPWM1 = 1; // ePWM1 모듈 클럭 활성화
    EDIS; // 보호된 레지스터 접근 비허용

    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // 타임-베이스 카운터를 업 카운트 모드로 설정
    EPwm1Regs.TBCTL.bit.CLKDIV = 0; // 클럭 분주비 1/1 (SYSCLK = 150MHz)
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 2; // 고속 클럭 분주비 1/2 (TBCLK = 75MHz)
    EPwm1Regs.TBPRD = 750; // 주기 레지스터 설정: 100kHz (10us)
    EPwm1Regs.CMPA.bit.CMPA = 375; // 비교 레지스터 A 설정: 50% 듀티
    EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // TBCTR=0일 때 PWM_A 출력을 High로 설정
    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // TBCTR=CMPA일 때 PWM_A 출력을 Low로 설정
    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 모드
}

// DMA 채널 1 설정 함수
void ConfigureDMA(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 모듈 클럭 활성화
    DmaRegs.DMACTRL.bit.HARDRESET = 1; // DMA 모듈 하드 리셋
    DmaRegs.DMACTRL.bit.PRIORITY = 0; // 고정 우선순위
    EDIS; // 보호된 레지스터 접근 비허용

    EALLOW; // 보호된 레지스터 접근 허용
    DmaRegs.CH1.MODE.bit.CH1EN = 1; // 채널 1 활성화
    DmaRegs.CH1.MODE.bit.DATASIZE = 0; // 16비트 데이터 전송
    DmaRegs.CH1.MODE.bit.TRIGMODE = 1; // 하드웨어 트리거 (ADC SOCA)
    DmaRegs.CH1.MODE.bit.ONESHOT = 0; // 연속 모드
    DmaRegs.CH1.MODE.bit.SYNCE = 0; // 동기화 비활성화
    DmaRegs.CH1.MODE.bit.OVRINTE = 1; // 오버플로우 인터럽트 활성화
    DmaRegs.CH1.BURST_SIZE.all = 0; // 버스트 크기: 1 워드
    DmaRegs.CH1.SRC_BURST_STEP = 0; // 소스 주소 고정 (ADC 결과 레지스터)
    DmaRegs.CH1.DST_BURST_STEP = 1; // 목적지 주소 증가
    DmaRegs.CH1.TRANSFER_SIZE = 255; // 전송 크기: 256 워드
    DmaRegs.CH1.SRC_ADDR = (Uint32)&AdcRegs.ADCRESULT0; // 소스: ADC 결과 레지스터
    DmaRegs.CH1.DST_ADDR = (Uint32)&AdcBuffer[0]; // 목적지: AdcBuffer
    DmaRegs.CH1.DMA_CH1_TRIGSEL = DMA_ADCSOC1; // 트리거: ADC SOCA
    DmaRegs.CH1.CONTROL.bit.RUN = 1; // DMA 전송 시작
    EDIS; // 보호된 레지스터 접근 비허용
}

void main(void) {
    InitSysCtrl(); // 시스템 클럭(150MHz)과 PLL 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 레지스터 비활성화
    IFR = 0x0000; // 인터럽트 플래그 레지스터 클리어
    InitPieVectTable(); // PIE 인터럽트 벡터 테이블 초기화

    EALLOW; // 보호된 레지스터 접근 허용
    PieVectTable.DMA_CH1_INT = &dma_ch1_isr; // DMA 채널 1 인터럽트 벡터 설정
    EDIS; // 보호된 레지스터 접근 비허용

    ConfigureGPIO(); // GPIO 설정 함수 호출
    ConfigureADC(); // ADC 설정 함수 호출
    ConfigureEPWM1(); // ePWM1 설정 함수 호출 (ADC 트리거용)
    ConfigureDMA(); // DMA 설정 함수 호출

    PieCtrlRegs.PIEIER7.bit.INTx1 = 1; // PIE 그룹 7에서 DMA 채널 1 인터럽트 활성화
    IER |= M_INT7; // CPU 인터럽트 그룹 7 활성화
    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    for(;;); // 무한 루프: DMA 전송 지속
}

설명:

  • 기능: ePWM1의 SOCA 트리거를 사용하여 ADC 데이터를 DMA로 전송하여 AdcBuffer에 저장
  • 설정:
    • ePWM1: 100kHz 주기, SOCA 트리거 활성화
    • ADC: 채널 A0, ePWM1 SOCA로 트리거
    • DMA 채널 1: ADC 결과 레지스터에서 AdcBuffer로 256 워드 전송
  • GPIO: GPIO34(LED)
  • 출력: AdcBuffer에 ADC 데이터 저장, LED ON

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

// File: dma_memory_transfer.c
// Description: TMS320F28335 DMA를 사용한 메모리 간 데이터 전송 예제
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28335

#include "F28x_Project.h"

volatile Uint16 SourceBuffer[128]; // 소스 버퍼
volatile Uint16 DestBuffer[128];   // 목적지 버퍼

// 인터럽트 서비스 루틴: DMA 채널 2 인터럽트 처리
__interrupt void dma_ch2_isr(void)
{
    DmaRegs.CH2.CONTROL.bit.TRANSFERSTS = 0; // 전송 상태 플래그 클리어
    DmaRegs.CH2.CONTROL.bit.ERRCLR = 1; // 에러 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹 7 인터럽트 ACK
}

// GPIO 설정 함수
void ConfigureGPIO(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // GPIO34를 출력으로 설정 (LED용)
    GpioDataRegs.GPBSET.bit.GPIO34 = 1; // GPIO34를 High로 설정하여 LED 켬
    EDIS; // 보호된 레지스터 접근 비허용
}

// 소스 버퍼 초기화 함수
void InitSourceBuffer(void) {
    Uint16 i;
    for (i = 0; i < 128; i++) {
        SourceBuffer[i] = i; // 소스 버퍼에 0~127 값 초기화
    }
}

// DMA 채널 2 설정 함수
void ConfigureDMA(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 모듈 클럭 활성화
    DmaRegs.DMACTRL.bit.HARDRESET = 1; // DMA 모듈 하드 리셋
    DmaRegs.DMACTRL.bit.PRIORITY = 0; // 고정 우선순위
    EDIS; // 보호된 레지스터 접근 비허용

    EALLOW; // 보호된 레지스터 접근 허용
    DmaRegs.CH2.MODE.bit.CH2EN = 1; // 채널 2 활성화
    DmaRegs.CH2.MODE.bit.DATASIZE = 0; // 16비트 데이터 전송
    DmaRegs.CH2.MODE.bit.TRIGMODE = 0; // 소프트웨어 트리거
    DmaRegs.CH2.MODE.bit.ONESHOT = 1; // 원샷 모드
    DmaRegs.CH2.MODE.bit.SYNCE = 0; // 동기화 비활성화
    DmaRegs.CH2.MODE.bit.OVRINTE = 1; // 오버플로우 인터럽트 활성화
    DmaRegs.CH2.BURST_SIZE.all = 3; // 버스트 크기: 4 워드
    DmaRegs.CH2.SRC_BURST_STEP = 1; // 소스 주소 증가
    DmaRegs.CH2.DST_BURST_STEP = 1; // 목적지 주소 증가
    DmaRegs.CH2.TRANSFER_SIZE = 31; // 전송 크기: 128 워드 (32 버스트)
    DmaRegs.CH2.SRC_ADDR = (Uint32)&SourceBuffer[0]; // 소스: SourceBuffer
    DmaRegs.CH2.DST_ADDR = (Uint32)&DestBuffer[0]; // 목적지: DestBuffer
    DmaRegs.CH2.CONTROL.bit.RUN = 1; // DMA 전송 시작
    EDIS; // 보호된 레지스터 접근 비허용
}

void main(void) {
    InitSysCtrl(); // 시스템 클럭(150MHz)과 PLL 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 레지스터 비활성화
    IFR = 0x0000; // 인터럽트 플래그 레지스터 클리어
    InitPieVectTable(); // PIE 인터럽트 벡터 테이블 초기화

    EALLOW; // 보호된 레지스터 접근 허용
    PieVectTable.DMA_CH2_INT = &dma_ch2_isr; // DMA 채널 2 인터럽트 벡터 설정
    EDIS; // 보호된 레지스터 접근 비허용

    ConfigureGPIO(); // GPIO 설정 함수 호출
    InitSourceBuffer(); // 소스 버퍼 초기화
    ConfigureDMA(); // DMA 설정 함수 호출

    PieCtrlRegs.PIEIER7.bit.INTx2 = 1; // PIE 그룹 7에서 DMA 채널 2 인터럽트 활성화
    IER |= M_INT7; // CPU 인터럽트 그룹 7 활성화
    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    for(;;); // 무한 루프: DMA 전송 완료 대기
}

설명:

  • 기능: 소프트웨어 트리거를 사용하여 SourceBuffer에서 DestBuffer로 128개의 16비트 데이터를 전송
  • 설정:
    • DMA 채널 2: 소프트웨어 트리거, 원샷 모드, 4 워드 버스트, 128 워드 전송
  • GPIO: GPIO34(LED)
  • 출력: DestBuffer에 SourceBuffer 데이터 복사, LED ON

5.3 예제 3: ePWM 데이터 DMA 전송

// File: dma_epwm_transfer.c
// Description: TMS320F28335 DMA를 사용한 ePWM 데이터 전송 예제
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28335

#include "F28x_Project.h"

volatile Uint16 PwmData[64]; // DMA 소스 버퍼: ePWM CMPA 값
volatile Uint16 PwmBuffer[64]; // DMA 목적지 버퍼: ePWM CMPA 저장

// 인터럽트 서비스 루틴: DMA 채널 3 인터럽트 처리
__interrupt void dma_ch3_isr(void)
{
    DmaRegs.CH3.CONTROL.bit.TRANSFERSTS = 0; // 전송 상태 플래그 클리어
    DmaRegs.CH3.CONTROL.bit.ERRCLR = 1; // 에러 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹 7 인터럽트 ACK
}

// GPIO 설정 함수
void ConfigureGPIO(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // GPIO0을 ePWM1A로 설정
    GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // GPIO34를 출력으로 설정 (LED용)
    GpioDataRegs.GPBSET.bit.GPIO34 = 1; // GPIO34를 High로 설정하여 LED 켬
    EDIS; // 보호된 레지스터 접근 비허용
}

// ePWM1 설정 함수
void ConfigureEPWM1(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR1.bit.EPWM1 = 1; // ePWM1 모듈 클럭 활성화
    EDIS; // 보호된 레지스터 접근 비허용

    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // 타임-베이스 카운터를 업 카운트 모드로 설정
    EPwm1Regs.TBCTL.bit.CLKDIV = 0; // 클럭 분주비 1/1 (SYSCLK = 150MHz)
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 2; // 고속 클럭 분주비 1/2 (TBCLK = 75MHz)
    EPwm1Regs.TBPRD = 750; // 주기 레지스터 설정: 100kHz (10us)
    EPwm1Regs.CMPA.bit.CMPA = 375; // 비교 레지스터 A 설정: 초기 50% 듀티
    EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // TBCTR=0일 때 PWM_A 출력을 High로 설정
    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // TBCTR=CMPA일 때 PWM_A 출력을 Low로 설정
    EPwm1Regs.ETSEL.bit.INTEN = 1; // ePWM1 인터럽트 활성화
    EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // TBCTR=0일 때 인터럽트 발생
    EPwm1Regs.ETPS.bit.INTPRD = 1; // 첫 번째 이벤트에서 인터럽트 발생
    EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; // Free run 모드
}

// 소스 버퍼 초기화 함수
void InitPwmData(void) {
    Uint16 i;
    for (i = 0; i < 64; i++) {
        PwmData[i] = 188 + (i * 4); // 듀티 사이클 25%~75% 범위로 초기화
    }
}

// DMA 채널 3 설정 함수
void ConfigureDMA(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 모듈 클럭 활성화
    DmaRegs.DMACTRL.bit.HARDRESET = 1; // DMA 모듈 하드 리셋
    DmaRegs.DMACTRL.bit.PRIORITY = 0; // 고정 우선순위
    EDIS; // 보호된 레지스터 접근 비허용

    EALLOW; // 보호된 레지스터 접근 허용
    DmaRegs.CH3.MODE.bit.CH3EN = 1; // 채널 3 활성화
    DmaRegs.CH3.MODE.bit.DATASIZE = 0; // 16비트 데이터 전송
    DmaRegs.CH3.MODE.bit.TRIGMODE = 1; // 하드웨어 트리거 (ePWM1 INT)
    DmaRegs.CH3.MODE.bit.ONESHOT = 0; // 연속 모드
    DmaRegs.CH3.MODE.bit.SYNCE = 0; // 동기화 비활성화
    DmaRegs.CH3.MODE.bit.OVRINTE = 1; // 오버플로우 인터럽트 활성화
    DmaRegs.CH3.BURST_SIZE.all = 0; // 버스트 크기: 1 워드
    DmaRegs.CH3.SRC_BURST_STEP = 1; // 소스 주소 증가
    DmaRegs.CH3.DST_BURST_STEP = 0; // 목적지 주소 고정 (ePWM1 CMPA)
    DmaRegs.CH3.TRANSFER_SIZE = 63; // 전송 크기: 64 워드
    DmaRegs.CH3.SRC_ADDR = (Uint32)&PwmData[0]; // 소스: PwmData
    DmaRegs.CH3.DST_ADDR = (Uint32)&EPwm1Regs.CMPA.all; // 목적지: ePWM1 CMPA
    DmaRegs.CH3.DMA_CH3_TRIGSEL = DMA_EPWM1_INT; // 트리거: ePWM1 인터럽트
    DmaRegs.CH3.CONTROL.bit.RUN = 1; // DMA 전송 시작
    EDIS; // 보호된 레지스터 접근 비허용
}

void main(void) {
    InitSysCtrl(); // 시스템 클럭(150MHz)과 PLL 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 레지스터 비활성화
    IFR = 0x0000; // 인터럽트 플래그 레지스터 클리어
    InitPieVectTable(); // PIE 인터럽트 벡터 테이블 초기화

    EALLOW; // 보호된 레지스터 접근 허용
    PieVectTable.DMA_CH3_INT = &dma_ch3_isr; // DMA 채널 3 인터럽트 벡터 설정
    EDIS; // 보호된 레지스터 접근 비허용

    ConfigureGPIO(); // GPIO 설정 함수 호출
    InitPwmData(); // PWM 데이터 초기화
    ConfigureEPWM1(); // ePWM1 설정 함수 호출
    ConfigureDMA(); // DMA 설정 함수 호출

    PieCtrlRegs.PIEIER7.bit.INTx3 = 1; // PIE 그룹 7에서 DMA 채널 3 인터럽트 활성화
    IER |= M_INT7; // CPU 인터럽트 그룹 7 활성화
    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    for(;;); // 무한 루프: DMA 전송 및 PWM 출력 지속
}

설명:

  • 기능: ePWM1 인터럽트를 트리거로 사용하여 PwmData에서 ePWM1 CMPA 레지스터로 데이터 전송, PWM 듀티 사이클 동적 변경
  • 설정:
    • ePWM1: 100kHz 주기, 인터럽트 활성화
    • DMA 채널 3: ePWM1 인터럽트 트리거, 64 워드 전송
  • GPIO: GPIO0(ePWM1A), GPIO34(LED)
  • 출력: ePWM1A에 동적 듀티 사이클 PWM 신호 출력, LED ON

5.4 예제 4: McBSP 데이터 DMA 전송

// File: dma_mcbsp_transfer.c
// Description: TMS320F28335 DMA를 사용한 McBSP 데이터 전송 예제
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28335

#include "F28x_Project.h"

volatile Uint16 McbspTxBuffer[128]; // McBSP 전송 버퍼
volatile Uint16 McbspRxBuffer[128]; // McBSP 수신 버퍼

// 인터럽트 서비스 루틴: DMA 채널 4 인터럽트 처리
__interrupt void dma_ch4_isr(void)
{
    DmaRegs.CH4.CONTROL.bit.TRANSFERSTS = 0; // 전송 상태 플래그 클리어
    DmaRegs.CH4.CONTROL.bit.ERRCLR = 1; // 에러 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹 7 인터럽트 ACK
}

// GPIO 설정 함수
void ConfigureGPIO(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    GpioCtrlRegs.GPBMUX1.bit.MCLKXA = 1; // McBSP 클럭 출력
    GpioCtrlRegs.GPBMUX1.bit.MDXA = 1; // McBSP 데이터 전송
    GpioCtrlRegs.GPBMUX1.bit.MDRXA = 1; // McBSP 데이터 수신
    GpioCtrlRegs.GPBMUX1.bit.MFSXA = 1; // McBSP 프레임 동기
    GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // GPIO34를 출력으로 설정 (LED용)
    GpioDataRegs.GPBSET.bit.GPIO34 = 1; // GPIO34를 High로 설정하여 LED 켬
    EDIS; // 보호된 레지스터 접근 비허용
}

// McBSP 설정 함수
void ConfigureMcBSP(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.MCBSPA = 1; // McBSP-A 모듈 클럭 활성화
    EDIS; // 보호된 레지스터 접근 비허용

    McbspbRegs.SPCR2.bit.GRST = 0; // McBSP 리셋
    McbspbRegs.SPCR1.bit.RRST = 0; // 수신 리셋
    McbspbRegs.RCR1.bit.RWDLEN1 = 1; // 16비트 데이터
    McbspbRegs.XCR1.bit.XWDLEN1 = 1; // 16비트 데이터
    McbspbRegs.SPCR2.bit.XRDY = 0; // 전송 준비 플래그 클리어
    McbspbRegs.SPCR1.bit.RRDY = 0; // 수신 준비 플래그 클리어
    McbspbRegs.PCR.bit.CLKXM = 1; // 클럭 마스터 모드
    McbspbRegs.PCR.bit.FSXM = 1; // 프레임 동기 마스터 모드
    McbspbRegs.SRGR2.bit.CLKSM = 1; // 클럭 소스: 내부
    McbspbRegs.SRGR1.bit.CLKGDV = 49; // 클럭 분주: 150MHz/(49+1) = 3MHz
    McbspbRegs.SPCR2.bit.GRST = 1; // McBSP 활성화
    McbspbRegs.SPCR2.bit.XRST = 1; // 전송 활성화
    McbspbRegs.SPCR1.bit.RRST = 1; // 수신 활성화
}

// 전송 버퍼 초기화 함수
void InitMcBSPTxBuffer(void) {
    Uint16 i;
    for (i = 0; i < 128; i++) {
        McbspTxBuffer[i] = i; // 전송 버퍼에 0~127 값 초기화
    }
}

// DMA 채널 4 설정 함수
void ConfigureDMA(void) {
    EALLOW; // 보호된 레지스터 접근 허용
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 모듈 클럭 활성화
    DmaRegs.DMACTRL.bit.HARDRESET = 1; // DMA 모듈 하드 리셋
    DmaRegs.DMACTRL.bit.PRIORITY = 0; // 고정 우선순위
    EDIS; // 보호된 레지스터 접근 비허용

    EALLOW; // 보호된 레지스터 접근 허용
    DmaRegs.CH4.MODE.bit.CH4EN = 1; // 채널 4 활성화
    DmaRegs.CH4.MODE.bit.DATASIZE = 0; // 16비트 데이터 전송
    DmaRegs.CH4.MODE.bit.TRIGMODE = 1; // 하드웨어 트리거 (McBSP TX)
    DmaRegs.CH4.MODE.bit.ONESHOT = 0; // 연속 모드
    DmaRegs.CH4.MODE.bit.SYNCE = 0; // 동기화 비활성화
    DmaRegs.CH4.MODE.bit.OVRINTE = 1; // 오버플로우 인터럽트 활성화
    DmaRegs.CH4.BURST_SIZE.all = 0; // 버스트 크기: 1 워드
    DmaRegs.CH4.SRC_BURST_STEP = 1; // 소스 주소 증가
    DmaRegs.CH4.DST_BURST_STEP = 0; // 목적지 주소 고정 (McBSP DXR)
    DmaRegs.CH4.TRANSFER_SIZE = 127; // 전송 크기: 128 워드
    DmaRegs.CH4.SRC_ADDR = (Uint32)&McbspTxBuffer[0]; // 소스: McbspTxBuffer
    DmaRegs.CH4.DST_ADDR = (Uint32)&McbspbRegs.DXR1.all; // 목적지: McBSP DXR
    DmaRegs.CH4.DMA_CH4_TRIGSEL = DMA_MXEVTA; // 트리거: McBSP 전송 이벤트
    DmaRegs.CH4.CONTROL.bit.RUN = 1; // DMA 전송 시작
    EDIS; // 보호된 레지스터 접근 비허용
}

void main(void) {
    InitSysCtrl(); // 시스템 클럭(150MHz)과 PLL 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 컨트롤러 초기화
    IER = 0x0000; // CPU 인터럽트 레지스터 비활성화
    IFR = 0x0000; // 인터럽트 플래그 레지스터 클리어
    InitPieVectTable(); // PIE 인터럽트 벡터 테이블 초기화

    EALLOW; // 보호된 레지스터 접근 허용
    PieVectTable.DMA_CH4_INT = &dma_ch4_isr; // DMA 채널 4 인터럽트 벡터 설정
    EDIS; // 보호된 레지스터 접근 비허용

    ConfigureGPIO(); // GPIO 설정 함수 호출
    InitMcBSPTxBuffer(); // McBSP 전송 버퍼 초기화
    ConfigureMcBSP(); // McBSP 설정 함수 호출
    ConfigureDMA(); // DMA 설정 함수 호출

    PieCtrlRegs.PIEIER7.bit.INTx4 = 1; // PIE 그룹 7에서 DMA 채널 4 인터럽트 활성화
    IER |= M_INT7; // CPU 인터럽트 그룹 7 활성화
    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    for(;;); // 무한 루프: DMA 전송 및 McBSP 통신 지속
}

설명:

  • 기능: McBSP 전송 이벤트를 트리거로 사용하여 McbspTxBuffer에서 McBSP DXR로 128 워드 전송
  • 설정:
    • McBSP: 3MHz 클럭, 16비트 데이터
    • DMA 채널 4: McBSP 전송 이벤트 트리거, 128 워드 전송
  • GPIO: McBSP 핀(MCLKXA, MDXA, MDRXA, MFSXA), GPIO34(LED)
  • 출력: McBSP를 통해 데이터 전송, LED ON

6. 사용 방법

6.1 환경 설정

  • C2000Ware 설치: C:\ti\c2000\C2000Ware_x_xx_xx_xx
  • CCS 프로젝트: TMS320F28335 타겟으로 프로젝트 생성, F28x_Project.h 포함
  • 링커 파일: device_support\f2833x 폴더에서 링커 파일 추가

6.2 코드 실행

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

6.3 하드웨어 준비

  • ADC 입력: ADCINA0 핀에 아날로그 신호 연결 (예제 1)
  • PWM 출력: GPIO0(ePWM1A)에 오실로스코프 연결 (예제 3)
  • McBSP 인터페이스: McBSP 핀에 외부 장치 연결 (예제 4)
  • LED: GPIO34에 LED 연결

6.4 디버깅

  • CCS Expressions 창에서 AdcBuffer, DestBuffer, PwmBuffer, McbspRxBuffer 확인
  • DmaRegs.CHx.CONTROL.bit.TRANSFERSTS로 전송 상태 점검
  • DmaRegs.CHx.CONTROL.bit.ERR로 에러 상태 확인

7. 추가 팁

  • 캘리브레이션: ADC 사용 시 Device_cal() 호출
  • 노이즈 감소: ADC 입력 또는 McBSP 신호에 저역통과 필터 사용
  • C2000Ware 참고: C:\ti\c2000\C2000Ware_x_xx_xx_xx\device_support\f2833x\examples\cpu1\dma
  • 문제 해결:
    •   DMA 전송 실패: MODE.bit.CHxEN, TRIGSEL 확인
    •   인터럽트 실패: PieVectTable.DMAx_INT, PIEIER7 설정 확인
    •   데이터 손실: 버스트 크기 및 메모리 정렬 확인
  • TI 리소스: TI E2E 포럼, C2000Ware 예제

8. 결론

이 문서는 TMS320F28335 DMA 모듈의 설정 방법과 Bitfield 구조를 활용한 예제 코드를 제공하여 ADC 데이터 전송, 메모리 복사, ePWM 데이터 업데이트, McBSP 통신 등 다양한 애플리케이션에 적용 가능하도록 구성했습니다.

키워드: TMS320F28335, DMA, C2000, ADC 데이터 전송, 메모리 전송, ePWM, McBSP, 마이크로컨트롤러, Code Composer Studio, 하드웨어 트리거, 인터럽트

반응형