이 문서에서는 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(Control Law Accelerator) 모듈을 제어하기 위해 자주 사용되는 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_disableCLB(CLB1_BASE);
- CLB_configureCounter(base, counter, loadValue)
CLB 카운터를 설정하고 초기 값을 지정합니다.
매개변수:- counter: CLB_COUNTER_0, CLB_COUNTER_1, CLB_COUNTER_2.
- loadValue: 카운터 초기 값 (32비트 정수).
사용 예:
CLB_configureCounter(CLB1_BASE, CLB_COUNTER_0, 1000);
- CLB_selectInputFilter(base, input, filterType)
CLB 입력 필터(동기화/비동기화)를 설정합니다.
매개변수:- input: CLB_IN0 ~ CLB_IN7.
- filterType: CLB_FILTER_NONE, CLB_FILTER_RISING_EDGE, CLB_FILTER_FALLING_EDGE, CLB_FILTER_BOTH_EDGE.
사용 예:
CLB_selectInputFilter(CLB1_BASE, CLB_IN0, CLB_FILTER_RISING_EDGE);
2.2. LUT 및 FSM 관련 함수
- CLB_configLUT4Function(base, lut, lut0Config, lut2Config)
CLB의 LUT(Look-Up Table)를 설정합니다.
매개변수:- lut: CLB_LUT_0, CLB_LUT_1, CLB_LUT_2.
- lut0Config: LUT0의 진리표 값 (예: NOT 연산은 0x5).
- lut2Config: LUT2의 진리표 값 (사용하지 않을 경우 0).
사용 예:
CLB_configLUT4Function(CLB1_BASE, CLB_LUT_0, 0x5, 0); // NOT 연산
- CLB_configFSMNextState(base, fsm, nextState)
CLB의 FSM(Finite State Machine) 상태 전이를 설정합니다.
매개변수:- fsm: CLB_FSM_0, CLB_FSM_1, CLB_FSM_2.
- nextState: 다음 상태 값.
사용 예:
CLB_configFSMNextState(CLB1_BASE, CLB_FSM_0, 1);
- CLB_configOutputLUT(base, output, lutNum)
CLB 출력 핀에 LUT 결과를 연결합니다.
매개변수:- output: CLB_OUT0 ~ CLB_OUT7.
- lutNum: 연결할 LUT 번호 (0~2).
사용 예:
CLB_configOutputLUT(CLB1_BASE, CLB_OUT0, 0);
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_HLC, CLB_INT_OUT0 ~ CLB_INT_OUT7 등.
사용 예:
CLB_enableInterrupt(CLB1_BASE, CLB_INT_HLC);
- interrupt: CLB_INT_HLC, CLB_INT_OUT0 ~ CLB_INT_OUT7 등.
- CLB_clearInterruptStatus(base)
CLB 인터럽트 플래그를 지웁니다.
매개변수: base (예: CLB1_BASE 등).
사용 예: - CLB_clearInterruptStatus(CLB1_BASE);
2.4. 주변 장치 관련 함수
- SysCtl_enablePeripheral(periph)
CLB를 포함한 주변 장치의 클럭을 활성화합니다.
매개변수: periph (예: SYSCTL_PERIPH_CLK_CLB1, SYSCTL_PERIPH_CLK_CLB2 등).
사용 예:SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
3. CLB 설정 및 동작 원리
- 시스템 초기화:
시스템 클럭, GPIO, 인터럽트 모듈을 초기화합니다.
예시:Device_init(); Device_initGPIO(); - CLB 클럭 활성화:
CLB 모듈에 시스템 클럭을 공급합니다.
예시:SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1); - CLB 타일 설정:
CLB 타일의 LUT, FSM, 카운터를 설정하고 입력/출력 핀을 매핑합니다.
예시:CLB_configLUT4Function(CLB1_BASE, CLB_LUT_0, 0x5, 0); // NOT 연산 CLB_configOutputLUT(CLB1_BASE, CLB_OUT0, 0);
- HLC 코드 작성:
HLC(High-Level Controller)를 사용하여 복잡한 로직을 C 또는 어셈블리 언어로 구현합니다.
TI의 CLB 툴을 통해 .c 또는 .asm 파일을 작성하고 컴파일하여 HLC 프로그램으로 변환합니다.
예시: HLC 프로그램은 CLB_HLC_BASE 레지스터를 통해 CPU와 데이터 교환 가능. - CLB 활성화:
CLB 모듈과 인터럽트를 활성화하여 논리 동작을 시작합니다.
예시:CLB_enableCLB(CLB1_BASE); CLB_enableInterrupt(CLB1_BASE, CLB_INT_HLC);
- 데이터 교환:
CPU와 CLB 간 데이터 교환은 CLB_HLC_BASE 레지스터를 통한 공유 메모리 또는 CLB 출력 핀을 통해 수행됩니다.
예시:uint32_t output = CLB_getOutput(CLB1_BASE, CLB_OUT0);
4. CLB 예제 코드
아래는 독립적인 CLB 예제 코드로, C2000Ware의 DriverLib를 기반으로 작성되었습니다. 모든 셋팅 값은 계산식을 통해 명시적으로 설정되며, 상세한 주석이 포함되어 있습니다. GPIO 설정은 별도의 initGPIO() 함수로 분리되어 있으며, 모든 코드는 CCS에서 바로 실행 가능합니다.
4.1. 예제 1: 기본 CLB 논리 구현 (AND 논리)
CLB1을 사용하여 두 입력 신호(GPIO0, GPIO1)의 AND 연산을 수행합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수: CLB 동작 상태 추적
// 0: 초기화 완료, 1: CLB 동작 중, 0xFFFF: 오류 발생
volatile uint32_t clbStatus = 0;
// GPIO 초기화 함수
// GPIO0, GPIO1을 CLB 입력으로 설정, GPIO31을 LED 출력으로 설정
void initGPIO(void)
{
// GPIO0 설정: CLB1_IN0에 연결될 일반 GPIO
GPIO_setPinConfig(GPIO_0_GPIO0); // pin_map.h: 0x00060000U
GPIO_setDirectionMode(0, GPIO_DIR_MODE_IN); // 입력 모드
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// GPIO1 설정: CLB1_IN1에 연결될 일반 GPIO
GPIO_setPinConfig(GPIO_1_GPIO1); // pin_map.h: 0x00060200U
GPIO_setDirectionMode(1, GPIO_DIR_MODE_IN); // 입력 모드
GPIO_setPadConfig(1, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// GPIO31 설정: 디버깅용 LED 출력
GPIO_setPinConfig(GPIO_31_GPIO31); // pin_map.h: 0x00081E00U
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
GPIO_writePin(31, 0); // 초기 상태: LED 꺼짐
}
// CLB 초기화 함수
// CLB1을 활성화하고, IN0 & IN1의 AND 연산 결과를 CLB_OUT0에 출력
void initCLB(void)
{
// CLB1 주변장치 클럭 활성화: 200MHz 시스템 클럭 공급
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
// CLB1 모듈 활성화
CLB_enableCLB(CLB1_BASE);
// CLB 입력 연결: GPIO0 -> CLB_IN0, GPIO1 -> CLB_IN1
// CLBINPUTXBAR INPUT1, INPUT2에 GPIO0, GPIO1 연결 (xbar.h)
XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT1, 0); // GPIO0 -> INPUT1
XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT2, 1); // GPIO1 -> INPUT2
CLB_configLocalInputMux(CLB1_BASE, CLB_IN0, CLB_LOCAL_IN_MUX_INPUT1); // CLB_IN0 -> INPUT1
CLB_configLocalInputMux(CLB1_BASE, CLB_IN1, CLB_LOCAL_IN_MUX_INPUT2); // CLB_IN1 -> INPUT2
// CLB 입력 필터 설정: 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 -> 0x8
CLB_selectLUT4Inputs(CLB1_BASE, (uint32_t)0, (uint32_t)1, (uint32_t)0, (uint32_t)0); // IN0=CLB_IN0, IN1=CLB_IN1, IN2=0, IN3=0
CLB_configLUT4Function(CLB1_BASE, (uint32_t)0x8, (uint32_t)0); // LUT0: AND 연산 (0x8), LUT2=0
// 출력 설정: LUT0 결과를 CLB_OUT0에 연결
CLB_configOutputLUT(CLB1_BASE, CLB_OUT0, 0); // OUT0 = LUT0 출력
CLB_setOutputMask(CLB1_BASE, CLB_OUTPUT_00, true); // CLB_OUT0 활성화
// CLB_OUT0을 OUTPUTXBAR1에 연결
XBAR_setOutputMuxConfig(OUTPUTXBAR_BASE, XBAR_OUTPUT1, XBAR_OUT_MUX00_CLB1_OUT0);
XBAR_enableOutputMux(OUTPUTXBAR_BASE, XBAR_OUTPUT1, XBAR_MUX00);
// OUTPUTXBAR1 래치 모드 활성화
XBAR_setOutputLatchMode(OUTPUTXBAR_BASE, XBAR_OUTPUT1, true);
// 상태 업데이트: CLB 초기화 완료
clbStatus = 1;
}
// CLB HLC 인터럽트 핸들러
// 현재는 플래그 지우기만 수행 (HLC 미사용)
#pragma CODE_SECTION(clbHLC, "Clb1Prog") // CLB1 프로그램 메모리에 매핑
__interrupt void clbHLC(void)
{
// 인터럽트 플래그 지우기: 다음 인터럽트를 위해 플래그 초기화
CLB_clearInterruptTag(CLB1_BASE);
}
// 메인 함수
// 시스템 초기화, GPIO/CLB 설정, CLB_OUT0 상태를 GPIO31에 반영
void main(void)
{
// 시스템 초기화: PLL, 클럭, 주변장치 설정 (C2000Ware 제공)
Device_init();
// GPIO 기본 초기화 (C2000Ware 제공)
Device_initGPIO();
// CLB 관련 GPIO 설정: GPIO0, GPIO1 (입력), GPIO31 (LED 출력)
initGPIO();
// 인터럽트 모듈 초기화: 벡터 테이블 및 인터럽트 설정
Interrupt_initModule();
Interrupt_initVectorTable();
// CLB1 인터럽트 핸들러 등록 (HLC 인터럽트 처리)
Interrupt_register(INT_CLB1, &clbHLC);
Interrupt_enable(INT_CLB1);
// 시스템 클럭 확인: 목표 클럭 200MHz
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000)
{
clbStatus = 0xFFFF; // 오류 상태 설정
GPIO_writePin(31, 0); // LED 꺼짐
ESTOP0; // 디버깅용 프로그램 정지
}
// CLB 초기화: AND 연산 및 출력 설정
initCLB();
// CLB 초기화 오류 확인
if (clbStatus != 1)
{
clbStatus = 0xFFFF; // 오류 상태 설정
GPIO_writePin(31, 0); // LED 꺼짐
ESTOP0; // 디버깅용 프로그램 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: CLB_OUT0 (AND 연산 결과)를 GPIO31에 반영
for(;;)
{
// OUTPUTXBAR1 상태를 래치 상태로 읽음
uint32_t output = XBAR_getOutputLatchStatus(OUTPUTXBAR_BASE, XBAR_OUTPUT1);
GPIO_writePin(31, output); // IN0 & IN1 = 1일 때 LED ON
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 초기화 및 동작 상태를 추적
// 0: 초기화 완료, 1: CLB 정상 동작, 0xFFFF: 오류 발생
volatile uint32_t clbStatus = 0;
// GPIO31 초기화 함수
// GPIO31을 CLB_OUT0과 연결하여 5ms 주기로 LED를 토글
void initGPIO(void)
{
// GPIO31을 GPIO 기능으로 설정
GPIO_setPinConfig(GPIO_31_GPIO31);
// GPIO31을 출력 모드로 설정
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
// GPIO31을 표준 풀업/풀다운 없이 설정
GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD);
// 초기 출력값을 0으로 설정 (LED 꺼짐)
GPIO_writePin(31, 0);
}
// CLB 초기화 함수
// CLB1을 활성화하고 5ms 주기(100Hz)로 CLB_OUT0을 토글하도록 설정
void initCLB(void)
{
// CLB1 주변장치 클럭 활성화 (SYSCTL_PERIPH_CLK_CLB1 사용)
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
// CLB1 모듈 활성화
CLB_enableCLB(CLB1_BASE);
// CLB 카운터 0 설정: 200MHz 클럭 기준
// LOAD=1,000,000 (5ms), MATCH1=500,000 (2.5ms), PRESCALE=0
CLB_configCounterLoadMatch(CLB1_BASE, CLB_CTR0, 1000000, 500000, 0);
// CLB_OUT0 출력 활성화 (HLC에서 토글)
CLB_setOutputMask(CLB1_BASE, CLB_OUTPUT_00, true);
// CLB 초기화 완료 상태 설정
clbStatus = 1;
}
// CLB HLC 인터럽트 핸들러
// 카운터 매치 이벤트에서 호출되어 CLB_OUT0을 토글
#pragma CODE_SECTION(clbHLC, "Clb1Prog") // CLB1 프로그램 메모리에 매핑
__interrupt void clbHLC(void)
{
// CLB_OUT0의 현재 출력 상태 읽기
uint32_t currentOutput = CLB_getOutputStatus(CLB1_BASE) & CLB_OUTPUT_00;
// 현재 상태에 따라 CLB_OUT0을 토글 (1->0 또는 0->1)
CLB_setOutputMask(CLB1_BASE, CLB_OUTPUT_00, currentOutput ? false : true);
// CLB 인터럽트 플래그 지우기
CLB_clearInterruptTag(CLB1_BASE);
}
// 메인 함수
// 시스템 초기화, GPIO/CLB 설정, 무한 루프에서 GPIO31 상태 업데이트
void main(void)
{
// 디바이스 초기화: PLL, 클럭, 주변장치 설정
Device_init();
// GPIO 기본 설정 초기화
Device_initGPIO();
// GPIO31 초기화
initGPIO();
// 인터럽트 모듈 및 벡터 테이블 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// CLB1 인터럽트 핸들러 등록
Interrupt_register(INT_CLB1, &clbHLC);
// CLB1 인터럽트 활성화
Interrupt_enable(INT_CLB1);
// 시스템 클럭 확인: 200MHz로 설정되어야 함
if (SysCtl_getClock(DEVICE_OSCSRC_FREQ) != 200000000)
{
// 클럭 오류 시 상태 설정 및 LED 꺼짐
clbStatus = 0xFFFF;
GPIO_writePin(31, 0);
// 디버깅용 정지
ESTOP0;
}
// CLB 초기화
initCLB();
// CLB 초기화 실패 시 오류 처리
if (clbStatus != 1)
{
clbStatus = 0xFFFF;
GPIO_writePin(31, 0);
ESTOP0;
}
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: CLB_OUT0 상태를 GPIO31에 실시간 반영
for(;;)
{
// CLB_OUT0 상태에 따라 GPIO31 출력 업데이트 (LED 토글)
GPIO_writePin(31, (CLB_getOutputStatus(CLB1_BASE) & CLB_OUTPUT_00) ? 1 : 0);
}
}
설명:
- 기능: 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 동작 상태 추적
// 0: 초기화 완료, 1: CLB 동작 중, 0xFFFF: 오류 발생
volatile uint32_t clbStatus = 0;
// GPIO 초기화 함수
// GPIO0을 ePWM1A 출력으로, GPIO31을 LED 출력으로 설정
void initGPIO(void)
{
// GPIO0 설정: ePWM1A 출력
GPIO_setPinConfig(GPIO_0_EPWM1A); // pin_map.h: 0x00060000U
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT); // 출력 모드
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// GPIO31 설정: 디버깅용 LED 출력
GPIO_setPinConfig(GPIO_31_GPIO31); // pin_map.h: 0x00081E00U
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
GPIO_writePin(31, 0); // 초기 상태: LED 꺼짐
}
// ePWM 초기화 함수
// ePWM1A를 200kHz PWM으로 설정 (50% 듀티 사이클)
void initEPWM(void)
{
// ePWM1 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
// 주기 설정: 200kHz PWM (시스템 클럭 200MHz, 주기 5us = 1000 사이클)
EPWM_setTimeBasePeriod(EPWM1_BASE, 1000);
EPWM_setTimeBaseCounterMode(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_UP_CMPA,
EPWM_AQ_OUTPUT_LOW);
// 초기 듀티 사이클: 50% (CMPA = 1000 * 0.5 = 500)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 500);
}
// CLB 초기화 함수
// CLB1을 활성화하고, ePWM1A를 반전하여 CLB_OUT0에 출력
void initCLB(void)
{
// CLB1 클럭 활성화: 200MHz 시스템 클럭 공급
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CLB1);
// CLB1 모듈 활성화
CLB_enableCLB(CLB1_BASE);
// 입력 설정: ePWM1A를 CLB_IN0에 연결
XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT1, 0); // GPIO0 (ePWM1A) -> INPUT1
CLB_configLocalInputMux(CLB1_BASE, CLB_IN0, CLB_LOCAL_IN_MUX_INPUT1); // CLB_IN0 -> INPUT1
CLB_selectInputFilter(CLB1_BASE, CLB_IN0, CLB_FILTER_NONE); // 필터 없음
// LUT0 설정: ePWM1A 신호 반전 (NOT 연산)
// 진리표: IN0=0 -> 1, IN0=1 -> 0 -> 0b0101 (0x5)
CLB_selectLUT4Inputs(CLB1_BASE, (uint32_t)0, (uint32_t)0, (uint32_t)0, (uint32_t)0); // IN0=CLB_IN0, IN1=0, IN2=0, IN3=0
CLB_configLUT4Function(CLB1_BASE, (uint32_t)0x5, (uint32_t)0); // LUT0: NOT 연산 (0x5), LUT2=0
// 출력 설정: LUT0 결과를 CLB_OUT0에 연결
CLB_configOutputLUT(CLB1_BASE, CLB_OUT0, 0); // OUT0 = LUT0 출력
CLB_setOutputMask(CLB1_BASE, CLB_OUTPUT_00, true); // CLB_OUT0 활성화
// CLB_OUT0을 OUTPUTXBAR1에 연결
XBAR_setOutputMuxConfig(OUTPUTXBAR_BASE, XBAR_OUTPUT1, XBAR_OUT_MUX00_CLB1_OUT0);
XBAR_enableOutputMux(OUTPUTXBAR_BASE, XBAR_OUTPUT1, XBAR_MUX00);
// OUTPUTXBAR1 래치 모드 활성화
XBAR_setOutputLatchMode(OUTPUTXBAR_BASE, XBAR_OUTPUT1, true);
// 상태 업데이트: CLB 초기화 완료
clbStatus = 1;
}
// 메인 함수
// 시스템 초기화, ePWM/CLB 설정, CLB_OUT0 상태를 GPIO31에 반영
void main(void)
{
// 시스템 초기화: PLL, 클럭, 주변장치 설정 (C2000Ware 제공)
Device_init();
// GPIO 기본 초기화 (C2000Ware 제공)
Device_initGPIO();
// ePWM 및 CLB 관련 GPIO 설정: GPIO0 (ePWM1A), GPIO31 (LED)
initGPIO();
// 인터럽트 모듈 초기화: 벡터 테이블 설정
Interrupt_initModule();
Interrupt_initVectorTable();
// 시스템 클럭 확인: 목표 클럭 200MHz
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000)
{
clbStatus = 0xFFFF; // 오류 상태 설정
GPIO_writePin(31, 0); // LED 꺼짐
ESTOP0; // 디버깅용 프로그램 정지
}
// ePWM 초기화: 200kHz PWM 설정
initEPWM();
// CLB 초기화: ePWM1A 반전 및 출력
initCLB();
// 초기화 오류 확인
if (clbStatus != 1)
{
clbStatus = 0xFFFF; // 오류 상태 설정
GPIO_writePin(31, 0); // LED 꺼짐
ESTOP0; // 디버깅용 프로그램 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: CLB_OUT0 (ePWM1A 반전 신호)를 GPIO31에 반영
for(;;)
{
// OUTPUTXBAR1 상태를 래치 상태로 읽음
uint32_t output = XBAR_getOutputLatchStatus(OUTPUTXBAR_BASE, XBAR_OUTPUT1);
GPIO_writePin(31, output); // ePWM1A 반전 신호에 따라 LED 점등/소등
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로 표시.
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, 실시간 제어
'MCU > C2000' 카테고리의 다른 글
TMS320F28388D DSP DMA 사용법: DriverLib API로 DMA 설정 및 코드(수정) (1) | 2025.08.17 |
---|---|
TMS320F28388D DSP SPI 사용법: DriverLib API로 SPI 설정 및 코드(수정) (3) | 2025.08.17 |
TMS320F28388D DSP CAN 사용법: DriverLib API로 CAN 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP SDFM 사용법: DriverLib API로 SDFM 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP CLA 사용법: DriverLib API로 CLA 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP EMIF 사용법: DriverLib API로 EMIF 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP eQEP 사용법: DriverLib API로 eQEP 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP eCAP 사용법: DriverLib API로 eCAP 설정 및 코드(수정) (3) | 2025.08.17 |