본문 바로가기
MCU/C2000

TMS320F28388D DSP SCI 사용법: Driverlib API로 UART 설정 및 예제(수정본)

by linuxgo 2025. 8. 8.

이 문서는 Texas Instruments의 TMS320F28388D 마이크로컨트롤러에서 SCI (Serial Communication Interface) 모듈을 Driverlib API를 사용하여 설정하고 사용하는 방법을 상세히 설명합니다. UART 기반 직렬 통신을 구현하는 데 필요한 모든 Driverlib SCI 함수를 다루며, FIFO, 인터럽트, 루프백 모드, 오토보드 록 등을 포함한 실습 가능한 예제 코드를 제공합니다. 각 코드에는 주석을 추가하여 초보자부터 숙련자까지 쉽게 이해할 수 있도록 했습니다. 이 문서는 C2000WareCode Composer Studio (CCS) 환경을 기준으로 작성되었습니다.

1. SCI 모듈 개요

TMS320F28388D의 SCI 모듈은 UART (Universal Asynchronous Receiver/Transmitter) 프로토콜을 기반으로 비동기 직렬 통신을 제공합니다. 이 모듈은 다음과 같은 기능을 지원합니다:

  • 데이터 워드 길이: 1~8비트
  • 보드레이트: 최대 115200bps 이상 (시스템 클럭에 따라 다름)
  • 패리티: None, Even, Odd
  • 스톱 비트: 1 또는 2 스톱 비트
  • FIFO: 송신/수신 FIFO로 데이터 처리 효율성 향상
  • 인터럽트: 송신, 수신, 에러 인터럽트
  • 루프백 모드: 테스트용 내부 루프백
  • 오토보드 록: 자동 보드레이트 동기화

Driverlib API는 하드웨어 레지스터를 직접 조작하지 않고, 추상화된 함수를 통해 SCI 모듈을 쉽게 설정하고 제어할 수 있도록 설계되었습니다. 

2. 사전 준비

SCI 모듈을 사용하기 위해 다음 사항을 준비하세요:

  • C2000Ware 설치: 최신 C2000Ware 패키지의 driverlib 폴더를 프로젝트에 포함.
  • 필요한 헤더 파일:
    #include "driverlib.h" // SCI 및 기타 주변 장치 API 포함
    #include "device.h"    // 디바이스별 설정 (예: DEVICE_LSPCLK_FREQ)
    
  • 개발 환경: Code Composer Studio (CCS) 권장.
  • GPIO 설정: SCI 모듈의 TX/RX 핀을 올바르게 설정 (예: SCIA는 GPIO28/TX, GPIO29/RX).
  • 시스템 클럭: SCI 보드레이트 계산에 필요한 저속 주변 장치 클럭(LSPCLK) 주파수 확인 (기본값: 50MHz).
  • 데이터시트: TMS320F28388D 데이터시트를 참조하여 핀맵 및 SCI 모듈 사양 확인.

3. Driverlib SCI 함수 목록 및 설명

아래는 driverlib/sci.h에 정의된 모든 SCI 관련 함수와 그 사용법입니다. 각 함수는 기능, 매개변수, 사용 사례를 포함하며, 예제 코드에서 활용됩니다.

3.1 SCI 모듈 제어 함수

  • SCI_enableModule(uint32_t base): SCI 모듈을 활성화하여 통신을 시작합니다.
    • 매개변수: base (SCI 모듈 주소, 예: SCIA_BASE)
    • 사용 사례: 설정 완료 후 통신 시작.
  • SCI_disableModule(uint32_t base): SCI 모듈을 비활성화하여 설정 변경을 안전하게 수행합니다.
    • 매개변수: base
    • 사용 사례: 설정 변경 전 모듈 비활성화.
  • SCI_resetChannels(uint32_t base): 송수신 채널을 리셋하여 초기 상태로 복구합니다.
    • 매개변수: base
    • 사용 사례: 오류 발생 후 채널 초기화.
  • SCI_resetReceiver(uint32_t base): 수신 채널만 리셋합니다.
    • 매개변수: base
    • 사용 사례: 수신 오류 복구.
  • SCI_resetTransmitter(uint32_t base): 송신 채널만 리셋합니다.
    • 매개변수: base
    • 사용 사례: 송신 오류 복구.

3.2 SCI 설정 함수

  • SCI_setConfig(uint32_t base, uint32_t lspclkHz, uint32_t baud, uint32_t config): 보드레이트, 데이터 워드 길이, 스톱 비트, 패리티를 설정합니다.
    • 매개변수:
      • base: SCI 모듈 주소
      • lspclkHz: 저속 주변 장치 클럭 주파수
      • baud: 보드레이트 (예: 9600)
      • config: SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE 등
    • 사용 사례: 기본 통신 설정.
  • SCI_setParityMode(uint32_t base, SCI_ParityMode parity): Even 또는 Odd 패리티를 설정합니다.
    • 매개변수: base, parity (SCI_PAR_EVEN 또는 SCI_PAR_ODD)
    • 사용 사례: 패리티 모드 변경.
  • SCI_getParityMode(uint32_t base): Even 또는 Odd 패리티를 리턴 받습니다.
    • 매개변수: base
    • 사용 사례: 패리티 모드 체크
  • SCI_setBaudRate(uint32_t base, uint32_t lspclkHz, uint32_t baud): 보드레이트를 설정합니다.
    • 매개변수: base, lspclkHz, baud
    • 사용 사례: 동적 보드레이트 변경.

