본문 바로가기
MCU/C2000

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

by linuxgo 2025. 8. 17.
반응형

이 문서에서는 Texas Instruments의 TMS320F28388D 마이크로컨트롤러에서 외부 메모리 인터페이스(EMIF, External Memory Interface) 모듈을 DriverLib API를 사용하여 설정하고 사용하는 방법을 상세히 다룹니다. C2000 시리즈의 고성능 마이크로컨트롤러인 TMS320F28388D의 EMIF를 활용하여 외부 SRAM, SDRAM, 또는 병렬 장치(ADC, FPGA)와 통신하는 방법을 배우고, 독립적인 예제 코드를 통해 실제 구현 방법을 익힐 수 있습니다. 각 코드는 상세한 주석을 포함하며, Code Composer Studio(CCS) 환경에서 실행 가능합니다.


1. TMS320F28388D EMIF 개요

TMS320F28388D는 Texas Instruments의 C2000 시리즈에 속하는 32비트 부동소수점 MCU로, 두 개의 EMIF 모듈(EMIF1, EMIF2)을 제공합니다. EMIF는 외부 메모리(SRAM, SDRAM, NOR/NAND 플래시) 및 병렬 장치(ADC, FPGA)와의 고속 데이터 전송을 지원하며, 산업용 제어, 전력 전자, 신호 처리 등에 최적화되어 있습니다.

EMIF 모듈의 주요 특징

  • 지원 메모리 유형:
    • 비동기: SRAM, NOR/NAND 플래시.
    • 동기: SDRAM (EMIF1만 지원).
    • 기타: FPGA, ADC, DAC.
  • 데이터 버스 폭:
    • EMIF1: 최대 32비트.
    • EMIF2: 최대 16비트.
  • 주소 버스:
    • EMIF1: 22비트 (4MB 주소 공간).
    • EMIF2: 13비트 (32KB 주소 공간).
  • 칩 선택(CS):
    • EMIF1: CS0n, CS2n, CS3n, CS4n (최대 4개 장치).
    • EMIF2: CS2n, CS3n (최대 2개 장치).
  • 타이밍 제어:
    • 비동기: Setup, Strobe, Hold.
    • 동기: CAS, RAS, 리프레시 주기.
  • DMA 지원: 6채널 DMA 컨트롤러로 고속 데이터 전송.
  • 클럭: 최대 50MHz (비동기 모드).
  • 대기 신호(EMx_WAIT): 외부 장치 동기화.

DriverLib API는 하드웨어 레지스터를 직접 조작하지 않고 추상화된 함수를 제공하여 EMIF 설정을 간소화합니다.


2. 주요 EMIF DriverLib API 함수

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

2.1. EMIF 기본 설정 관련 함수

  • EMIF_setAsyncDataBusWidth(base, cs, width)
    • 설명: 비동기 모드의 데이터 버스 폭 설정 (8/16/32비트).
    • 매개변수: base (EMIF1/2 베이스 주소), cs (칩 선택), width (EMIF_ASYNC_DATA_WIDTH_8/16/32).
    • 사용 예: EMIF1 CS2를 16비트로 설정.
  • EMIF_setAsyncTimingParams(base, cs, params)
    • 설명: 비동기 모드의 타이밍 파라미터(Setup, Strobe, Hold, Turnaround) 설정.
    • 매개변수: params (EMIF_AsyncTimingParams 구조체).
    • 사용 예: Setup=2, Strobe=4, Hold=2 설정.
  • SysCtl_enablePeripheral(peripheral)
    • 설명: EMIF 모듈 클럭 활성화.
    • 매개변수: peripheral (SYSCTL_PERIPH_CLK_EMIF1/2).
  • EMIF_enableAsyncWait(base, cs)
    • 설명: 대기 신호 활성화.
    • 사용 예: 외부 장치의 데이터 준비 신호 처리.

2.2. 동기 모드 관련 함수

  • EMIF_setSyncTimingParams(base, cas, ras, refresh)
    • 설명: SDRAM의 동기 타이밍 설정.
    • 매개변수: cas (CAS 지연), ras (RAS 지연), refresh (리프레시 주기).
    • 사용 예: CAS=3, RAS=2, 리프레시=64ms.
  • EMIF_enableSyncMode(base)
    • 설명: 동기 모드 활성화.

