본문 바로가기
MCU/C2000

TMS320F28377D DSP EMIF 사용법 : Bitfield 구조 활용 예제 코드(수정)

by linuxgo 2025. 8. 17.

TI의 TMS320F28377D는 C2000 Delfino 시리즈의 32비트 마이크로컨트롤러로, 외부 메모리 인터페이스(EMIF, External Memory Interface)를 통해 SRAM, NOR Flash, SDRAM, 그리고 외부 ADC/DAC 같은 병렬 인터페이스 장치와 고속으로 통신할 수 있습니다. EMIF 모듈은 고속 데이터 전송, 외부 장치 연결, 메모리 매핑 등을 지원하며, 모터 제어, 데이터 로깅, 대용량 데이터 처리, 아날로그-디지털 변환 애플리케이션에 적합합니다. 이 문서에서는 TMS320F28377D EMIF 모듈의 상세 설정 방법, Bitfield 구조를 활용한 레지스터 설정, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두 쉽게 활용할 수 있도록 돕겠습니다. 모든 예제는 Code Composer Studio(CCS)와 C2000Ware 환경에서 실행 가능합니다.

1. TMS320F28377D EMIF 모듈 개요

TMS320F28377D는 두 개의 EMIF 모듈(EMIF1, EMIF2)을 제공하며, 각각 독립적으로 외부 메모리 또는 병렬 인터페이스 장치와 인터페이스를 구성할 수 있습니다. 아래는 주요 사양입니다:

  • 지원 장치 유형:
    • 비동기 메모리(SRAM, NOR Flash)
    • 동기 메모리(SDRAM)
    • 병렬 인터페이스 장치(ADC, DAC, FPGA 등)
  • 주요 기능:
    • 16비트/32비트 데이터 버스
    • 최대 256MB 주소 공간(EMIF1), 2MB 주소 공간(EMIF2)
    • 프로그래밍 가능한 타이밍 파라미터
    • 인터럽트 지원
    • DMA(Direct Memory Access) 지원
  • 클럭 소스: 시스템 클럭(SYSCLK, 최대 200MHz)
  • 핀 구성:
    • EMIF1:
      • 데이터: EM1D[31:0]
      • 주소: EM1A[21:0]
      • 뱅크 주소: EM1BA[1:0] (SDRAM에서 뱅크 선택용)
      • 제어 신호: EM1CS[4:2], EM1WE, EM1OE, EM1SDCE, EM1CAS, EM1RAS
    • EMIF2:
      • 데이터: EM2D[15:0]
      • 주소: EM2A[11:0]
      • 뱅크 주소: EM2BA[1:0] (SDRAM에서 뱅크 선택용)
      • 제어 신호: EM2CS[0], EM2WE, EM2OE
  • EMIF_BA[1:0] 역할:
    •   EMIF_BA[1:0]은 SDRAM의 내부 뱅크를 선택하기 위해 사용됩니다.
    •   SDRAM은 일반적으로 2개 또는 4개의 내부 뱅크를 가지며, EMIF_BA[1:0]는 액세스할 뱅크를 지정하여 병렬 처리 및 성능 최적화를 지원합니다.
    •   예: 4뱅크 SDRAM의 경우, EM1BA[1:0] 또는 EM2BA[1:0]는 00, 01, 10, 11 값을 통해 각 뱅크를 선택합니다.
    •   비동기 메모리(SRAM, NOR Flash) 또는 병렬 ADC/DAC 인터페이스에서는 일반적으로 사용되지 않으며, SDRAM 전용 신호로 간주됩니다.
    •   GPIO 매핑 예: EM1BA0 (GPIO36), EM1BA1 (GPIO37), EM2BA0 (GPIO29), EM2BA1 (GPIO30).
  • 주요 레지스터:
    •   RCSR: 리비전 및 모듈 제어
    •   ASYNC_CSx_CTRL: 비동기 칩 선택 제어
    •   SDRAM_CR: SDRAM 제어
    •   SDRAM_TR: SDRAM 타이밍
    •   INT_EN: 인터럽트 활성화

2. EMIF Bitfield 설정 상세

TMS320F28377D의 EMIF 레지스터는 Bitfield 구조로 정의되어 있으며, F2837xD_emif.h 헤더 파일을 통해 접근합니다. Bitfield는 레지스터의 개별 비트를 명확히 설정하여 코드 가독성과 유지보수성을 높입니다. 주요 레지스터와 Bitfield는 다음과 같습니다:

2.1 RCSR (리비전 및 제어 레지스터)

  • bit.MODULE_ID: 모듈 식별자 (읽기 전용)
  • bit.MAJOR_REVISION: 메이저 리비전 번호
  • bit.MINOR_REVISION: 마이너 리비전 번호

2.2 ASYNC_CSx_CTRL (비동기 칩 선택 제어 레지스터, x=2,3,4)

  • bit.CS_EN: 칩 선택 활성화 (1: 활성화)
  • bit.ASIZE: 주소 크기 (0: 32비트, 1: 16비트, 2: 8비트)
  • bit.W_SETUP/W_STROBE/W_HOLD: 쓰기 동작 타이밍
  • bit.R_SETUP/R_STROBE/R_HOLD: 읽기 동작 타이밍
  • bit.TURN_AROUND: 턴어라운드 시간

2.3 SDRAM_CR (SDRAM 제어 레지스터)

  • bit.SD_EN: SDRAM 활성화 (1: 활성화)
  • bit.BANK_SIZE: 뱅크 크기 (0: 4뱅크, 1: 2뱅크, EMIF_BA[1:0]와 연계)
  • bit.PAGE_SIZE: 페이지 크기 (0: 256워드, 1: 512워드, 2: 1024워드)
  • bit.CL: CAS 지연 시간 (2: CL=2, 3: CL=3)
  • bit.IBANK: 내부 뱅크 구조

2.4 SDRAM_TR (SDRAM 타이밍 레지스터)

  • bit.T_RFC: 자동 리프레시 주기
  • bit.T_RP: 로우 프리차지 시간
  • bit.T_RCD: 로우 활성화에서 컬럼 액세스 시간
  • bit.T_WR: 쓰기 복구 시간
  • bit.T_RAS: 로우 활성화 시간
  • bit.T_RC: 로우 사이클 시간

3. EMIF 설정 절차

EMIF 모듈을 효과적으로 설정하려면 다음 단계를 따라야 합니다:

  1. 시스템 초기화:
    •   InitSysCtrl()를 호출하여 시스템 클럭과 PLL을 초기화합니다.
    •   인터럽트를 비활성화하고 PIE(Peripheral Interrupt Expansion)를 초기화합니다 (DINT, InitPieCtrl, InitPieVectTable).
  2. EMIF 클럭 활성화:
    •   CpuSysRegs.PCLKCR1.bit.EMIF1 또는 CpuSysRegs.PCLKCR1.bit.EMIF2를 설정하여 EMIF 모듈 클럭 활성화.
    •   보호된 레지스터 접근을 위해 EALLOW와 EDIS 사용.
  3. GPIO 설정:
    •   EMIF 핀을 적절한 기능(EMIF1/EMIF2)으로 설정 (예: GpioCtrlRegs.GPAMUXx.bit.GPIOx).
    •   데이터, 주소, 제어 신호, 그리고 SDRAM 사용 시 EMIF_BA[1:0] 핀을 모두 매핑.
    •   병렬 ADC/DAC의 경우, 칩 선택(CS)과 읽기/쓰기 신호(EMxWE, EMxOE)를 활용하여 데이터 전송 제어.
  4. 비동기 메모리 또는 장치 설정 (SRAM/NOR Flash/ADC/DAC):
    •   ASYNC_CSx_CTRL로 칩 선택 활성화 및 타이밍 설정.
    •   읽기/쓰기 타이밍 파라미터(W_SETUP, W_STROBE, R_SETUP, R_STROBE 등) 설정.
  5. SDRAM 설정 (필요 시):
    •   SDRAM_CR로 SDRAM 활성화, 뱅크 크기(EMIF_BA[1:0]와 연계), 페이지 크기, CAS 지연 설정.
    •   SDRAM_TR로 타이밍 파라미터 설정.
    •   초기화 시퀀스 수행 (예: 리프레시 주기 설정).
  6. 모듈 실행:
    •   메모리 또는 장치 테스트를 통해 설정 확인.
    •   외부 메모리 읽기/쓰기 또는 ADC/DAC 데이터 전송 수행.

