본문 바로가기
MCU/C2000

[TMS320F28388D] CLA 사용법: DriverLib API로 CLA 설정 및 코드

by linuxgo 2025. 8. 17.
반응형

이 문서에서는 Texas Instruments의 TMS320F28388D 마이크로컨트롤러에서 CLA(Control Law Accelerator)를 DriverLib API를 사용하여 설정하고 사용하는 방법을 상세히 다룹니다. C2000 시리즈의 고성능 마이크로컨트롤러인 TMS320F28388D의 CLA 모듈을 활용하여 병렬 연산을 수행하는 방법을 배우고, 다양한 독립적인 예제 코드를 통해 실제 구현 방법을 익힐 수 있습니다. 각 코드에는 상세한 주석이 포함되어 있으며, Code Composer Studio(CCS) 환경에서 실행 가능합니다.

1. TMS320F28388D CLA 개요

TMS320F28388D는 Texas Instruments의 C2000 시리즈에 속하는 고성능 32비트 마이크로컨트롤러로, CLA(Control Law Accelerator)는 CPU와 독립적으로 동작하는 부동소수점 코프로세서입니다. CLA는 모터 제어, 디지털 전력 변환, 신호 처리 등 고속 연산이 필요한 실시간 제어 애플리케이션에서 CPU 부하를 줄이며 병렬 처리를 수행합니다.

CLA 모듈의 주요 특징

  • 독립적인 프로세서: CLA는 CPU와 별도의 프로그램 및 데이터 메모리(LS RAM)를 가지며, 병렬로 연산을 수행합니다.
  • 부동소수점 지원: 32비트 부동소수점 연산을 지원하여 복잡한 제어 알고리즘(예: PID, FFT)을 효율적으로 처리.
  • 태스크 기반 실행: 최대 8개의 태스크(Task 1~8)를 지원하며, ADC, ePWM, 타이머 등 다양한 트리거 소스로 활성화.
  • 메모리 구조: LS RAM(L0~L7)을 CPU와 CLA 간 공유 가능, 전용 CLA 메모리 할당.
  • 인터럽트: 각 태스크는 독립적인 인터럽트를 가지며, CPU와의 통신은 공유 메모리 또는 메시지 RAM을 통해 이루어짐.
  • 클럭: 시스템 클럭(최대 200MHz)과 동기화, CPU와 동일한 클럭 속도로 동작.
  • 고급 기능: 빠른 컨텍스트 스위칭, 낮은 레이턴시, ADC 및 ePWM과의 긴밀한 통합.

DriverLib API는 CLA 설정을 간소화하며, 하드웨어 레지스터를 직접 조작하는 대신 추상화된 함수를 제공합니다.

2. 주요 CLA DriverLib API 함수

아래는 TMS320F28388D의 CLA 모듈을 제어하기 위해 자주 사용되는 DriverLib API 함수와 그 사용 방법입니다.

2.1. CLA 초기화 및 설정 관련 함수

  • CLA_enableCLA(base)
    • 설명: CLA 모듈을 활성화합니다.
    • 매개변수: base (CLA1_BASE).
    • 사용 예: CLA_enableCLA(CLA1_BASE);
  • CLA_disableCLA(base)
    • 설명: CLA 모듈을 비활성화합니다.
    • 매개변수: base (CLA1_BASE).
  • CLA_enableTasks(base, tasks)
    • 설명: 특정 CLA 태스크를 활성화합니다.
    • 매개변수: tasks (CLA_TASK_1, CLA_TASK_2 등, 비트 마스크로 조합 가능).
    • 사용 예: CLA_enableTasks(CLA1_BASE, CLA_TASK_1);
  • CLA_mapTaskVector(base, taskNumber, vector)
    • 설명: CLA 태스크에 인터럽트 벡터를 매핑합니다.
    • 매개변수: taskNumber (CLA_TASK_1~8), vector (인터럽트 소스, 예: CLA_INT_TRIG_ADCA1).
    • 사용 예: CLA_mapTaskVector(CLA1_BASE, CLA_TASK_1, CLA_INT_TRIG_ADCA1);