2.3. DMA 관련 함수

  • DMA_configSource(channel, source)
    • 설명: DMA 소스 주소 설정 (예: EMIF 메모리 주소).
    • 사용 예: EMIF CS2에서 내부 SRAM으로 데이터 전송.
  • DMA_configDestination(channel, destination)
    • 설명: DMA 목적지 주소 설정.
  • DMA_configBurst(channel, size)
    • 설명: 버스트 전송 크기 설정.

2.4. 인터럽트 관련 함수

  • EMIF_enableInterrupt(base, intFlags)
    • 설명: EMIF 인터럽트 활성화.
    • 매개변수: intFlags (예: EMIF_INT_ASYNC_WAIT).
  • Interrupt_register(intNumber, handler)
    • 설명: 인터럽트 서비스 루틴(ISR) 등록.

3. EMIF 설정 및 동작 원리

  1. 시스템 초기화: 시스템 클럭, GPIO, 인터럽트 초기화 (Device_init, Device_initGPIO).
  2. EMIF 모듈 설정: 클럭 활성화, 데이터 버스 폭, 타이밍 설정.
  3. 칩 선택 및 메모리 매핑: CS 주소 범위 설정 및 메모리 접근.
  4. DMA 설정(선택): 대량 데이터 전송을 위해 DMA 구성.
  5. 인터럽트 설정(선택): 대기 신호 또는 전송 완료 인터럽트 처리.
  6. EMIF 동작: 메모리 읽기/쓰기 또는 장치 통신.

4. EMIF 예제 코드

아래는 독립적인 EMIF 예제 코드로, C2000Ware의 DriverLib를 기반으로 작성되었습니다. GPIO 설정은 initGPIO() 함수로 분리되었으며, 모든 코드는 CCS에서 TMDSCNCD28388D controlCARD에서 바로 실행 가능합니다.

4.1. 예제 1: 기본 SRAM 읽기/쓰기

EMIF1 CS2를 사용하여 16비트 SRAM에 데이터를 쓰고 읽습니다. 상세 주석과 인터럽트 설정이 포함되어 있습니다.

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

// EMIF1 CS2 메모리 주소 정의 (메모리 매핑: 0x00200000 ~ 0x002FFFFF)
#define CS2_ADDRESS 0x00200000
// volatile 포인터로 EMIF1 CS2 메모리 접근
volatile uint16_t *emifCS2 = (volatile uint16_t *)CS2_ADDRESS;

// 디버깅용 상태 변수 (0: 초기화 완료, 1: 동작 중, 0xFFFF: 오류)
volatile uint32_t emifStatus = 0;

// GPIO 초기화 함수
void initGPIO(void)
{
    // EMIF1 CS2 관련 핀 설정
    GPIO_setPinConfig(GPIO_29_EM1CS2N);  // 칩 선택 신호 (CS2n)
    GPIO_setPinConfig(GPIO_30_EM1A0);    // 주소 비트 0
    GPIO_setPinConfig(GPIO_31_EM1A1);    // 주소 비트 1
    GPIO_setPinConfig(GPIO_32_EM1A2);    // 주소 비트 2
    GPIO_setPinConfig(GPIO_33_EM1A3);    // 주소 비트 3
    GPIO_setPinConfig(GPIO_34_EM1A4);    // 주소 비트 4
    GPIO_setPinConfig(GPIO_35_EM1A5);    // 주소 비트 5
    GPIO_setPinConfig(GPIO_36_EM1A6);    // 주소 비트 6
    GPIO_setPinConfig(GPIO_37_EM1A7);    // 주소 비트 7
    GPIO_setPinConfig(GPIO_38_EM1A8);    // 주소 비트 8
    GPIO_setPinConfig(GPIO_39_EM1A9);    // 주소 비트 9
    GPIO_setPinConfig(GPIO_40_EM1A10);   // 주소 비트 10
    GPIO_setPinConfig(GPIO_41_EM1A11);   // 주소 비트 11
    GPIO_setPinConfig(GPIO_42_EM1A12);   // 주소 비트 12
    GPIO_setPinConfig(GPIO_43_EM1A13);   // 주소 비트 13
    GPIO_setPinConfig(GPIO_44_EM1A14);   // 주소 비트 14
    GPIO_setPinConfig(GPIO_45_EM1A15);   // 주소 비트 15
    GPIO_setPinConfig(GPIO_46_EM1D0);    // 데이터 비트 0
    GPIO_setPinConfig(GPIO_47_EM1D1);    // 데이터 비트 1
    GPIO_setPinConfig(GPIO_48_EM1D2);    // 데이터 비트 2
    GPIO_setPinConfig(GPIO_49_EM1D3);    // 데이터 비트 3
    GPIO_setPinConfig(GPIO_50_EM1D4);    // 데이터 비트 4
    GPIO_setPinConfig(GPIO_51_EM1D5);    // 데이터 비트 5
    GPIO_setPinConfig(GPIO_52_EM1D6);    // 데이터 비트 6
    GPIO_setPinConfig(GPIO_53_EM1D7);    // 데이터 비트 7
    GPIO_setPinConfig(GPIO_54_EM1D8);    // 데이터 비트 8
    GPIO_setPinConfig(GPIO_55_EM1D9);    // 데이터 비트 9
    GPIO_setPinConfig(GPIO_56_EM1D10);   // 데이터 비트 10
    GPIO_setPinConfig(GPIO_57_EM1D11);   // 데이터 비트 11
    GPIO_setPinConfig(GPIO_58_EM1D12);   // 데이터 비트 12
    GPIO_setPinConfig(GPIO_59_EM1D13);   // 데이터 비트 13
    GPIO_setPinConfig(GPIO_60_EM1D14);   // 데이터 비트 14
    GPIO_setPinConfig(GPIO_61_EM1D15);   // 데이터 비트 15
    GPIO_setPinConfig(GPIO_62_EM1WEN);   // 쓰기 활성화 (WEn)
    GPIO_setPinConfig(GPIO_63_EM1OEN);   // 읽기 활성화 (OEn)
    GPIO_setPinConfig(GPIO_64_EM1WAIT);  // 대기 신호 (WAIT)

    // 디버깅용 LED 설정 (GPIO31)
    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
}

