본문 바로가기
MCU/C2000

TMS320F28388D DSP CLB 사용법: DriverLib API로 CLB 설정 및 코드

by linuxgo 2025. 8. 17.
반응형

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

1. TMS320F28388D CLB 개요

TMS320F28388D는 Texas Instruments의 C2000 시리즈에 속하는 고성능 32비트 마이크로컨트롤러로, CLB는 사용자 정의 논리 블록을 제공하여 복잡한 디지털 논리, 타이밍 제어, 그리고 외부 신호 처리를 하드웨어 수준에서 수행할 수 있습니다. CLB는 CPU 부하를 줄이고, ePWM, ADC, GPIO 등과 통합하여 고속 실시간 애플리케이션(예: 모터 제어, 디지털 전력 변환)을 지원합니다.

CLB 모듈의 주요 특징

  • 사용자 정의 논리: CLB는 LUT(Look-Up Table), FSM(Finite State Machine), 카운터를 포함하여 사용자 정의 논리 회로를 구현 가능.
  • 타일 구조: 최대 8개의 CLB 타일(CLB1~CLB8)을 지원하며, 각 타일은 독립적인 논리 블록(LUT, 카운터, FSM)으로 구성.
  • 외부 인터페이스: GPIO, ePWM, SPI, ADC 등과의 긴밀한 통합을 통해 외부 신호 입력 및 출력 가능.
  • 고속 동작: 시스템 클럭(최대 200MHz)과 동기화, 낮은 레이턴시로 동작.
  • HLC(High-Level Controller): 각 타일에 포함된 HLC는 간단한 C 코드를 실행하여 복잡한 제어 로직을 처리.
  • 인터럽트 지원: CLB 타일별 인터럽트 발생 가능, CPU와의 통신은 공유 메모리 또는 인터럽트를 통해 수행.
  • 시뮬레이터: TI의 CLB Tool을 통해 논리 설계를 시뮬레이션하고 코드 생성 가능.

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

2. 주요 CLB DriverLib API 함수

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

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

  • CLB_enableCLB(base): CLB 모듈을 활성화합니다.
    • 매개변수: base (CLB1_BASE, CLB2_BASE 등).
    • 사용 예: CLB_enableCLB(CLB1_BASE);
  • CLB_disableCLB(base): CLB 모듈을 비활성화합니다.
    • 매개변수: base (CLB1_BASE 등).
  • CLB_configureCounter(base, counter, loadValue): CLB 카운터를 설정하고 초기 값을 지정합니다.
    • 매개변수: counter (CLB_COUNTER_0~2), loadValue (카운터 초기 값).
    • 사용 예: CLB_configureCounter(CLB1_BASE, CLB_COUNTER_0, 1000);
  • CLB_selectInputFilter(base, input, filterType): CLB 입력 필터(동기화/비동기화)를 설정합니다.
    • 매개변수: input (CLB_IN0~7), filterType (CLB_FILTER_NONE, CLB_FILTER_RISING 등).
    • 사용 예: CLB_selectInputFilter(CLB1_BASE, CLB_IN0, CLB_FILTER_RISING);

2.2. LUT 및 FSM 관련 함수

  • CLB_configLUT(base, lut, config): CLB의 LUT(Look-Up Table)를 설정합니다.
    • 매개변수: lut (CLB_LUT_0~2), config (논리 테이블 설정 값).
    • 사용 예: CLB_configLUT(CLB1_BASE, CLB_LUT_0, 0xAAAA);
  • CLB_configFSM(base, fsm, config): CLB의 FSM(Finite State Machine)을 설정합니다.
    • 매개변수: fsm (CLB_FSM_0~2), config (상태 전이 설정).
  • CLB_setOutput(base, output, value): CLB 출력 핀의 값을 설정합니다.
    • 매개변수: output (CLB_OUT0~7), value (0 또는 1).

