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; // 에러 플래그 클리어
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"
#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 전송, 인터럽트, 버스트 모드, 순환 버퍼
'MCU > C2000' 카테고리의 다른 글
C2000 DSP CMD 파일: 상세 설명, 구조, 작성 방법 및 예제 (2) | 2025.08.18 |
---|---|
TMS320F28377D DSP SDFM 사용법 : Bitfield 구조 활용 예제 코드(수정) (1) | 2025.08.18 |
TMS320F28377D DSP ePWM CMPASS 사용법: Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.18 |
TMS320F28377D DSP SPI 사용법 : Bitfield 구조 활용 예제 코드(수정) (2) | 2025.08.18 |
TMS320F28377D DSP CAN 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.18 |
TMS320F28377D DSP EMIF 사용법 : Bitfield 구조 활용 예제 코드(수정) (1) | 2025.08.17 |
TMS320F28377D DSP eCAP 사용법 : Bitfield 구조 활용 예제 코드(수정) (1) | 2025.08.17 |
TMS320F28377D DSP eQEP 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.17 |