// EMIF1 초기화 함수
void initEMIF(void)
{
    // EMIF1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EMIF1);

    // 비동기 모드에서 16비트 데이터 버스 폭 설정
    EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);

    // 비동기 타이밍 설정 (클럭 사이클 단위)
    EMIF_AsyncTimingParams timingParams = {
        .setup = 2,      // 주소/제어 신호 설정 시간
        .strobe = 4,     // 데이터 읽기/쓰기 활성 시간
        .hold = 2,       // 데이터 유지 시간
        .turnAround = 1  // 연속 접근 간 대기 시간
    };
    EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &timingParams);

    // 대기 신호 활성화 (외부 장치의 데이터 준비 신호 처리)
    EMIF_enableAsyncWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);

    // 초기화 성공 상태
    emifStatus = 1;
}

// EMIF를 통해 데이터 쓰기 함수
void writeEMIF(uint16_t addressOffset, uint16_t data)
{
    // 지정된 주소 오프셋에 데이터 쓰기
    emifCS2[addressOffset] = data;
}

// EMIF를 통해 데이터 읽기 함수
uint16_t readEMIF(uint16_t addressOffset)
{
    // 지정된 주소 오프셋에서 데이터 읽기
    return emifCS2[addressOffset];
}

// EMIF 인터럽트 서비스 루틴 (ISR)
__interrupt void emifISR(void)
{
    // 대기 신호 인터럽트 처리 (예: 데이터 읽기 완료)
    uint16_t data = readEMIF(0x100); // 테스트 주소에서 읽기
    emifStatus = (data != 0) ? 1 : 0xFFFF; // 데이터 유효성 확인

    // EMIF 인터럽트 플래그 지우기
    EMIF_clearInterruptStatus(EMIF1_BASE, EMIF_INT_ASYNC_WAIT);

    // PIE 그룹 9 인터럽트 ACK (인터럽트 처리 완료)
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

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

    // GPIO 초기화: 기본 GPIO 설정
    Device_initGPIO();

    // 인터럽트 컨트롤러 초기화
    Interrupt_initModule(); // PIE(Peripheral Interrupt Expansion) 초기화

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

    // EMIF1 인터럽트 등록 (INT_EMIF1은 그룹 9에 속함)
    Interrupt_register(INT_EMIF1, &emifISR);

    // EMIF 관련 GPIO 설정
    initGPIO();

    // 시스템 클럭 확인 (200MHz로 설정되어야 함)
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        emifStatus = 0xFFFF; // 클럭 오류 상태
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 디버깅용 정지
    }

    // 글로벌 인터럽트 비활성화 (안전한 초기화 보장)
    DINT; // Disable Interrupts

    // EMIF1 초기화
    initEMIF();

    // 초기화 오류 확인
    if (emifStatus != 1)
    {
        emifStatus = 0xFFFF; // 초기화 실패
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 디버깅용 정지
    }

    // EMIF 인터럽트 활성화
    EMIF_enableInterrupt(EMIF1_BASE, EMIF_INT_ASYNC_WAIT);

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

    // 테스트 데이터 쓰기 및 읽기
    uint16_t testData = 0xABCD; // 테스트 데이터
    uint16_t testAddress = 0x100; // 임의의 주소 오프셋
    writeEMIF(testAddress, testData); // SRAM에 데이터 쓰기
    uint16_t readData = readEMIF(testAddress); // SRAM에서 데이터 읽기

    // 데이터 검증
    if (readData != testData)
    {
        emifStatus = 0xFFFF; // 데이터 오류
        GPIO_writePin(31, 0); // LED OFF
        ESTOP0; // 디버깅용 정지
    }

    // Watchdog 활성화 (실시간 애플리케이션용)
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();

    // 무한 루프: EMIF 동작 유지 및 상태 표시
    for(;;)
    {
        // 상태에 따라 LED 제어 (정상: ON, 오류: OFF)
        GPIO_writePin(31, (emifStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000); // 1초 대기 (CPU 부하 감소)
    }
}