3.3 FIFO 관련 함수

  • SCI_enableFIFO(uint32_t base): FIFO를 활성화하여 다중 데이터 처리 효율성을 높입니다.
    • 매개변수: base
    • 사용 사례: 대량 데이터 송수신.
  • SCI_disableFIFO(uint32_t base): FIFO를 비활성화합니다.
    • 매개변수: base
    • 사용 사례: FIFO 사용 중지.
  • SCI_resetTxFIFO(uint32_t base): 송신 FIFO를 리셋합니다.
    • 매개변수: base
    • 사용 사례: 송신 FIFO 초기화.
  • SCI_resetRxFIFO(uint32_t base): 수신 FIFO를 리셋합니다.
    • 매개변수: base
    • 사용 사례: 수신 FIFO 초기화.
  • SCI_setFIFOInterruptLevel(uint32_t base, SCI_TxFIFOLevel txLevel, SCI_RxFIFOLevel rxLevel): FIFO 인터럽트 레벨을 설정합니다.
    • 매개변수: base, txLevel (예: SCI_FIFO_TX4), rxLevel (예: SCI_FIFO_RX4)
    • 사용 사례: FIFO 인터럽트 트리거 설정.
  • SCI_getTxFIFOStatus(uint32_t base): 송신 FIFO 상태를 반환합니다.
    • 매개변수: base
    • 반환값: 송신 FIFO 데이터 수
    • 사용 사례: 송신 FIFO 상태 확인.
  • SCI_getRxFIFOStatus(uint32_t base): 수신 FIFO 상태를 반환합니다.
    • 매개변수: base
    • 반환값: 수신 FIFO 데이터 수
    • 사용 사례: 수신 FIFO 상태 확인.

3.4 데이터 송수신 함수

  • SCI_writeCharArray(uint32_t base, const uint16_t *array, uint16_t length): 문자 배열을 송신합니다.
    • 매개변수: base, array, length
    • 사용 사례: 문자열 송신.
  • SCI_readCharArray(uint32_t base, uint16_t *array, uint16_t length): 문자 배열을 수신합니다.
    • 매개변수: base, array, length
    • 사용 사례: 다중 데이터 수신.
  • SCI_writeCharBlockingFIFO(uint32_t base, uint16_t data): 차단 모드로 단일 문자를 송신합니다.
    • 매개변수: base, data
    • 사용 사례: 안정적인 단일 문자 송신.
  • SCI_writeCharBlockingNonFIFO(uint32_t base, uint16_t data): 비차단 모드로 단일 문자를 송신합니다.
    • 매개변수: base, data
    • 반환값: void
  • SCI_writeCharNonBlocking(uint32_t base, uint16_t data): 비차단 모드로 단일 문자를 송신합니다.
    • 매개변수: base, data
    • 반환값: void
    • 사용 사례: 빠른 송신 처리.
  • SCI_readCharBlockingFIFO(uint32_t base): 차단 모드로 단일 문자를 수신합니다.
    • 매개변수: base
    • 반환값: 수신된 문자
    • 사용 사례: 데이터 수신 대기.
  • SCI_readCharBlockingNonFIFO(uint32_t base): 차단 모드로 단일 문자를 수신합니다.
    • 매개변수: base
    • 반환값: 수신된 문자
    • 사용 사례: 데이터 수신 대기.
  • SCI_readCharNonBlocking(uint32_t base): 비차단 모드로 단일 문자를 수신합니다.
    • 매개변수: base
    • 반환값: 수신된 문자 또는 SCI_INVALID_DATA
    • 사용 사례: 빠른 수신 확인.

3.5 인터럽트 관련 함수

  • SCI_enableInterrupt(uint32_t base, uint32_t intFlags): 지정된 인터럽트를 활성화합니다.
    • 매개변수: base, intFlags (예: SCI_INT_RXFF | SCI_INT_TXFF)
    • 사용 사례: 송수신 인터럽트 처리.
  • SCI_disableInterrupt(uint32_t base, uint32_t intFlags): 지정된 인터럽트를 비활성화합니다.
    • 매개변수: base, intFlags
    • 사용 사례: 인터럽트 중지.
  • SCI_clearInterruptStatus(uint32_t base, uint32_t intFlags): 인터럽트 플래그를 지웁니다.
    • 매개변수: base, intFlags
    • 사용 사례: 인터럽트 처리 후 초기화.
  • SCI_getInterruptStatus(uint32_t base): 인터럽트 상태를 반환합니다.
    • 매개변수: base
    • 반환값: 활성화된 인터럽트 플래그
    • 사용 사례: 인터럽트 원인 확인.

