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
- EMIF1:
- 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 모듈을 효과적으로 설정하려면 다음 단계를 따라야 합니다:
- 시스템 초기화:
- InitSysCtrl()를 호출하여 시스템 클럭과 PLL을 초기화합니다.
- 인터럽트를 비활성화하고 PIE(Peripheral Interrupt Expansion)를 초기화합니다 (DINT, InitPieCtrl, InitPieVectTable).
- EMIF 클럭 활성화:
- CpuSysRegs.PCLKCR1.bit.EMIF1 또는 CpuSysRegs.PCLKCR1.bit.EMIF2를 설정하여 EMIF 모듈 클럭 활성화.
- 보호된 레지스터 접근을 위해 EALLOW와 EDIS 사용.
- GPIO 설정:
- EMIF 핀을 적절한 기능(EMIF1/EMIF2)으로 설정 (예: GpioCtrlRegs.GPAMUXx.bit.GPIOx).
- 데이터, 주소, 제어 신호, 그리고 SDRAM 사용 시 EMIF_BA[1:0] 핀을 모두 매핑.
- 병렬 ADC/DAC의 경우, 칩 선택(CS)과 읽기/쓰기 신호(EMxWE, EMxOE)를 활용하여 데이터 전송 제어.
- 비동기 메모리 또는 장치 설정 (SRAM/NOR Flash/ADC/DAC):
- ASYNC_CSx_CTRL로 칩 선택 활성화 및 타이밍 설정.
- 읽기/쓰기 타이밍 파라미터(W_SETUP, W_STROBE, R_SETUP, R_STROBE 등) 설정.
- SDRAM 설정 (필요 시):
- SDRAM_CR로 SDRAM 활성화, 뱅크 크기(EMIF_BA[1:0]와 연계), 페이지 크기, CAS 지연 설정.
- SDRAM_TR로 타이밍 파라미터 설정.
- 초기화 시퀀스 수행 (예: 리프레시 주기 설정).
- 모듈 실행:
- 메모리 또는 장치 테스트를 통해 설정 확인.
- 외부 메모리 읽기/쓰기 또는 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개의 실용적인 예제 코드입니다.
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, 인터럽트, 타이밍 설정, 메모리 매핑
'MCU > C2000' 카테고리의 다른 글
TMS320F28377D DSP ePWM CMPASS 사용법: Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.18 |
---|---|
TMS320F28377D DSP SPI 사용법 : Bitfield 구조 활용 예제 코드(수정) (2) | 2025.08.18 |
TMS320F28377D DSP DMA 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.18 |
TMS320F28377D DSP CAN 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.18 |
TMS320F28377D DSP eCAP 사용법 : Bitfield 구조 활용 예제 코드(수정) (1) | 2025.08.17 |
TMS320F28377D DSP eQEP 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.17 |
TMS320F28377D DSP ePWM 사용법 : Bitfield 구조 활용 예제 코드(수정) (1) | 2025.08.17 |
TMS320F28388D DSP DMA 사용법: DriverLib API로 DMA 설정 및 코드(수정) (1) | 2025.08.17 |