설명:

  • 기능: EMIF1 CS2를 사용해 16비트 SRAM에 데이터 쓰기/읽기, 대기 신호 인터럽트 처리.
  • 설정: 16비트 데이터 버스, 타이밍 (Setup=2, Strobe=4, Hold=2), 대기 신호 및 인터럽트 활성화.
  • GPIO: EMIF1 핀 (GPIO29~64), 디버깅용 LED (GPIO31).
  • 인터럽트: EMIF_INT_ASYNC_WAIT 인터럽트 등록, PIE 그룹 9 사용.
  • 출력: 주소 0x100에 0xABCD 쓰기/읽기 성공 시 LED ON.
  • 용도: 외부 SRAM 데이터 로깅, 인터럽트 기반 데이터 처리.

4.2. 예제 2: DMA를 사용한 SRAM 데이터 전송

EMIF1 CS2에서 내부 SRAM으로 DMA를 통해 데이터를 전송합니다.

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

// EMIF1 CS2 메모리 주소 정의
#define CS2_ADDRESS 0x00200000
volatile uint16_t *emifCS2 = (volatile uint16_t *)CS2_ADDRESS;

// 내부 SRAM 버퍼
#define BUFFER_SIZE 256
volatile uint16_t internalBuffer[BUFFER_SIZE];

// 디버깅용 상태 변수
volatile uint32_t emifStatus = 0;

// GPIO 초기화 함수
void initGPIO(void)
{
    // EMIF1 CS2, 16비트 데이터 버스, 주소 0~15
    GPIO_setPinConfig(GPIO_29_EM1CS2N);
    GPIO_setPinConfig(GPIO_30_EM1A0);
    GPIO_setPinConfig(GPIO_31_EM1A1);
    GPIO_setPinConfig(GPIO_32_EM1A2);
    GPIO_setPinConfig(GPIO_33_EM1A3);
    GPIO_setPinConfig(GPIO_34_EM1A4);
    GPIO_setPinConfig(GPIO_35_EM1A5);
    GPIO_setPinConfig(GPIO_36_EM1A6);
    GPIO_setPinConfig(GPIO_37_EM1A7);
    GPIO_setPinConfig(GPIO_38_EM1A8);
    GPIO_setPinConfig(GPIO_39_EM1A9);
    GPIO_setPinConfig(GPIO_40_EM1A10);
    GPIO_setPinConfig(GPIO_41_EM1A11);
    GPIO_setPinConfig(GPIO_42_EM1A12);
    GPIO_setPinConfig(GPIO_43_EM1A13);
    GPIO_setPinConfig(GPIO_44_EM1A14);
    GPIO_setPinConfig(GPIO_45_EM1A15);
    GPIO_setPinConfig(GPIO_46_EM1D0);
    GPIO_setPinConfig(GPIO_47_EM1D1);
    GPIO_setPinConfig(GPIO_48_EM1D2);
    GPIO_setPinConfig(GPIO_49_EM1D3);
    GPIO_setPinConfig(GPIO_50_EM1D4);
    GPIO_setPinConfig(GPIO_51_EM1D5);
    GPIO_setPinConfig(GPIO_52_EM1D6);
    GPIO_setPinConfig(GPIO_53_EM1D7);
    GPIO_setPinConfig(GPIO_54_EM1D8);
    GPIO_setPinConfig(GPIO_55_EM1D9);
    GPIO_setPinConfig(GPIO_56_EM1D10);
    GPIO_setPinConfig(GPIO_57_EM1D11);
    GPIO_setPinConfig(GPIO_58_EM1D12);
    GPIO_setPinConfig(GPIO_59_EM1D13);
    GPIO_setPinConfig(GPIO_60_EM1D14);
    GPIO_setPinConfig(GPIO_61_EM1D15);
    GPIO_setPinConfig(GPIO_62_EM1WEN);
    GPIO_setPinConfig(GPIO_63_EM1OEN);
    GPIO_setPinConfig(GPIO_64_EM1WAIT);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PULL_UP);
    GPIO_writePin(31, 0);
}