3.6 상태 확인 함수

  • SCI_getRxStatus(uint32_t base): 수신 상태를 반환합니다.
    • 매개변수: base
    • 반환값: SCI_RXSTATUS_READY 등
    • 사용 사례: 수신 데이터 준비 확인.
  • SCI_isTransmitterBusy(uint32_t base): 송신기 상태를 확인합니다.
    • 매개변수: base
    • 반환값: 송신 중이면 true
    • 사용 사례: 송신기 사용 여부 확인.
  • SCI_isSpaceAvailableNonFIFO(uint32_t base): 비차단 모드송신 버퍼 공간을 확인합니다.
    • 매개변수: base
    • 반환값: 공간 있으면 true
    • 사용 사례: 비차단 송신 전 확인.
  • SCI_isDataAvailableNonFIFO(uint32_t base): 비차단 모드송신 문자열을 확인합니다.
    • 매개변수: base
    • 반환값: 문자 있으면 true
    • 사용 사례: 비차단 송신 전 확인.

3.7 루프백 및 오토보드 록 함수

  • SCI_enableLoopback(uint32_t base): 루프백 모드를 활성화합니다.
    • 매개변수: base
    • 사용 사례: 테스트용 내부 송수신.
  • SCI_disableLoopback(uint32_t base): 루프백 모드를 비활성화합니다.
    • 매개변수: base
    • 사용 사례: 정상 통신 복귀.

4. 예제 코드

아래는 모든 SCI 함수를 활용하는 독립적인 예제 코드들입니다. 각 예제는 특정 기능에 초점을 맞추며, 상세한 주석을 포함하여 코드의 모든 줄을 명확히 설명합니다. 

tms320f28388d SCI 통신

예제 1: 기본 SCI 설정 및 단일 문자 송수신

TMS320F28388D에서 기본 SCI 설정으로 단일 문자를 송수신합니다.

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

// 함수 선언: GPIO 및 SCI 초기화
void initGPIO(void);
void initSCI(void);

void main(void) {
    // 시스템 초기화: 클럭, PLL, 주변 장치 설정
    Device_init();

    // 기본 GPIO 초기화
    Device_initGPIO();

    // 인터럽트 컨트롤러 초기화
    Interrupt_initModule();

    // 인터럽트 벡터 테이블 초기화
    Interrupt_initVectorTable();

    // GPIO 초기화: SCI TX/RX 핀 설정 (GPIO28/RX, GPIO29/TX)
    initGPIO();

    // SCI 초기화: 9600bps, 8비트 데이터, 1 스톱 비트, 패리티 없음
    initSCI();

    // 글로벌 인터럽트 활성화
    EINT;

    // 실시간 인터럽트 활성화
    ERTM;

    // 송신할 단일 문자 정의
    uint16_t sendChar = 'A'; // SCI_writeCharArray는 uint16_t 배열 사용 (sci.h)

    // 송신 버퍼 공간 확인 (FIFO 모드)
    if (SCI_getTxFIFOStatus(SCIA_BASE) < SCI_FIFO_TX16) {
        // 단일 문자 송신
        SCI_writeCharArray(SCIA_BASE, &sendChar, 1);
    }

    // 수신 데이터 저장 변수
    uint16_t receivedChar;

    // 무한 루프: 수신 데이터 처리
    while(1) {
        // Watchdog 서비스 (리셋 방지)
        SysCtl_serviceWatchdog();

        // 수신 상태 확인
        if (SCI_getRxFIFOStatus(SCIA_BASE) >= SCI_FIFO_RX1) {
            // 단일 문자 수신
            SCI_readCharArray(SCIA_BASE, &receivedChar, 1);

            // 송신 버퍼 공간 확인 후 에코백
            if (SCI_getTxFIFOStatus(SCIA_BASE) < SCI_FIFO_TX16) {
                SCI_writeCharArray(SCIA_BASE, &receivedChar, 1);
            }
        }
    }
}

// GPIO 초기화 함수: SCI 송수신 핀 설정 (pin_map.h 기준)
void initGPIO(void) {
    // SCIA RX 핀 설정: GPIO28 (pin_map.h: GPIO_28_SCIA_RX, 0x00081801U)
    GPIO_setPinConfig(GPIO_28_SCIA_RX);

    // SCIA TX 핀 설정: GPIO29 (pin_map.h: GPIO_29_SCIA_TX, 0x00081A01U)
    GPIO_setPinConfig(GPIO_29_SCIA_TX);

    // RX 핀 방향: 입력
    GPIO_setDirectionMode(28, GPIO_DIR_MODE_IN);

    // TX 핀 방향: 출력
    GPIO_setDirectionMode(29, GPIO_DIR_MODE_OUT);

    // RX 핀 패드: 풀업 저항
    GPIO_setPadConfig(28, GPIO_PIN_TYPE_PULLUP);

    // TX 핀 패드: 표준 출력
    GPIO_setPadConfig(29, GPIO_PIN_TYPE_STD);

    // RX 핀 입력 자격: 비동기
    GPIO_setQualificationMode(28, GPIO_QUAL_ASYNC);
}

// SCI 초기화 함수: 기본 SCI 설정 (FIFO 활성화, sci.h 기준)
void initSCI(void) {
    // SCI 모듈 비활성화
    SCI_disableModule(SCIA_BASE);

    // 송수신 채널 리셋
    SCI_resetChannels(SCIA_BASE);

    // SCI 설정: 9600bps, 8비트, 1 스톱 비트, 패리티 없음
    SCI_setConfig(SCIA_BASE, SysCtl_getLowSpeedClock(DEVICE_LSPCLK_FREQ), 9600,
                  (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));

    // FIFO 활성화
    SCI_enableFIFO(SCIA_BASE);

    // TX/RX FIFO 인터럽트 레벨 설정: 1바이트
    SCI_setFIFOInterruptLevel(SCIA_BASE, SCI_FIFO_TX1, SCI_FIFO_RX1);

    // FIFO 리셋
    SCI_resetTxFIFO(SCIA_BASE);
    SCI_resetRxFIFO(SCIA_BASE);

    // SCI 모듈 활성화
    SCI_enableModule(SCIA_BASE);
}