2.3. HLC 및 인터럽트 관련 함수

  • CLB_enableHLC(base): CLB의 HLC(High-Level Controller)를 활성화합니다.
    • 매개변수: base (CLB1_BASE 등).
    • 사용 예: CLB_enableHLC(CLB1_BASE);
  • CLB_enableInterrupt(base, interrupt): CLB 인터럽트를 활성화합니다.
    • 매개변수: interrupt (CLB_INT_LOCAL, CLB_INT_GLOBAL 등).
  • CLB_clearInterruptTag(base): CLB 인터럽트 플래그를 지웁니다.
    • 매개변수: base (CLB1_BASE 등).

2.4. 주변 장치 관련 함수

  • SysCtl_enablePeripheral(periph): CLB 주변 장치 클럭을 활성화합니다.
    • 매개변수: periph (SYSCTL_PERIPH_CLK_CLB1 등).
    • 사용 예: SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);

3. CLB 설정 및 동작 원리

  1. 시스템 초기화: 시스템 클럭, GPIO, 인터럽트 모듈 초기화(Device_init(), Device_initGPIO()).
  2. CLB 클럭 활성화: CLB 모듈에 시스템 클럭을 공급(SysCtl_enablePeripheral).
  3. CLB 타일 설정: CLB 타일의 LUT, FSM, 카운터를 설정하고 입력/출력 핀을 매핑.
  4. HLC 코드 작성: HLC를 사용하여 복잡한 로직을 C 언어로 구현(.clb 파일).
  5. CLB 활성화: CLB 모듈과 인터럽트를 활성화하여 논리 동작 시작.
  6. 데이터 교환: CPU와 CLB 간 데이터 교환은 공유 메모리 또는 CLB 출력 핀을 통해 수행.

4. CLB 예제 코드

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

4.1. 예제 1: 기본 CLB 논리 구현 (AND 논리)

CLB1을 사용하여 두 입력 신호(GPIO0, GPIO1)의 AND 연산을 수행합니다.

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

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

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO0을 CLB1_IN0에 연결, 입력 모드로 설정
    GPIO_setPinConfig(GPIO_0_CLB1_IN0); // GPIO0 -> CLB1_IN0
    GPIO_setDirectionMode(0, GPIO_DIR_MODE_IN); // 입력 모드 설정
    GPIO_setPadConfig(0, GPIO_PULL_UP); // 풀업 저항 활성화
    
    // GPIO1을 CLB1_IN1에 연결, 입력 모드로 설정
    GPIO_setPinConfig(GPIO_1_CLB1_IN1); // GPIO1 -> CLB1_IN1
    GPIO_setDirectionMode(1, GPIO_DIR_MODE_IN); // 입력 모드 설정
    GPIO_setPadConfig(1, 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
}

// CLB 초기화 함수
void initCLB(void)
{
    // CLB1 클럭 활성화: CLB1 모듈에 시스템 클럭(200MHz) 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
    
    // CLB1 모듈 활성화
    CLB_enableCLB(CLB1_BASE);
    
    // CLB1 입력 필터 설정: CLB_IN0, CLB_IN1에 필터 없음 (직접 입력)
    CLB_selectInputFilter(CLB1_BASE, CLB_IN0, CLB_FILTER_NONE);
    CLB_selectInputFilter(CLB1_BASE, CLB_IN1, CLB_FILTER_NONE);
    
    // LUT0 설정: AND 연산 (IN0 & IN1)
    // 진리표: (0,0)=0, (0,1)=0, (1,0)=0, (1,1)=1 -> 0b1000 (0x8)
    CLB_configLUT(CLB1_BASE, CLB_LUT_0, 0x8);
    
    // 출력 설정: LUT0 결과를 CLB_OUT0에 연결
    CLB_setOutput(CLB1_BASE, CLB_OUT0, CLB_LUT_0);
    
    // 상태 업데이트: CLB 초기화 완료
    clbStatus = 1;
}