// EMIF1 초기화 함수
void initEMIF(void)
{
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EMIF1);
    EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);
    EMIF_AsyncTimingParams timingParams = {
        .setup = 2,
        .strobe = 4,
        .hold = 2,
        .turnAround = 1
    };
    EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &timingParams);
    EMIF_enableAsyncWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);
    emifStatus = 1;
}

// DMA 초기화 함수
void initDMA(void)
{
    // DMA 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DMA);

    // DMA 채널 1 설정: EMIF1 CS2에서 내부 SRAM으로 전송
    DMA_configSource(DMA_CHANNEL_1, (void *)CS2_ADDRESS);
    DMA_configDestination(DMA_CHANNEL_1, (void *)internalBuffer);
    DMA_configBurst(DMA_CHANNEL_1, BUFFER_SIZE);
    DMA_configTransfer(DMA_CHANNEL_1, 1, DMA_ADDR_INCREMENT_2);
    DMA_enableTrigger(DMA_CHANNEL_1);
    DMA_startChannel(DMA_CHANNEL_1);
}

void main(void)
{
    // 시스템 초기화
    Device_init();
    Device_initGPIO();

    // 인터럽트 초기화
    Interrupt_initModule();
    Interrupt_initVectorTable();
    EINT;

    // GPIO 설정
    initGPIO();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // EMIF1 초기화
    initEMIF();

    // 초기화 오류 확인
    if (emifStatus != 1)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // 테스트 데이터 쓰기
    for (uint16_t i = 0; i < BUFFER_SIZE; i++)
    {
        writeEMIF(i, 0x1000 + i);
    }

    // DMA 초기화 및 전송
    initDMA();

    // DMA 전송 완료 대기
    while (DMA_isChannelActive(DMA_CHANNEL_1))
    {
        DEVICE_DELAY_US(10);
    }

    // 데이터 검증
    for (uint16_t i = 0; i < BUFFER_SIZE; i++)
    {
        if (internalBuffer[i] != (0x1000 + i))
        {
            emifStatus = 0xFFFF;
            GPIO_writePin(31, 0);
            ESTOP0;
        }
    }

    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();

    // 무한 루프
    for(;;)
    {
        GPIO_writePin(31, (emifStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000);
    }
}

설명:

  • 기능: EMIF1 CS2에서 내부 SRAM으로 256개의 16비트 데이터를 DMA로 전송.
  • 설정: 16비트 데이터 버스, DMA 채널 1, 타이밍 (Setup=2, Strobe=4, Hold=2).
  • GPIO: EMIF1 핀 (GPIO29~64), 디버깅용 LED (GPIO31).
  • 출력: 데이터 전송 성공 시 LED ON.
  • 용도: 대용량 데이터 로깅, 고속 데이터 처리.

4.3. 예제 3: 외부 ADC 인터페이스

EMIF1 CS2를 사용하여 16비트 병렬 ADC(예: ADS8686S)에서 데이터를 읽습니다.

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

// EMIF1 CS2 메모리 주소 정의 (ADC 매핑)
#define ADC_ADDRESS 0x00200000
volatile uint16_t *adcData = (volatile uint16_t *)ADC_ADDRESS;

// 디버깅용 상태 변수
volatile uint32_t emifStatus = 0;

// ADC 데이터 버퍼
#define ADC_BUFFER_SIZE 256
volatile uint16_t adcBuffer[ADC_BUFFER_SIZE];
volatile uint16_t adcIndex = 0;

// GPIO 초기화 함수
void initGPIO(void)
{
    // EMIF1 CS2, 16비트 데이터 버스, 주소 0
    GPIO_setPinConfig(GPIO_29_EM1CS2N);
    GPIO_setPinConfig(GPIO_30_EM1A0);
    GPIO_setPinConfig(GPIO_46_EM1D0);
    GPIO_setPinConfig(GPIO_47_EM1D1);
    GPIO_setPinConfig(GPIO_48_EM1D2);
    GPIO_setPinConfig(GPIO_49_EM1D3);
    GPIO_setPinConfig(GPIO_50_EM1D4);
    GPIO_setPinConfig(GPIO_51_EM1D5);
    GPIO_setPinConfig(GPIO_52_EM1D6);
    GPIO_setPinConfig(GPIO_53_EM1D7);
    GPIO_setPinConfig(GPIO_54_EM1D8);
    GPIO_setPinConfig(GPIO_55_EM1D9);
    GPIO_setPinConfig(GPIO_56_EM1D10);
    GPIO_setPinConfig(GPIO_57_EM1D11);
    GPIO_setPinConfig(GPIO_58_EM1D12);
    GPIO_setPinConfig(GPIO_59_EM1D13);
    GPIO_setPinConfig(GPIO_60_EM1D14);
    GPIO_setPinConfig(GPIO_61_EM1D15);
    GPIO_setPinConfig(GPIO_62_EM1WEN);
    GPIO_setPinConfig(GPIO_63_EM1OEN);
    GPIO_setPinConfig(GPIO_64_EM1WAIT);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PULL_UP);
    GPIO_writePin(31, 0);
}