예제 2: FIFO 및 문자열 송수신

FIFO를 활성화하여 문자열을 송수신하는 방법을 보여줍니다.

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

// 함수 선언
void initGPIO(void); // SCI 송수신 핀 설정
void initSCI(void);  // SCI 및 FIFO 설정

void main(void) {
    // 시스템 초기화: 클럭, PLL, 주변 장치 설정
    Device_init();
    
    // 기본 GPIO 초기화
    Device_initGPIO();
    
    // 인터럽트 컨트롤러 초기화
    Interrupt_initModule();
    
    // 인터럽트 벡터 테이블 초기화
    Interrupt_initVectorTable();
    
    // GPIO 초기화: SCI TX/RX 핀 설정
    initGPIO();
    
    // SCI 초기화: FIFO 활성화 및 설정
    initSCI();
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // 실시간 인터럽트 활성화
    ERTM;
    
    // 송신 문자열 정의: FIFO를 통해 송신
    const char message[] = "Hello, SCI with FIFO!\n";
    uint16_t messageBuffer[sizeof(message)];
    
    // char 배열을 uint16_t로 변환 (sci.h의 SCI_writeCharArray 요구사항)
    uint16_t i; // 변수 i를 명시적으로 선언
    for (i = 0; i < sizeof(message); i++) {
        messageBuffer[i] = (uint16_t)message[i];
    }
    
    // 문자열 송신: 문자 배열을 송신 FIFO에 기록
    SCI_writeCharArray(SCIA_BASE, messageBuffer, sizeof(message));
    
    // 송신 FIFO 상태 확인: 송신 완료 대기
    while (SCI_getTxFIFOStatus(SCIA_BASE) != SCI_FIFO_TX0) {
        // Watchdog 서비스 (리셋 방지)
        SysCtl_serviceWatchdog();
    }
    
    // 수신 데이터 저장 배열: 최대 32바이트
    uint16_t receivedData[32];
    
    // 수신 데이터 인덱스
    uint16_t index = 0;
    
    // 무한 루프: 수신 데이터 처리
    while(1) {
        // Watchdog 서비스 (리셋 방지)
        SysCtl_serviceWatchdog();
        
        // 수신 FIFO 상태 확인: 데이터가 있는지 확인
        if (SCI_getRxFIFOStatus(SCIA_BASE) >= SCI_FIFO_RX1) {
            // 수신 에러 확인
            if (SCI_getRxStatus(SCIA_BASE) & SCI_RXSTATUS_ERROR) {
                // 에러 발생 시 소프트웨어 리셋
                SCI_performSoftwareReset(SCIA_BASE);
                SCI_clearOverflowStatus(SCIA_BASE);
                index = 0; // 버퍼 인덱스 초기화
                continue;
            }
            
            // 단일 문자 수신: FIFO에서 한 문자 읽기
            SCI_readCharArray(SCIA_BASE, &receivedData[index], 1);
            
            // 인덱스 증가
            index++;
            
            // 버퍼 오버플로우 방지: 배열 크기 초과 시 에코백
            if (index >= 32) {
                // 송신 FIFO 공간 확인 후 에코백
                if (SCI_getTxFIFOStatus(SCIA_BASE) <= SCI_FIFO_TX12) {
                    SCI_writeCharArray(SCIA_BASE, receivedData, 32);
                }
                index = 0; // 인덱스 초기화
            }
        }
    }
}

// GPIO 초기화 함수
void initGPIO(void) {
    // SCIA RX 핀 설정: GPIO28 (pin_map.h: GPIO_28_SCIA_RX, 0x00081801U)
    GPIO_setPinConfig(GPIO_28_SCIA_RX);
    
    // SCIA TX 핀 설정: GPIO29 (pin_map.h: GPIO_29_SCIA_TX, 0x00081A01U)
    GPIO_setPinConfig(GPIO_29_SCIA_TX);
    
    // RX 핀 방향: 입력
    GPIO_setDirectionMode(28, GPIO_DIR_MODE_IN);
    
    // TX 핀 방향: 출력
    GPIO_setDirectionMode(29, GPIO_DIR_MODE_OUT);
    
    // RX 핀 패드: 풀업 저항 활성화
    GPIO_setPadConfig(28, GPIO_PIN_TYPE_PULLUP);
    
    // TX 핀 패드: 표준 출력
    GPIO_setPadConfig(29, GPIO_PIN_TYPE_STD);
    
    // RX 핀 입력 자격: 비동기 입력
    GPIO_setQualificationMode(28, GPIO_QUAL_ASYNC);
}