2.2. 태스크 및 인터럽트 관련 함수

  • CLA_enableTaskInterrupts(base, tasks)
    • 설명: CLA 태스크 인터럽트를 활성화합니다.
    • 매개변수: tasks (CLA_TASK_1~8).
  • CLA_clearTaskInterruptFlag(base, task)
    • 설명: 특정 태스크의 인터럽트 플래그를 지웁니다.
    • 매개변수: task (CLA_TASK_1~8).
  • CLA_forceTasks(base, tasks)
    • 설명: 소프트웨어로 CLA 태스크를 강제로 트리거합니다.
    • 사용 예: CLA_forceTasks(CLA1_BASE, CLA_TASK_1);

2.3. 메모리 및 데이터 관련 함수

  • CLA_configureCLAMemory(base, config)
    • 설명: CLA 메모리(LS RAM)를 프로그램 또는 데이터 메모리로 설정합니다.
    • 매개변수: config (CLA_PROG_ENABLE, CLA_DATA_ENABLE).
    • 사용 예: CLA_configureCLAMemory(CLA1_BASE, CLA_PROG_ENABLE);
  • SysCtl_enablePeripheral(periph)
    • 설명: CLA 주변 장치 클럭을 활성화합니다.
    • 매개변수: periph (SYSCTL_PERIPH_CLK_CLA1).

3. CLA 설정 및 동작 원리

  1. 시스템 초기화: 시스템 클럭, GPIO, 인터럽트 모듈 초기화(Device_init(), Device_initGPIO()).
  2. CLA 메모리 설정: LS RAM을 CLA 프로그램 및 데이터 메모리로 할당. 링크 스크립트(.cmd 파일)에서 메모리 섹션 정의.
  3. CLA 태스크 설정: 태스크 벡터와 트리거 소스(ADC, ePWM 등)를 매핑.
  4. CLA 코드 작성: .cla 확장자 파일에 CLA 태스크 코드를 작성. C 언어 기반, 부동소수점 연산 지원.
  5. CLA 활성화: CLA 모듈과 태스크를 활성화하여 병렬 연산 시작.
  6. 데이터 교환: CPU와 CLA 간 데이터 교환은 공유 메모리(LS RAM) 또는 메시지 RAM을 통해 수행.

4. CLA 예제 코드

아래는 독립적인 CLA 예제 코드로, C2000Ware의 DriverLib를 기반으로 작성되었습니다. 모든 셋팅 값은 계산식을 통해 명시적으로 설정되며, 상세한 주석이 포함되어 있습니다. GPIO 설정은 별도의 initGPIO() 함수로 분리되어 있으며, 모든 코드는 CCS에서 바로 실행 가능합니다.

4.1. 예제 1: 기본 CLA 태스크 실행

CLA Task 1을 사용하여 간단한 부동소수점 연산을 수행합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CLA 동작 상태를 추적
volatile uint32_t claStatus = 0; // 0: 초기화 완료, 1: CLA 동작 중, 0xFFFF: 오류 발생

// 공유 메모리: CPU와 CLA 간 데이터 교환을 위해 Cla1DataRam0에 할당
#pragma DATA_SECTION(inputData, "Cla1DataRam0")
float inputData[2] = {2.5f, 3.5f}; // 입력 데이터: 고정값 2.5와 3.5로 초기화
#pragma DATA_SECTION(outputData, "Cla1DataRam0")
float outputData = 0.0f; // 출력 데이터: CLA 태스크의 연산 결과 저장

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO31을 디버깅용 LED로 설정
    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
}