// EMIF1 초기화 함수
void initEMIF(void)
{
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EMIF1);
    EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);
    EMIF_AsyncTimingParams timingParams = {
        .setup = 2,
        .strobe = 4,
        .hold = 2,
        .turnAround = 1
    };
    EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &timingParams);
    EMIF_enableAsyncWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);
    emifStatus = 1;
}

void main(void)
{
    // 시스템 초기화
    Device_init();
    Device_initGPIO();

    // 인터럽트 초기화
    Interrupt_initModule();
    Interrupt_initVectorTable();
    EINT;

    // GPIO 설정
    initGPIO();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // EMIF1 초기화
    initEMIF();

    // 초기화 오류 확인
    if (emifStatus != 1)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // ADC 데이터 읽기
    for (adcIndex = 0; adcIndex < ADC_BUFFER_SIZE; adcIndex++)
    {
        adcBuffer[adcIndex] = *adcData;
        DEVICE_DELAY_US(10); // ADC 변환 시간 대기
    }

    // 데이터 검증 (예: 데이터가 0이 아닌지 확인)
    for (uint16_t i = 0; i < ADC_BUFFER_SIZE; i++)
    {
        if (adcBuffer[i] == 0)
        {
            emifStatus = 0xFFFF;
            GPIO_writePin(31, 0);
            ESTOP0;
        }
    }

    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();

    // 무한 루프
    for(;;)
    {
        GPIO_writePin(31, (emifStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000);
    }
}

설명:

  • 기능: EMIF1 CS2를 통해 16비트 병렬 ADC(예: ADS8686S)에서 데이터 읽기.
  • 설정: 16비트 데이터 버스, 단일 주소(A0), 대기 신호.
  • GPIO: EMIF1 핀 (GPIO29, 30, 46~64), 디버깅용 LED (GPIO31).
  • 출력: ADC 데이터 256개 저장, 성공 시 LED ON.
  • 용도: 고속 ADC 데이터 수집.

4.4. 예제 4: SDRAM 설정 및 데이터 전송

EMIF1을 동기 모드로 설정하여 SDRAM에 데이터를 쓰고 읽습니다.

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

// EMIF1 CS0 메모리 주소 정의 (SDRAM)
#define SDRAM_ADDRESS 0x00100000
volatile uint16_t *sdram = (volatile uint16_t *)SDRAM_ADDRESS;

// 디버깅용 상태 변수
volatile uint32_t emifStatus = 0;

// GPIO 초기화 함수
void initGPIO(void)
{
    // EMIF1 CS0, 16비트 데이터 버스, 주소 0~15, SDRAM 신호
    GPIO_setPinConfig(GPIO_28_EM1CS0N);
    GPIO_setPinConfig(GPIO_30_EM1A0);
    GPIO_setPinConfig(GPIO_31_EM1A1);
    GPIO_setPinConfig(GPIO_32_EM1A2);
    GPIO_setPinConfig(GPIO_33_EM1A3);
    GPIO_setPinConfig(GPIO_34_EM1A4);
    GPIO_setPinConfig(GPIO_35_EM1A5);
    GPIO_setPinConfig(GPIO_36_EM1A6);
    GPIO_setPinConfig(GPIO_37_EM1A7);
    GPIO_setPinConfig(GPIO_38_EM1A8);
    GPIO_setPinConfig(GPIO_39_EM1A9);
    GPIO_setPinConfig(GPIO_40_EM1A10);
    GPIO_setPinConfig(GPIO_41_EM1A11);
    GPIO_setPinConfig(GPIO_42_EM1A12);
    GPIO_setPinConfig(GPIO_43_EM1A13);
    GPIO_setPinConfig(GPIO_44_EM1A14);
    GPIO_setPinConfig(GPIO_45_EM1A15);
    GPIO_setPinConfig(GPIO_46_EM1D0);
    GPIO_setPinConfig(GPIO_47_EM1D1);
    GPIO_setPinConfig(GPIO_48_EM1D2);
    GPIO_setPinConfig(GPIO_49_EM1D3);
    GPIO_setPinConfig(GPIO_50_EM1D4);
    GPIO_setPinConfig(GPIO_51_EM1D5);
    GPIO_setPinConfig(GPIO_52_EM1D6);
    GPIO_setPinConfig(GPIO_53_EM1D7);
    GPIO_setPinConfig(GPIO_54_EM1D8);
    GPIO_setPinConfig(GPIO_55_EM1D9);
    GPIO_setPinConfig(GPIO_56_EM1D10);
    GPIO_setPinConfig(GPIO_57_EM1D11);
    GPIO_setPinConfig(GPIO_58_EM1D12);
    GPIO_setPinConfig(GPIO_59_EM1D13);
    GPIO_setPinConfig(GPIO_60_EM1D14);
    GPIO_setPinConfig(GPIO_61_EM1D15);
    GPIO_setPinConfig(GPIO_62_EM1WEN);
    GPIO_setPinConfig(GPIO_63_EM1OEN);
    GPIO_setPinConfig(GPIO_65_EM1CLK);
    GPIO_setPinConfig(GPIO_66_EM1RAS);
    GPIO_setPinConfig(GPIO_67_EM1CAS);
    GPIO_setPinConfig(GPIO_68_EM1BA0);
    GPIO_setPinConfig(GPIO_69_EM1BA1);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PULL_UP);
    GPIO_writePin(31, 0);
}