// SCI 초기화 함수: FIFO 포함
void initSCI(void) {
    // SCI 모듈 비활성화: 설정 변경 전 비활성화
    SCI_disableModule(SCIA_BASE);
    
    // 송수신 채널 리셋: 상태 초기화
    SCI_resetChannels(SCIA_BASE);
    
    // SCI 설정: 115200bps, 8비트 데이터, 1 스톱 비트, 패리티 없음
    SCI_setConfig(SCIA_BASE, SysCtl_getLowSpeedClock(DEVICE_LSPCLK_FREQ), 115200, 
                  (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));
    
    // FIFO 활성화: 송수신 FIFO 사용
    SCI_enableFIFO(SCIA_BASE);
    
    // FIFO 인터럽트 레벨 설정: 송신/수신 4바이트 트리거
    SCI_setFIFOInterruptLevel(SCIA_BASE, SCI_FIFO_TX4, SCI_FIFO_RX4);
    
    // 송신 FIFO 리셋: 초기화
    SCI_resetTxFIFO(SCIA_BASE);
    
    // 수신 FIFO 리셋: 초기화
    SCI_resetRxFIFO(SCIA_BASE);
    
    // SCI 모듈 활성화: 통신 시작
    SCI_enableModule(SCIA_BASE);
}

예제 3: 인터럽트 및 패리티 설정

인터럽트패리티를 사용하여 데이터를 처리합니다.

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

// 함수 선언
void initGPIO(void);          // GPIO 설정
void initSCI(void);           // SCI 및 패리티 설정
void initSCIInterrupts(void); // SCI 인터럽트 설정
__interrupt void sciRxISR(void); // 수신 인터럽트 서비스 루틴
__interrupt void sciTxISR(void); // 송신 인터럽트 서비스 루틴

// 전역 변수: 수신 데이터 저장
  uint16_t receivedData[16];

// 전역 변수: 수신 데이터 인덱스
  uint16_t rxIndex = 0;

void main(void) {
    // 시스템 초기화: 클럭, PLL, 주변 장치 설정
    Device_init();

    // 기본 GPIO 초기화
    Device_initGPIO();

    // 인터럽트 컨트롤러 초기화
    Interrupt_initModule();

    // 인터럽트 벡터 테이블 초기화
    Interrupt_initVectorTable();

    // GPIO 초기화
    initGPIO();

    // SCI 초기화: 패리티 및 인터럽트 설정
    initSCI();

    // SCI 인터럽트 초기화
    initSCIInterrupts();

    // 글로벌 인터럽트 활성화
    EINT;

    // 실시간 인터럽트 활성화
    ERTM;

    // 송신 문자열 정의
    const char message[] = "Interrupt-based SCI!\n";
    uint16_t messageBuffer[sizeof(message)];

    // char 배열을 uint16_t로 변환 (sci.h의 SCI_writeCharArray 요구사항)
    uint16_t i;
    for (i = 0; i < sizeof(message); i++) {
        messageBuffer[i] = (uint16_t)message[i];
    }

    // 문자열 송신: 인터럽트를 통해 처리
    SCI_writeCharArray(SCIA_BASE, messageBuffer, sizeof(message));

    // 무한 루프: 인터럽트로 데이터 처리
    while(1) {
        // Watchdog 서비스 (리셋 방지)
        SysCtl_serviceWatchdog();
    }
}

// GPIO 초기화 함수
void initGPIO(void) {
    // SCIA RX 핀 설정: GPIO28 (pin_map.h: GPIO_28_SCIA_RX, 0x00081801U)
    GPIO_setPinConfig(GPIO_28_SCIA_RX);

    // SCIA TX 핀 설정: GPIO29 (pin_map.h: GPIO_29_SCIA_TX, 0x00081A01U)
    GPIO_setPinConfig(GPIO_29_SCIA_TX);

    // RX 핀 방향: 입력
    GPIO_setDirectionMode(28, GPIO_DIR_MODE_IN);

    // TX 핀 방향: 출력
    GPIO_setDirectionMode(29, GPIO_DIR_MODE_OUT);

    // RX 핀 패드: 풀업 저항
    GPIO_setPadConfig(28, GPIO_PIN_TYPE_PULLUP);

    // TX 핀 패드: 표준 출력
    GPIO_setPadConfig(29, GPIO_PIN_TYPE_STD);

    // RX 핀 입력 자격: 비동기
    GPIO_setQualificationMode(28, GPIO_QUAL_ASYNC);
}

// SCI 초기화 함수: 패리티 및 FIFO 설정
void initSCI(void) {
    // SCI 모듈 비활성화: 설정 변경 전 비활성화
    SCI_disableModule(SCIA_BASE);

    // 송수신 채널 리셋: 초기 상태 복구
    SCI_resetChannels(SCIA_BASE);

    // SCI 설정: 9600bps, 7비트 데이터, 2 스톱 비트, Even 패리티
    SCI_setConfig(SCIA_BASE, SysCtl_getLowSpeedClock(DEVICE_LSPCLK_FREQ), 9600,
                  (SCI_CONFIG_WLEN_7 | SCI_CONFIG_STOP_TWO | SCI_CONFIG_PAR_EVEN));

    // FIFO 활성화: 다중 데이터 처리
    SCI_enableFIFO(SCIA_BASE);

    // FIFO 인터럽트 레벨 설정: 4바이트 트리거
    SCI_setFIFOInterruptLevel(SCIA_BASE, SCI_FIFO_TX4, SCI_FIFO_RX4);

    // 송신 FIFO 리셋
    SCI_resetTxFIFO(SCIA_BASE);

    // 수신 FIFO 리셋
    SCI_resetRxFIFO(SCIA_BASE);

    // SCI 모듈 활성화
    SCI_enableModule(SCIA_BASE);
}

