반응형
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_initController();
- DMA_configChannel()
- 설명: 특정 DMA 채널의 동작 모드를 설정합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소 (예: DMA_CHANNEL1).
- channel: 채널 번호 (1~6).
- mode: 동작 모드 (예: DMA_MODE_BLOCK, DMA_MODE_SINGLE).
- 사용 예: DMA 채널 1을 블록 전송 모드로 설정: DMA_configChannel(DMA_CHANNEL1, 1, DMA_MODE_BLOCK);
- DMA_configAddresses()
- 설명: DMA 전송의 소스 및 목적지 주소를 설정합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- dest: 목적지 메모리 주소 (포인터).
- src: 소스 메모리 주소 (포인터).
- 사용 예: ADC 결과에서 버퍼로 전송: DMA_configAddresses(DMA_CHANNEL1, adcBuffer, (uint16_t *)ADCARESULT_BASE);
- DMA_configBurst()
- 설명: 버스트 전송 크기와 주소 증가 단위를 설정합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- size: 버스트당 전송 단위 수 (1~16).
- srcStep: 소스 주소 증가 단위 (예: 1 또는 0).
- destStep: 목적지 주소 증가 단위.
- 사용 예: 1단위 전송, 목적지 증가: DMA_configBurst(DMA_CHANNEL1, 1, 0, 1);
- DMA_configTransfer()
- 설명: 전체 전송 크기와 주소 증가 단위를 설정합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- size: 전체 전송 단위 수.
- srcStep: 소스 주소 증가 단위.
- destStep: 목적지 주소 증가 단위.
- 사용 예: 256단위 전송: DMA_configTransfer(DMA_CHANNEL1, 256, 0, 1);
- DMA_configTrigger()
- 설명: DMA 전송 트리거 소스를 설정합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- trigger: 트리거 소스 (예: DMA_TRIGGER_EPWM1_SOCA, DMA_TRIGGER_SOFTWARE).
- 사용 예: ePWM1 SOCA 트리거 설정: DMA_configTrigger(DMA_CHANNEL1, DMA_TRIGGER_EPWM1_SOCA);
- DMA_enableTrigger()
- 설명: DMA 채널의 트리거를 활성화합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- 사용 예: 트리거 활성화: DMA_enableTrigger(DMA_CHANNEL1);
- DMA_startChannel()
- 설명: DMA 채널을 시작하여 데이터 전송을 개시합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- 사용 예: DMA 전송 시작: DMA_startChannel(DMA_CHANNEL1);
2.2. 인터럽트 관련 함수
- DMA_enableInterrupt()
- 설명: DMA 채널의 인터럽트를 활성화합니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- 사용 예: 인터럽트 활성화: DMA_enableInterrupt(DMA_CHANNEL1);
- DMA_setInterruptMode()
- 설명: 인터럽트 발생 조건을 설정합니다 (예: 전송 완료 시).
- 매개변수:
- base: DMA 채널의 베이스 주소.
- mode: 인터럽트 모드 (예: DMA_INT_MODE_TRANSFER_COMPLETE).
- 사용 예: 전송 완료 인터럽트 설정: DMA_setInterruptMode(DMA_CHANNEL1, DMA_INT_MODE_TRANSFER_COMPLETE);
- DMA_clearInterruptFlag()
- 설명: DMA 인터럽트 플래그를 지웁니다.
- 매개변수:
- base: DMA 채널의 베이스 주소.
- 사용 예: 인터럽트 플래그 지우기: DMA_clearInterruptFlag(DMA_CHANNEL1);
- Interrupt_register()
- 설명: 인터럽트 서비스 루틴(ISR)을 등록합니다.
- 매개변수:
- intNumber: 인터럽트 번호 (예: INT_DMA_CH1).
- handler: ISR 함수 포인터.
- 사용 예: DMA 채널 1 ISR 등록: Interrupt_register(INT_DMA_CH1, &dmaCh1ISR);
3. DMA 설정 및 동작 원리
- 시스템 초기화: 시스템 클럭, GPIO, 인터럽트 초기화 (Device_init(), Device_initGPIO()).
- DMA 컨트롤러 초기화: DMA_initController() 호출.
- DMA 채널 설정: 소스/목적지 주소, 전송 크기, 트리거 소스 설정.
- 트리거 및 인터럽트 설정: 트리거 소스와 인터럽트 활성화.
- DMA 시작: **DMA_startChannel()**로 데이터 전송 시작.
4. DMA 예제 코드
아래는 C2000Ware의 DriverLib를 기반으로 작성된 DMA 예제 코드로, Code Composer Studio(CCS)에서 실행 가능합니다. 각 예제는 독립적이며 상세한 주석을 포함합니다.
4.1. 예제 1: ADC 결과를 DMA로 버퍼에 저장
ADC 변환 결과를 DMA를 통해 메모리 버퍼로 전송합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수 (0: 초기화 완료, 1: DMA 동작 중, 0xFFFF: 오류)
volatile uint32_t dmaStatus = 0;
// ADC 결과 저장 버퍼
#define BUFFER_SIZE 256
uint16_t adcBuffer[BUFFER_SIZE];
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO31을 디버깅용 LED로 설정 (LAUNCHXL-F28379D 기준)
GPIO_setPinConfig(GPIO_31_GPIO31); // GPIO31을 일반 GPIO로 설정
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드 설정
GPIO_setPadConfig(31, GPIO_PULL_UP); // 풀업 저항 활성화
GPIO_writePin(31, 0); // 초기 LED OFF
}
// DMA 인터럽트 서비스 루틴
__interrupt void dmaCh1ISR(void)
{
// DMA 인터럽트 플래그 지우기
DMA_clearInterruptFlag(DMA_CHANNEL1);
// PIE 인터럽트 그룹 ACK
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
// DMA 동작 상태 업데이트
dmaStatus = 1;
}
// ADC 및 DMA 초기화 함수
void initADCandDMA(void)
{
// ADC-A 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
// ADC 설정: 50MHz 클럭, 12비트 해상도, 단일 엔드 모드
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
// ADC SOC0 설정: ePWM1 SOCA 트리거, ADCIN0 채널, 샘플링 윈도우 15 사이클
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN0, 15);
// ADC 컨버터 활성화
ADC_enableConverter(ADCA_BASE);
// ADC 안정화를 위해 1ms 대기
DEVICE_DELAY_US(1000);
// ePWM1 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
// ePWM1 주기 설정: 100kHz (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
// ePWM1 카운터 모드: Up 카운터
EPWM_setCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// SOCA 트리거 설정: 카운터=0일 때 발생
EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_SOC_A, 1);
// ePWM1 모듈 활성화
EPWM_enableModule(EPWM1_BASE);
// DMA 컨트롤러 초기화
DMA_initController();
// DMA 채널 1 설정: 블록 전송 모드
DMA_configChannel(DMA_CHANNEL1, DMA_CH1_BASE, DMA_MODE_BLOCK);
// DMA 주소 설정: ADC 결과 레지스터에서 adcBuffer로 전송
DMA_configAddresses(DMA_CHANNEL1, adcBuffer, (uint16_t *)ADCARESULT_BASE);
// 버스트 전송: 단일 16비트 데이터, 소스 고정, 목적지 증가
DMA_configBurst(DMA_CHANNEL1, 1, 0, 1);
// 전체 전송: BUFFER_SIZE(256) 단위 전송
DMA_configTransfer(DMA_CHANNEL1, BUFFER_SIZE, 0, 1);
// 트리거 소스: ePWM1 SOCA
DMA_configTrigger(DMA_CHANNEL1, DMA_TRIGGER_EPWM1_SOCA);
// DMA 인터럽트 활성화
DMA_enableInterrupt(DMA_CHANNEL1);
// DMA 트리거 활성화
DMA_enableTrigger(DMA_CHANNEL1);
// DMA 채널 시작
DMA_startChannel(DMA_CHANNEL1);
}
void main(void)
{
// 시스템 클럭, PLL, Watchdog, 주변 장치 초기화
Device_init();
// GPIO 기본 초기화
Device_initGPIO();
// 디버깅용 GPIO 설정
initGPIO();
// 인터럽트 모듈 및 벡터 테이블 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// DMA 채널 1 인터럽트 ISR 등록
Interrupt_register(INT_DMA_CH1, &dmaCh1ISR);
// 시스템 클럭 확인 (200MHz 예상)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000)
{
dmaStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// ADC 및 DMA 초기화
initADCandDMA();
// 초기화 오류 확인
if (dmaStatus != 1)
{
dmaStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF
ESTOP0; // 디버깅용 정지
}
// 글로벌 인터럽트 활성화
EINT;
// Watchdog 활성화 (실시간 애플리케이션용)
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
SysCtl_serviceWatchdog();
// 무한 루프: DMA가 하드웨어로 자동 전송
for(;;)
{
// 디버깅용: 상태 표시 (정상 동작 시 LED ON)
GPIO_writePin(31, (dmaStatus == 1) ? 1 : 0);
DEVICE_DELAY_US(1000000); // 1초 대기 (CPU 부하 감소)
}
}
설명:
- 기능: 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;
// 소스 및 목적지 버퍼
#define BUFFER_SIZE 256
uint16_t srcBuffer[BUFFER_SIZE];
uint16_t destBuffer[BUFFER_SIZE];
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO31을 디버깅용 LED로 설정 (LAUNCHXL-F28379D 기준)
GPIO_setPinConfig(GPIO_31_GPIO31); // GPIO31을 일반 GPIO로 설정
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드 설정
GPIO_setPadConfig(31, GPIO_PULL_UP); // 풀업 저항 활성화
GPIO_writePin(31, 0); // 초기 LED OFF
}
// DMA 인터럽트 서비스 루틴
__interrupt void dmaCh1ISR(void)
{
// DMA 인터럽트 플래그 지우기
DMA_clearInterruptFlag(DMA_CHANNEL1);
// PIE 인터럽트 그룹 ACK
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
// DMA 동작 상태 업데이트
dmaStatus = 1;
}
// DMA 초기화 함수
void initDMA(void)
{
// 소스 버퍼 초기화 (0부터 255까지 값으로 채움)
for (uint16_t i = 0; i < BUFFER_SIZE; i++)
{
srcBuffer[i] = i;
}
// DMA 컨트롤러 초기화
DMA_initController();
// DMA 채널 1 설정: 블록 전송 모드
DMA_configChannel(DMA_CHANNEL1, DMA_CH1_BASE, DMA_MODE_BLOCK);
// DMA 주소 설정: srcBuffer에서 destBuffer로 전송
DMA_configAddresses(DMA_CHANNEL1, destBuffer, srcBuffer);
// 버스트 전송: 단일 16비트 데이터, 소스 및 목적지 주소 증가
DMA_configBurst(DMA_CHANNEL1, 1, 1, 1);
// 전체 전송: BUFFER_SIZE(256) 단위 전송
DMA_configTransfer(DMA_CHANNEL1, BUFFER_SIZE, 1, 1);
// 트리거 소스: 소프트웨어 트리거
DMA_configTrigger(DMA_CHANNEL1, DMA_TRIGGER_SOFTWARE);
// DMA 인터럽트 활성화
DMA_enableInterrupt(DMA_CHANNEL1);
// DMA 트리거 활성화
DMA_enableTrigger(DMA_CHANNEL1);
// DMA 채널 시작
DMA_startChannel(DMA_CHANNEL1);
}
void main(void)
{
// 시스템 클럭, PLL, Watchdog, 주변 장치 초기화
Device_init();
// GPIO 기본 초기화
Device_initGPIO();
// 디버깅용 GPIO 설정
initGPIO();
// 인터럽트 모듈 및 벡터 테이블 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// DMA 채널 1 인터럽트 ISR 등록
Interrupt_register(INT_DMA_CH1, &dmaCh1ISR);
// 시스템 클럭 확인 (200MHz 예상)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000)
{
dmaStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// DMA 초기화
initDMA();
// 초기화 오류 확인
if (dmaStatus != 1)
{
dmaStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF
ESTOP0; // 디버깅용 정지
}
// 글로벌 인터럽트 활성화
EINT;
// Watchdog 활성화 (실시간 애플리케이션용)
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
SysCtl_serviceWatchdog();
// 무한 루프: DMA가 하드웨어로 자동 전송
for(;;)
{
// 디버깅용: 상태 표시 (정상 동작 시 LED ON)
GPIO_writePin(31, (dmaStatus == 1) ? 1 : 0);
DEVICE_DELAY_US(1000000); // 1초 대기 (CPU 부하 감소)
}
}
설명:
- 기능: 소스 버퍼에서 목적지 버퍼로 데이터를 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, 인터럽트, 실시간 제어
반응형
'MCU > C2000' 카테고리의 다른 글
[TMS320F28377D] eCAP 사용법 : Bitfield 구조 활용 예제 코드 (1) | 2025.08.17 |
---|---|
[TMS320F28377D] eQEP 사용법 : Bitfield 구조 활용 예제 코드 (0) | 2025.08.17 |
[TMS320F28377D] ePWM 사용법 : Bitfield 구조 활용 예제 코드 (1) | 2025.08.17 |
[TMS320F28388D] CPU1, CPU2 멀티코어 사용법: DriverLib API로 멀티코어 설정 및 코드 (0) | 2025.08.17 |
[TMS320F28388D] SPI 사용법: DriverLib API로 SPI 설정 및 코드 (0) | 2025.08.17 |
[TMS320F28388D] CAN 사용법: DriverLib API로 CAN 설정 및 코드 (0) | 2025.08.17 |
[TMS320F28388D] SDFM 사용법: DriverLib API로 SDFM 설정 및 코드 (0) | 2025.08.17 |
[TMS320F28388D] CLB 사용법: DriverLib API로 CLB 설정 및 코드 (0) | 2025.08.17 |