4. EMIF 설정 고려사항

  • 클럭 설정: SYSCLK(200MHz)에서 EMIF 동작 클럭 확인.
  • 타이밍 계산: 외부 메모리 또는 장치(ADC/DAC 포함)의 데이터시트를 참조하여 읽기/쓰기 타이밍 설정.
  • 핀 멀티플렉싱: EMIF 핀(특히 EMIF_BA[1:0])과 다른 기능(GPIO, ePWM 등) 간 충돌 방지.
  • SDRAM 초기화: 리프레시 주기와 타이밍 파라미터를 정확히 설정, EMIF_BA[1:0] 핀 매핑 확인.
  • ADC/DAC 인터페이스: 병렬 ADC/DAC의 데이터시트에 따라 칩 선택 및 타이밍 설정, 데이터 버스 폭 확인.
  • 메모리 매핑: EMIF1(0x08000000~0x0FFFFFFF), EMIF2(0x00100000~0x0013FFFF) 주소 공간 확인.

5. EMIF 예제 코드 

아래는 TMS320F28377D EMIF 모듈을 Bitfield 구조로 설정한 7개의 실용적인 예제 코드입니다. 

TMS320F28377D EMIF

5.1 예제 1: 비동기 SRAM 읽기/쓰기

// File: emif_async_sram.c
// Description: TMS320F28377D EMIF 비동기 SRAM 읽기/쓰기 예제 (TI 제공 함수, 16비트, CS2)
// Compiler: Code Composer Studio (TI C2000 Compiler 22.6.1.LTS)
// Target: TMS320F28377D

#include "F28x_Project.h"

// 사용자 제공 extern 함수 선언 (C2000Ware F2837xD_Emif.c에 정의)
extern void setup_emif1_pinmux_async_16bit(Uint16);
extern void Emif1Initialize();
extern void ASync_cs2_config(Uint16 inst, Uint16 async_mem_data_width,
                             Uint16 turn_around_time, Uint16 r_hold_time,
                             Uint16 r_strobe_time, Uint16 r_setup, Uint16 w_hold,
                             Uint16 w_strobe, Uint16 w_setup, Uint16 extend_wait,
                             Uint16 strobe_sel);

#define SRAM_BASE 0x100000  // EMIF1 CS2 메모리 주소 (TRM Table 6-3 수정)

// EMIF1 GPIO 설정 함수 (TI 제공 함수 사용)
void SetupEmif1Gpio(void)
{
    EALLOW;
    setup_emif1_pinmux_async_16bit(GPIO_MUX_CPU1);  // TI의 16비트 비동기 EMIF1 핀 설정
    EDIS;
}

// EMIF1 CS2 설정 함수 (TI 제공 함수 사용)
void SetupEmif1CS2(void)
{
    EALLOW;
    Emif1Initialize();  // EMIF1 모듈 초기화 (소프트 리셋)
    
    // EMIF 보호 설정 (TI 예제 참조)
    Emif1ConfigRegs.EMIF1ACCPROT0.all = 0x0;  // 접근 보호 해제
    Emif1ConfigRegs.EMIF1COMMIT.all = 0x1;    // 커밋
    Emif1ConfigRegs.EMIF1LOCK.all = 0x1;      // 잠금
    
    // 클럭 분주 (/2 = 100MHz, SYSCLK=200MHz 가정)
    ClkCfgRegs.PERCLKDIVSEL.bit.EMIF1CLKDIV = 1;
    
    // CS2 타이밍 설정 (16비트, 느슨한 타이밍: TA=2, R_STROBE=6 등)
    ASync_cs2_config(0, 1, 2, 2, 6, 2, 2, 6, 2, 0, 0);  // EMIF1, 16비트, TA=2, R_HOLD=2, R_STROBE=6, R_SETUP=2, W_HOLD=2, W_STROBE=6, W_SETUP=2, EW=0, SS=0
    EDIS;
}

void main(void)
{
    // 에러 체크를 위한 플래그
    volatile Uint16 error_flag = 0;

    // 시스템 초기화
    InitSysCtrl();  // 시스템 클럭 및 PLL 초기화 (SYSCLK 200MHz 설정)
    
    // GPIO 초기화 및 설정
    InitGpio();  // 기본 GPIO 초기화
    SetupEmif1Gpio();  // EMIF1 GPIO 설정 (TI 함수)
    SetupEmif1CS2();   // EMIF1 CS2 설정 (TI 함수)
    
    // 인터럽트 초기화
    DINT;  // 모든 인터럽트 비활성화
    InitPieCtrl();  // PIE 초기화
    IER = 0x0000;  // CPU 인터럽트 비활성화
    IFR = 0x0000;  // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable();  // PIE 벡터 테이블 초기화
    
    // EMIF1 클럭 활성화
    EALLOW;
    CpuSysRegs.PCLKCR1.bit.EMIF1 = 1;  // EMIF1 모듈 클럭 활성화
    asm(" NOP");  // 클럭 안정화 대기
    EDIS;
    
    EINT;  // 글로벌 인터럽트 활성화
    ERTM;  // 실시간 모드 활성화
    
    // 메모리 테스트
    volatile Uint16 *sram = (volatile Uint16 *)SRAM_BASE;
    sram[0] = 0x1234;  // 데이터 쓰기
    DELAY_US(1);  // 쓰기 후 안정화 대기 (SRAM 데이터시트 tWR 기준)
    
    Uint16 read_data = sram[0];  // 데이터 읽기
    
    // 데이터 검증
    if (read_data != 0x1234) {
        error_flag = 1;  // 읽기 데이터 불일치
    }
    
    for(;;);  // 무한 루프
}

설명:

  • 기능: EMIF1 CS2를 통해 비동기 SRAM에 데이터 쓰기 및 읽기.
  • 설정: 16비트 데이터 버스, 읽기/쓰기 타이밍 설정, CS2 활성화.
  • GPIO:
    • 칩 선택: EM1CS2 (GPIO34)
    • 데이터: EM1D0~15(GPIO40~47,GPIO64~71)
    • 주소: EM1A0~11(GPIO58~63,GPIO72~77)
    • 제어: EM1WE (GPIO56), EM1OE (GPIO57)
  • LED: GPIO31
  • 출력: SRAM_BASE(0x08000000)에 0x1234 쓰기 및 읽기, 정상 동작 시 LED ON.

5.2 예제 2: SDRAM 초기화 및 액세스

// File: emif_sdram.c
// Description: TMS320F28377D EMIF1 SDRAM 초기화 및 액세스 예제 (TI 제공 함수, 데이터 핀 방향 EMIF 자동 제어, LED 제거, PCLKCR1 사용, 사용자 제공 extern 선언, F2837xD_emif.h 기반, DMA 제외, Micron MT48LC32M16A2 기준)
// Compiler: Code Composer Studio (TI C2000 Compiler 22.6.1.LTS)
// Target: TMS320F28377D


#include "F28x_Project.h"

// Defines
#define SDRAM_CS0_START_ADDR 0x80000000 // EMIF1 CS0 SDRAM 메모리 주소

// Globals
volatile Uint16 ErrCount = 0; // EMIF1 설정 오류 카운터

// 사용자 제공 extern 함수 선언 (SDRAM용)
extern void setup_emif1_pinmux_sdram_16bit(Uint16);
extern void Emif1Initialize();

// EMIF1 GPIO 설정 함수 (TI 제공 함수)
void SetupEmif1Gpio(void)
{
    EALLOW;
    setup_emif1_pinmux_sdram_16bit(GPIO_MUX_CPU1); // TI의 16비트 SDRAM EMIF1 핀 설정
    EDIS;
}