// SCI 인터럽트 초기화 함수
void initSCIInterrupts(void) {
    // 송신/수신 인터럽트 활성화: FIFO 및 에러 인터럽트 사용
    SCI_enableInterrupt(SCIA_BASE, (SCI_INT_RXFF | SCI_INT_TXFF | SCI_INT_RXERR));

    // 수신 인터럽트 벡터 등록
    Interrupt_register(INT_SCIA_RX, &sciRxISR);

    // 송신 인터럽트 벡터 등록
    Interrupt_register(INT_SCIA_TX, &sciTxISR);

    // 수신 인터럽트 활성화
    Interrupt_enable(INT_SCIA_RX);

    // 송신 인터럽트 활성화
    Interrupt_enable(INT_SCIA_TX);
}

// 수신 인터럽트 서비스 루틴
__interrupt void sciRxISR(void) {
    // 인터럽트 상태 확인
    uint32_t intStatus = SCI_getInterruptStatus(SCIA_BASE);

    // 수신 에러 처리
    if (intStatus & SCI_INT_RXERR) {
        // 에러 플래그 확인
        uint16_t rxStatus = SCI_getRxStatus(SCIA_BASE);
        if (rxStatus & (SCI_RXSTATUS_PARITY | SCI_RXSTATUS_OVERRUN | SCI_RXSTATUS_FRAMING)) {
            // 소프트웨어 리셋 및 오버플로우 플래그 지우기
            SCI_performSoftwareReset(SCIA_BASE);
            SCI_clearOverflowStatus(SCIA_BASE);
            rxIndex = 0; // 버퍼 인덱스 초기화
        }
        SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_RXERR);
    }

    // 수신 FIFO 인터럽트 처리
    if (intStatus & SCI_INT_RXFF) {
        // FIFO에 데이터가 있는지 확인
        if (SCI_getRxFIFOStatus(SCIA_BASE) >= SCI_FIFO_RX1) {
            // 비차단 모드로 데이터 수신
            SCI_readCharArray(SCIA_BASE, &receivedData[rxIndex], 1);

            // 인덱스 증가
            rxIndex++;

            // 버퍼 오버플로우 방지
            if (rxIndex >= 16) {
                // 송신 FIFO 공간 확인 후 에코백
                if (SCI_getTxFIFOStatus(SCIA_BASE) <= SCI_FIFO_TX12) {
                    SCI_writeCharArray(SCIA_BASE, (uint16_t*)receivedData, 16);
                }
                rxIndex = 0; // 인덱스 초기화
            }
        }
        SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_RXFF);
    }

    // 인터럽트 그룹 확인: 그룹 9
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

// 송신 인터럽트 서비스 루틴
__interrupt void sciTxISR(void) {
    // 송신 FIFO 상태 확인
    if (SCI_getTxFIFOStatus(SCIA_BASE) == SCI_FIFO_TX0) {
        // 송신 FIFO가 비어 있으면 추가 작업 없음
    }

    // 송신 인터럽트 플래그 지우기
    SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXFF);

    // 인터럽트 그룹 확인: 그룹 9
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

예제 4: 루프백 및 오토보드 록 테스트

루프백 모드오토보드 록을 사용하여 SCI 모듈을 테스트합니다.

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

// 함수 선언
void initGPIO(void); // GPIO 설정
void initSCI(void);  // SCI 및 루프백 설정

void main(void) {
    // 시스템 초기화: 클럭, PLL, 주변 장치 설정
    Device_init();
    
    // 기본 GPIO 초기화
    Device_initGPIO();
    
    // 인터럽트 컨트롤러 초기화
    Interrupt_initModule();
    
    // 인터럽트 벡터 테이블 초기화
    Interrupt_initVectorTable();
    
    // GPIO 초기화
    initGPIO();
    
    // SCI 초기화: 루프백 및 오토보드 록 설정
    initSCI();
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // 실시간 인터럽트 활성화
    ERTM;
    
    // 테스트 문자열 정의
    const char testMessage[] = "Loopback Test\n";
    uint16_t messageBuffer[sizeof(testMessage)];
    
    // char 배열을 uint16_t로 변환 (sci.h의 SCI_writeCharArray 요구사항)
    uint16_t i;
    for (i = 0; i < sizeof(testMessage); i++) {
        messageBuffer[i] = (uint16_t)testMessage[i];
    }
    
    // 문자열 송신: 루프백 모드로 내부 수신
    SCI_writeCharArray(SCIA_BASE, messageBuffer, sizeof(testMessage));
    
    // 수신 데이터 저장 변수
    uint16_t receivedChar;
    
    // 무한 루프: 수신 데이터 처리
    while(1) {
        // Watchdog 서비스 (리셋 방지)
        SysCtl_serviceWatchdog();
        
        // 수신 상태 확인: 데이터 준비 여부
        if (SCI_getRxFIFOStatus(SCIA_BASE) >= SCI_FIFO_RX1) {
            // 수신 에러 확인
            if (SCI_getRxStatus(SCIA_BASE) & SCI_RXSTATUS_ERROR) {
                // 에러 발생 시 소프트웨어 리셋
                SCI_performSoftwareReset(SCIA_BASE);
                SCI_clearOverflowStatus(SCIA_BASE);
                continue;
            }
            
            // 비차단 모드로 데이터 수신
            SCI_readCharArray(SCIA_BASE, &receivedChar, 1);
            
            // 루프백이므로 송신 데이터와 동일해야 함
            if (SCI_getTxFIFOStatus(SCIA_BASE) < SCI_FIFO_TX16) {
                SCI_writeCharArray(SCIA_BASE, &receivedChar, 1);
            }
        }
    }
}