// CLB HLC 코드 (별도의 .clb 파일에 저장)
#pragma CODE_SECTION(clbHLC, "Clb1Prog")
__interrupt void clbHLC(void)
{
    // 이 예제에서는 HLC 사용하지 않음
    // 인터럽트 플래그 지우기: 다음 인터럽트를 위해 플래그 초기화
    CLB_clearInterruptTag(CLB1_BASE);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화: C2000Ware 제공 함수
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // CLB 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인: 목표 클럭 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // CLB 초기화
    initCLB();
    
    // 초기화 오류 확인
    if (clbStatus != 1)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // 무한 루프: CLB 출력 모니터링
    for(;;)
    {
        // CLB_OUT0 값을 GPIO31(LED)에 반영
        // AND 연산 결과에 따라 LED 점등/소등
        uint32_t output = CLB_getOutput(CLB1_BASE, CLB_OUT0);
        GPIO_writePin(31, output);
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: CLB1의 LUT0를 사용하여 GPIO0과 GPIO1의 AND 연산을 수행, 결과를 CLB_OUT0에 출력.
  • 설정: CLB1_IN0(GPIO0), CLB1_IN1(GPIO1), LUT0(AND), 출력은 CLB_OUT0.
  • GPIO: GPIO0, GPIO1(입력), GPIO31(LED, 출력).
  • 출력: GPIO0=1, GPIO1=1일 때 CLB_OUT0=1, LED ON.

4.2. 예제 2: CLB 카운터를 사용한 주기적 출력

CLB1의 카운터를 사용하여 주기적으로 출력 신호를 생성합니다.

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

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

// 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
}

// CLB 초기화 함수
void initCLB(void)
{
    // CLB1 클럭 활성화: CLB1 모듈에 시스템 클럭(200MHz) 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
    
    // CLB1 모듈 활성화
    CLB_enableCLB(CLB1_BASE);
    
    // 카운터0 설정: 5ms 주기 (200MHz * 5ms = 1,000,000 사이클)
    CLB_configureCounter(CLB1_BASE, CLB_COUNTER_0, 1000000);
    
    // 출력 설정: 카운터0 오버플로우 시 CLB_OUT0 토글
    CLB_setOutput(CLB1_BASE, CLB_OUT0, CLB_COUNTER_0);
    
    // CLB 인터럽트 활성화: 카운터 오버플로우 시 인터럽트 발생
    CLB_enableInterrupt(CLB1_BASE, CLB_INT_LOCAL);
    
    // 상태 업데이트: CLB 초기화 완료
    clbStatus = 1;
}

// CLB HLC 코드 (별도의 .clb 파일에 저장)
#pragma CODE_SECTION(clbHLC, "Clb1Prog")
__interrupt void clbHLC(void)
{
    // 카운터 오버플로우 시 CLB_OUT0 토글
    // 현재 출력 상태를 반전
    CLB_setOutput(CLB1_BASE, CLB_OUT0, !CLB_getOutput(CLB1_BASE, CLB_OUT0));
    
    // 인터럽트 플래그 지우기: 다음 인터럽트를 위해 플래그 초기화
    CLB_clearInterruptTag(CLB1_BASE);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화: C2000Ware 제공 함수
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // CLB 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인: 목표 클럭 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // CLB 초기화
    initCLB();
    
    // 초기화 오류 확인
    if (clbStatus != 1)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // 무한 루프: CLB 출력 모니터링
    for(;;)
    {
        // CLB_OUT0 값을 GPIO31(LED)에 반영
        // 5ms마다 LED 토글
        GPIO_writePin(31, CLB_getOutput(CLB1_BASE, CLB_OUT0));
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: CLB1의 카운터0를 사용하여 5ms 주기로 CLB_OUT0을 토글.
  • 설정: 카운터0(1,000,000 사이클), 출력은 CLB_OUT0.
  • GPIO: GPIO31(LED, 출력).
  • 출력: 5ms마다 LED 토글.

4.3. 예제 3: ePWM과 연계한 CLB 동작

CLB1을 ePWM1의 신호와 연계하여 PWM 신호를 변조합니다.

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

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

// 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, 1000);
    
    // ePWM 모듈 활성화
    EPWM_enableModule(EPWM1_BASE);
}

// CLB 초기화 함수
void initCLB(void)
{
    // CLB1 클럭 활성화: CLB1 모듈에 시스템 클럭(200MHz) 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
    
    // CLB1 모듈 활성화
    CLB_enableCLB(CLB1_BASE);
    
    // 입력 설정: ePWM1A를 CLB_IN0에 연결
    CLB_selectInputFilter(CLB1_BASE, CLB_IN0, CLB_FILTER_NONE);
    
    // LUT0 설정: ePWM1A 신호 반전
    // 진리표: (0)=1, (1)=0 -> 0b0101 (0x5)
    CLB_configLUT(CLB1_BASE, CLB_LUT_0, 0x5);
    
    // 출력 설정: LUT0 결과를 CLB_OUT0에 연결
    CLB_setOutput(CLB1_BASE, CLB_OUT0, CLB_LUT_0);
    
    // 상태 업데이트: CLB 초기화 완료
    clbStatus = 1;
}

// CLB HLC 코드 (별도의 .clb 파일에 저장)
#pragma CODE_SECTION(clbHLC, "Clb1Prog")
__interrupt void clbHLC(void)
{
    // 이 예제에서는 HLC 사용하지 않음
    // 인터럽트 플래그 지우기: 다음 인터럽트를 위해 플래그 초기화
    CLB_clearInterruptTag(CLB1_BASE);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화: C2000Ware 제공 함수
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // ePWM 및 CLB 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인: 목표 클럭 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // ePWM 초기화
    initEPWM();
    
    // CLB 초기화
    initCLB();
    
    // 초기화 오류 확인
    if (clbStatus != 1)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // 무한 루프: CLB 출력 모니터링
    for(;;)
    {
        // CLB_OUT0 값을 GPIO31(LED)에 반영
        // ePWM1A의 반전 신호에 따라 LED 점등/소등
        GPIO_writePin(31, CLB_getOutput(CLB1_BASE, CLB_OUT0));
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: CLB1의 LUT0를 사용하여 ePWM1A 신호를 반전, CLB_OUT0에 출력.
  • 설정: CLB1_IN0(ePWM1A), LUT0(반전), 출력은 CLB_OUT0.
  • GPIO: GPIO0(ePWM1A), GPIO31(LED, 출력).
  • 출력: ePWM1A의 반전 신호가 CLB_OUT0에 출력, LED로 표시.

4.4. 예제 4: CLB를 사용한 OR 논리 구현

CLB1을 사용하여 두 입력 신호(GPIO2, GPIO3)의 OR 연산을 수행합니다.

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

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

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO2을 CLB1_IN2에 연결, 입력 모드로 설정
    GPIO_setPinConfig(GPIO_2_CLB1_IN2); // GPIO2 -> CLB1_IN2
    GPIO_setDirectionMode(2, GPIO_DIR_MODE_IN); // 입력 모드 설정
    GPIO_setPadConfig(2, GPIO_PULL_UP); // 풀업 저항 활성화
    
    // GPIO3을 CLB1_IN3에 연결, 입력 모드로 설정
    GPIO_setPinConfig(GPIO_3_CLB1_IN3); // GPIO3 -> CLB1_IN3
    GPIO_setDirectionMode(3, GPIO_DIR_MODE_IN); // 입력 모드 설정
    GPIO_setPadConfig(3, 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
}

// CLB 초기화 함수
void initCLB(void)
{
    // CLB1 클럭 활성화: CLB1 모듈에 시스템 클럭(200MHz) 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
    
    // CLB1 모듈 활성화
    CLB_enableCLB(CLB1_BASE);
    
    // CLB1 입력 필터 설정: CLB_IN2, CLB_IN3에 필터 없음 (직접 입력)
    CLB_selectInputFilter(CLB1_BASE, CLB_IN2, CLB_FILTER_NONE);
    CLB_selectInputFilter(CLB1_BASE, CLB_IN3, CLB_FILTER_NONE);
    
    // LUT0 설정: OR 연산 (IN2 | IN3)
    // 진리표: (0,0)=0, (0,1)=1, (1,0)=1, (1,1)=1 -> 0b1110 (0xE)
    CLB_configLUT(CLB1_BASE, CLB_LUT_0, 0xE);
    
    // 출력 설정: LUT0 결과를 CLB_OUT0에 연결
    CLB_setOutput(CLB1_BASE, CLB_OUT0, CLB_LUT_0);
    
    // 상태 업데이트: CLB 초기화 완료
    clbStatus = 1;
}

// CLB HLC 코드 (별도의 .clb 파일에 저장)
#pragma CODE_SECTION(clbHLC, "Clb1Prog")
__interrupt void clbHLC(void)
{
    // 이 예제에서는 HLC 사용하지 않음
    // 인터럽트 플래그 지우기: 다음 인터럽트를 위해 플래그 초기화
    CLB_clearInterruptTag(CLB1_BASE);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화: C2000Ware 제공 함수
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // CLB 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인: 목표 클럭 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // CLB 초기화
    initCLB();
    
    // 초기화 오류 확인
    if (clbStatus != 1)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // 무한 루프: CLB 출력 모니터링
    for(;;)
    {
        // CLB_OUT0 값을 GPIO31(LED)에 반영
        // OR 연산 결과에 따라 LED 점등/소등
        uint32_t output = CLB_getOutput(CLB1_BASE, CLB_OUT0);
        GPIO_writePin(31, output);
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: CLB1의 LUT0를 사용하여 GPIO2와 GPIO3의 OR 연산을 수행, 결과를 CLB_OUT0에 출력.
  • 설정: CLB1_IN2(GPIO2), CLB1_IN3(GPIO3), LUT0(OR), 출력은 CLB_OUT0.
  • GPIO: GPIO2, GPIO3(입력), GPIO31(LED, 출력).
  • 출력: GPIO2=1 또는 GPIO3=1일 때 CLB_OUT0=1, LED ON.

4.5. 예제 5: CLB FSM을 사용한 상태 전이

CLB1의 FSM을 사용하여 간단한 상태 머신을 구현합니다.

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

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

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO4을 CLB1_IN4에 연결, 입력 모드로 설정 (FSM 트리거)
    GPIO_setPinConfig(GPIO_4_CLB1_IN4); // GPIO4 -> CLB1_IN4
    GPIO_setDirectionMode(4, GPIO_DIR_MODE_IN); // 입력 모드 설정
    GPIO_setPadConfig(4, 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
}

// CLB 초기화 함수
void initCLB(void)
{
    // CLB1 클럭 활성화: CLB1 모듈에 시스템 클럭(200MHz) 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
    
    // CLB1 모듈 활성화
    CLB_enableCLB(CLB1_BASE);
    
    // CLB1 입력 필터 설정: CLB_IN4에 상승 에지 감지
    CLB_selectInputFilter(CLB1_BASE, CLB_IN4, CLB_FILTER_RISING);
    
    // FSM0 설정: 2상태 전이 (0 -> 1 -> 0)
    // 상태 0: CLB_IN4=1일 때 상태 1로 전이
    // 상태 1: CLB_IN4=1일 때 상태 0으로 전이, CLB_OUT0=1
    CLB_configFSM(CLB1_BASE, CLB_FSM_0, 0x3); // 간단한 토글 FSM
    
    // 출력 설정: FSM0 결과를 CLB_OUT0에 연결
    CLB_setOutput(CLB1_BASE, CLB_OUT0, CLB_FSM_0);
    
    // 상태 업데이트: CLB 초기화 완료
    clbStatus = 1;
}

// CLB HLC 코드 (별도의 .clb 파일에 저장)
#pragma CODE_SECTION(clbHLC, "Clb1Prog")
__interrupt void clbHLC(void)
{
    // 이 예제에서는 HLC 사용하지 않음
    // 인터럽트 플래그 지우기: 다음 인터럽트를 위해 플래그 초기화
    CLB_clearInterruptTag(CLB1_BASE);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화: C2000Ware 제공 함수
    Device_init();
    
    // GPIO 기본 초기화: C2000Ware 제공 함수
    Device_initGPIO();
    
    // CLB 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인: 목표 클럭 200MHz = 200,000,000 Hz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // CLB 초기화
    initCLB();
    
    // 초기화 오류 확인
    if (clbStatus != 1)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화: 시스템 안정성 확보
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // 무한 루프: CLB 출력 모니터링
    for(;;)
    {
        // CLB_OUT0 값을 GPIO31(LED)에 반영
        // FSM 상태에 따라 LED 점등/소등
        uint32_t output = CLB_getOutput(CLB1_BASE, CLB_OUT0);
        GPIO_writePin(31, output);
        DEVICE_DELAY_US(1000000); // 1초 대기 (1,000,000us)
    }
}

설명:

  • 기능: CLB1의 FSM0를 사용하여 GPIO4의 상승 에지로 상태 전이(0->1->0)를 수행, CLB_OUT0에 출력.
  • 설정: CLB1_IN4(GPIO4), FSM0(2상태 토글), 출력은 CLB_OUT0.
  • GPIO: GPIO4(입력), GPIO31(LED, 출력).
  • 출력: GPIO4 상승 에지마다 FSM 상태 전이, LED 토글.

4.6. 예제 6: ADC와 연계한 CLB 동작

CLB1을 사용하여 ADC 변환 완료 신호를 처리합니다.

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

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

// 공유 메모리: CPU와 CLB 간 데이터 교환
#pragma DATA_SECTION(adcResult, "Clb1Data")
volatile uint16_t adcResult = 0; // 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
}

// ADC 초기화 함수
void initADC(void)
{
    // ADC-A 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
    
    // ADC 설정: 12비트 해상도, 내부 3.3V 참조
    ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0); // 200MHz / 4 = 50MHz ADC 클럭
    ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
    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 대기
    DEVICE_DELAY_US(1000000);
}

// CLB 초기화 함수
void initCLB(void)
{
    // CLB1 클럭 활성화: CLB1 모듈에 시스템 클럭(200MHz) 공급
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
    
    // CLB1 모듈 활성화
    CLB_enableCLB(CLB1_BASE);
    
    // 입력 설정: ADC_INT1을 CLB_IN0에 연결
    CLB_selectInputFilter(CLB1_BASE, CLB_IN0, CLB_FILTER_RISING);
    
    // LUT0 설정: ADC_INT1 신호를 그대로 출력
    // 진리표: (0)=0, (1)=1 -> 0b1010 (0xA)
    CLB_configLUT(CLB1_BASE, CLB_LUT_0, 0xA);
    
    // 출력 설정: LUT0 결과를 CLB_OUT0에 연결
    CLB_setOutput(CLB1_BASE, CLB_OUT0, CLB_LUT_0);
    
    //izál

    // HLC 활성화: ADC 데이터를 처리
    CLB_enableHLC(CLB1_BASE);
    
    // 상태 업데이트: CLB 초기화 완료
    clbStatus = 1;
}

// CLB HLC 코드 (별도의 .clb 파일에 저장)
#pragma CODE_SECTION(clbHLC, "Clb1Prog")
__interrupt void clbHLC(void)
{
    // ADC 결과 읽기: 12비트 ADC 값(0~4095)을 읽음
    adcResult = ADC_readResult(ADCA_BASE, ADC_SOC_NUMBER0);
    
    // ADC 값이 임계값(2048, 약 1.65V) 이상이면 CLB_OUT0=1
    if (adcResult > 2048)
    {
        CLB_setOutput(CLB1_BASE, CLB_OUT0, 1);
    }
    else
    {
        CLB_setOutput(CLB1_BASE, CLB_OUT0, 0);
    }
    
    // 인터럽트 플래그 지우기
    CLB_clearInterruptTag(CLB1_BASE);
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화
    Device_init();
    
    // GPIO 기본 초기화
    Device_initGPIO();
    
    // CLB 관련 GPIO 설정
    initGPIO();
    
    // 인터럽트 모듈 초기화
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // 시스템 클럭 확인: 목표 클럭 200MHz
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // ADC 초기화
    initADC();
    
    // CLB 초기화
    initCLB();
    
    // 초기화 오류 확인
    if (clbStatus != 1)
    {
        clbStatus = 0xFFFF; // 오류 상태 설정
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 오류 발생 시 프로그램 정지
    }
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();
    
    // ADC 변환 시작
    ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
    
    // 무한 루프: CLB 출력 모니터링
    for(;;)
    {
        // CLB_OUT0 값을 GPIO31(LED)에 반영
        GPIO_writePin(31, CLB_getOutput(CLB1_BASE, CLB_OUT0));
        DEVICE_DELAY_US(1000000); // 1초 대기
    }
}

설명:

  • 기능: CLB1의 HLC를 사용하여 ADC 변환 결과를 처리, 임계값(1.65V) 이상 시 CLB_OUT0=1.
  • 설정: CLB1_IN0(ADC_INT1), LUT0(직접 출력), HLC(ADC 처리), 출력은 CLB_OUT0.
  • GPIO: GPIO31(LED, 출력).
  • 출력: ADC 값 > 1.65V일 때 LED ON.

5. 추가 고려 사항

CLB를 효과적으로 사용하기 위해 다음 사항들을 상세히 고려해야 합니다:

  • 메모리 할당:
    • CLB는 내부 레지스터와 전용 메모리를 사용하여 논리 및 HLC 코드를 저장합니다. CLB 프로그램은 Clb1Prog 섹션에, 데이터는 Clb1Data 섹션에 할당됩니다.
    • 링크 스크립트(.cmd 파일)에서 CLB 메모리를 명시적으로 정의해야 합니다. 예: Clb1Prog :> CLB1RAM, PAGE = 0.
    • CPU와 CLB 간 메모리 충돌을 방지하기 위해, 메모리 섹션을 명확히 분리해야 합니다.

               예를 들어, 2838x_flash_lnk_cpu1.cmd 파일에서 CLB 메모리 영역을 정확히 지정하세요.

    • 메모리 할당 오류는 CLB 동작 실패로 이어질 수 있으므로, C2000Ware의 예제 링크 스크립트를 참고하여 설정하세요.
  • CLB 코드 작성:
    • CLB의 HLC 코드는 .clb 확장자 파일에 작성되며, C 언어 기반으로 간단한 제어 로직을 구현합니다.
    • HLC는 제한된 명령어 세트를 사용하므로, 복잡한 연산(예: 부동소수점 연산)은 피하고 간단한 논리 및 비교 연산에 집중해야 합니다.
    • TI의 CLB Tool을 사용하여 LUT, FSM, 카운터의 동작을 시뮬레이션하고 자동으로 코드를 생성할 수 있습니다. CLB Tool은 CCS와 통합되어 있어 설계를 시각적으로 검증할 수 있습니다.
    • HLC 코드 디버깅 시, CCS의 CLB 디버깅 모드를 사용하여 레지스터 값과 출력 상태를 실시간으로 확인하세요.
  • 트리거 소스:
    • CLB는 다양한 입력 소스(GPIO, ePWM, ADC, 타이머 등)를 지원하며, CLB_selectInputFilter를 통해 입력 신호의 동기화 또는 필터링(예: 상승/하강 에지 감지)을 설정할 수 있습니다.
    • 트리거 소스는 CLB 타일의 입력 핀(CLB_IN0~7)에 매핑되며, 각 입력은 단일 소스에만 연결 가능합니다.
    • 트리거 충돌을 방지하려면, 인터럽트 플래그를 CLB_clearInterruptTag로 주기적으로 초기화해야 합니다.
    • 예: ADC 변환 완료 신호를 CLB_IN0에 매핑하여 실시간 데이터 처리를 수행할 수 있습니다.
  • 데이터 교환:
    • CPU와 CLB 간 데이터 교환은 공유 메모리 또는 CLB 출력 핀을 통해 이루어집니다.
    • 공유 메모리 사용 시, #pragma DATA_SECTION 지시자를 사용하여 변수를 Clb1Data 섹션에 할당하세요.
    • 예: #pragma DATA_SECTION(var, "Clb1Data").
    • 동기화 문제: CPU와 CLB가 동시에 동일한 메모리에 접근하면 데이터 무결성 문제가 발생할 수 있습니다. 이를 방지하려면 세마포어, 플래그, 또는 인터럽트를 사용하여 동기화를 관리하세요.
    • CLB 출력 핀(CLB_OUT0~7)은 GPIO 또는 내부 모듈(ePWM, ADC 등)로 직접 연결 가능하며, 하드웨어 수준의 빠른 데이터 전송을 지원합니다.
  • 성능 최적화:
    • CLB는 하드웨어 기반 논리 처리로 CPU 부하를 줄이고, 고속 디지털 신호 처리 및 타이밍 제어를 가능하게 합니다.
    • 복잡한 제어 로직(예: PID 제어, 신호 필터링)을 CLB로 오프로드하면 CPU의 실시간 처리 부담을 줄일 수 있습니다.
    • CLB Tool을 활용하여 LUT와 FSM의 논리 최적화를 수행하면 코드 크기와 실행 시간을 줄일 수 있습니다.
    • CLB의 낮은 레이턴시를 활용하여 고속 PWM 변조, 센서 데이터 처리 등에 적합합니다.
  • 디버깅 및 테스트:
    • CCS의 CLB 디버깅 모드를 사용하여 CLB 레지스터, 입력/출력 핀, HLC 상태를 실시간으로 모니터링할 수 있습니다.
    • CLB Tool은 논리 설계의 시뮬레이션과 검증을 지원하며, 예상 출력과 실제 출력을 비교하여 오류를 빠르게 파악할 수 있습니다.
    • 테스트 시, CLB 입력 신호를 오실로스코프로 확인하여 타이밍과 논리 동작을 검증하세요.
    • C2000Ware의 예제 프로젝트(예: device_support/f2838x/examples)를 참고하여 초기 설정을 검증하세요.
  • 전력 및 클럭 관리:
    • CLB는 시스템 클럭(최대 200MHz)에 동기화되므로, 시스템 클럭 설정이 정확해야 합니다. SysCtl_getClock로 클럭을 확인하세요.
    • 전력 소모를 줄이기 위해 사용하지 않는 CLB 타일을 비활성화(CLB_disableCLB)하세요.
    • 클럭 주파수와 타이밍 요구사항을 고려하여 카운터 및 FSM 설정을 최적화하세요.
  • C2000Ware 활용:
    • C2000Ware(C:\ti\c2000)는 CLB 설정 및 디버깅에 필요한 DriverLib, 헤더 파일, 예제 코드를 제공합니다.
    • CLB 관련 예제는 device_support/f2838x/examples/clb 디렉토리에서 확인 가능하며, 기본 설정과 테스트 코드를 참고하세요.
    • .syscfg 파일을 사용하여 CLB 설정을 시각적으로 구성할 수 있으며, 이는 코드 작성 오류를 줄이는 데 유용합니다.
  • 애플리케이션별 고려사항:
    • 모터 제어: CLB를 사용하여 고속 PWM 변조 및 엔코더 신호 처리를 구현할 수 있습니다. 예: 엔코더 펄스 카운팅을 CLB 카운터로 처리.
    • 디지털 전력 변환: CLB를 활용해 복잡한 타이밍 제어(예: 위상 이동 PWM)를 하드웨어 수준에서 처리하여 CPU 부하를 줄임.
    • 신호 처리: ADC 데이터를 CLB로 빠르게 처리하여 실시간 필터링 또는 임계값 비교를 수행.
    • 안전성: CLB의 독립적인 논리 처리는 시스템 오류를 줄이고, 안전 관련 애플리케이션(SIL, ASIL)에서 신뢰성을 높입니다.

키워드: TMS320F28388D, CLB, Configurable Logic Block, DriverLib, C2000, LUT, FSM, HLC, Code Composer Studio, ePWM, ADC, GPIO, 실시간 제어

반응형