// EMIF1 SDRAM 설정 함수 (F2837xD_emif.h 기반, Micron MT48LC32M16A2 기준)
void SetupEmif1SDRAM(void)
{
    int i;
    EALLOW;
    Emif1Initialize(); // EMIF1 모듈 초기화 (소프트 리셋)
    
    // SDRAM 제어 레지스터 설정
    Emif1Regs.SDRAM_CR.bit.PAGESIGE = 2; // 1024워드 페이지 (10비트 컬럼 주소)
    Emif1Regs.SDRAM_CR.bit.IBANK = 2; // 4 내부 뱅크
    Emif1Regs.SDRAM_CR.bit.CL = 3; // CAS 지연 3
    Emif1Regs.SDRAM_CR.bit.NM = 1; // 16비트 모드
    Emif1Regs.SDRAM_CR.bit.BIT_11_9_LOCK = 1; // CL 쓰기 허용
    Emif1Regs.SDRAM_CR.bit.PDWR = 0; // Power Down 리프레시 비활성화
    Emif1Regs.SDRAM_CR.bit.PD = 0; // Power Down 비활성화
    Emif1Regs.SDRAM_CR.bit.SR = 0; // Self Refresh 비활성화

    // SDRAM 타이밍 설정 (100MHz EMIF1CLK 기준, Micron MT48LC32M16A2)
    Emif1Regs.SDRAM_TR.bit.T_RFC = 6; // 자동 리프레시 주기 (60ns)
    Emif1Regs.SDRAM_TR.bit.T_RP = 1; // 로우 프리차지 (18ns)
    Emif1Regs.SDRAM_TR.bit.T_RCD = 1; // 로우 활성화에서 컬럼 액세스 (18ns)
    Emif1Regs.SDRAM_TR.bit.T_WR = 1; // 쓰기 복구 (1CLK+6ns)
    Emif1Regs.SDRAM_TR.bit.T_RAS = 4; // 로우 활성화 (42ns)
    Emif1Regs.SDRAM_TR.bit.T_RC = 6; // 로우 사이클 (60ns)
    Emif1Regs.SDRAM_TR.bit.T_RRD = 1; // 다른 뱅크 간 활성화 타이밍 (12ns)

    // SDRAM Self Refresh Exit 타이밍
    Emif1Regs.SDR_EXT_TMNG.bit.T_XS = 7; // Self Refresh exit (70ns)

    // SDRAM 리프레시 주기 설정
    Emif1Regs.SDRAM_RCR.bit.REFRESH_RATE = 0x30E; // 7.81us 리프레시 주기 (100MHz 기준)

    // 추가 지연
    for(i = 0; i < 123; i++) { }
    EDIS;
}

void main(void)
{
    // 에러 체크를 위한 플래그
    volatile Uint16 error_flag = 0;

    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭 및 PLL 초기화 (SYSCLK 200MHz 설정)
    
    // 인터럽트 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable(); // PIE 벡터 테이블 초기화
    
    // EMIF1 클럭 활성화 및 분주 설정
    EALLOW;
    CpuSysRegs.PCLKCR1.bit.EMIF1 = 1; // EMIF1 모듈 클럭 활성화
    ClkCfgRegs.PERCLKDIVSEL.bit.EMIF1CLKDIV = 0x1; // EMIF1CLK = CPU1SYSCLK/2 (100MHz)
    asm(" NOP"); // 클럭 안정화 대기
    EDIS;

    // EMIF1 소유권 및 보호 설정
    EALLOW;
    Emif1ConfigRegs.EMIF1MSEL.all = 0x93A5CE71; // CPU1이 EMIF1 소유
    if(Emif1ConfigRegs.EMIF1MSEL.all != 0x1)
    {
        ErrCount++;
    }
    Emif1ConfigRegs.EMIF1ACCPROT0.all = 0x0; // CPU_FETCH/CPU_WR/DMA_WR 접근 보호 비활성화
    if(Emif1ConfigRegs.EMIF1ACCPROT0.all != 0x0)
    {
        ErrCount++;
    }
    Emif1ConfigRegs.EMIF1COMMIT.all = 0x1; // 보호 설정 커밋
    if(Emif1ConfigRegs.EMIF1COMMIT.all != 0x1)
    {
        ErrCount++;
    }
    Emif1ConfigRegs.EMIF1LOCK.all = 0x1; // 설정 잠금
    if(Emif1ConfigRegs.EMIF1LOCK.all != 0x1)
    {
        ErrCount++;
    }
    EDIS;

    // GPIO 및 SDRAM 설정
    InitGpio(); // 기본 GPIO 초기화
    SetupEmif1Gpio(); // EMIF1 GPIO 설정 (TI 함수)
    SetupEmif1SDRAM(); // EMIF1 SDRAM 설정

    // 인터럽트 활성화
    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    // 메모리 테스트
    volatile Uint16 *sdram = (volatile Uint16 *)SDRAM_CS0_START_ADDR;
    sdram[0] = 0xABCD; // 데이터 쓰기
    asm(" RPT #100 || NOP"); // 쓰기 후 안정화 대기
    
    Uint16 read_data = sdram[0]; // 데이터 읽기
    
    // 데이터 검증
    if(read_data != 0xABCD)
    {
        error_flag = 1; // 읽기 데이터 불일치
    }
    if(ErrCount != 0)
    {
        error_flag = 1; // EMIF1 설정 오류
    }
    
    for(;;); // 무한 루프
}

설명:

  • 기능: EMIF1을 통해 SDRAM 초기화 및 데이터 쓰기/읽기, EM1BA[1:0]로 뱅크 선택.
  • 설정: 512워드 페이지, 4뱅크, CAS 지연 3, 타이밍 파라미터 설정, 7.81us 리프레시 주기.
  • GPIO:
    • SDRAM 제어: EM1SDCE (GPIO32), EM1CAS (GPIO33), EM1RAS (GPIO35)
    • 뱅크 주소: EM1BA0 (GPIO36), EM1BA1 (GPIO37)
    • 데이터: EM1D0~15(GPIO40~47,GPIO64~71)
    • 주소: EM1A0~11(GPIO58~63,GPIO72~77)
    • 제어: EM1WE (GPIO56), EM1OE (GPIO57)
    • LED: GPIO31
  • 출력: SDRAM_BASE(0x08000000)에 0xABCD 쓰기 및 읽기, 정상 동작 시 LED ON.

5.3 예제 3: EMIF2 NOR Flash 읽기


// File: emif_nor_flash.c
// Description: TMS320F28377D EMIF1 CS2를 사용한 비동기 NOR Flash (SST39VF3201B) 프로그래밍 예제
// - 16비트 비동기 모드, GPIO_SetupPinOptions로 핀 설정, F2837xD_emif.h 기준 오류 수정
// - SST39VF3201B: 32Mbit (2M x 16비트), tWC/tRC=70ns, 섹터 지우기 40ms, 워드 쓰기 20us
// Compiler: Code Composer Studio (TI C2000 Compiler 22.6.1.LTS)
// Target: TMS320F28377D
// References: TRM (SPRUHM8 Rev. I), C2000Ware 6.00.00.00, SST39VF3201B 데이터시트, E2E 포럼

#include "F28x_Project.h"

// 외부 함수 선언 (C2000Ware F2837xD_Emif.c 제공)
// - setup_emif1_pinmux_async_16bit: EMIF1 핀을 16비트 비동기 모드로 MUX 설정 (GPIO MUX=2)
// - Emif1Initialize: EMIF1 모듈 소프트 리셋
// - ASync_cs2_config: EMIF1 CS2 비동기 타이밍 설정 (ASIZE, TA, R_STROBE 등)
extern void setup_emif1_pinmux_async_16bit(Uint16);
extern void Emif1Initialize();
extern void ASync_cs2_config(Uint16 inst, Uint16 async_mem_data_width,
                             Uint16 turn_around_time, Uint16 r_hold_time,
                             Uint16 r_strobe_time, Uint16 r_setup, Uint16 w_hold,
                             Uint16 w_strobe, Uint16 w_setup, Uint16 extend_wait,
                             Uint16 strobe_sel);