// GPIO 초기화 함수
void initGPIO(void) {
    // SCIA RX 핀 설정: GPIO28 (pin_map.h: GPIO_28_SCIA_RX, 0x00081801U)
    GPIO_setPinConfig(GPIO_28_SCIA_RX);
    
    // SCIA TX 핀 설정: GPIO29 (pin_map.h: GPIO_29_SCIA_TX, 0x00081A01U)
    GPIO_setPinConfig(GPIO_29_SCIA_TX);
    
    // RX 핀 방향: 입력
    GPIO_setDirectionMode(28, GPIO_DIR_MODE_IN);
    
    // TX 핀 방향: 출력
    GPIO_setDirectionMode(29, GPIO_DIR_MODE_OUT);
    
    // RX 핀 패드: 풀업 저항
    GPIO_setPadConfig(28, GPIO_PIN_TYPE_PULLUP);
    
    // TX 핀 패드: 표준 출력
    GPIO_setPadConfig(29, GPIO_PIN_TYPE_STD);
    
    // RX 핀 입력 자격: 비동기
    GPIO_setQualificationMode(28, GPIO_QUAL_ASYNC);
}

// SCI 초기화 함수: 루프백 및 오토보드 록
void initSCI(void) {
    // SCI 모듈 비활성화
    SCI_disableModule(SCIA_BASE);
    
    // 송수신 채널 리셋
    SCI_resetChannels(SCIA_BASE);
    
    // SCI 설정: 9600bps, 8비트 데이터, 1 스톱 비트, 패리티 없음
    SCI_setConfig(SCIA_BASE, SysCtl_getLowSpeedClock(DEVICE_LSPCLK_FREQ), 9600, 
                  (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));
    
    // FIFO 활성화: 루프백 데이터 처리
    SCI_enableFIFO(SCIA_BASE);
    
    // FIFO 인터럽트 레벨 설정: 1바이트 트리거
    SCI_setFIFOInterruptLevel(SCIA_BASE, SCI_FIFO_TX1, SCI_FIFO_RX1);
    
    // 송신 FIFO 리셋
    SCI_resetTxFIFO(SCIA_BASE);
    
    // 수신 FIFO 리셋
    SCI_resetRxFIFO(SCIA_BASE);
    
    // 루프백 모드 활성화: 송신 데이터를 내부적으로 수신
    SCI_enableLoopback(SCIA_BASE);
    
    // 오토보드 록 활성화: 'A' 또는 'a'로 보드레이트 동기화
    SCI_lockAutobaud(SCIA_BASE);
    
    // SCI 모듈 활성화
    SCI_enableModule(SCIA_BASE);
}

예제 5: 보드레이트 동적 변경 및 상태 확인

보드레이트를 동적으로 변경하고 상태 확인 함수를 활용합니다.

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

// 함수 선언
void initGPIO(void); // GPIO 설정
void initSCI(void);  // SCI 설정

void main(void) {
    // 시스템 초기화: 클럭, PLL, 주변 장치 설정
    Device_init();
    
    // 기본 GPIO 초기화
    Device_initGPIO();
    
    // 인터럽트 컨트롤러 초기화
    Interrupt_initModule();
    
    // 인터럽트 벡터 테이블 초기화
    Interrupt_initVectorTable();
    
    // GPIO 초기화
    initGPIO();
    
    // SCI 초기화
    initSCI();
    
    // 글로벌 인터럽트 활성화
    EINT;
    
    // 실시간 인터럽트 활성화
    ERTM;
    
    // 초기 보드레이트 문자열
    const char message[] = "Initial Baud: 9600\n";
    uint16_t messageBuffer[sizeof(message)];
    
    // char 배열을 uint16_t로 변환 (sci.h의 SCI_writeCharArray 요구사항)
    uint16_t i;
    for (i = 0; i < sizeof(message); i++) {
        messageBuffer[i] = (uint16_t)message[i];
    }
    
    // 문자열 송신
    SCI_writeCharArray(SCIA_BASE, messageBuffer, sizeof(message));
    
    // 송신 완료 대기
    while (SCI_isTransmitterBusy(SCIA_BASE)) {
        SysCtl_serviceWatchdog();
    }
    
    // 보드레이트 변경: 115200bps로 동적 변경
    SCI_setBaud(SCIA_BASE, SysCtl_getLowSpeedClock(DEVICE_LSPCLK_FREQ), 115200);
    
    // 변경된 보드레이트 문자열
    const char newMessage[] = "New Baud: 115200\n";
    uint16_t newMessageBuffer[sizeof(newMessage)];
    
    // char 배열을 uint16_t로 변환
    for (i = 0; i < sizeof(newMessage); i++) {
        newMessageBuffer[i] = (uint16_t)newMessage[i];
    }
    
    // 문자열 송신
    SCI_writeCharArray(SCIA_BASE, newMessageBuffer, sizeof(newMessage));
    
    // 송신 완료 대기
    while (SCI_isTransmitterBusy(SCIA_BASE)) {
        SysCtl_serviceWatchdog();
    }
    
    // 수신 데이터 저장 변수
    uint16_t receivedChar;
    
    // 무한 루프: 수신 데이터 처리
    while(1) {
        // Watchdog 서비스 (리셋 방지)
        SysCtl_serviceWatchdog();
        
        // 수신 상태 확인
        if (SCI_getRxFIFOStatus(SCIA_BASE) >= SCI_FIFO_RX1) {
            // 수신 에러 확인
            if (SCI_getRxStatus(SCIA_BASE) & SCI_RXSTATUS_ERROR) {
                // 에러 발생 시 소프트웨어 리셋
                SCI_performSoftwareReset(SCIA_BASE);
                SCI_clearOverflowStatus(SCIA_BASE);
                continue;
            }
            
            // 비차단 모드로 데이터 수신
            SCI_readCharArray(SCIA_BASE, &receivedChar, 1);
            
            // 송신기 상태 확인: 송신 중이 아니면 전송
            if (!SCI_isTransmitterBusy(SCIA_BASE)) {
                SCI_writeCharArray(SCIA_BASE, &receivedChar, 1);
            }
        }
    }
}