// EMIF1 SDRAM 초기화 함수
void initEMIF(void)
{
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EMIF1);
    EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS0_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);
    EMIF_setSyncTimingParams(EMIF1_BASE, 3, 2, 64); // CAS=3, RAS=2, Refresh=64ms
    EMIF_enableSyncMode(EMIF1_BASE);
    emifStatus = 1;
}

void main(void)
{
    // 시스템 초기화
    Device_init();
    Device_initGPIO();

    // 인터럽트 초기화
    Interrupt_initModule();
    Interrupt_initVectorTable();
    EINT;

    // GPIO 설정
    initGPIO();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // EMIF1 초기화
    initEMIF();

    // 초기화 오류 확인
    if (emifStatus != 1)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // 테스트 데이터 쓰기
    for (uint16_t i = 0; i < 256; i++)
    {
        sdram[i] = 0x2000 + i;
    }

    // 데이터 읽기 및 검증
    for (uint16_t i = 0; i < 256; i++)
    {
        if (sdram[i] != (0x2000 + i))
        {
            emifStatus = 0xFFFF;
            GPIO_writePin(31, 0);
            ESTOP0;
        }
    }

    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();

    // 무한 루프
    for(;;)
    {
        GPIO_writePin(31, (emifStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000);
    }
}

설명:

  • 기능: EMIF1 CS0을 동기 모드로 설정하여 SDRAM에 데이터 쓰기/읽기.
  • 설정: 16비트 데이터 버스, CAS=3, RAS=2, 리프레시=64ms.
  • GPIO: EMIF1 핀 (GPIO28~69), 디버깅용 LED (GPIO31).
  • 출력: 256개 데이터 쓰기/읽기 성공 시 LED ON.
  • 용도: 대용량 데이터 저장, 실시간 신호 처리.

4.5. 예제 5: EMIF 인터럽트 및 대기 신호

EMIF1 CS2에서 대기 신호를 사용하여 외부 장치 데이터를 읽습니다.

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

// EMIF1 CS2 메모리 주소 정의
#define CS2_ADDRESS 0x00200000
volatile uint16_t *emifCS2 = (volatile uint16_t *)CS2_ADDRESS;

// 디버깅용 상태 변수
volatile uint32_t emifStatus = 0;

// 인터럽트 서비스 루틴
__interrupt void emifISR(void)
{
    // 대기 신호 인터럽트 처리
    uint16_t data = *emifCS2;
    emifStatus = (data != 0) ? 1 : 0xFFFF;

    // 인터럽트 플래그 지우기
    EMIF_clearInterruptStatus(EMIF1_BASE, EMIF_INT_ASYNC_WAIT);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

void initGPIO(void)
{
    // EMIF1 CS2, 16비트 데이터 버스, 주소 0
    GPIO_setPinConfig(GPIO_29_EM1CS2N);
    GPIO_setPinConfig(GPIO_30_EM1A0);
    GPIO_setPinConfig(GPIO_46_EM1D0);
    GPIO_setPinConfig(GPIO_47_EM1D1);
    GPIO_setPinConfig(GPIO_48_EM1D2);
    GPIO_setPinConfig(GPIO_49_EM1D3);
    GPIO_setPinConfig(GPIO_50_EM1D4);
    GPIO_setPinConfig(GPIO_51_EM1D5);
    GPIO_setPinConfig(GPIO_52_EM1D6);
    GPIO_setPinConfig(GPIO_53_EM1D7);
    GPIO_setPinConfig(GPIO_54_EM1D8);
    GPIO_setPinConfig(GPIO_55_EM1D9);
    GPIO_setPinConfig(GPIO_56_EM1D10);
    GPIO_setPinConfig(GPIO_57_EM1D11);
    GPIO_setPinConfig(GPIO_58_EM1D12);
    GPIO_setPinConfig(GPIO_59_EM1D13);
    GPIO_setPinConfig(GPIO_60_EM1D14);
    GPIO_setPinConfig(GPIO_61_EM1D15);
    GPIO_setPinConfig(GPIO_62_EM1WEN);
    GPIO_setPinConfig(GPIO_63_EM1OEN);
    GPIO_setPinConfig(GPIO_64_EM1WAIT);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PULL_UP);
    GPIO_writePin(31, 0);
}

void initEMIF(void)
{
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EMIF1);
    EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);
    EMIF_AsyncTimingParams timingParams = {
        .setup = 2,
        .strobe = 4,
        .hold = 2,
        .turnAround = 1
    };
    EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &timingParams);
    EMIF_enableAsyncWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);
    EMIF_enableInterrupt(EMIF1_BASE, EMIF_INT_ASYNC_WAIT);
    emifStatus = 1;
}