// 메모리 매핑 상수 (TRM Table 6-3 기준)
// - FLASH_BASE: EMIF1 CS2 메모리 시작 주소 (0x100000 ~ 0x2FFFFF, 2MB, 16비트)
#define FLASH_BASE 0x100000
// NOR Flash 명령어 주소 (SST39VF3201B 데이터시트, Word 주소 기준)
// - CMD_ADDR1: 0x5555 (0xAAAA 바이트 주소), CMD_ADDR2: 0x2AAA (0x5554 바이트 주소)
#define CMD_ADDR1 0x5555
#define CMD_ADDR2 0x2AAA

// EMIF1 GPIO 설정 함수
// - EMIF1 데이터 핀 (EM1D0~D15: GPIO40~47, 64~71)을 풀업 및 비동기 모드로 설정
// - setup_emif1_pinmux_async_16bit로 주소/제어 핀 (EM1A0~A19, EM1CS2, EM1WE, EM1OE 등) 자동 설정
void SetupEmif1Gpio(void)
{
    EALLOW;  // GPIO 레지스터 접근 허용 (TRM Section 8.7)

    // TI 제공 함수로 EMIF1 핀을 16비트 비동기 모드로 설정 (MUX=2)
    // - 설정: EM1D0~D15, EM1A0~A19, EM1CS2, EM1WE, EM1OE, EM1WAIT 등
    // - GPIO_MUX_CPU1: CPU1 소유 (듀얼 코어 고려)
    setup_emif1_pinmux_async_16bit(GPIO_MUX_CPU1);
    
    // 데이터 핀에 풀업 및 비동기 설정 (노이즈 방지, E2E 권장)
    // - EM1D0~D7 (GPIO40~47), EM1D8~D15 (GPIO64~71)
    // - GPIO_SetupPinOptions(pin, direction, flags): 방향과 풀업/비동기 설정
    // - GPIO_INPUT: EMIF가 데이터 핀 방향을 자동 제어 (읽기/쓰기 시 bidirectional)
    // - GPIO_PULLUP: 내부 10kΩ 풀업 활성화 (외부 저항 생략 가능)
    // - GPIO_ASYNC: 비동기 모드로 EMIF 타이밍 최적화
    Uint16 i;
    for (i = 40; i <= 47; i++) {  // EM1D0~D7
        GPIO_SetupPinOptions(i, GPIO_INPUT, GPIO_PULLUP | GPIO_ASYNC);
    }
    for (i = 64; i <= 71; i++) {  // EM1D8~D15
        GPIO_SetupPinOptions(i, GPIO_INPUT, GPIO_PULLUP | GPIO_ASYNC);
    }
    
    EDIS;  // GPIO 레지스터 접근 비활성화
}

// EMIF1 CS2 설정 함수
// - EMIF1 모듈 초기화, 보호 설정, 클럭 분주, 비동기 타이밍, 인터럽트 설정
// - SST39VF3201B 타이밍 (tWC/tRC=70ns) 충족
void SetupEmif1CS2(void)
{
    EALLOW;  // EMIF 및 클럭 레지스터 접근 허용 (TRM Section 7.3.3, 25.5)

    // EMIF1 모듈 초기화 (소프트 리셋, TRM Section 25.3.1)
    // - Emif1Regs.RCSR.bit.SR = 1 설정 후 클리어
    Emif1Initialize();
    
    // EMIF 보호 설정 (TI 예제, E2E 권장)
    // - EMIF1ACCPROT0=0: 접근 보호 해제 (CPU1/CPU2/CMA)
    // - EMIF1COMMIT=1: 설정 커밋
    // - EMIF1LOCK=1: 레지스터 잠금 (변경 방지)
    Emif1ConfigRegs.EMIF1ACCPROT0.all = 0x0;
    Emif1ConfigRegs.EMIF1COMMIT.all = 0x1;
    Emif1ConfigRegs.EMIF1LOCK.all = 0x1;
    
    // 클럭 분주 (TRM Section 7.3.2)
    // - EMIFCLK = SYSCLK / 2 = 200MHz / 2 = 100MHz (1사이클=10ns)
    // - SST39VF3201B tWC/tRC=70ns 충족 위해 느슨한 타이밍 사용
    ClkCfgRegs.PERCLKDIVSEL.bit.EMIF1CLKDIV = 1;
    
    // CS2 비동기 타이밍 설정 (헤더 ASYNC_CS2_CR_BITS 기준)
    // - inst=0: EMIF1
    // - async_mem_data_width=1: 16비트 (ASIZE=1)
    // - turn_around_time=2: TA=2사이클 (20ns)
    // - r_hold_time=2, r_strobe_time=6, r_setup=2: 읽기 10사이클 (100ns)
    // - w_hold=2, w_strobe=6, w_setup=2: 쓰기 10사이클 (100ns)
    // - extend_wait=0: Extended Wait 비활성 (EM1WAIT 미사용)
    // - strobe_sel=0: Normal Mode (Select Strobe 비활성)
    // - 총 타이밍: (Setup+Strobe+Hold) * 10ns = 100ns > 70ns, 안전
    ASync_cs2_config(0, 1, 2, 2, 6, 2, 2, 6, 2, 0, 0);
    
    // EMIF 인터럽트 마스크 활성화 (헤더 INT_MSK_SET_BITS 기준)
    // - AT_MASK_SET=1: Asynchronous Timeout 인터럽트 활성화
    // - 타임아웃 발생 시 INT_RAW.bit.AT=1 설정
    Emif1Regs.INT_MSK_SET.bit.AT_MASK_SET = 1;
    
    EDIS;  // 레지스터 접근 비활성화
}

// NOR Flash 명령어 쓰기
// - addr: Word 주소 (예: 0x5555, 0x2AAA)
// - data: 명령어 데이터 (예: 0xAA, 0x55)
// - DELAY_US(1): tWC=70ns 이상 보장 (1000ns 지연)
void FlashWriteCmd(Uint16 addr, Uint16 data)
{
    volatile Uint16 *flash = (volatile Uint16 *)(FLASH_BASE + addr);  // 주소 계산
    *flash = data;  // 명령어 쓰기
    DELAY_US(1);    // 쓰기 사이클 시간 (SST39VF3201B tWC=70ns)
}

// NOR Flash 단일 워드 프로그래밍
// - addr: Word 단위 오프셋 (0x0000 ~ 0x1FFFFF 내)
// - data: 16비트 데이터 (예: 0x1234)
// - SST39VF3201B 명령어 시퀀스: 0x5555/0xAA, 0x2AAA/0x55, 0x5555/0xA0, addr/data
// - Data# Polling (DQ7)으로 쓰기 완료 확인 (tBP=20us 이내)
void FlashProgramWord(Uint32 addr, Uint16 data)
{
    EALLOW;  // 메모리 접근 허용
    
    // 명령어 시퀀스 (SST39VF3201B 데이터시트, Table 8)
    FlashWriteCmd(CMD_ADDR1, 0xAA);   // Cycle 1: 0x5555 <- 0xAA
    FlashWriteCmd(CMD_ADDR2, 0x55);   // Cycle 2: 0x2AAA <- 0x55
    FlashWriteCmd(CMD_ADDR1, 0xA0);   // Cycle 3: 0x5555 <- 0xA0 (Program)
    volatile Uint16 *flash = (volatile Uint16 *)(FLASH_BASE + addr);
    *flash = data;  // 데이터 쓰기
    
    // Data# Polling (DQ7): 쓰기 완료 시 DQ7 == data의 DQ7
    // - *flash & 0x0080: DQ7 비트 추출
    // - tBP=20us 이내 완료, 1us 간격 폴링
    while ((*flash & 0x0080) != (data & 0x0080)) {
        DELAY_US(1);
    }
    
    EDIS;
}