// GPIO 초기화 함수
void initGPIO(void) {
    // SCIA RX 핀 설정: GPIO28 (pin_map.h: GPIO_28_SCIA_RX, 0x00081801U)
    GPIO_setPinConfig(GPIO_28_SCIA_RX);
    
    // SCIA TX 핀 설정: GPIO29 (pin_map.h: GPIO_29_SCIA_TX, 0x00081A01U)
    GPIO_setPinConfig(GPIO_29_SCIA_TX);
    
    // RX 핀 방향: 입력
    GPIO_setDirectionMode(28, GPIO_DIR_MODE_IN);
    
    // TX 핀 방향: 출력
    GPIO_setDirectionMode(29, GPIO_DIR_MODE_OUT);
    
    // RX 핀 패드: 풀업 저항
    GPIO_setPadConfig(28, GPIO_PIN_TYPE_PULLUP);
    
    // TX 핀 패드: 표준 출력
    GPIO_setPadConfig(29, GPIO_PIN_TYPE_STD);
    
    // RX 핀 입력 자격: 비동기
    GPIO_setQualificationMode(28, GPIO_QUAL_ASYNC);
}

// SCI 초기화 함수
void initSCI(void) {
    // SCI 모듈 비활성화
    SCI_disableModule(SCIA_BASE);
    
    // 송수신 채널 리셋
    SCI_resetChannels(SCIA_BASE);
    
    // 초기 SCI 설정: 9600bps, 8비트 데이터, 1 스톱 비트, 패리티 없음
    SCI_setConfig(SCIA_BASE, SysCtl_getLowSpeedClock(DEVICE_LSPCLK_FREQ), 9600, 
                  (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));
    
    // FIFO 활성화: 다중 데이터 처리
    SCI_enableFIFO(SCIA_BASE);
    
    // FIFO 인터럽트 레벨 설정: 1바이트 트리거
    SCI_setFIFOInterruptLevel(SCIA_BASE, SCI_FIFO_TX1, SCI_FIFO_RX1);
    
    // 송신 FIFO 리셋
    SCI_resetTxFIFO(SCIA_BASE);
    
    // 수신 FIFO 리셋
    SCI_resetRxFIFO(SCIA_BASE);
    
    // SCI 모듈 활성화
    SCI_enableModule(SCIA_BASE);
}

 

5. 디버깅 팁

  • 보드레이트 불일치: 송신/수신 장치의 보드레이트가 동일한지 확인 (SCI_setBaudRate 사용).
  • GPIO 핀 확인: TMS320F28388D 데이터시트에서 핀맵 확인 (예: GPIO28/TX, GPIO29/RX).
  • FIFO 상태 확인: SCI_getTxFIFOStatus, SCI_getRxFIFOStatus로 FIFO 상태 점검.
  • 인터럽트 문제: Interrupt_register, Interrupt_enable 호출 확인.
  • 루프백 테스트: 하드웨어 연결 문제 시 SCI_enableLoopback으로 테스트.
  • 오토보드 록: SCI_enableAutoBaud 사용 시 호환 장치 확인.
  • 디버거 사용: Code Composer Studio로 레지스터 값 확인.

6. 추가 참고 자료

  • C2000Ware: C2000Ware_x_xx_xx_xx\driverlib\f2838x\examples\c28x\sci에서 예제 코드 확인.
  • TI 문서: F2837xS Peripheral Driver Library User’s Guide, TMS320F28388D Technical Reference Manual.
  • Driverlib 소스: driverlib/sci.c, driverlib/sci.h에서 API 정의 확인.

키워드: TMS320F28388D SCI, Driverlib API, UART 설정, C2000 SCI 예제, FIFO 설정, 인터럽트 처리, 루프백 테스트, 오토보드 록, Code Composer Studio, C2000Ware