// CLA 초기화 함수
void initCLA(void)
{
    // CLA 클럭 활성화: CLA1 모듈에 시스템 클럭 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLA1);
    
    // CLA 메모리 설정
    // L0: 프로그램 메모리(CLA 코드 저장), L1: 데이터 메모리(공유 데이터 저장)
    CLA_configureCLAMemory(CLA1_BASE, CLA_PROG_ENABLE_L0 | CLA_DATA_ENABLE_L1);
    
    // CLA 태스크 1 설정
    // 소프트웨어 트리거를 사용하여 태스크 실행
    CLA_mapTaskVector(CLA1_BASE, CLA_TASK_1, CLA_INT_TRIG_SOFT);
    CLA_enableTasks(CLA1_BASE, CLA_TASK_1); // Task 1 활성화
    
    // CLA 모듈 활성화
    CLA_enableCLA(CLA1_BASE);
    
    // 상태 업데이트: 초기화 완료
    claStatus = 1;
}

// CLA 태스크 코드 (별도의 .cla 파일에 저장)
#pragma CODE_SECTION(claTask1, "Cla1Prog")
__interrupt void claTask1(void)
{
    // 부동소수점 연산: output = inputData[0] * inputData[1]
    // 계산: 2.5 * 3.5 = 8.75
    outputData = inputData[0] * inputData[1];
    
    // 태스크 인터럽트 플래그 지우기: 다음 트리거를 위해 플래그 초기화
    CLA_clearTaskInterruptFlag(CLA1_BASE, CLA_TASK_1);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // CLA 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인
    // 목표 클럭: 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        claStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // CLA 초기화
    initCLA();
    
    // CLA 초기화 오류 확인
    if (claStatus != 1)
    {
        claStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // CLA 태스크 1 소프트웨어 트리거
    CLA_forceTasks(CLA1_BASE, CLA_TASK_1);
    
    // 무한 루프: 상태 모니터링
    for(;;)
    {
        // 디버깅용: 상태에 따라 LED 점등
        // claStatus == 1: 정상 동작, LED ON
        // claStatus != 1: 오류, LED OFF
        GPIO_writePin(31, (claStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: CLA Task 1에서 두 입력 데이터(2.5, 3.5)를 곱하여 결과를 공유 메모리에 저장.
  • 설정: 소프트웨어 트리거로 Task 1 실행, LS0(프로그램), LS1(데이터) 메모리 할당.
  • GPIO: GPIO31(LED).
  • 출력: outputData = 2.5 * 3.5 = 8.75, 정상 동작 시 LED ON.

4.2. 예제 2: ADC 트리거를 사용한 CLA 태스크

CLA Task 1을 ADC 변환 완료 트리거로 실행하여 ADC 데이터를 처리합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CLA 동작 상태를 추적
volatile uint32_t claStatus = 0; // 0: 초기화 완료, 1: CLA 동작 중, 0xFFFF: 오류 발생

// 공유 메모리: CPU와 CLA 간 데이터 교환을 위해 Cla1DataRam0에 할당
#pragma DATA_SECTION(adcResult, "Cla1DataRam0")
float adcResult = 0.0f; // ADC 변환 결과: 12비트 ADC 값을 스케일링하여 저장
#pragma DATA_SECTION(outputData, "Cla1DataRam0")
float outputData = 0.0f; // 처리 결과: ADC 값의 제곱 저장

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO31을 디버깅용 LED로 설정
    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
}

// CLA 초기화 함수
void initCLA(void)
{
    // CLA 클럭 활성화: CLA1 모듈에 시스템 클럭 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLA1);
    
    // CLA 메모리 설정
    // L0: 프로그램 메모리(CLA 코드 저장), L1: 데이터 메모리(공유 데이터 저장)
    CLA_configureCLAMemory(CLA1_BASE, CLA_PROG_ENABLE_L0 | CLA_DATA_ENABLE_L1);
    
    // CLA 태스크 1 설정
    // ADC-A 인터럽트(ADCA1)로 트리거
    CLA_mapTaskVector(CLA1_BASE, CLA_TASK_1, CLA_INT_TRIG_ADCA1);
    CLA_enableTasks(CLA1_BASE, CLA_TASK_1); // Task 1 활성화
    
    // CLA 모듈 활성화
    CLA_enableCLA(CLA1_BASE);
    
    // 상태 업데이트: 초기화 완료
    claStatus = 1;
}

// ADC 초기화 함수
void initADC(void)
{
    // ADC-A 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
    
    // ADC 설정
    // 프리스케일러: 시스템 클럭 200MHz / 4 = 50MHz ADC 클럭
    ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
    
    // 참조 전압: 내부 3.3V 참조 사용
    ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
    
    // ADC 모드: 12비트 해상도, 싱글 엔디드 모드
    ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
    
    // SOC0 설정: 소프트웨어 트리거, ADCIN0 채널, 샘플링 윈도우 15 SYSCLK
    // 샘플링 윈도우 = 15 * (1 / 200MHz) = 75ns
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW, ADC_CH_ADCIN0, 15);
    
    // 인터럽트 활성화: ADC_INT1 사용
    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
    
    // ADC 컨버터 활성화
    ADC_enableConverter(ADCA_BASE);
    
    // ADC 안정화를 위해 1ms 대기 (1ms = 1,000,000us)
    DEVICE_DELAY_US(1000000);
}

// CLA 태스크 코드 (별도의 .cla 파일에 저장)
#pragma CODE_SECTION(claTask1, "Cla1Prog")
__interrupt void claTask1(void)
{
    // ADC 결과 읽기
    // 12비트 ADC 값(0~4095)을 스케일링하여 0~3.3V로 변환
    // 계산: ADC_readResult(0~4095) * (3.3V / 4096) = 전압 값
    adcResult = (float)ADC_readResult(ADCA_BASE, ADC_SOC_NUMBER0) * 3.3f / 4096.0f;
    
    // 처리: ADC 값의 제곱 계산
    // 예: adcResult = 1.65V -> outputData = 1.65 * 1.65 = 2.7225
    outputData = adcResult * adcResult;
    
    // 태스크 인터럽트 플래그 지우기: 다음 트리거를 위해 플래그 초기화
    CLA_clearTaskInterruptFlag(CLA1_BASE, CLA_TASK_1);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // CLA 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인
    // 목표 클럭: 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        claStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // ADC 초기화
    initADC();
    
    // CLA 초기화
    initCLA();
    
    // 초기화 오류 확인
    if (claStatus != 1)
    {
        claStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // ADC 변환 시작: SOC0 트리거로 CLA Task 1 실행
    ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
    
    // 무한 루프: 상태 모니터링
    for(;;)
    {
        // 디버깅용: 상태에 따라 LED 점등
        // claStatus == 1: 정상 동작, LED ON
        // claStatus != 1: 오류, LED OFF
        GPIO_writePin(31, (claStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: ADC-A의 변환 결과를 CLA Task 1에서 읽고 제곱하여 저장.
  • 설정: ADC-A 인터럽트로 Task 1 트리거, LS0(프로그램), LS1(데이터) 메모리 할당.
  • GPIO: GPIO31(LED).
  • 출력: outputData = adcResult * adcResult, 정상 동작 시 LED ON.

4.3. 예제 3: ePWM 트리거를 사용한 CLA 태스크

CLA Task 1을 ePWM SOCA 트리거로 실행하여 PWM 데이터를 처리합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수: CLA 동작 상태를 추적
volatile uint32_t claStatus = 0; // 0: 초기화 완료, 1: CLA 동작 중, 0xFFFF: 오류 발생

// 공유 메모리: CPU와 CLA 간 데이터 교환을 위해 Cla1DataRam0에 할당
#pragma DATA_SECTION(pwmDuty, "Cla1DataRam0")
float pwmDuty = 0.5f; // 초기 듀티 사이클: 50% (0.5)
#pragma DATA_SECTION(outputData, "Cla1DataRam0")
float outputData = 0.0f; // 처리 결과: 듀티 사이클 저장

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO0을 ePWM1A 출력으로 설정
    GPIO_setPinConfig(GPIO_0_EPWM1A); // GPIO0을 ePWM1A로 설정
    GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT); // 출력 모드로 설정
    GPIO_setPadConfig(0, GPIO_PULL_UP); // 풀업 저항 활성화
    
    // GPIO31을 디버깅용 LED로 설정
    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
}

// ePWM 초기화 함수
void initEPWM(void)
{
    // ePWM1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
    
    // 주기 설정: 100kHz PWM
    // 시스템 클럭: 200MHz, 목표 주기: 1/100kHz = 10us
    // 주기 카운터 = 200MHz * 10us = 2000
    EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
    EPWM_setCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP); // 업 카운터 모드
    
    // PWM_A 동작 설정
    // 카운터=0일 때 HIGH, CMPA에서 LOW
    EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A, 
                                 EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO, EPWM_AQ_OUTPUT_HIGH);
    EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A, 
                                 EPWM_AQ_OUTPUT_ON_TIMEBASE_CMPA_UP, EPWM_AQ_OUTPUT_LOW);
    
    // 초기 듀티 사이클: 50%
    // CMPA = 주기(2000) * 듀티(0.5) = 1000
    EPWM_setCompareA(EPWM1_BASE, (uint16_t)(2000 * 0.5f));
    
    // 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); // 매 주기마다 트리거
    
    // ePWM 모듈 활성화
    EPWM_enableModule(EPWM1_BASE);
}

// CLA 초기화 함수
void initCLA(void)
{
    // CLA 클럭 활성화: CLA1 모듈에 시스템 클럭 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLA1);
    
    // CLA 메모리 설정
    // L0: 프로그램 메모리(CLA 코드 저장), L1: 데이터 메모리(공유 데이터 저장)
    CLA_configureCLAMemory(CLA1_BASE, CLA_PROG_ENABLE_L0 | CLA_DATA_ENABLE_L1);
    
    // CLA 태스크 1 설정
    // ePWM1 SOCA로 트리거
    CLA_mapTaskVector(CLA1_BASE, CLA_TASK_1, CLA_INT_TRIG_EPWM1SOCA);
    CLA_enableTasks(CLA1_BASE, CLA_TASK_1); // Task 1 활성화
    
    // CLA 모듈 활성화
    CLA_enableCLA(CLA1_BASE);
    
    // 상태 업데이트: 초기화 완료
    claStatus = 1;
}

// CLA 태스크 코드 (별도의 .cla 파일에 저장)
#pragma CODE_SECTION(claTask1, "Cla1Prog")
__interrupt void claTask1(void)
{
    // 듀티 사이클 조정: 10% 증가
    // 계산: pwmDuty += 0.1 (최대 1.0, 즉 100%)
    pwmDuty += 0.1f;
    if (pwmDuty > 1.0f) pwmDuty = 0.1f; // 최대값 초과 시 10%로 리셋
    
    // ePWM CMPA 업데이트
    // CMPA = 주기(2000) * pwmDuty
    // 예: pwmDuty = 0.6 -> CMPA = 2000 * 0.6 = 1200
    EPWM_setCompareA(EPWM1_BASE, (uint16_t)(2000 * pwmDuty));
    
    // 처리 결과 저장
    outputData = pwmDuty;
    
    // 태스크 인터럽트 플래그 지우기: 다음 트리거를 위해 플래그 초기화
    CLA_clearTaskInterruptFlag(CLA1_BASE, CLA_TASK_1);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // ePWM 및 CLA 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인
    // 목표 클럭: 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        claStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // ePWM 초기화
    initEPWM();
    
    // CLA 초기화
    initCLA();
    
    // 초기화 오류 확인
    if (claStatus != 1)
    {
        claStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // 무한 루프: 상태 모니터링
    for(;;)
    {
        // 디버깅용: 상태에 따라 LED 점등
        // claStatus == 1: 정상 동작, LED ON
        // claStatus != 1: 오류, LED OFF
        GPIO_writePin(31, (claStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: ePWM1 SOCA 트리거로 CLA Task 1 실행, PWM 듀티 사이클을 10%씩 증가.
  • 설정: ePWM1 SOCA로 Task 1 트리거, LS0(프로그램), LS1(데이터) 메모리 할당.
  • GPIO: GPIO0(ePWM1A), GPIO31(LED).
  • 출력: PWM 듀티 사이클이 10~100%로 변화, outputData = pwmDuty, 정상 동작 시 LED ON.

5. 추가 고려 사항

  • 메모리 할당
    CLA는 TMS320F28388D의 LS(Local Shared) RAM(L0~L7)을 사용하여 프로그램과 데이터를 저장합니다. 이 메모리는 CPU와 CLA가 공유할 수 있으며, CLA 전용으로 할당할 수도 있습니다. 메모리 할당은 링크 스크립트(.cmd 파일)에서 Cla1Prog와 Cla1DataRam 섹션을 명시적으로 정의하여 수행됩니다.
    • 프로그램 메모리: CLA 태스크 코드는 Cla1Prog 섹션에 저장되며, LS RAM(L0~L7) 중 하나에 매핑됩니다. 예: Cla1Prog :> L0RAM, PAGE = 0.
    • 데이터 메모리: CLA와 CPU 간 공유 데이터는 Cla1DataRam 섹션에 저장되며, LS RAM(L0~L7) 중 다른 영역에 할당됩니다. 예: Cla1DataRam0 :> L1RAM, PAGE = 1.
    • 설정 방법: CLA_configureCLAMemory 함수를 사용하여 LS RAM을 프로그램 또는 데이터 메모리로 설정합니다. 예: CLA_configureCLAMemory(CLA1_BASE, CLA_PROG_ENABLE_L0 | CLA_DATA_ENABLE_L1);.
    • 링크 스크립트 예시: C2000Ware의 device_support\f2838x\examples 디렉토리에서 제공하는 .cmd 파일(예: 2838x_flash_lnk_cpu1.cmd)을 참조하여 메모리 섹션을 정의하세요. 잘못된 메모리 할당은 CLA 태스크 실행 실패로 이어질 수 있으므로, 메모리 충돌을 피하기 위해 CPU와 CLA 간 메모리 사용을 명확히 분리해야 합니다.
  • CLA 코드 작성
    CLA 코드는 .cla 확장자 파일에 작성되며, C 언어 기반이지만 CLA의 아키텍처에 맞춘 최적화가 필요합니다. CLA는 부동소수점 연산을 지원하며, 전용 명령어(MADD32, MMUL32, MF32TOI32 등)를 사용하여 연산 효율을 높일 수 있습니다.
    • C 언어 기반: 표준 C 문법을 따르지만, CLA는 제한된 레지스터 세트(MR0~MR3, MSTF 등)를 사용하므로 변수 사용을 최소화해야 합니다.
    • 최적화 명령어: TI의 CLA C Compiler Guide (SPRUI84)에서 제공하는 전용 명령어를 활용하여 성능을 최적화할 수 있습니다. 예: MADD32는 부동소수점 덧셈, MMUL32는 곱셈을 하드웨어 수준에서 가속화합니다.
    • 제약 사항: CLA는 스택이 없으므로 재귀 호출이나 복잡한 함수 호출을 피해야 하며, 모든 태스크는 인터럽트 서비스 루틴(ISR) 형태로 작성됩니다.
    • 작성 예시: .cla 파일에서 __interrupt void claTask1(void) 형식으로 태스크를 정의하며, 연산 결과를 공유 메모리에 저장합니다. TI의 Code Composer Studio에서 제공하는 CLA 디버깅 도구를 사용하여 코드 실행을 추적할 수 있습니다.
  • 트리거 소스
    CLA 태스크는 다양한 트리거 소스에 의해 실행됩니다. 주요 트리거 소스는 ADC, ePWM, 타이머, 소프트웨어 트리거 등이 있으며, 이는 CLA_mapTaskVector 함수로 태스크와 매핑됩니다.
    • ADC 트리거: ADC 변환 완료 시(예: ADCA_INT1) CLA 태스크를 트리거하여 실시간 데이터 처리를 수행합니다. 예: CLA_mapTaskVector(CLA1_BASE, CLA_TASK_1, CLA_INT_TRIG_ADCA1);.
    • ePWM 트리거: ePWM의 SOCA/SOCB 신호로 CLA 태스크를 트리거하여 PWM 제어와 연계된 연산을 처리합니다. 예: CLA_mapTaskVector(CLA1_BASE, CLA_TASK_1, CLA_INT_TRIG_EPWM1SOCA);.
    • 타이머 트리거: CPUTimer0~2를 사용하여 주기적인 태스크 실행을 설정할 수 있습니다.
    • 소프트웨어 트리거: CLA_forceTasks 함수로 CPU에서 직접 태스크를 실행합니다. 예: CLA_forceTasks(CLA1_BASE, CLA_TASK_1);.
    • 설정 주의점: 각 태스크는 단일 트리거 소스에만 매핑 가능하며, 트리거 충돌을 방지하기 위해 CLA_clearTaskInterruptFlag로 플래그를 지워야 합니다.
  • 데이터 교환
    CPU와 CLA 간 데이터 교환은 공유 LS RAM 또는 메시지 RAM을 통해 이루어집니다. 동기화는 신중히 관리해야 합니다.
    • 공유 LS RAM: CPU와 CLA가 동일한 LS RAM(L0~L7)에 접근 가능하도록 설정합니다. 예: #pragma DATA_SECTION(var, "Cla1DataRam0")로 변수를 특정 메모리에 할당.
    • 메시지 RAM: CLA 전용 메시지 RAM(Cla1MsRam)을 사용하여 CPU와 CLA 간 데이터를 주고받을 수 있습니다. 메시지 RAM은 고속 데이터 전송에 적합합니다.
    • 동기화 주의점: CPU와 CLA가 동시에 동일한 메모리에 접근하면 데이터 무결성 문제가 발생할 수 있습니다. 이를 방지하려면 CPU에서 메모리 쓰기를 완료한 후 CLA 태스크를 트리거하거나, 세마포어와 같은 동기화 메커니즘을 구현해야 합니다.
    • 예시: CPU가 입력 데이터를 Cla1DataRam0에 쓰고, CLA 태스크가 이를 읽어 처리한 후 결과를 동일한 메모리에 저장합니다. CPU는 결과가 준비되었는지 확인하기 위해 태스크 완료 인터럽트를 사용할 수 있습니다.
  • C2000Ware: 예제 코드는 C2000Ware의 DriverLib 기반. C:\ti\c2000에 설치.
  • 디버깅: CCS의 CLA 디버깅 모드를 사용하여 태스크 실행 추적 가능. .syscfg 툴로 CLA 설정 시각적 구성 가능.
  • 성능 최적화: CLA는 CPU와 병렬 실행으로 실시간 성능 향상. 복잡한 연산(PID, 필터링)을 CLA로 오프로드 권장.

키워드: TMS320F28388D, CLA, Control Law Accelerator, DriverLib, C2000, 부동소수점, 병렬 처리, Code Composer Studio, ADC 트리거, ePWM 트리거, 공유 메모리, 실시간 제어

반응형