// NOR Flash 섹터 지우기 (64KB 섹터)
// - sector_addr: 섹터 시작 주소 (64KB 정렬, e.g., 0x0000, 0x10000)
// - SST39VF3201B 6바이트 명령어: 0x5555/0xAA, 0x2AAA/0x55, 0x5555/0x80, ...
// - Data# Polling (DQ7=1)으로 지우기 완료 확인 (tSE=40ms 이내)
void FlashEraseSector(Uint32 sector_addr)
{
    EALLOW;  // 메모리 접근 허용
    
    // 명령어 시퀀스 (SST39VF3201B 데이터시트, Table 8)
    FlashWriteCmd(CMD_ADDR1, 0xAA);   // Cycle 1: 0x5555 <- 0xAA
    FlashWriteCmd(CMD_ADDR2, 0x55);   // Cycle 2: 0x2AAA <- 0x55
    FlashWriteCmd(CMD_ADDR1, 0x80);   // Cycle 3: 0x5555 <- 0x80
    FlashWriteCmd(CMD_ADDR1, 0xAA);   // Cycle 4: 0x5555 <- 0xAA
    FlashWriteCmd(CMD_ADDR2, 0x55);   // Cycle 5: 0x2AAA <- 0x55
    volatile Uint16 *flash = (volatile Uint16 *)(FLASH_BASE + sector_addr);
    *flash = 0x30;  // Cycle 6: 섹터 주소 <- 0x30 (Erase)
    
    // Data# Polling (DQ7=1): 지우기 완료 시 DQ7=1 (0xFFFF 상태)
    // - tSE=40ms 이내 완료, 100us 간격 폴링
    while ((*flash & 0x0080) != 0x0080) {
        DELAY_US(100);
    }
    
    EDIS;
}

// NOR Flash 읽기 검증
// - addr: Word 단위 오프셋
// - 일반 메모리 읽기 (CS2n low, OEn low, tRC=70ns)
Uint16 FlashRead(Uint32 addr)
{
    volatile Uint16 *flash = (volatile Uint16 *)(FLASH_BASE + addr);
    return *flash;  // 16비트 데이터 읽기
}

void main(void)
{
    // 에러 플래그: 읽기/쓰기 불일치 또는 EMIF 타임아웃 시 1
    volatile Uint16 error_flag = 0;
    // 테스트 데이터: 임의의 16비트 값
    volatile Uint16 test_data = 0x1234;
    // 테스트 주소: 첫 번째 섹터 내 오프셋 (64KB 내 0x1000)
    volatile Uint32 test_addr = 0x1000;

    // 시스템 초기화 (C2000Ware F2837xD_SysCtrl.c)
    // - SYSCLK=200MHz, PLL 설정, 주변장치 클럭 초기화
    InitSysCtrl();
    
    // GPIO 초기화 (F2837xD_Gpio.c)
    // - 모든 GPIO 기본 상태로 초기화 (PUD 활성화 등)
    InitGpio();
    // EMIF1 GPIO 설정: 데이터 핀 풀업 및 비동기
    SetupEmif1Gpio();
    // EMIF1 CS2 설정: 타이밍, 보호, 인터럽트
    SetupEmif1CS2();
    
    // 인터럽트 초기화 (F2837xD_PieCtrl.c)
    // - 모든 인터럽트 비활성화 및 플래그 클리어
    // - PIE 벡터 테이블 초기화 (EMIF 인터럽트 미사용, 폴링 방식)
    DINT;                    // 글로벌 인터럽트 비활성화
    InitPieCtrl();           // PIE 컨트롤러 초기화
    IER = 0x0000;            // CPU 인터럽트 비활성화
    IFR = 0x0000;            // 대기 인터럽트 플래그 클리어
    InitPieVectTable();      // PIE 벡터 테이블 초기화
    
    // EMIF1 클럭 활성화 (TRM Section 7.3.3)
    // - PCLKCR1.bit.EMIF1=1: EMIF1 모듈 클럭 활성화
    // - NOP: 클럭 안정화 대기
    EALLOW;
    CpuSysRegs.PCLKCR1.bit.EMIF1 = 1;
    asm(" NOP");
    EDIS;
    
    // 인터럽트 활성화 (폴링 방식이므로 무해)
    EINT;  // 글로벌 인터럽트 활성화
    ERTM;  // 실시간 모드 활성화
    
    // NOR Flash 테스트
    // 1. 섹터 지우기
    // - test_addr & 0xFFFF0000: 64KB 섹터 시작 주소 (예: 0x0000)
    // - 지우기 후 모든 데이터 0xFFFF 상태
    FlashEraseSector(test_addr & 0xFFFF0000);
    
    // 2. 워드 프로그래밍
    // - test_addr에 test_data(0x1234) 쓰기
    FlashProgramWord(test_addr, test_data);
    
    // 3. 데이터 검증
    // - 읽기 데이터와 test_data 비교
    Uint16 read_data = FlashRead(test_addr);
    if (read_data != test_data) {
        error_flag = 1;  // 읽기 데이터 불일치
    }
    
    // EMIF 오류 확인 (헤더 F2837xD_emif.h 기준)
    // - INT_RAW.bit.AT: Asynchronous Timeout 발생 시 1
    // - 읽기 시 자동 클리어 (TRM Section 25.5.10)
    // - 디버깅: INT_MSK.bit.AT_MASKED로 마스크 상태 확인 가능
    if (Emif1Regs.INT_RAW.bit.AT == 1) {
        error_flag = 1;  // EMIF 타임아웃 오류
    }
    
    // 무한 루프: 디버깅 시 error_flag 확인 (CCS Watch 창)
    // - 오실로스코프: CS2n, WEn, OEn 신호 점검
    // - Memory Browser: 0x100000+0x1000 = 0x1234 확인
    for(;;);
}

설명:

  • 기능: EMIF2 CS0를 통해 NOR Flash에서 데이터 읽기.
  • 설정: 16비트 데이터 버스, 읽기/쓰기 타이밍 설정(NOR Flash에 적합), CS0 활성화.
  • GPIO:
    • 칩 선택: EM2CS0 (GPIO28)
    • 데이터: EM1D0~15(GPIO40~47,GPIO64~71)
    • 주소: EM1A0~11(GPIO58~63,GPIO72~77)
    • 제어: EM2WE (GPIO30), EM2OE (GPIO31)
  • LED: GPIO31
  • 출력: NOR_BASE(0x00100000)에서 데이터 읽기, 정상 동작 시 LED ON.

5.4 예제 4: EMIF1 DMA 데이터 전송

// File: emif_sdram_dma.c
// Description: TMS320F28377D EMIF1 SDRAM 초기화 및 DMA 데이터 전송 예제 (TI 제공 함수, 데이터 핀 방향 EMIF 자동 제어, LED 제거, PCLKCR1 사용, 사용자 제공 extern 선언, F2837xD_emif.h 기반, Micron MT48LC32M16A2 기준)
// Compiler: Code Composer Studio (TI C2000 Compiler 22.6.1.LTS)
// Target: TMS320F28377D


#include "F28x_Project.h"

// Defines
#define TEST_PASS            0xABCDABCD
#define TEST_FAIL            0xDEADDEAD
#define SDRAM_CS0_START_ADDR 0x80000000 // EMIF1 CS0 SDRAM 메모리 주소
#define MEM_BUFFER_SIZE      1024       // 32-Bit Word

// Globals
#pragma DATA_SECTION(g_ulSrcBuf0, "ramgs0");
#pragma DATA_SECTION(g_ulDstBuf1, "ramgs1");
Uint32 g_ulSrcBuf0[MEM_BUFFER_SIZE];
Uint32 g_ulDstBuf1[MEM_BUFFER_SIZE];
__attribute__((far)) volatile Uint32 g_ulSDRAMBuf[MEM_BUFFER_SIZE]; // Far memory for SDRAM
volatile Uint32 InitData = 0;
volatile Uint32 *DMADest;
volatile Uint32 *DMASource;
volatile Uint16 ErrCount = 0;
Uint32 TEST_STATUS;

// 사용자 제공 extern 함수 선언 (SDRAM용)
extern void setup_emif1_pinmux_sdram_16bit(Uint16);
extern void Emif1Initialize();