void main(void)
{
    // 시스템 초기화
    Device_init();
    Device_initGPIO();

    // 인터럽트 초기화
    Interrupt_initModule();
    Interrupt_initVectorTable();
    Interrupt_register(INT_EMIF1, &emifISR);
    EINT;

    // GPIO 설정
    initGPIO();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != 200000000)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // EMIF1 초기화
    initEMIF();

    // 초기화 오류 확인
    if (emifStatus != 1)
    {
        emifStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // Watchdog 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_WD);
    SysCtl_serviceWatchdog();

    // 무한 루프
    for(;;)
    {
        GPIO_writePin(31, (emifStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000);
    }
}

설명:

  • 기능: EMIF1 CS2에서 대기 신호로 외부 장치 데이터 읽기, 인터럽트 처리.
  • 설정: 16비트 데이터 버스, 대기 신호 인터럽트.
  • GPIO: EMIF1 핀 (GPIO29, 30, 46~64), 디버깅용 LED (GPIO31).
  • 출력: 유효 데이터 수신 시 LED ON.
  • 용도: 외부 장치(ADC, FPGA) 동기화.

5. 추가 고려 사항

  • 타이밍 설정: 메모리/장치 데이터시트 기반으로 Setup, Strobe, Hold 값 조정.
  • DMA 최적화: 대량 데이터 전송 시 DMA 필수.
  • 핀 다중화: EMIF 핀은 GPIO와 공유되므로 충돌 주의.
  • C2000Ware: 예제는 C2000Ware DriverLib 기반 (C:\ti\c2000).
  • 디버깅: CCS의 .syscfg 툴로 EMIF 및 GPIO 설정 시각적 구성 가능.
  • 전력 소모: 32비트 모드에서 전력 증가 주의, 16비트/8비트 사용 권장.

키워드: TMS320F28388D, EMIF, DriverLib, C2000, SRAM, SDRAM, ADC, FPGA, DMA, Code Composer Studio, 비동기 모드, 동기 모드, 대기 신호, 칩 선택

반응형