// DMA_DstDataClear - Clear local and far memory buffers
void DMA_DstDataClear(void)
{
    int i;
    for(i = 0; i < MEM_BUFFER_SIZE; i++)
    {
        __addr32_write_uint32(((Uint32)g_ulSDRAMBuf + (i*2)), 0x0);
    }
    for(i = 0; i < MEM_BUFFER_SIZE; i++)
    {
        g_ulDstBuf1[i] = 0x0;
    }
}

// EMIF1 GPIO 설정 함수 (TI 제공 함수)
void SetupEmif1Gpio(void)
{
    EALLOW;
    setup_emif1_pinmux_sdram_16bit(GPIO_MUX_CPU1); // TI의 16비트 SDRAM EMIF1 핀 설정
    EDIS;
}

// EMIF1 SDRAM 설정 함수 (F2837xD_emif.h 기반, Micron MT48LC32M16A2 기준)
void SetupEmif1SDRAM(void)
{
    int i;
    EALLOW;
    Emif1Initialize(); // EMIF1 모듈 초기화 (소프트 리셋)
    
    // SDRAM 제어 레지스터 설정
    Emif1Regs.SDRAM_CR.bit.PAGESIGE = 2; // 1024워드 페이지 (10비트 컬럼 주소)
    Emif1Regs.SDRAM_CR.bit.IBANK = 2; // 4 내부 뱅크
    Emif1Regs.SDRAM_CR.bit.CL = 3; // CAS 지연 3
    Emif1Regs.SDRAM_CR.bit.NM = 1; // 16비트 모드
    Emif1Regs.SDRAM_CR.bit.BIT_11_9_LOCK = 1; // CL 쓰기 허용
    Emif1Regs.SDRAM_CR.bit.PDWR = 0; // Power Down 리프레시 비활성화
    Emif1Regs.SDRAM_CR.bit.PD = 0; // Power Down 비활성화
    Emif1Regs.SDRAM_CR.bit.SR = 0; // Self Refresh 비활성화

    // SDRAM 타이밍 설정 (100MHz EMIF1CLK 기준, Micron MT48LC32M16A2)
    Emif1Regs.SDRAM_TR.bit.T_RFC = 6; // 자동 리프레시 주기 (60ns)
    Emif1Regs.SDRAM_TR.bit.T_RP = 1; // 로우 프리차지 (18ns)
    Emif1Regs.SDRAM_TR.bit.T_RCD = 1; // 로우 활성화에서 컬럼 액세스 (18ns)
    Emif1Regs.SDRAM_TR.bit.T_WR = 1; // 쓰기 복구 (1CLK+6ns)
    Emif1Regs.SDRAM_TR.bit.T_RAS = 4; // 로우 활성화 (42ns)
    Emif1Regs.SDRAM_TR.bit.T_RC = 6; // 로우 사이클 (60ns)
    Emif1Regs.SDRAM_TR.bit.T_RRD = 1; // 다른 뱅크 간 활성화 타이밍 (12ns)

    // SDRAM Self Refresh Exit 타이밍
    Emif1Regs.SDR_EXT_TMNG.bit.T_XS = 7; // Self Refresh exit (70ns)

    // SDRAM 리프레시 주기 설정
    Emif1Regs.SDRAM_RCR.bit.REFRESH_RATE = 0x30E; // 7.81us 리프레시 주기 (100MHz 기준)

    // 추가 지연
    for(i = 0; i < 123; i++) { }
    EDIS;
}

void main(void)
{
    int i;
    TEST_STATUS = TEST_FAIL;

    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭 및 PLL 초기화 (SYSCLK 200MHz 설정)
    
    // 인터럽트 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable(); // PIE 벡터 테이블 초기화
    
    // EMIF1 클럭 활성화 및 분주 설정
    EALLOW;
    CpuSysRegs.PCLKCR1.bit.EMIF1 = 1; // EMIF1 모듈 클럭 활성화
    ClkCfgRegs.PERCLKDIVSEL.bit.EMIF1CLKDIV = 0x1; // EMIF1CLK = CPU1SYSCLK/2 (100MHz)
    CpuSysRegs.PCLKCR0.bit.DMA = 1; // DMA 클럭 활성화
    asm(" NOP"); // 클럭 안정화 대기
    EDIS;

    // EMIF1 소유권 및 보호 설정
    EALLOW;
    Emif1ConfigRegs.EMIF1MSEL.all = 0x93A5CE71; // CPU1이 EMIF1 소유
    if(Emif1ConfigRegs.EMIF1MSEL.all != 0x1)
    {
        ErrCount++;
    }
    Emif1ConfigRegs.EMIF1ACCPROT0.all = 0x0; // CPU_FETCH/CPU_WR/DMA_WR 접근 보호 비활성화
    if(Emif1ConfigRegs.EMIF1ACCPROT0.all != 0x0)
    {
        ErrCount++;
    }
    Emif1ConfigRegs.EMIF1COMMIT.all = 0x1; // 보호 설정 커밋
    if(Emif1ConfigRegs.EMIF1COMMIT.all != 0x1)
    {
        ErrCount++;
    }
    Emif1ConfigRegs.EMIF1LOCK.all = 0x1; // 설정 잠금
    if(Emif1ConfigRegs.EMIF1LOCK.all != 0x1)
    {
        ErrCount++;
    }
    EDIS;

    // GPIO 및 SDRAM 설정
    InitGpio(); // 기본 GPIO 초기화
    SetupEmif1Gpio(); // EMIF1 GPIO 설정 (TI 함수)
    SetupEmif1SDRAM(); // EMIF1 SDRAM 설정

    // 인터럽트 활성화
    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    // 소스 버퍼 초기화 (emif_dma.c의 패턴 사용)
    for(i = 0; i < MEM_BUFFER_SIZE; i++)
    {
        g_ulSrcBuf0[i] = 0x1111 + (i % 16) * 0x1111; // 0x1111, 0x2222, ..., 0xFFFF, 0x0000 패턴 반복
    }

    // DMA 초기화
    DMAInitialize();

    // DMA 채널 1 설정 (16비트, 내부 메모리 -> SDRAM)
    DMADest = g_ulSDRAMBuf;
    DMASource = (volatile Uint32 *)g_ulSrcBuf0;
    DMACH1AddrConfig32bit(DMADest, DMASource);
    DMACH1BurstConfig(31, 1, 1);
    DMACH1TransferConfig(((MEM_BUFFER_SIZE*2/32) - 1), 1, 1);
    DMACH1WrapConfig(0xFFFF, 0, 0xFFFF, 0);
    DMACH1ModeConfig(0x0, PERINT_ENABLE, ONESHOT_ENABLE, CONT_DISABLE, SYNC_DISABLE, SYNC_SRC, OVRFLOW_DISABLE, SIXTEEN_BIT, CHINT_END, CHINT_ENABLE);

    // DMA 채널 2 설정 (32비트, SDRAM -> 내부 메모리)
    DMADest = (volatile Uint32 *)g_ulDstBuf1;
    DMASource = g_ulSDRAMBuf;
    DMACH2AddrConfig32bit(DMADest, DMASource);
    DMACH2BurstConfig(31, 2, 2);
    DMACH2TransferConfig(((MEM_BUFFER_SIZE*2/32) - 1), 2, 2);
    DMACH2WrapConfig(0xFFFF, 0, 0xFFFF, 0);
    DMACH2ModeConfig(0x0, PERINT_ENABLE, ONESHOT_ENABLE, CONT_DISABLE, SYNC_DISABLE, SYNC_SRC, OVRFLOW_DISABLE, THIRTYTWO_BIT, CHINT_END, CHINT_ENABLE);

    // 메모리 버퍼 초기화
    DMA_DstDataClear();

    // DMA 쓰기 시작
    EALLOW;
    DmaRegs.CH1.CONTROL.bit.PERINTFRC = 1;
    while(DmaRegs.CH1.CONTROL.bit.TRANSFERSTS != 1) {}
    while(DmaRegs.CH1.CONTROL.bit.TRANSFERSTS != 0) {}
    EDIS;

    // DMA 읽기 시작
    EALLOW;
    DmaRegs.CH2.CONTROL.bit.PERINTFRC = 1;
    while(DmaRegs.CH2.CONTROL.bit.TRANSFERSTS != 1) {}
    while(DmaRegs.CH2.CONTROL.bit.TRANSFERSTS != 0) {}
    EDIS;

    // 데이터 검증
    for(i = 0; i < MEM_BUFFER_SIZE; i++)
    {
        if(g_ulSrcBuf0[i] != g_ulDstBuf1[i])
        {
            ErrCount++;
        }
    }

    // 테스트 결과 설정
    if(ErrCount == 0)
    {
        TEST_STATUS = TEST_PASS;
    }

    for(;;); // 무한 루프
}

설명:

  • 기능: EMIF1 CS2를 통해 내부 메모리에서 SRAM으로 DMA를 사용한 데이터 전송.
  • 설정: 16비트 데이터 버스, 읽기/쓰기 타이밍 설정, DMA 채널 1 설정(16워드 전송).
  • GPIO:
    • 칩 선택: EM2CS0 (GPIO28)
    • 데이터: EM1D0~15(GPIO40~47,GPIO64~71)
    • 주소: EM1A0~11(GPIO58~63,GPIO72~77)
    • 제어: EM2WE (GPIO30), EM2OE (GPIO31)
  •  
  • 출력: SRAM_BASE(0x08000000)에 internal_buffer 데이터 전송, 정상 동작 시 LED ON.

5.5 예제 5: 병렬 ADC 데이터 읽기

// File: emif_adc.c
// Description: TMS320F28377D EMIF 병렬 ADC 데이터 읽기 예제 (Bitfield 구조, TI 제공 함수 사용)
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28377D

#include "F28x_Project.h"

// 사용자 제공 extern 함수 선언 (CS3 버전으로 가정)
extern void setup_emif1_pinmux_async_16bit(Uint16);
extern void Emif1Initialize();
extern void ASync_cs3_config(Uint16 inst, Uint16 async_mem_data_width,
                             Uint16 turn_around_time, Uint16 r_hold_time,
                             Uint16 r_strobe_time, Uint16 r_setup, Uint16 w_hold,
                             Uint16 w_strobe, Uint16 w_setup, Uint16 extend_wait,
                             Uint16 strobe_sel);

#define ADC_BASE 0x300000 // EMIF1 CS3 메모리 주소 (TRM 기준)
#define ADC_CONTROL_ADDR (ADC_BASE + 0x2) // ADC 제어 레지스터 주소 (ADC 데이터시트 기준)

// EMIF1 GPIO 설정 함수 (TI 제공 함수 사용)
void SetupEmif1Gpio(void)
{
    EALLOW;
    setup_emif1_pinmux_async_16bit(GPIO_MUX_CPU1); // TI의 16비트 비동기 EMIF1 핀 설정
    EDIS;
}

// EMIF1 CS3 설정 함수 (TI 제공 함수 사용)
void SetupEmif1CS3(void)
{
    EALLOW;
    Emif1Initialize(); // EMIF1 모듈 초기화 (소프트 리셋)
    
    // EMIF 보호 설정 (TI 예제 참조)
    Emif1ConfigRegs.EMIF1ACCPROT0.all = 0x0;  // 접근 보호 해제
    Emif1ConfigRegs.EMIF1COMMIT.all = 0x1;    // 커밋
    Emif1ConfigRegs.EMIF1LOCK.all = 0x1;      // 잠금
    
    // CS3 타이밍 설정 (SRAM 예제 기반: 16비트, 느린 ADC용 느슨한 타이밍)
    ASync_cs3_config(0, 1, 2, 2, 6, 2, 2, 6, 2, 0, 0); // EMIF1, 16비트, TA=2, R_HOLD=2, R_STROBE=6, 등
    EDIS;
}

void main(void)
{
    // 에러 체크를 위한 플래그
    volatile Uint16 error_flag = 0;
    volatile Uint16 adc_data = 0;

    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭 및 PLL 초기화 (SYSCLK 200MHz 설정)

    // GPIO 초기화 및 설정
    InitGpio(); // 기본 GPIO 초기화
    SetupEmif1Gpio(); // EMIF1 GPIO 설정 (TI 함수)
    SetupEmif1CS3(); // EMIF1 CS3 설정 (TI 함수)

    // 인터럽트 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // EMIF1 클럭 활성화 (수정: PCLKCR1 사용)
    EALLOW;
    CpuSysRegs.PCLKCR1.bit.EMIF1 = 1; // EMIF1 모듈 클럭 활성화
    asm(" NOP"); // 클럭 안정화 대기
    EDIS;

    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    // ADC 초기화 (변환 시작)
    volatile Uint16 *adc_control = (volatile Uint16 *)ADC_CONTROL_ADDR;
    *adc_control = 0x0001; // 변환 시작 명령 (ADC 데이터시트 참조)

    // 지연 (ADC 변환 완료 대기, 데이터시트 기준)
    DELAY_US(10); // 10us 지연 (ADC 변환 시간으로 조정 필요)

    // ADC 데이터 읽기
    volatile Uint16 *adc = (volatile Uint16 *)ADC_BASE;
    adc_data = *adc; // 16비트 ADC 데이터 읽기

    // 데이터 검증 (예: 12-bit ADC 가정 시 0x0000 ~ 0x0FFF 범위, 16-bit 확장)
    if (adc_data == 0x0000 || adc_data == 0xFFFF || (adc_data & 0xF000) != 0x0000) {
        error_flag = 1; // 읽기 데이터 오류 (올 유효 범위 초과)
    }

    for(;;); // 무한 루프
}

설명:

  • 기능: EMIF1 CS3를 통해 병렬 16비트 ADC에서 데이터 읽기.
  • 설정: 16비트 데이터 버스, 빠른 읽기/쓰기 타이밍(ADC에 최적화), CS3 활성화.
  • GPIO:
    • 칩 선택: EM1CS3 (GPIO35)
    • 데이터: EM1D0~15(GPIO40~47,GPIO64~71)
    • 주소: EM1A0~11(GPIO58~63 , 제어 레지스터 접근용)
    • 제어: EM1WE (GPIO56, ADC 제어), EM1OE (GPIO57, 데이터 읽기)
    • LED: GPIO31
  • 출력: ADC_BASE(0x08010000)에서 변환된 데이터 읽기, 정상 동작 시 LED ON.
  • 참고: ADC 데이터시트에 따라 제어 명령(예: 변환 시작)과 타이밍 조정 필요.

5.6 예제 6: 병렬 DAC 데이터 쓰기

#include "F28x_Project.h"

// 사용자 제공 extern 함수 선언 (CS4 버전으로 가정)
extern void setup_emif1_pinmux_async_16bit(Uint16);
extern void Emif1Initialize();
extern void ASync_cs4_config(Uint16 inst, Uint16 async_mem_data_width,
                             Uint16 turn_around_time, Uint16 r_hold_time,
                             Uint16 r_strobe_time, Uint16 r_setup, Uint16 w_hold,
                             Uint16 w_strobe, Uint16 w_setup, Uint16 extend_wait,
                             Uint16 strobe_sel);

#define DAC_BASE 0x400000 // EMIF1 CS4 메모리 주소 (TRM 기준)
#define DAC_CONTROL_ADDR (DAC_BASE + 0x2) // DAC 제어 레지스터 주소 (DAC 데이터시트 기준)

// EMIF1 GPIO 설정 함수 (TI 제공 함수 사용)
void SetupEmif1Gpio(void)
{
    EALLOW;
    setup_emif1_pinmux_async_16bit(GPIO_MUX_CPU1); // TI의 16비트 비동기 EMIF1 핀 설정
    EDIS;
}

// EMIF1 CS4 설정 함수 (TI 제공 함수 사용)
void SetupEmif1CS4(void)
{
    EALLOW;
    Emif1Initialize(); // EMIF1 모듈 초기화 (소프트 리셋)
    
    // EMIF 보호 설정 (TI 예제 참조)
    Emif1ConfigRegs.EMIF1ACCPROT0.all = 0x0;  // 접근 보호 해제
    Emif1ConfigRegs.EMIF1COMMIT.all = 0x1;    // 커밋
    Emif1ConfigRegs.EMIF1LOCK.all = 0x1;      // 잠금
    
    // CS4 타이밍 설정 (SRAM 예제 기반: 16비트, 느린 DAC용 느슨한 타이밍)
    ASync_cs4_config(0, 1, 2, 2, 6, 2, 2, 6, 2, 0, 0); // EMIF1, 16비트, TA=2, R_HOLD=2, R_STROBE=6, 등
    EDIS;
}

void main(void)
{
    // 에러 체크를 위한 플래그
    volatile Uint16 error_flag = 0;
    volatile Uint16 dac_data = 0x7FFF; // DAC 중간 값 (예: 0V~3.3V 기준)

    // 시스템 초기화
    InitSysCtrl(); // 시스템 클럭 및 PLL 초기화 (SYSCLK 200MHz 설정)

    // GPIO 초기화 및 설정
    InitGpio(); // 기본 GPIO 초기화
    SetupEmif1Gpio(); // EMIF1 GPIO 설정 (TI 함수)
    SetupEmif1CS4(); // EMIF1 CS4 설정 (TI 함수)

    // 인터럽트 초기화
    DINT; // 모든 인터럽트 비활성화
    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // CPU 인터럽트 비활성화
    IFR = 0x0000; // 대기 중인 인터럽트 플래그 지우기
    InitPieVectTable(); // PIE 벡터 테이블 초기화

    // EMIF1 클럭 활성화 (수정: PCLKCR1 사용)
    EALLOW;
    CpuSysRegs.PCLKCR1.bit.EMIF1 = 1; // EMIF1 모듈 클럭 활성화
    asm(" NOP"); // 클럭 안정화 대기
    EDIS;

    EINT; // 글로벌 인터럽트 활성화
    ERTM; // 실시간 모드 활성화

    // DAC 데이터 쓰기
    volatile Uint16 *dac = (volatile Uint16 *)DAC_BASE;
    *dac = dac_data; // 16비트 DAC에 데이터 쓰기

    // DAC 출력 업데이트
    volatile Uint16 *dac_control = (volatile Uint16 *)DAC_CONTROL_ADDR;
    *dac_control = 0x0001; // 출력 업데이트 명령 (DAC 데이터시트 참조)

    // 지연 (DAC 출력 안정화 대기, 데이터시트 기준)
    DELAY_US(10); // 10us 지연 (DAC settling time으로 조정 필요)

    // 데이터 검증 (DAC가 읽기 지원 시, 예: DAC에 읽기 레지스터 있음 가정)
    volatile Uint16 read_data = *dac;
    if (read_data != dac_data) {
        error_flag = 1; // 쓰기 데이터 불일치
    }

    for(;;); // 무한 루프
}

설명:

  • 기능: EMIF1 CS4를 통해 병렬 16비트 DAC에 데이터 쓰기.
  • 설정: 16비트 데이터 버스, 빠른 쓰기 타이밍(DAC에 최적화), CS4 활성화.
  • GPIO:
    • 칩 선택: EM1CS4 (GPIO36)
    • 데이터: EM1D0~15(GPIO40~47,GPIO64~71) 
    • 주소: EM1A0~11(GPIO58~63 , 제어 레지스터 접근용)
    • 제어: EM1WE (GPIO56, 데이터 쓰기), EM1OE (GPIO57)
    • LED: GPIO31
  • 출력: DAC_BASE(0x08020000)에 0x7FFF 쓰기(중간 전압 출력), 정상 동작 시 LED ON.
  • 참고: DAC 데이터시트에 따라 제어 명령(예: 출력 업데이트)과 타이밍 조정 필요.

6. 사용 방법

6.1 환경 설정

  • C2000Ware 설치: C:\ti\c2000\C2000Ware_x_xx_xx_xx에서 라이브러리 다운로드.
  • CCS 프로젝트: TMS320F28377D 타겟으로 프로젝트 생성, F28x_Project.h 포함.
  • 링커 파일: device_support\f2837xd 폴더에서 링커 파일 추가.

6.2 코드 실행

  • 각 예제를 별도의 .c 파일로 저장하거나, main.c에 복사.
  • 원하는 예제만 실행되도록 다른 코드 주석 처리.

6.3 하드웨어 준비

  • 메모리/장치 연결: EMIF1 또는 EMIF2 핀에 SRAM, SDRAM, NOR Flash, ADC, DAC 연결. SDRAM의 경우 EMIF_BA[1:0] 핀 연결 필수.
  • 타이밍 확인: 메모리 또는 장치(ADC/DAC 포함) 데이터시트에 따라 타이밍 파라미터 조정.
  • LED: GPIO31에 LED 연결 (정상 동작 확인용).
  • 디버깅 도구: 오실로스코프 또는 로직 분석기로 신호 확인.

6.4 디버깅

  • CCS Expressions 창: Emif1Regs.ASYNC_CSx_CTRL, Emif1Regs.SDRAM_CR, Emif1Regs.SDRAM_TR, Emif2Regs.ASYNC_CS0_CTRL 확인.
  • 인터럽트 상태: Emif1Regs.INT_RAW로 인터럽트 플래그 점검.
  • 메모리/장치 테스트: 읽기/쓰기 데이터 일치 여부 확인.
  • 문제 해결:
    • 메모리/장치 액세스 실패: GPIO 설정(특히 EMIF_BA[1:0], ADC/DAC 제어), 타이밍 파라미터 확인.
    • 인터럽트 미발생: INT_EN, PIEIER12, IER 설정 확인.
    • DMA 전송 실패: DMA 설정(DMACH1AddrConfig, DMACH1BurstConfig) 확인.
    • SDRAM 뱅크 액세스 오류: SDRAM_CR.bit.BANK_SIZE, EMIF_BA[1:0] 핀 매핑 확인.
    • ADC/DAC 오류: 데이터시트 기반으로 제어 신호 및 타이밍 점검.

7. 추가 팁

  • 캘리브레이션: Device_cal() 호출로 클럭 보정.
  • 타이밍 최적화: 메모리 또는 장치(ADC/DAC 포함) 데이터시트 기반으로 최소 타이밍 설정.
  • EMIF_BA[1:0] 확인: SDRAM 사용 시 뱅크 선택이 올바르게 매핑되었는지 확인 (예: GPIO36, GPIO37 for EM1BA[1:0]).
  • ADC/DAC 설정: 장치별 데이터시트를 참조하여 제어 레지스터 명령 및 타이밍 최적화.
  • C2000Ware 참고: C:\ti\c2000\C2000Ware_x_xx_xx_xx\device_support\f2837xd\examples\cpu1\emif.
  • 문제 해결:
    • 데이터 오류: ASIZE, PAGE_SIZE, BANK_SIZE, EMIF_BA[1:0], ADC/DAC 설정 확인.
    • SDRAM 초기화 실패: SDRAM_RCR, 타이밍 설정, EMIF_BA[1:0] 핀 점검.
    • ADC/DAC 동작 실패: EMIF 타이밍 및 제어 신호(EMxWE, EMxOE) 점검.
  • TI 리소스: TI E2E 포럼, C2000Ware 예제.

8. 결론

이 문서는 TMS320F28377D EMIF 모듈의 설정 방법과 Bitfield 구조를 활용한 예제 코드를 제공하여, 초보자부터 숙련된 개발자까지 쉽게 활용할 수 있도록 구성했습니다. 비동기 SRAM 읽기/쓰기, SDRAM 초기화(EMIF_BA[1:0] 포함), 인터럽트 기반 데이터 전송, NOR Flash 읽기, DMA 데이터 전송, 병렬 ADC 데이터 읽기, 병렬 DAC 데이터 쓰기 예제를 통해 다양한 애플리케이션에 적용 가능합니다.

키워드: TMS320F28377D, EMIF, C2000, SRAM, SDRAM, NOR Flash, ADC, DAC, 비동기 메모리, 동기 메모리, DMA, EMIF_BA, 마이크로컨트롤러, Code Composer Studio, 인터럽트, 타이밍 설정, 메모리 매핑