이 문서에서는 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(External Memory Interface) 모듈을 제어하기 위해 자주 사용되는 DriverLib API 함수와 그 사용 방법입니다. C2000Ware v6.00.00.00 기반으로 작성되었으며, 비동기 및 동기(SDRAM) 모드, DMA 연동, 인터럽트 처리를 포함합니다. 예제는 Micron MT48LC32M16A2 SDRAM과 emif_sdram_dma.c를 기준으로 합니다.
참고 자료:
- TMS320F2838x 기술 참조 매뉴얼 (TRM) 섹션 15 (EMIF), 섹션 14 (DMA)
- C2000Ware v6.00.00.00 DriverLib 문서 (emif.h, dma.h, sysctl.h)
- Micron MT48LC32M16A2 데이터시트 (타이밍 및 메모리 구성)
2.1. EMIF 기본 설정 관련 함수
- EMIF_setAsyncDataBusWidth(base, cs, width)
- 설명: 비동기 모드에서 데이터 버스 폭을 설정 (8/16/32비트).
- 매개변수:
- base: EMIF1/2 베이스 주소 (EMIF1_BASE, EMIF2_BASE).
- cs: 칩 선택 (EMIF_ASYNC_CS0, EMIF_ASYNC_CS2, EMIF_ASYNC_CS3, EMIF_ASYNC_CS4).
- width: 데이터 폭 (EMIF_ASYNC_DATA_WIDTH_8, EMIF_ASYNC_DATA_WIDTH_16, EMIF_ASYNC_DATA_WIDTH_32).
- 사용 예:
EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2, EMIF_ASYNC_DATA_WIDTH_16); // EMIF1 CS2를 16비트 비동기 모드로 설정 (예: SRAM 연결)
- 참고: 비동기 메모리(SRAM, NOR 플래시 등)에 사용. 하드웨어 회로도 확인 필요.
- EMIF_setAsyncTimingParams(base, cs, params)
- 설명: 비동기 모드의 타이밍 파라미터 설정 (Setup, Strobe, Hold, Turnaround).
- 매개변수:
- base: EMIF1/2 베이스 주소.
- cs: 칩 선택.
- params: EMIF_AsyncTimingParams 구조체 (tRSetup, tRStrobe, tRHold, turnAround).
- 사용 예:
EMIF_AsyncTimingParams params = { .tRSetup = 2, // 읽기 Setup: 2 사이클 .tRStrobe = 4, // 읽기 Strobe: 4 사이클 .tRHold = 2, // 읽기 Hold: 2 사이클 .turnAround = 1 // 턴어라운드: 1 사이클 }; EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2, ¶ms); // 비동기 메모리 타이밍 설정
- 참고: 외부 메모리 데이터시트 기반으로 타이밍 값 설정.
- SysCtl_enablePeripheral(peripheral)
- 설명: EMIF 모듈 클럭 활성화.
- 매개변수:
- peripheral: SYSCTL_PERIPH_CLK_EMIF1 또는 SYSCTL_PERIPH_CLK_EMIF2.
- 사용 예:
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EMIF1); // EMIF1 모듈 클럭 활성화 (시스템 초기화 단계)
- 참고: Device_init()에서 호출되며, EMIF 동작 전 필수.
- EMIF_enableAsyncWait(base, cs)
- 설명: 비동기 모드에서 대기 신호 활성화 (외부 장치의 데이터 준비 신호 처리).
- 매개변수:
- base: EMIF1/2 베이스 주소.
- cs: 칩 선택.
- 사용 예:
EMIF_enableAsyncWait(EMIF1_BASE, EMIF_ASYNC_CS2); // CS2 대기 신호 활성화 (EMIF1_WAIT 핀 사용)
- 참고: 대기 신호 핀 연결 확인 (예: GPIO35 for EMIF1_WAIT).
2.2. 동기 모드 관련 함수
- EMIF_setSyncTimingParams(base, ¶ms)
- 설명: 동기 SDRAM의 타이밍 파라미터 설정 (tRfc, tRp, tRcd, tWr, tRas, tRc, tRrd).
- 매개변수:
- base: EMIF1/2 베이스 주소.
- params: EMIF_SyncTimingParams 구조체.
- 사용 예:
EMIF_SyncTimingParams tParam = { .tRfc = 0x6U, // 60ns (6 사이클, 100MHz) .tRp = 0x1U, // 18ns (1 사이클) .tRcd = 0x1U, // 18ns (1 사이클) .tWr = 0x1U, // 1CLK + 6ns (1 사이클) .tRas = 0x4U, // 42ns (4 사이클) .tRc = 0x6U, // 60ns (6 사이클) .tRrd = 0x1U // 12ns (1 사이클) }; EMIF_setSyncTimingParams(EMIF1_BASE, &tParam); // Micron MT48LC32M16A2 SDRAM 타이밍 설정
- 참고: 100MHz EMIF 클럭 기준, SDRAM 데이터시트 확인 (예: Micron MT48LC32M16A2).
- EMIF_setSyncMemoryConfig(base, &config)
- 설명: 동기 SDRAM 모드 구성 (CAS Latency, 뱅크 수, 데이터 폭, 열 주소 폭).
- 매개변수:
- base: EMIF1/2 베이스 주소.
- config: EMIF_SyncConfig 구조체 (casLatency, iBank, narrowMode, pageSize).
- 사용 예:
EMIF_SyncConfig sdConfig = { .casLatency = EMIF_SYNC_CAS_LAT_3, // CAS 지연 시간: 3 .iBank = EMIF_SYNC_BANK_4, // 4뱅크 .narrowMode = EMIF_SYNC_NARROW_MODE_TRUE, // 16비트 데이터 폭 .pageSize = EMIF_SYNC_COLUMN_WIDTH_10 // 10비트 열 주소 (1024열) }; EMIF_setSyncMemoryConfig(EMIF1_BASE, &sdConfig); // Micron MT48LC32M16A2 SDRAM 구성
- 참고: 동기 모드 활성화 및 메모리 구성, emif_sdram_dma.c에서 사용.
- EMIF_setSyncSelfRefreshExitTmng(base, txsr)
- 설명: SDRAM Self Refresh 종료 타이밍 설정.
- 매개변수:
- base: EMIF1/2 베이스 주소.
- txsr: 종료 타이밍 (사이클 단위, 예: 70ns = 7 사이클 at 100MHz).
- 사용 예:
EMIF_setSyncSelfRefreshExitTmng(EMIF1_BASE, 0x7U); // Txsr = 70ns (7 사이클)
- 참고: Self Refresh 모드 종료 후 안정화 시간.
- EMIF_setSyncRefreshRate(base, rate)
- 설명: SDRAM 리프레시 주기 설정.
- 매개변수:
- base: EMIF1/2 베이스 주소.
- rate: 리프레시 주기 (예: 64ms/8192행 = 781.25 at 100MHz).
- 사용 예:
EMIF_setSyncRefreshRate(EMIF1_BASE, 781); // Tref = 64ms/8192행, RR = 781.25 (0x30E)
- 참고: SDRAM 리프레시 요구사항 준수 (데이터시트 확인).
2.3. DMA 관련 함수
- DMA_configAddresses(channel, dest, src)
- 설명: DMA 소스 및 목적지 주소 설정.
- 매개변수:
- channel: DMA 채널 베이스 주소 (DMA_CH1_BASE, DMA_CH2_BASE, 등).
- dest: 목적지 주소 (예: 내부 RAM 또는 EMIF 메모리).
- src: 소스 주소 (예: EMIF 메모리 또는 내부 RAM).
- 사용 예:
volatile uint32_t *extSDRAMBuf = (volatile uint32_t *)0x00100000; // EMIF1 CS0 uint32_t localRAMBuf[1024]; DMA_configAddresses(DMA_CH1_BASE, extSDRAMBuf, localRAMBuf); // 로컬 RAM에서 SDRAM으로 데이터 전송 설정
- 참고: emif_sdram_dma.c에서 extSDRAMBuf (0x00100000) 사용.
- DMA_configBurst(channel, size, srcStep, destStep)
- 설명: DMA 버스트 전송 크기 및 증분 설정.
- 매개변수:
- channel: DMA 채널 베이스 주소.
- size: 버스트 크기 (전송 단위 수).
- srcStep: 소스 주소 증분 (단위: 워드).
- destStep: 목적지 주소 증분 (단위: 워드).
- 사용 예:
DMA_configBurst(DMA_CH1_BASE, 32U, 1U, 1U); // 버스트 크기 32, 소스/목적지 증분 1
- 참고: SDRAM의 16비트 버스 고려 (srcStep, destStep).
- DMA_configTransfer(channel, transferSize, srcStep, destStep)
- 설명: DMA 전송 횟수 및 증분 설정.
- 매개변수:
- channel: DMA 채널 베이스 주소.
- transferSize: 전체 전송 횟수 (버스트 단위).
- srcStep: 소스 주소 증분 (버스트 간).
- destStep: 목적지 주소 증분 (버스트 간).
- 사용 예:
DMA_configTransfer(DMA_CH1_BASE, (1024 * 2) / 32, 1, 1); // 1024 워드 전송, 버스트 32, 증분 1
- 참고: emif_sdram_dma.c에서 MEM_BUFFER_SIZE=0x400 기준.
- DMA_configMode(channel, trigger, config)
- 설명: DMA 트리거 및 동작 모드 설정 (원샷, 연속, 데이터 크기).
- 매개변수:
- channel: DMA 채널 베이스 주소.
- trigger: 트리거 소스 (DMA_TRIGGER_SOFTWARE, 등).
- config: 모드 설정 (DMA_CFG_ONESHOT_ENABLE, DMA_CFG_CONTINUOUS_DISABLE, DMA_CFG_SIZE_16BIT/32BIT).
- 사용 예:
DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SOFTWARE, DMA_CFG_ONESHOT_ENABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT); // 소프트웨어 트리거, 원샷 모드, 16비트 전송
- 참고: SDRAM(16비트) 및 로컬 RAM(32비트) 데이터 폭 고려.
2.4. 인터럽트 관련 함수
- EMIF_enableInterrupt(base, intFlags)
- 설명: EMIF 인터럽트 활성화 (예: 비동기 대기 신호).
- 매개변수:
- base: EMIF1/2 베이스 주소.
- intFlags: 인터럽트 플래그 (EMIF_INT_ASYNC_WAIT, 등).
- 사용 예:
EMIF_enableInterrupt(EMIF1_BASE, EMIF_INT_ASYNC_WAIT); // 비동기 대기 신호 인터럽트 활성화
- 참고: 인터럽트 핸들러 등록 필요.
- Interrupt_register(intNumber, handler)
- 설명: 인터럽트 서비스 루틴(ISR) 등록.
- 매개변수:
- intNumber: 인터럽트 번호 (예: INT_EMIF1_1).
- handler: ISR 함수 포인터.
- 사용 예:
void emifISR(void); Interrupt_register(INT_EMIF1_1, emifISR); // EMIF1 인터럽트 ISR 등록
- 참고: Interrupt_initModule() 및 Interrupt_initVectorTable() 호출 필요.
3. EMIF 설정 및 동작 원리
- 시스템 초기화:
- 시스템 클럭, PLL, 주변 장치 초기화 (Device_init).
- GPIO 초기화 (Device_initGPIO, pin_map.h 기반 EMIF1 핀 설정).
- 인터럽트 초기화 (Interrupt_initModule, Interrupt_initVectorTable).
- 참고: 200MHz CPU1SYSCLK, EMIF1 클럭 100MHz (2분주).
- EMIF 모듈 설정:
- 클럭 활성화: SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EMIF1).
- 동기 모드 설정: EMIF_setSyncMemoryConfig (CAS Latency, 뱅크 수, 데이터 폭).
- 타이밍 설정: EMIF_setSyncTimingParams (tRfc, tRp, 등).
- 리프레시 설정: EMIF_setSyncSelfRefreshExitTmng, EMIF_setSyncRefreshRate.
- 참고: Micron MT48LC32M16A2 기준 (16비트, 4뱅크, 10비트 열 주소).
- 칩 선택 및 메모리 매핑:
- EMIF1 CS0 주소: 0x00100000–0x008FFFFF (8MB, 링커 스크립트에 EMIF1_CS0 정의).
- .farbss 섹션 매핑: extSDRAMBuf를 SDRAM에 할당.
- 참고: 2838x_RAM_lnk_cpu1.cmd에 .farbss : > EMIF1_CS0, PAGE = 1.
- DMA 설정(선택):
- DMA 초기화: DMA_initController.
- 주소 설정: DMA_configAddresses (예: extSDRAMBuf ↔ localSrcRAMBuf).
- 버스트/전송 설정: DMA_configBurst, DMA_configTransfer.
- 모드 설정: DMA_configMode (소프트웨어 트리거, 원샷, 16/32비트).
- 참고: emif_sdram_dma.c에서 채널 1(16비트 쓰기), 채널 2(32비트 읽기).
- 인터럽트 설정(선택):
- 인터럽트 활성화: EMIF_enableInterrupt (비동기 대기 등).
- ISR 등록: Interrupt_register.
- 참고: 동기 SDRAM에서는 인터럽트 사용 드물음.
- EMIF 동작:
- 메모리 읽기/쓰기: DMA를 통해 SDRAM 데이터 전송 (extSDRAMBuf).
- 데이터 검증: localSrcRAMBuf와 localDstRAMBuf 비교.
- 상태 모니터링: testStatusGlobal, errCountGlobal, GPIO31 LED.
- 참고: 오실로스코프로 EMIF1 신호(CS0N, CLK, RAS, CAS, D0–D15) 확인.
4. EMIF 예제 코드
아래는 독립적인 EMIF 예제 코드로, C2000Ware의 DriverLib를 기반으로 작성되었습니다. GPIO 설정은 initGPIO() 함수로 분리되었으며, 모든 코드는 CCS에서 TMDSCNCD28388D controlCARD에서 바로 실행 가능합니다.
4.1. 예제 1: 기본 SRAM 읽기/쓰기
EMIF1 CS2를 사용하여 16비트 SRAM에 데이터를 쓰고 읽습니다. 상세 주석과 인터럽트 설정이 포함되어 있습니다.
#include "driverlib.h"
#include "device.h"
#include "emif.h" // EMIF 관련 함수 및 정의 (EMIF_clearAsyncInterruptStatus, EMIF_INT_* 등)
#include "sysctl.h" // 워치독 및 시스템 제어 함수
// 상수 정의
#define TEST_PASS 0xABCDABCD // 테스트 성공 플래그
#define TEST_FAIL 0xDEADDEAD // 테스트 실패 플래그
#define ASRAM_CS2_START_ADDR 0x00100000 // EMIF1 CS2 시작 주소 (CY7C1041CV33 SRAM)
#define ASRAM_CS2_SIZE 0x8000 // 메모리 크기 (32K 워드, 16비트)
// 전역 변수
uint16_t errCountGlobal = 0; // 메모리 테스트 오류 카운트
uint32_t testStatusGlobal = TEST_FAIL; // 테스트 상태 (TEST_PASS 또는 TEST_FAIL)
volatile uint32_t emifStatus = 0; // EMIF 상태: 0(초기화 완료), 1(정상 동작), 0xFFFF(오류)
volatile uint16_t *emifCS2 = (volatile uint16_t *)ASRAM_CS2_START_ADDR; // EMIF1 CS2 메모리 포인터
volatile uint16_t lastEmifIntFlags = 0; // 마지막으로 발생한 EMIF 인터럽트 플래그 기록 (디버깅용)
// 함수 프로토타입
void setupEMIF1PinmuxAsync16Bit(void); // EMIF1 GPIO 핀 설정
void initEMIF(void); // EMIF1 초기화
void initWatchdog(void); // 워치독 초기화
void checkEMIFStatus(void); // EMIF 비동기 인터럽트 상태 폴링
void writeEMIF(uint16_t addressOffset, uint16_t data); // EMIF 메모리 쓰기
uint16_t readEMIF(uint16_t addressOffset); // EMIF 메모리 읽기
uint16_t readWriteMem(uint32_t startAddr, uint32_t memSize); // 메모리 읽기/쓰기 테스트
uint16_t walkMemData(uint32_t startAddr, uint32_t memSize); // 메모리 데이터 워킹 테스트
uint16_t walkMemAddr(uint32_t startAddr, uint32_t addrSize); // 메모리 주소 워킹 테스트
uint16_t accessMemData(uint32_t startAddr, uint32_t sizeToCheck); // 메모리 데이터 크기 테스트
// EMIF1 GPIO 핀 설정 함수
void setupEMIF1PinmuxAsync16Bit(void)
{
uint16_t i;
// 제어 신호 핀 설정 (CS, WEN, OEN 등)
GPIO_setPinConfig(GPIO_28_EMIF1_CS4N); // CS4N (사용 안 함)
GPIO_setPinConfig(GPIO_29_EMIF1_SDCKE); // SDCKE (SRAM에서 사용 안 함)
GPIO_setPinConfig(GPIO_30_EMIF1_CLK); // CLK (SRAM에서 사용 안 함)
GPIO_setPinConfig(GPIO_31_EMIF1_WEN); // 쓰기 활성화
GPIO_setPinConfig(GPIO_32_EMIF1_CS0N); // CS0N (사용 안 함)
GPIO_setPinConfig(GPIO_33_EMIF1_RNW); // 읽기/쓰기 선택
GPIO_setPinConfig(GPIO_34_EMIF1_CS2N); // CS2N (SRAM 연결)
GPIO_setPinConfig(GPIO_35_EMIF1_CS3N); // CS3N (사용 안 함)
GPIO_setPinConfig(GPIO_36_EMIF1_WAIT); // WAIT 신호
GPIO_setPinConfig(GPIO_37_EMIF1_OEN); // 출력 활성화
// 주소 라인 설정 (A0-A14)
GPIO_setPinConfig(GPIO_38_EMIF1_A0);
GPIO_setPinConfig(GPIO_39_EMIF1_A1);
GPIO_setPinConfig(GPIO_40_EMIF1_A2);
GPIO_setPinConfig(GPIO_41_EMIF1_A3);
GPIO_setPinConfig(GPIO_44_EMIF1_A4);
GPIO_setPinConfig(GPIO_45_EMIF1_A5);
GPIO_setPinConfig(GPIO_46_EMIF1_A6);
GPIO_setPinConfig(GPIO_47_EMIF1_A7);
GPIO_setPinConfig(GPIO_48_EMIF1_A8);
GPIO_setPinConfig(GPIO_49_EMIF1_A9);
GPIO_setPinConfig(GPIO_50_EMIF1_A10);
GPIO_setPinConfig(GPIO_51_EMIF1_A11);
GPIO_setPinConfig(GPIO_52_EMIF1_A12);
GPIO_setPinConfig(GPIO_86_EMIF1_A13);
GPIO_setPinConfig(GPIO_87_EMIF1_A14);
// 데이터 라인 설정 (D0-D15)
GPIO_setPinConfig(GPIO_69_EMIF1_D15);
GPIO_setPinConfig(GPIO_70_EMIF1_D14);
GPIO_setPinConfig(GPIO_71_EMIF1_D13);
GPIO_setPinConfig(GPIO_72_EMIF1_D12);
GPIO_setPinConfig(GPIO_73_EMIF1_D11);
GPIO_setPinConfig(GPIO_74_EMIF1_D10);
GPIO_setPinConfig(GPIO_75_EMIF1_D9);
GPIO_setPinConfig(GPIO_76_EMIF1_D8);
GPIO_setPinConfig(GPIO_77_EMIF1_D7);
GPIO_setPinConfig(GPIO_78_EMIF1_D6);
GPIO_setPinConfig(GPIO_79_EMIF1_D5);
GPIO_setPinConfig(GPIO_80_EMIF1_D4);
GPIO_setPinConfig(GPIO_81_EMIF1_D3);
GPIO_setPinConfig(GPIO_82_EMIF1_D2);
GPIO_setPinConfig(GPIO_83_EMIF1_D1);
GPIO_setPinConfig(GPIO_85_EMIF1_D0);
// DQM 및 뱅크 선택 핀 (SRAM에서 선택적)
GPIO_setPinConfig(GPIO_88_EMIF1_DQM0);
GPIO_setPinConfig(GPIO_89_EMIF1_DQM1);
GPIO_setPinConfig(GPIO_92_EMIF1_BA1);
GPIO_setPinConfig(GPIO_93_EMIF1_BA0);
// 데이터 핀에 풀업 및 비동기 모드 설정
for(i = 69; i <= 85; i++)
{
if(i != 84) // GPIO84 제외
{
GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP); // 풀업 활성화
GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC); // 비동기 입력
}
}
// 디버깅용 LED 설정 (GPIO42)
GPIO_setPinConfig(GPIO_42_GPIO42); // GPIO42를 일반 GPIO로 설정
GPIO_setDirectionMode(42, GPIO_DIR_MODE_OUT); // 출력 모드
GPIO_setPadConfig(42, GPIO_PIN_TYPE_STD); // 표준 패드
GPIO_writePin(42, 0); // LED 초기 상태: 꺼짐
}
// EMIF1 초기화 함수
void initEMIF(void)
{
// EMIF1 클럭 분주 설정 (CPU1SYSCLK 사용)
SysCtl_setEMIF1ClockDivider(SYSCTL_EMIF1CLK_DIV_1);
// EMIF1을 CPU1에 할당
EMIF_selectController(EMIF1CONFIG_BASE, EMIF_CONTROLLER_CPU1_G);
// 접근 보호 비활성화 (CPU 패치, 쓰기, DMA 쓰기)
EMIF_setAccessProtection(EMIF1CONFIG_BASE, 0x0);
// 설정 커밋 및 잠금
EMIF_commitAccessConfig(EMIF1CONFIG_BASE);
EMIF_lockAccessConfig(EMIF1CONFIG_BASE);
// CS2를 비동기 모드로 설정 (ASRAM)
EMIF_setAsyncMode(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_NORMAL_MODE);
// 확장 대기 모드 비활성화
EMIF_disableAsyncExtendedWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);
// 데이터 버스 폭 설정 (16비트)
EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);
// 비동기 타이밍 파라미터 설정 (CY7C1041CV33, 10ns SRAM, 200MHz 클럭)
EMIF_AsyncTimingParams tparam = {
.rSetup = 0, // 읽기 설정 시간 (0ns)
.rStrobe = 3, // 읽기 스트로브 시간 (15ns)
.rHold = 0, // 읽기 유지 시간 (0ns)
.wSetup = 0, // 쓰기 설정 시간 (0ns)
.wStrobe = 1, // 쓰기 스트로브 시간 (5ns)
.wHold = 0, // 쓰기 유지 시간 (0ns)
.turnArnd = 0 // 턴어라운드 시간 (0ns)
};
EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &tparam);
// 모든 비동기 인터럽트 플래그 초기화
EMIF_clearAsyncInterruptStatus(EMIF1_BASE, EMIF_INT_MSK_SET_AT_MASK_SET |
EMIF_INT_MSK_SET_LT_MASK_SET |
EMIF_INT_MSK_SET_WR_MASK_SET_M);
// 초기화 성공
emifStatus = 1;
}
// 워치독 초기화 함수
void initWatchdog(void)
{
EALLOW; // 보호된 레지스터 접근 허용
// 워치독 활성화 (INTOSC1/512, 리셋 모드)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 프리스케일러 설정 (예: /64)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_PRESCALE_64;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 즉시 리셋 방지를 위해 워치독 서비스
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_RSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
EDIS; // 보호된 레지스터 접근 비활성화
}
// EMIF 비동기 인터럽트 상태 폴링 함수
void checkEMIFStatus(void)
{
// EMIF 비동기 인터럽트 상태 읽기
uint16_t intStatus = EMIF_getAsyncInterruptStatus(EMIF1_BASE);
uint16_t intFlags = 0;
// 접근 시간 위반 (AT_MASK_SET) 체크
if(intStatus & EMIF_INT_MSK_SET_AT_MASK_SET)
{
uint16_t data = readEMIF(0x100); // 오프셋 0x100에서 데이터 읽기
emifStatus = (data != 0) ? 1 : 0xFFFF; // 데이터가 0이면 오류
intFlags |= EMIF_INT_MSK_SET_AT_MASK_SET;
lastEmifIntFlags |= EMIF_INT_MSK_SET_AT_MASK_SET; // 플래그 기록
}
// 지연 트랜잭션 (LT_MASK_SET) 체크
if(intStatus & EMIF_INT_MSK_SET_LT_MASK_SET)
{
emifStatus = 0xFFFF; // 오류 상태 설정
intFlags |= EMIF_INT_MSK_SET_LT_MASK_SET;
lastEmifIntFlags |= EMIF_INT_MSK_SET_LT_MASK_SET; // 플래그 기록
}
// 쓰기 마스크 설정 (WR_MASK_SET_M) 체크
if(intStatus & EMIF_INT_MSK_SET_WR_MASK_SET_M)
{
emifStatus = 0xFFFF; // 오류 상태 설정
intFlags |= EMIF_INT_MSK_SET_WR_MASK_SET_M;
lastEmifIntFlags |= EMIF_INT_MSK_SET_WR_MASK_SET_M; // 플래그 기록
}
// 인터럽트 플래그가 발생한 경우 클리어
if(intFlags != 0)
{
EMIF_clearAsyncInterruptStatus(EMIF1_BASE, intFlags);
}
}
// EMIF 메모리 쓰기 함수
void writeEMIF(uint16_t addressOffset, uint16_t data)
{
emifCS2[addressOffset] = data; // 지정된 오프셋에 데이터 쓰기
DEVICE_DELAY_US(10); // 쓰기 안정화 지연 (10us)
}
// EMIF 메모리 읽기 함수
uint16_t readEMIF(uint16_t addressOffset)
{
return emifCS2[addressOffset]; // 지정된 오프셋에서 데이터 읽기
}
// 메모리 읽기/쓰기 테스트 함수
uint16_t readWriteMem(uint32_t startAddr, uint32_t memSize)
{
uint16_t memReadData, memWriteData;
uint16_t *memPtr = (uint16_t *)startAddr;
uint32_t i;
// 데이터 쓰기
memWriteData = 0x0123;
for(i = 0; i < memSize; i++)
{
*memPtr++ = memWriteData;
memWriteData += 0x1111; // 다음 데이터 패턴
}
// 데이터 검증
memWriteData = 0x0123;
memPtr = (uint16_t *)startAddr;
for(i = 0; i < memSize; i++)
{
memReadData = *memPtr++;
if(memReadData != memWriteData)
{
return 1; // 오류 발생
}
memWriteData += 0x1111;
}
return 0; // 성공
}
// 메모리 데이터 워킹 테스트 함수
uint16_t walkMemData(uint32_t startAddr, uint32_t memSize)
{
uint16_t sramReadData, sramWriteData;
uint16_t *memPtr = (uint16_t *)startAddr;
uint16_t *memPtrIter;
uint32_t i, k, m;
for(i = 0; i < memSize; i += 64)
{
for(m = 0; m < 2; m++)
{
// 쓰기 루프
memPtrIter = memPtr;
sramWriteData = 0x01;
for(k = 0; k < 16; k++)
{
*memPtrIter++ = (m == 0) ? sramWriteData : ~sramWriteData;
sramWriteData <<= 1; // 비트 쉬프트
}
// 읽기 루프
memPtrIter = memPtr;
sramWriteData = 0x01;
for(k = 0; k < 16; k++)
{
sramReadData = *memPtrIter++;
if(m == 1) sramReadData = ~sramReadData;
if(sramReadData != sramWriteData)
{
return 1; // 오류 발생
}
sramWriteData <<= 1;
}
}
memPtr = memPtrIter;
}
return 0; // 성공
}
// 메모리 주소 워킹 테스트 함수
uint16_t walkMemAddr(uint32_t startAddr, uint32_t addrSize)
{
uint16_t sramReadData, sramWriteData;
uint16_t *memPtrIter;
uint32_t k, xshift;
// 쓰기 루프
xshift = 0x00000001;
sramWriteData = 0x00;
for(k = 0; k < addrSize; k++)
{
memPtrIter = (uint16_t *)(startAddr + xshift);
*memPtrIter = sramWriteData++;
xshift <<= 1; // 주소 쉬프트
}
// 읽기 루프
xshift = 0x00000001;
sramWriteData = 0x00;
for(k = 0; k < addrSize; k++)
{
memPtrIter = (uint16_t *)(startAddr + xshift);
sramReadData = *memPtrIter;
if(sramReadData != sramWriteData)
{
return 1; // 오류 발생
}
xshift <<= 1;
sramWriteData++;
}
return 0; // 성공
}
// 메모리 데이터 크기 테스트 함수
uint16_t accessMemData(uint32_t startAddr, uint32_t sizeToCheck)
{
uint16_t memRdShort, memWrShort;
uint16_t *memPtrShort = (uint16_t *)startAddr;
uint32_t i;
// 16비트 데이터 쓰기
memWrShort = 0x0605;
for(i = 0; i < sizeToCheck; i++)
{
*memPtrShort++ = memWrShort;
memWrShort += 0x0202; // 다음 데이터 패턴
}
// 16비트 데이터 읽기 및 검증
memPtrShort = (uint16_t *)startAddr;
memWrShort = 0x0605;
for(i = 0; i < sizeToCheck; i++)
{
memRdShort = *memPtrShort++;
if(memRdShort != memWrShort)
{
return 1; // 오류 발생
}
memWrShort += 0x0202;
}
return 0; // 성공
}
// 메인 함수
void main(void)
{
uint16_t errCountLocal;
// 시스템 초기화
Device_init(); // 디바이스 초기화 (클럭, PLL 등)
Device_initGPIO(); // GPIO 초기화
Interrupt_initModule(); // 인터럽트 모듈 초기화 (미사용이지만 향후 확장 대비)
Interrupt_initVectorTable(); // 인터럽트 벡터 테이블 초기화
// EMIF1 GPIO 설정
setupEMIF1PinmuxAsync16Bit();
// 시스템 클럭 확인 (200MHz)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if(sysClockHz != 200000000)
{
emifStatus = 0xFFFF; // 클럭 오류
GPIO_writePin(42, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
// EMIF 초기화
initEMIF();
// 워치독 초기화
initWatchdog();
// 초기화 오류 확인
if(emifStatus != 1)
{
emifStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(42, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
// 메모리 테스트 실행
errCountLocal = readWriteMem(ASRAM_CS2_START_ADDR, ASRAM_CS2_SIZE);
errCountGlobal += errCountLocal;
errCountLocal = walkMemAddr(ASRAM_CS2_START_ADDR, 16);
errCountGlobal += errCountLocal;
errCountLocal = walkMemData(ASRAM_CS2_START_ADDR, ASRAM_CS2_SIZE);
errCountGlobal += errCountLocal;
errCountLocal = accessMemData(ASRAM_CS2_START_ADDR, 4);
errCountGlobal += errCountLocal;
// 테스트 결과 설정
if(errCountGlobal == 0)
{
testStatusGlobal = TEST_PASS; // 모든 테스트 성공
}
// 메인 루프
for(;;)
{
checkEMIFStatus(); // EMIF 비동기 인터럽트 상태 확인
GPIO_writePin(42, (emifStatus == 1 && testStatusGlobal == TEST_PASS) ? 1 : 0); // LED 상태 업데이트
SysCtl_serviceWatchdog(); // 워치독 서비스
DEVICE_DELAY_US(100000); // 100ms 지연 (폴링 주기)
}
}
설명:
- 기능: 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" // TI C2000Ware DriverLib 헤더 파일 (EMIF, DMA, GPIO 등)
#include "device.h" // 디바이스별 설정 (TMS320F28388D)
#include "emif.h" // EMIF 관련 함수 및 정의 (비동기 SRAM 제어)
#include "sysctl.h" // 시스템 제어 및 워치독 관련 함수
#include "dma.h" // DMA 관련 함수 및 정의
// 상수 정의
#define CS2_ADDRESS 0x00200000 // EMIF1 CS2 메모리 시작 주소 (CY7C1041CV33 SRAM, 256K x 16비트)
#define BUFFER_SIZE 256 // 내부 SRAM 버퍼 크기 (256 워드, 16비트 단위)
// 전역 변수
volatile uint16_t *emifCS2 = (volatile uint16_t *)CS2_ADDRESS; // EMIF1 CS2 메모리 포인터 (외부 SRAM 접근용)
volatile uint16_t internalBuffer[BUFFER_SIZE]; // 내부 SRAM 버퍼 (DMA 전송 대상, 256 x 16비트)
volatile uint32_t emifStatus = 0; // EMIF 상태: 0(초기화 완료), 1(정상 동작), 0xFFFF(오류)
volatile uint16_t lastEmifIntFlags = 0; // 마지막 EMIF 비동기 인터럽트 플래그 (디버깅용)
// 함수 프로토타입
void initGPIO(void); // GPIO 초기화 (EMIF1 핀 및 디버깅 LED 설정)
void initEMIF(void); // EMIF1 초기화 (비동기 SRAM 모드, CS2)
void initWatchdog(void); // 워치독 타이머 초기화
void initDMA(void); // DMA 초기화 (EMIF1 CS2에서 내부 SRAM으로 전송)
void checkEMIFStatus(void); // EMIF 비동기 인터럽트 상태 폴링
void writeEMIF(uint16_t addressOffset, uint16_t data); // EMIF 메모리 쓰기 (SRAM에 데이터 쓰기)
// GPIO 초기화 함수
// 역할: EMIF1 비동기 SRAM(CY7C1041CV33) 연결을 위한 GPIO 핀 설정 및 디버깅 LED 설정
// 참고: pin_map.h 기반으로 핀 매핑 (TMS320F28388D 데이터시트 및 회로도 확인 필요)
void initGPIO(void)
{
// EMIF1 제어 신호 설정 (CS2N, WEN, OEN, WAIT)
GPIO_setPinConfig(GPIO_28_EMIF1_CS2N); // 칩 선택 신호 (CS2N, GPIO28, SRAM 연결)
GPIO_setPinConfig(GPIO_31_EMIF1_WEN); // 쓰기 활성화 신호 (Write Enable, GPIO31)
GPIO_setPinConfig(GPIO_32_EMIF1_OEN); // 출력 활성화 신호 (Output Enable, GPIO32)
GPIO_setPinConfig(GPIO_36_EMIF1_WAIT); // 대기 신호 (WAIT, GPIO36, SRAM 대기 응답)
// 주소 라인 설정 (A0-A15, 16비트 주소 공간)
// CY7C1041CV33 SRAM은 18비트 주소(256K 워드)를 지원하므로 A0-A15 사용
GPIO_setPinConfig(GPIO_35_EMIF1_A0);
GPIO_setPinConfig(GPIO_39_EMIF1_A1);
GPIO_setPinConfig(GPIO_40_EMIF1_A2);
GPIO_setPinConfig(GPIO_41_EMIF1_A3);
GPIO_setPinConfig(GPIO_44_EMIF1_A4);
GPIO_setPinConfig(GPIO_45_EMIF1_A5);
GPIO_setPinConfig(GPIO_46_EMIF1_A6);
GPIO_setPinConfig(GPIO_47_EMIF1_A7);
GPIO_setPinConfig(GPIO_48_EMIF1_A8);
GPIO_setPinConfig(GPIO_49_EMIF1_A9);
GPIO_setPinConfig(GPIO_50_EMIF1_A10);
GPIO_setPinConfig(GPIO_51_EMIF1_A11);
GPIO_setPinConfig(GPIO_52_EMIF1_A12);
GPIO_setPinConfig(GPIO_86_EMIF1_A13);
GPIO_setPinConfig(GPIO_87_EMIF1_A14);
GPIO_setPinConfig(GPIO_88_EMIF1_A15);
// 데이터 라인 설정 (D0-D15, 16비트 데이터 버스)
// CY7C1041CV33은 16비트 데이터 폭 지원
GPIO_setPinConfig(GPIO_55_EMIF1_D0);
GPIO_setPinConfig(GPIO_56_EMIF1_D1);
GPIO_setPinConfig(GPIO_57_EMIF1_D2);
GPIO_setPinConfig(GPIO_58_EMIF1_D3);
GPIO_setPinConfig(GPIO_59_EMIF1_D4);
GPIO_setPinConfig(GPIO_60_EMIF1_D5);
GPIO_setPinConfig(GPIO_61_EMIF1_D6);
GPIO_setPinConfig(GPIO_77_EMIF1_D7);
GPIO_setPinConfig(GPIO_76_EMIF1_D8);
GPIO_setPinConfig(GPIO_75_EMIF1_D9);
GPIO_setPinConfig(GPIO_74_EMIF1_D10);
GPIO_setPinConfig(GPIO_73_EMIF1_D11);
GPIO_setPinConfig(GPIO_72_EMIF1_D12);
GPIO_setPinConfig(GPIO_71_EMIF1_D13);
GPIO_setPinConfig(GPIO_70_EMIF1_D14);
GPIO_setPinConfig(GPIO_69_EMIF1_D15);
// 데이터 핀에 풀업 및 비동기 모드 설정
// 풀업: 외부 SRAM의 입력 안정성 확보
// 비동기 입력: EMIF1 비동기 모드와 호환 (타이밍 동기화 불필요)
uint16_t i;
for(i = 55; i <= 61; i++)
{
GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP); // 풀업 활성화 (전기적 노이즈 방지)
GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC); // 비동기 입력 모드
}
for(i = 69; i <= 77; i++)
{
GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP); // 풀업 활성화
GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC); // 비동기 입력 모드
}
// 디버깅용 LED 설정 (GPIO31)
// GPIO31은 I2CA_SDA 등 다른 기능과 충돌 없음 (회로도 확인 필요)
GPIO_setPinConfig(GPIO_31_GPIO31); // GPIO31을 일반 GPIO로 설정
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드 (LED 제어)
GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD); // 표준 패드 (풀업 비활성화)
GPIO_writePin(31, 0); // LED 초기 상태: 꺼짐 (emifStatus로 제어)
}
// EMIF1 초기화 함수
// 역할: EMIF1을 비동기 SRAM 모드로 설정 (CS2, CY7C1041CV33, 10ns 접근 시간)
// 참고: TMS320F2838x TRM 섹션 15 (EMIF), CY7C1041CV33 데이터시트
void initEMIF(void)
{
// EMIF1 클럭 활성화 및 분주 설정
// CPU1SYSCLK(200MHz)를 직접 사용 (DIV_1, 5ns 사이클)
SysCtl_setEMIF1ClockDivider(SYSCTL_EMIF1CLK_DIV_1);
// EMIF1을 CPU1에 할당
// CPU1_G: CPU1 전용 제어 (다른 코어와 공유 없음)
EMIF_selectController(EMIF1CONFIG_BASE, EMIF_CONTROLLER_CPU1_G);
// 접근 보호 비활성화
// CPU 패치, CPU 쓰기, DMA 쓰기 허용 (보안 설정 없음)
EMIF_setAccessProtection(EMIF1CONFIG_BASE, 0x0);
// 설정 커밋 및 잠금
// EMIF1ACCPROT0 레지스터 변경 방지
EMIF_commitAccessConfig(EMIF1CONFIG_BASE);
EMIF_lockAccessConfig(EMIF1CONFIG_BASE);
// CS2를 비동기 모드로 설정
// EMIF_ASYNC_NORMAL_MODE: 표준 비동기 모드 (CY7C1041CV33 호환)
EMIF_setAsyncMode(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_NORMAL_MODE);
// 데이터 버스 폭 설정
// 16비트 데이터 폭 (CY7C1041CV33은 16비트 데이터 지원)
EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);
// 비동기 타이밍 파라미터 설정
// CY7C1041CV33 (10ns SRAM, 200MHz 클럭 기준, 5ns/사이클)
// rSetup, rHold, wSetup, wHold: 0ns (최소 설정)
// rStrobe: 15ns (3 사이클), wStrobe: 5ns (1 사이클)
// turnArnd: 0ns (최소 턴어라운드)
EMIF_AsyncTimingParams tparam = {
.rSetup = 0, // 읽기 설정 시간 (0ns)
.rStrobe = 3, // 읽기 스트로브 시간 (15ns, 3 사이클)
.rHold = 0, // 읽기 유지 시간 (0ns)
.wSetup = 0, // 쓰기 설정 시간 (0ns)
.wStrobe = 1, // 쓰기 스트로브 시간 (5ns, 1 사이클)
.wHold = 0, // 쓰기 유지 시간 (0ns)
.turnArnd = 0 // 턴어라운드 시간 (0ns)
};
EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &tparam);
// 비동기 확장 대기 모드 활성화
// WAIT 신호를 통해 SRAM의 준비 상태 확인
EMIF_enableAsyncExtendedWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);
// 모든 비동기 인터럽트 플래그 초기화
// AT_MASK_SET(접근 시간 위반), LT_MASK_SET(지연 트랜잭션), WR_MASK_SET_M(쓰기 마스크) 클리어
EMIF_clearAsyncInterruptStatus(EMIF1_BASE, EMIF_INT_MSK_SET_AT_MASK_SET |
EMIF_INT_MSK_SET_LT_MASK_SET |
EMIF_INT_MSK_SET_WR_MASK_SET_M);
// 초기화 성공 상태 설정
emifStatus = 1;
}
// 워치독 초기화 함수
// 역할: 시스템 안정성을 위해 워치독 타이머 설정 (리셋 모드)
// 참고: TMS320F2838x TRM 섹션 8 (워치독)
void initWatchdog(void)
{
EALLOW; // 보호된 레지스터 접근 허용
// 워치독 활성화
// INTOSC1/512, 리셋 모드 활성화 (WDCR: Watchdog Control Register)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연 (안정화)
// 프리스케일러 설정
// /64 분주 (약 1.28ms 틱, 200MHz 기준)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_PRESCALE_64;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 즉시 리셋 방지를 위해 워치독 서비스
// WDKEY 레지스터에 두 번 연속 쓰기 (ENRSTKEY, RSTKEY)
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_RSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
EDIS; // 보호된 레지스터 접근 비활성화
}
// DMA 초기화 함수
// 역할: DMA 채널 1을 설정하여 EMIF1 CS2(SRAM)에서 내부 SRAM(internalBuffer)으로 데이터 전송
// 참고: TMS320F2838x TRM 섹션 17 (DMA), emif_ex5_16bit_sdram_dma.c 참조
void initDMA(void)
{
// DMA 컨트롤러 초기화
// 모든 DMA 채널 레지스터를 기본값으로 재설정 (C2000Ware DriverLib)
DMA_initController();
// DMA 클럭 활성화
// SYSCTL_PERIPH_CLK_DMA를 활성화하여 DMA 모듈 동작 준비
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DMA);
// DMA 채널 1 설정: EMIF1 CS2에서 내부 SRAM으로 전송
// 소스: CS2_ADDRESS (0x00200000, 외부 SRAM)
// 목적지: internalBuffer (내부 SRAM)
DMA_configAddresses(DMA_CH1_BASE, (const void *)internalBuffer, (const void *)CS2_ADDRESS);
// 버스트 설정
// 16 워드 버스트, 소스/목적지 주소 2바이트(16비트) 증가
// CY7C1041CV33의 16비트 데이터 폭과 호환
DMA_configBurst(DMA_CH1_BASE, 16, 2, 2);
// 전송 설정
// 총 256 워드 / 16 = 16회 전송, 소스/목적지 2바이트 증가
DMA_configTransfer(DMA_CH1_BASE, BUFFER_SIZE / 16, 2, 2);
// 래핑 설정
// 메모리 경계(0x10000)에서 주소 래핑, 실제로는 사용되지 않음 (0 회)
// emif_ex5_16bit_sdram_dma.c 스타일 유지
DMA_configWrap(DMA_CH1_BASE, 0x10000U, 0, 0x10000U, 0);
// DMA 모드 설정
// 소프트웨어 트리거, 원샷 모드 비활성화, 연속 모드 비활성화, 16비트 데이터 크기
DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SOFTWARE, DMA_CFG_ONESHOT_DISABLE |
DMA_CFG_CONTINUOUS_DISABLE |
DMA_CFG_SIZE_16BIT);
// 스퓨리어스 트리거 및 오류 플래그 클리어
// DMA 동작 전 잘못된 트리거/오류 플래그 제거 (안정성 확보)
DMA_clearTriggerFlag(DMA_CH1_BASE);
DMA_clearErrorFlag(DMA_CH1_BASE);
// DMA 트리거 활성화
// 소프트웨어 트리거를 허용하여 DMA 전송 준비
DMA_enableTrigger(DMA_CH1_BASE);
// DMA 채널 시작
// 채널 1 활성화, 전송 준비 완료
DMA_startChannel(DMA_CH1_BASE);
}
// EMIF 비동기 인터럽트 상태 폴링 함수
// 역할: EMIF1 비동기 인터럽트 상태를 확인하고 오류 플래그 처리
// 참고: TMS320F2838x TRM 섹션 15.5 (EMIF 인터럽트)
void checkEMIFStatus(void)
{
// EMIF 비동기 인터럽트 상태 읽기
// ASYNC_INT_STATUS 레지스터에서 플래그 확인
uint16_t intStatus = EMIF_getAsyncInterruptStatus(EMIF1_BASE);
uint16_t intFlags = 0;
// 접근 시간 위반 (AT_MASK_SET) 체크
// 읽기/쓰기 타이밍 위반 시 발생, emifStatus를 오류로 설정
if(intStatus & EMIF_INT_MSK_SET_AT_MASK_SET)
{
emifStatus = 0xFFFF; // 오류 상태 설정
intFlags |= EMIF_INT_MSK_SET_AT_MASK_SET;
lastEmifIntFlags |= EMIF_INT_MSK_SET_AT_MASK_SET; // 디버깅용 플래그 기록
}
// 지연 트랜잭션 (LT_MASK_SET) 체크
// 대기 신호 지연 시 발생, emifStatus를 오류로 설정
if(intStatus & EMIF_INT_MSK_SET_LT_MASK_SET)
{
emifStatus = 0xFFFF; // 오류 상태 설정
intFlags |= EMIF_INT_MSK_SET_LT_MASK_SET;
lastEmifIntFlags |= EMIF_INT_MSK_SET_LT_MASK_SET; // 디버깅용 플래그 기록
}
// 쓰기 마스크 설정 (WR_MASK_SET_M) 체크
// 쓰기 보호 위반 시 발생, emifStatus를 오류로 설정
if(intStatus & EMIF_INT_MSK_SET_WR_MASK_SET_M)
{
emifStatus = 0xFFFF; // 오류 상태 설정
intFlags |= EMIF_INT_MSK_SET_WR_MASK_SET_M;
lastEmifIntFlags |= EMIF_INT_MSK_SET_WR_MASK_SET_M; // 디버깅용 플래그 기록
}
// 인터럽트 플래그가 발생한 경우 클리어
// 누적된 플래그 제거로 후속 인터럽트 처리 준비
if(intFlags != 0)
{
EMIF_clearAsyncInterruptStatus(EMIF1_BASE, intFlags);
}
}
// EMIF 메모리 쓰기 함수
// 역할: EMIF1 CS2(SRAM)에 지정된 오프셋에 데이터 쓰기
// 입력: addressOffset (0~255), data (16비트 데이터)
void writeEMIF(uint16_t addressOffset, uint16_t data)
{
emifCS2[addressOffset] = data; // CS2_ADDRESS + 오프셋에 데이터 쓰기
DEVICE_DELAY_US(10); // 쓰기 안정화 지연 (10us, CY7C1041CV33 타이밍 준수)
}
// 메인 함수
// 역할: 시스템 초기화, EMIF1/DMA 설정, 데이터 전송 및 검증, 상태 모니터링
// 참고: TMS320F28388D, C2000Ware v6.00.00.00, CY7C1041CV33 SRAM
void main(void)
{
// 시스템 초기화
// 클럭, PLL, 주변 장치 초기화 (200MHz CPU1SYSCLK)
Device_init();
// GPIO 초기화
// EMIF1 핀 및 디버깅 LED(GPIO31) 설정
Device_initGPIO();
// 인터럽트 모듈 초기화
// PIE(Peripheral Interrupt Expansion) 제어 레지스터 초기화
Interrupt_initModule();
// 인터럽트 벡터 테이블 초기화
// 기본 핸들러로 벡터 테이블 설정 (확장 대비)
Interrupt_initVectorTable();
// 전역 인터럽트 활성화
// INTM 및 DBGM 활성화 (현재 미사용, 향후 확장 대비)
EINT;
ERTM;
// GPIO 설정
// EMIF1 핀(CS2N, WEN, OEN, WAIT, A0-A15, D0-D15) 및 LED 설정
initGPIO();
// 시스템 클럭 확인
// 200MHz 확인, 실패 시 오류 처리 (LED 끄기, 정지)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if(sysClockHz != 200000000)
{
emifStatus = 0xFFFF; // 클럭 오류 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지 (디버깅용)
}
// EMIF1 초기화
// 비동기 SRAM 모드 설정 (CS2, 16비트, CY7C1041CV33 타이밍)
initEMIF();
// 워치독 초기화
// 리셋 모드, /64 프리스케일러 설정
initWatchdog();
// 초기화 오류 확인
// EMIF 초기화 실패 시 오류 처리 (LED 끄기, 정지)
if(emifStatus != 1)
{
emifStatus = 0xFFFF; // 초기화 실패 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
// 테스트 데이터 쓰기
// EMIF1 CS2(SRAM)에 256 워드(0x1000 ~ 0x10FF) 쓰기
uint16_t i;
for(i = 0; i < BUFFER_SIZE; i++)
{
writeEMIF(i, 0x1000 + i); // 오프셋 i에 데이터 0x1000+i 쓰기
}
// DMA 초기화 및 전송
// EMIF1 CS2에서 internalBuffer로 256 워드 전송
initDMA();
// DMA 전송 트리거 및 완료 대기
// DMA_forceTrigger로 전송 시작, DMA_CONTROL_TRANSFERSTS로 완료 확인
EALLOW; // 보호된 레지스터 접근 허용
DMA_forceTrigger(DMA_CH1_BASE); // DMA 채널 1 전송 시작
while((HWREGH(DMA_CH1_BASE + DMA_O_CONTROL) & DMA_CONTROL_TRANSFERSTS) != 0x0U)
{
checkEMIFStatus(); // 전송 중 EMIF 오류 확인
DEVICE_DELAY_US(10); // 10us 지연 (폴링 간격)
}
EDIS; // 보호된 레지스터 접근 비활성화
// 데이터 검증
// internalBuffer의 데이터가 0x1000 ~ 0x10FF인지 확인
for(i = 0; i < BUFFER_SIZE; i++)
{
if(internalBuffer[i] != (0x1000 + i))
{
emifStatus = 0xFFFF; // 데이터 검증 실패 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
}
// 메인 루프
// EMIF 상태 모니터링, 워치독 서비스, LED 상태 업데이트
for(;;)
{
checkEMIFStatus(); // EMIF 비동기 인터럽트 상태 확인
GPIO_writePin(31, (emifStatus == 1) ? 1 : 0); // LED 상태 업데이트 (정상: 켜짐, 오류: 꺼짐)
SysCtl_serviceWatchdog(); // 워치독 서비스 (리셋 방지)
DEVICE_DELAY_US(100000); // 100ms 지연 (폴링 주기)
}
}
설명:
- 기능: 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" // TI C2000Ware DriverLib 헤더 파일 (EMIF, GPIO, 시스템 제어)
#include "device.h" // 디바이스별 설정 (TMS320F28388D)
// 상수 정의
#define ADC_ADDRESS 0x00200000 // EMIF1 CS2 메모리 시작 주소 (ADC 데이터 매핑, 16비트)
#define ADC_BUFFER_SIZE 256 // ADC 데이터 버퍼 크기 (256 샘플, 16비트 단위)
// 전역 변수
volatile uint16_t *adcData = (volatile uint16_t *)ADC_ADDRESS; // EMIF1 CS2 메모리 포인터 (ADC 데이터 읽기용)
volatile uint32_t emifStatus = 0; // EMIF 상태: 0(초기화 완료), 1(정상 동작), 0xFFFF(오류)
volatile uint16_t adcBuffer[ADC_BUFFER_SIZE]; // ADC 데이터 저장 버퍼 (256 x 16비트)
volatile uint16_t adcIndex = 0; // ADC 데이터 버퍼 인덱스
// 함수 프로토타입
void initGPIO(void); // GPIO 초기화 (EMIF1 핀 및 디버깅 LED 설정)
void initEMIF(void); // EMIF1 초기화 (비동기 모드, CS2, ADC 연결)
void initWatchdog(void); // 워치독 타이머 초기화
// GPIO 초기화 함수
// 역할: EMIF1 비동기 모드로 ADC 데이터 읽기를 위한 GPIO 핀 설정 및 디버깅 LED 설정
// 참고: pin_map.h 기반으로 핀 매핑 (TMS320F28388D 데이터시트 및 ADC 하드웨어 회로도 확인 필요)
void initGPIO(void)
{
// EMIF1 제어 신호 설정 (CS2N, WEN, OEN, WAIT)
// ADC와 연결된 EMIF1 CS2를 사용, 쓰기/대기 신호 포함
GPIO_setPinConfig(GPIO_28_EMIF1_CS2N); // 칩 선택 신호 (CS2N, GPIO28, ADC 선택)
GPIO_setPinConfig(GPIO_31_EMIF1_WEN); // 쓰기 활성화 신호 (Write Enable, GPIO31, ADC 미사용 가능)
GPIO_setPinConfig(GPIO_32_EMIF1_OEN); // 출력 활성화 신호 (Output Enable, GPIO32, 데이터 읽기)
GPIO_setPinConfig(GPIO_36_EMIF1_WAIT); // 대기 신호 (WAIT, GPIO36, ADC 준비 상태 응답)
// 주소 라인 설정 (A0)
// ADC는 단일 주소(0x00200000) 사용, A0만 설정
GPIO_setPinConfig(GPIO_35_EMIF1_A0);
// 데이터 라인 설정 (D0-D15, 16비트 데이터 버스)
// ADC는 16비트 데이터 출력 지원
GPIO_setPinConfig(GPIO_55_EMIF1_D0);
GPIO_setPinConfig(GPIO_56_EMIF1_D1);
GPIO_setPinConfig(GPIO_57_EMIF1_D2);
GPIO_setPinConfig(GPIO_58_EMIF1_D3);
GPIO_setPinConfig(GPIO_59_EMIF1_D4);
GPIO_setPinConfig(GPIO_60_EMIF1_D5);
GPIO_setPinConfig(GPIO_61_EMIF1_D6);
GPIO_setPinConfig(GPIO_77_EMIF1_D7);
GPIO_setPinConfig(GPIO_76_EMIF1_D8);
GPIO_setPinConfig(GPIO_75_EMIF1_D9);
GPIO_setPinConfig(GPIO_74_EMIF1_D10);
GPIO_setPinConfig(GPIO_73_EMIF1_D11);
GPIO_setPinConfig(GPIO_72_EMIF1_D12);
GPIO_setPinConfig(GPIO_71_EMIF1_D13);
GPIO_setPinConfig(GPIO_70_EMIF1_D14);
GPIO_setPinConfig(GPIO_69_EMIF1_D15);
// 데이터 핀에 풀업 및 비동기 모드 설정
// 풀업: ADC 데이터 입력 안정성 확보
// 비동기 입력: EMIF1 비동기 모드와 호환 (타이밍 동기화 불필요)
uint16_t i; // 루프 변수 선언
for(i = 55; i <= 61; i++)
{
GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP); // 풀업 활성화 (전기적 노이즈 방지)
GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC); // 비동기 입력 모드
}
for(i = 69; i <= 77; i++)
{
GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP); // 풀업 활성화
GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC); // 비동기 입력 모드
}
// 디버깅용 LED 설정 (GPIO31)
// GPIO31은 I2CA_SDA 등 다른 기능과 충돌 없음 (회로도 확인 필요)
GPIO_setPinConfig(GPIO_31_GPIO31); // GPIO31을 일반 GPIO로 설정
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드 (LED 제어)
GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD); // 표준 패드 (풀업 비활성화)
GPIO_writePin(31, 0); // LED 초기 상태: 꺼짐 (emifStatus로 제어)
}
// EMIF1 초기화 함수
// 역할: EMIF1을 비동기 모드로 설정하여 ADC 데이터 읽기 지원 (CS2, 16비트)
// 참고: TMS320F2838x TRM 섹션 15 (EMIF), ADC 하드웨어 타이밍 요구사항
void initEMIF(void)
{
// EMIF1 클럭 활성화
// CPU1SYSCLK(200MHz)를 직접 사용 (DIV_1, 5ns 사이클)
SysCtl_setEMIF1ClockDivider(SYSCTL_EMIF1CLK_DIV_1);
// EMIF1을 CPU1에 할당
// CPU1_G: CPU1 전용 제어 (다른 코어와 공유 없음)
EMIF_selectController(EMIF1CONFIG_BASE, EMIF_CONTROLLER_CPU1_G);
// 접근 보호 비활성화
// CPU 패치, CPU 쓰기, DMA 쓰기 허용 (ADC는 읽기 전용)
EMIF_setAccessProtection(EMIF1CONFIG_BASE, 0x0);
// 설정 커밋 및 잠금
// EMIF1ACCPROT0 레지스터 변경 방지
EMIF_commitAccessConfig(EMIF1CONFIG_BASE);
EMIF_lockAccessConfig(EMIF1CONFIG_BASE);
// CS2를 비동기 모드로 설정
// EMIF_ASYNC_NORMAL_MODE: 표준 비동기 모드 (ADC 읽기 호환)
EMIF_setAsyncMode(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_NORMAL_MODE);
// 데이터 버스 폭 설정
// 16비트 데이터 폭 (ADC는 16비트 데이터 출력)
EMIF_setAsyncDataBusWidth(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, EMIF_ASYNC_DATA_WIDTH_16);
// 비동기 타이밍 파라미터 설정
// ADC 읽기 타이밍 기준, 200MHz 클럭(5ns/사이클)
// rSetup: 0ns, rStrobe: 15ns (3 사이클), rHold: 0ns, turnArnd: 0ns
EMIF_AsyncTimingParams tparam = {
.rSetup = 0, // 읽기 설정 시간 (0ns)
.rStrobe = 3, // 읽기 스트로브 시간 (15ns, 3 사이클)
.rHold = 0, // 읽기 유지 시간 (0ns)
.wSetup = 0, // 쓰기 설정 시간 (0ns, ADC 미사용)
.wStrobe = 1, // 쓰기 스트로브 시간 (5ns, 1 사이클, 예비)
.wHold = 0, // 쓰기 유지 시간 (0ns)
.turnArnd = 0 // 턴어라운드 시간 (0ns)
};
EMIF_setAsyncTimingParams(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET, &tparam);
// 비동기 확장 대기 모드 활성화
// WAIT 신호를 통해 ADC의 준비 상태 확인
EMIF_enableAsyncExtendedWait(EMIF1_BASE, EMIF_ASYNC_CS2_OFFSET);
// 초기화 성공 상태 설정
emifStatus = 1;
}
// 워치독 초기화 함수
// 역할: 시스템 안정성을 위해 워치독 타이머 설정 (리셋 모드)
// 참고: TMS320F2838x TRM 섹션 8 (워치독)
void initWatchdog(void)
{
EALLOW; // 보호된 레지스터 접근 허용
// 워치독 활성화
// INTOSC1/512, 리셋 모드 활성화 (WDCR: Watchdog Control Register)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연 (안정화)
// 프리스케일러 설정
// /64 분주 (약 1.28ms 틱, 200MHz 기준)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_PRESCALE_64;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 즉시 리셋 방지를 위해 워치독 서비스
// WDKEY 레지스터에 두 번 연속 쓰기 (ENRSTKEY, RSTKEY)
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_RSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
EDIS; // 보호된 레지스터 접근 비활성화
}
// 메인 함수
// 역할: 시스템 초기화, EMIF1 설정, ADC 데이터 읽기 및 검증, 상태 모니터링
// 참고: TMS320F28388D, C2000Ware v6.00.00.00, ADC 하드웨어
void main(void)
{
uint16_t i; // 루프 변수 선언 (C89 호환, for 루프 외부 선언)
// 시스템 초기화
// 클럭, PLL, 주변 장치 초기화 (200MHz CPU1SYSCLK)
Device_init();
// GPIO 초기화
// EMIF1 핀 및 디버깅 LED(GPIO31) 설정
Device_initGPIO();
// 인터럽트 모듈 초기화
// PIE(Peripheral Interrupt Expansion) 제어 레지스터 초기화
Interrupt_initModule();
// 인터럽트 벡터 테이블 초기화
// 기본 핸들러로 벡터 테이블 설정 (확장 대비)
Interrupt_initVectorTable();
// 전역 인터럽트 활성화
// INTM 활성화 (현재 미사용, 향후 확장 대비)
EINT;
// GPIO 설정
// EMIF1 핀(CS2N, WEN, OEN, WAIT, A0, D0-D15) 및 LED 설정
initGPIO();
// 시스템 클럭 확인
// 200MHz 확인, 실패 시 오류 처리 (LED 끄기, 정지)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if(sysClockHz != 200000000)
{
emifStatus = 0xFFFF; // 클럭 오류 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지 (디버깅용)
}
// EMIF1 초기화
// 비동기 모드 설정 (CS2, 16비트, ADC 읽기)
initEMIF();
// 워치독 초기화
// 리셋 모드, /64 프리스케일러 설정
initWatchdog();
// 초기화 오류 확인
// EMIF 초기화 실패 시 오류 처리 (LED 끄기, 정지)
if(emifStatus != 1)
{
emifStatus = 0xFFFF; // 초기화 실패 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
// ADC 데이터 읽기
// EMIF1 CS2(0x00200000)에서 256 샘플 읽어 adcBuffer에 저장
for(i = 0; i < ADC_BUFFER_SIZE; i++)
{
adcBuffer[i] = *adcData; // ADC 데이터 읽기
DEVICE_DELAY_US(10); // ADC 변환 시간 대기 (10us, ADC 데이터시트 확인 필요)
}
// 데이터 검증
// ADC 데이터가 0이 아닌지 확인 (0은 오류로 간주)
for(i = 0; i < ADC_BUFFER_SIZE; i++)
{
if(adcBuffer[i] == 0)
{
emifStatus = 0xFFFF; // 데이터 검증 실패 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
}
// 무한 루프
// EMIF 상태 모니터링, 워치독 서비스, LED 상태 업데이트
for(;;)
{
GPIO_writePin(31, (emifStatus == 1) ? 1 : 0); // LED 상태 업데이트 (정상: 켜짐, 오류: 꺼짐)
SysCtl_serviceWatchdog(); // 워치독 서비스 (리셋 방지)
DEVICE_DELAY_US(1000000); // 1초 지연 (폴링 주기)
}
}
설명:
- 기능: 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" // TI C2000Ware DriverLib 헤더 파일 (EMIF, GPIO, 시스템 제어)
#include "device.h" // 디바이스별 설정 (TMS320F28388D)
// 상수 정의
#define TEST_PASS 0xABCDABCD // 테스트 성공 상태
#define TEST_FAIL 0xDEADDEAD // 테스트 실패 상태
#define MEM_BUFFER_SIZE 0x400 // 버퍼 크기 (1024 워드, 32비트 단위)
// 전역 변수
uint16_t errCountGlobal = 0; // 오류 카운터
uint32_t testStatusGlobal; // 테스트 상태 (TEST_PASS 또는 TEST_FAIL)
volatile uint32_t initData = 0; // 초기 데이터 값
volatile uint32_t *sdram = (volatile uint32_t *)0x00100000; // EMIF1 CS0 메모리 포인터 (SDRAM, 32비트)
uint32_t localSrcRAMBuf[MEM_BUFFER_SIZE]; // 소스 버퍼 (로컬 RAM)
#pragma DATA_SECTION(localSrcRAMBuf, "ramgs0"); // GS0 RAM에 할당
// 함수 프로토타입
void initGPIO(void); // GPIO 초기화 (EMIF1 핀 및 디버깅 LED 설정)
void initEMIF(void); // EMIF1 초기화 (동기 SDRAM 모드, CS0)
void initWatchdog(void); // 워치독 타이머 초기화
void clearDestDataBuffer(void); // SDRAM 버퍼 초기화
// GPIO 초기화 함수
// 역할: EMIF1 동기 SDRAM 모드로 데이터 읽기/쓰기를 위한 GPIO 핀 설정 및 디버깅 LED 설정
// 참고: pin_map.h 기반으로 핀 매핑 (TMS320F28388D 데이터시트 및 SDRAM 회로도 확인 필요)
void initGPIO(void)
{
uint16_t i; // 루프 변수 선언 (C89 호환)
// EMIF1 제어 신호 설정 (pin_map.h 기준)
// SDRAM(Micron MT48LC32M16A2 등)과 연결된 EMIF1 CS0 사용
GPIO_setPinConfig(GPIO_32_EMIF1_CS0N); // 칩 선택 신호 (CS0N, GPIO32, 0x00460002U)
GPIO_setPinConfig(GPIO_31_EMIF1_WEN); // 쓰기 활성화 신호 (WEN, GPIO31, 0x00081E02U)
GPIO_setPinConfig(GPIO_37_EMIF1_OEN); // 출력 활성화 신호 (OEN, GPIO37, 0x00460A02U)
GPIO_setPinConfig(GPIO_30_EMIF1_CLK); // 클럭 신호 (CLK, GPIO30, 0x00081C02U)
GPIO_setPinConfig(GPIO_87_EMIF1_RAS); // 행 주소 스트로브 (RAS, GPIO87, 0x00880E03U)
GPIO_setPinConfig(GPIO_86_EMIF1_CAS); // 열 주소 스트로브 (CAS, GPIO86, 0x00880C02U)
GPIO_setPinConfig(GPIO_93_EMIF1_BA0); // 뱅크 주소 0 (BA0, GPIO93, 0x00881A03U)
GPIO_setPinConfig(GPIO_94_EMIF1_BA1); // 뱅크 주소 1 (BA1, GPIO94, 0x00881C09U)
GPIO_setPinConfig(GPIO_29_EMIF1_SDCKE); // SDRAM 클럭 활성화 (SDCKE, GPIO29, 0x00081A02U)
// 주소 라인 설정 (A0-A15, pin_map.h 기준)
// SDRAM은 16비트 주소 공간 사용 (예: MT48LC32M16A2, 13행/10열 주소)
GPIO_setPinConfig(GPIO_35_EMIF1_A0); // A0, GPIO35, 0x00460609U
GPIO_setPinConfig(GPIO_36_EMIF1_A1); // A1, GPIO36, 0x00460809U
GPIO_setPinConfig(GPIO_38_EMIF1_A3); // A3, GPIO38, 0x00460C09U
GPIO_setPinConfig(GPIO_39_EMIF1_A4); // A4, GPIO39, 0x00460E09U
GPIO_setPinConfig(GPIO_44_EMIF1_A4); // A4, GPIO44, 0x00461802U (중복 확인)
GPIO_setPinConfig(GPIO_45_EMIF1_A5); // A5, GPIO45, 0x00461A02U
GPIO_setPinConfig(GPIO_46_EMIF1_A6); // A6, GPIO46, 0x00461C02U
GPIO_setPinConfig(GPIO_47_EMIF1_A7); // A7, GPIO47, 0x00461E02U
GPIO_setPinConfig(GPIO_48_EMIF1_A8); // A8, GPIO48, 0x00480002U
GPIO_setPinConfig(GPIO_49_EMIF1_A9); // A9, GPIO49, 0x00480209U
GPIO_setPinConfig(GPIO_50_EMIF1_A10); // A10, GPIO50, 0x00480402U
GPIO_setPinConfig(GPIO_51_EMIF1_A11); // A11, GPIO51, 0x00480602U
GPIO_setPinConfig(GPIO_52_EMIF1_A12); // A12, GPIO52, 0x00480802U
GPIO_setPinConfig(GPIO_86_EMIF1_A13); // A13, GPIO86, 0x00880C02U
GPIO_setPinConfig(GPIO_87_EMIF1_A14); // A14, GPIO87, 0x00880E02U
GPIO_setPinConfig(GPIO_88_EMIF1_A15); // A15, GPIO88, 0x00881002U
// 데이터 라인 설정 (D0-D15, 16비트 데이터 버스, pin_map.h 기준)
// SDRAM은 16비트 데이터 폭 지원
GPIO_setPinConfig(GPIO_85_EMIF1_D0); // D0, GPIO85, 0x00880A02U
GPIO_setPinConfig(GPIO_83_EMIF1_D1); // D1, GPIO83, 0x00880602U
GPIO_setPinConfig(GPIO_82_EMIF1_D2); // D2, GPIO82, 0x00880402U
GPIO_setPinConfig(GPIO_81_EMIF1_D3); // D3, GPIO81, 0x00880202U
GPIO_setPinConfig(GPIO_80_EMIF1_D4); // D4, GPIO80, 0x00880002U
GPIO_setPinConfig(GPIO_79_EMIF1_D5); // D5, GPIO79, 0x00861E02U
GPIO_setPinConfig(GPIO_78_EMIF1_D6); // D6, GPIO78, 0x00861C02U
GPIO_setPinConfig(GPIO_77_EMIF1_D7); // D7, GPIO77, 0x00861A02U
GPIO_setPinConfig(GPIO_76_EMIF1_D8); // D8, GPIO76, 0x00861802U
GPIO_setPinConfig(GPIO_75_EMIF1_D9); // D9, GPIO75, 0x00861602U
GPIO_setPinConfig(GPIO_74_EMIF1_D10); // D10, GPIO74, 0x00861402U
GPIO_setPinConfig(GPIO_73_EMIF1_D11); // D11, GPIO73, 0x00861202U
GPIO_setPinConfig(GPIO_72_EMIF1_D12); // D12, GPIO72, 0x00861002U
GPIO_setPinConfig(GPIO_71_EMIF1_D13); // D13, GPIO71, 0x00860E02U
GPIO_setPinConfig(GPIO_70_EMIF1_D14); // D14, GPIO70, 0x00860C02U
GPIO_setPinConfig(GPIO_69_EMIF1_D15); // D15, GPIO69, 0x00860A02U
// 데이터 핀에 풀업 및 비동기 모드 설정
// 풀업: SDRAM 데이터 입력 안정성 확보
// 비동기 입력: 동기 모드지만 데이터 핀은 비동기 처리 가능
for(i = 69; i <= 85; i++)
{
if(i == 84) continue; // GPIO84는 EMIF1_Dx에 포함되지 않음 (pin_map.h 기준)
GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP); // 풀업 활성화 (전기적 노이즈 방지)
GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC); // 비동기 입력 모드
}
// 디버깅용 LED 설정 (GPIO31)
// GPIO31은 EMIF1_WEN과 공유 가능 (pin_map.h: 0x00081E00U, 0x00081E02U)
GPIO_setPinConfig(GPIO_31_GPIO31); // GPIO31을 일반 GPIO로 설정 (0x00081E00U)
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드 (LED 제어)
GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD); // 표준 패드 (풀업 비활성화)
GPIO_writePin(31, 0); // LED 초기 상태: 꺼짐 (testStatusGlobal로 제어)
}
// EMIF1 초기화 함수
// 역할: EMIF1을 동기 SDRAM 모드로 설정하여 데이터 읽기/쓰기 지원 (CS0, 16비트)
// 참고: TMS320F2838x TRM 섹션 15 (EMIF), Micron MT48LC32M16A2 데이터시트, C2000Ware v6.00.00.00
void initEMIF(void)
{
EMIF_SyncTimingParams tParam;
EMIF_SyncConfig sdConfig;
// EMIF1 클럭 활성화
// CPU1SYSCLK(200MHz)를 2분주하여 100MHz EMIF 클럭 생성 (SDRAM 타이밍 준수)
SysCtl_setEMIF1ClockDivider(SYSCTL_EMIF1CLK_DIV_2);
// EMIF1을 CPU1에 할당
// CPU1_G: CPU1 전용 제어 (다른 코어와 공유 없음)
EMIF_selectController(EMIF1CONFIG_BASE, EMIF_CONTROLLER_CPU1_G);
// 접근 보호 비활성화
// CPU 패치, CPU 쓰기, DMA 쓰기 허용
EMIF_setAccessProtection(EMIF1CONFIG_BASE, 0x0);
// 설정 커밋 및 잠금
// EMIF1ACCPROT0 레지스터 변경 방지
EMIF_commitAccessConfig(EMIF1CONFIG_BASE);
EMIF_lockAccessConfig(EMIF1CONFIG_BASE);
// SDRAM 타이밍 파라미터 설정
// Micron MT48LC32M16A2 기준, 100MHz 클럭(10ns/사이클)
// tRFC = 60ns (6 사이클), tRP = 18ns (1 사이클), tRCD = 18ns (1 사이클)
// tWR = 1CLK + 6ns (1 사이클), tRAS = 42ns (4 사이클), tRC = 60ns (6 사이클)
// tRRD = 12ns (1 사이클)
tParam.tRfc = 0x6U;
tParam.tRp = 0x1U;
tParam.tRcd = 0x1U;
tParam.tWr = 0x1U;
tParam.tRas = 0x4U;
tParam.tRc = 0x6U;
tParam.tRrd = 0x1U;
EMIF_setSyncTimingParams(EMIF1_BASE, &tParam);
// Self Refresh 종료 타이밍 설정
// Txsr = 70ns (7 사이클)
EMIF_setSyncSelfRefreshExitTmng(EMIF1_BASE, 0x7U);
// 리프레시 주기 설정
// Tref = 64ms/8192행, RR = 64000*100MHz/8192 = 781.25 (0x30E)
EMIF_setSyncRefreshRate(EMIF1_BASE, 781);
// SDRAM 메모리 구성
// MT48LC32M16A2: 13행 주소, 10열 주소, 4뱅크, 16비트 폭
sdConfig.casLatency = EMIF_SYNC_CAS_LAT_3; // CAS 지연 시간: 3
sdConfig.iBank = EMIF_SYNC_BANK_4; // 4뱅크
sdConfig.narrowMode = EMIF_SYNC_NARROW_MODE_TRUE; // 16비트 데이터 폭
sdConfig.pageSize = EMIF_SYNC_COLUMN_WIDTH_10; // 열 주소 10비트 (1024열)
EMIF_setSyncMemoryConfig(EMIF1_BASE, &sdConfig);
// 초기화 성공 상태 설정
testStatusGlobal = TEST_PASS;
}
// 워치독 초기화 함수
// 역할: 시스템 안정성을 위해 워치독 타이머 설정 (리셋 모드)
// 참고: TMS320F2838x TRM 섹션 8 (워치독)
void initWatchdog(void)
{
EALLOW; // 보호된 레지스터 접근 허용
// 워치독 활성화
// INTOSC1/512, 리셋 모드 활성화 (WDCR: Watchdog Control Register)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연 (안정화)
// 프리스케일러 설정
// /64 분주 (약 1.28ms 틱, 200MHz 기준)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_PRESCALE_64;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 즉시 리셋 방지를 위해 워치독 서비스
// WDKEY 레지스터에 두 번 연속 쓰기 (ENRSTKEY, RSTKEY)
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_RSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
EDIS; // 보호된 레지스터 접근 비활성화
}
// SDRAM 버퍼 초기화 함수
// 역할: SDRAM 메모리 초기화 (0x0으로 클리어)
// 참고: Micron MT48LC32M16A2 데이터시트
void clearDestDataBuffer(void)
{
uint16_t i;
// SDRAM 버퍼 초기화 (0x00100000에서 MEM_BUFFER_SIZE 워드)
for(i = 0; i < MEM_BUFFER_SIZE; i++)
{
sdram[i] = 0x0;
DEVICE_DELAY_US(10); // 쓰기 안정화 지연 (10us)
}
}
// 메인 함수
// 역할: 시스템 초기화, EMIF1 SDRAM 설정, 데이터 쓰기/읽기 및 검증, 상태 모니터링
// 참고: TMS320F28388D, C2000Ware v6.00.00.00, Micron MT48LC32M16A2, pin_map.h
void main(void)
{
uint16_t i; // 루프 변수 선언 (C89 호환)
// 테스트 상태 초기화
testStatusGlobal = TEST_FAIL;
// 시스템 초기화
// 클럭, PLL, 주변 장치 초기화 (200MHz CPU1SYSCLK)
Device_init();
// 인터럽트 모듈 초기화
// PIE(Peripheral Interrupt Expansion) 제어 레지스터 초기화
Interrupt_initModule();
// 인터럽트 벡터 테이블 초기화
// 기본 핸들러로 벡터 테이블 설정 (확장 대비)
Interrupt_initVectorTable();
// 전역 인터럽트 활성화
// INTM 활성화 (현재 미사용, 향후 확장 대비)
EINT;
// GPIO 설정
// EMIF1 핀(CS0N, WEN, OEN, CLK, RAS, CAS, BA0, BA1, SDCKE, A0-A15, D0-D15) 및 LED 설정
Device_initGPIO();
initGPIO();
// 시스템 클럭 확인
// 200MHz 확인, 실패 시 오류 처리 (LED 끄기, 정지)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if(sysClockHz != 200000000)
{
testStatusGlobal = TEST_FAIL; // 클럭 오류 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지 (디버깅용)
}
// EMIF1 초기화
// 동기 SDRAM 모드 설정 (CS0, 16비트)
initEMIF();
// 초기화 오류 확인
// EMIF 초기화 실패 시 오류 처리 (LED 끄기, 정지)
if(testStatusGlobal != TEST_PASS)
{
testStatusGlobal = TEST_FAIL; // 초기화 실패 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
// 소스 버퍼 초기화
// initData = 0x12103456, 각 워드에 0x11111111 추가
initData = 0x12103456;
for(i = 0; i < MEM_BUFFER_SIZE; i++)
{
initData = initData + 0x11111111;
localSrcRAMBuf[i] = initData;
}
// SDRAM 버퍼 초기화
clearDestDataBuffer();
// 테스트 데이터 쓰기
// SDRAM(0x00100000)에 MEM_BUFFER_SIZE 워드 쓰기
for(i = 0; i < MEM_BUFFER_SIZE; i++)
{
sdram[i] = localSrcRAMBuf[i]; // 로컬 버퍼에서 SDRAM으로 데이터 복사
DEVICE_DELAY_US(10); // 쓰기 안정화 지연 (10us)
}
// 데이터 읽기 및 검증
// SDRAM에서 읽은 데이터가 localSrcRAMBuf와 동일한지 확인
for(i = 0; i < MEM_BUFFER_SIZE; i++)
{
if(sdram[i] != localSrcRAMBuf[i])
{
errCountGlobal++; // 오류 카운트 증가
testStatusGlobal = TEST_FAIL; // 테스트 실패
}
}
// 테스트 결과 설정
if(errCountGlobal == 0)
{
testStatusGlobal = TEST_PASS; // 테스트 성공
}
// 워치독 초기화
// 리셋 모드, /64 프리스케일러 설정
initWatchdog();
// 무한 루프
// 테스트 상태 모니터링, 워치독 서비스, LED 상태 업데이트
for(;;)
{
GPIO_writePin(31, (testStatusGlobal == TEST_PASS) ? 1 : 0); // LED 상태 업데이트 (정상: 켜짐, 오류: 꺼짐)
SysCtl_serviceWatchdog(); // 워치독 서비스 (리셋 방지)
DEVICE_DELAY_US(1000000); // 1초 지연 (폴링 주기)
}
}
설명:
- 기능: EMIF1 CS0을 동기 모드로 설정하여 SDRAM에 데이터 쓰기/읽기.
- 설정: 16비트 데이터 버스, CAS=3, RAS=2, 리프레시=64ms.
- GPIO: EMIF1 핀 (GPIO28~69), 디버깅용 LED (GPIO31).
- 출력: 256개 데이터 쓰기/읽기 성공 시 LED ON.
- 용도: 대용량 데이터 저장, 실시간 신호 처리.
4.5. 예제 4:DMA를 사용한 SDRAM 데이터 전송
EMIF1을 동기 모드로 DMA를 이용하여 SDRAM에 데이터를 쓰고 읽습니다.
#include "driverlib.h" // TI C2000Ware DriverLib 헤더 파일 (EMIF, GPIO, DMA, 시스템 제어)
#include "device.h" // 디바이스별 설정 (TMS320F28388D)
// 상수 정의
#define TEST_PASS 0xABCDABCD // 테스트 성공 상태
#define TEST_FAIL 0xDEADDEAD // 테스트 실패 상태
#define MEM_BUFFER_SIZE 0x400 // 버퍼 크기 (1024 워드, 32비트 단위)
// 전역 변수
uint16_t errCountGlobal = 0; // 오류 카운터
uint32_t testStatusGlobal; // 테스트 상태 (TEST_PASS 또는 TEST_FAIL)
volatile uint32_t initData = 0; // 초기 데이터 값
volatile uint32_t *destDMA; // DMA 목적지 포인터
volatile uint32_t *srcDMA; // DMA 소스 포인터
uint32_t localSrcRAMBuf[MEM_BUFFER_SIZE]; // 소스 버퍼 (로컬 RAM)
uint32_t localDstRAMBuf[MEM_BUFFER_SIZE]; // 목적지 버퍼 (로컬 RAM)
__attribute__((far)) volatile uint32_t extSDRAMBuf[MEM_BUFFER_SIZE]; // SDRAM 버퍼 (far 속성, 22비트 이상)
#pragma DATA_SECTION(localSrcRAMBuf, "ramgs0"); // GS0 RAM에 할당
#pragma DATA_SECTION(localDstRAMBuf, "ramgs1"); // GS1 RAM에 할당
#pragma DATA_SECTION(extSDRAMBuf, ".farbss"); // far 메모리 섹션 (SDRAM)
// 함수 프로토타입
void initGPIO(void); // GPIO 초기화 (EMIF1 핀 및 디버깅 LED 설정)
void initEMIF(void); // EMIF1 초기화 (동기 SDRAM 모드, CS0)
void initWatchdog(void); // 워치독 타이머 초기화
void clearDestDataBuffer(uint32_t memSize); // SDRAM 및 로컬 버퍼 초기화
void configDMAChannel1(void); // DMA 채널 1 설정 (SDRAM 쓰기)
void configDMAChannel2(void); // DMA 채널 2 설정 (SDRAM 읽기)
// GPIO 초기화 함수
// 역할: EMIF1 동기 SDRAM 모드로 데이터 읽기/쓰기를 위한 GPIO 핀 설정 및 디버깅 LED 설정
// 참고: pin_map.h 기반으로 핀 매핑 (TMS320F28388D 데이터시트 및 SDRAM 회로도 확인 필요)
void initGPIO(void)
{
uint16_t i; // 루프 변수 선언 (C89 호환)
// EMIF1 제어 신호 설정 (pin_map.h 기준)
// SDRAM(Micron MT48LC32M16A2 등)과 연결된 EMIF1 CS0 사용
GPIO_setPinConfig(GPIO_32_EMIF1_CS0N); // 칩 선택 신호 (CS0N, GPIO32, 0x00460002U)
GPIO_setPinConfig(GPIO_31_EMIF1_WEN); // 쓰기 활성화 신호 (WEN, GPIO31, 0x00081E02U)
GPIO_setPinConfig(GPIO_37_EMIF1_OEN); // 출력 활성화 신호 (OEN, GPIO37, 0x00460A02U)
GPIO_setPinConfig(GPIO_30_EMIF1_CLK); // 클럭 신호 (CLK, GPIO30, 0x00081C02U)
GPIO_setPinConfig(GPIO_87_EMIF1_RAS); // 행 주소 스트로브 (RAS, GPIO87, 0x00880E03U)
GPIO_setPinConfig(GPIO_86_EMIF1_CAS); // 열 주소 스트로브 (CAS, GPIO86, 0x00880C02U)
GPIO_setPinConfig(GPIO_93_EMIF1_BA0); // 뱅크 주소 0 (BA0, GPIO93, 0x00881A03U)
GPIO_setPinConfig(GPIO_94_EMIF1_BA1); // 뱅크 주소 1 (BA1, GPIO94, 0x00881C09U)
GPIO_setPinConfig(GPIO_29_EMIF1_SDCKE); // SDRAM 클럭 활성화 (SDCKE, GPIO29, 0x00081A02U)
// 주소 라인 설정 (A0-A15, pin_map.h 기준)
// SDRAM은 16비트 주소 공간 사용 (예: MT48LC32M16A2, 13행/10열 주소)
GPIO_setPinConfig(GPIO_35_EMIF1_A0); // A0, GPIO35, 0x00460609U
GPIO_setPinConfig(GPIO_36_EMIF1_A1); // A1, GPIO36, 0x00460809U
GPIO_setPinConfig(GPIO_38_EMIF1_A3); // A3, GPIO38, 0x00460C09U
GPIO_setPinConfig(GPIO_39_EMIF1_A4); // A4, GPIO39, 0x00460E09U
GPIO_setPinConfig(GPIO_44_EMIF1_A4); // A4, GPIO44, 0x00461802U (중복 확인)
GPIO_setPinConfig(GPIO_45_EMIF1_A5); // A5, GPIO45, 0x00461A02U
GPIO_setPinConfig(GPIO_46_EMIF1_A6); // A6, GPIO46, 0x00461C02U
GPIO_setPinConfig(GPIO_47_EMIF1_A7); // A7, GPIO47, 0x00461E02U
GPIO_setPinConfig(GPIO_48_EMIF1_A8); // A8, GPIO48, 0x00480002U
GPIO_setPinConfig(GPIO_49_EMIF1_A9); // A9, GPIO49, 0x00480209U
GPIO_setPinConfig(GPIO_50_EMIF1_A10); // A10, GPIO50, 0x00480402U
GPIO_setPinConfig(GPIO_51_EMIF1_A11); // A11, GPIO51, 0x00480602U
GPIO_setPinConfig(GPIO_52_EMIF1_A12); // A12, GPIO52, 0x00480802U
GPIO_setPinConfig(GPIO_86_EMIF1_A13); // A13, GPIO86, 0x00880C02U
GPIO_setPinConfig(GPIO_87_EMIF1_A14); // A14, GPIO87, 0x00880E02U
GPIO_setPinConfig(GPIO_88_EMIF1_A15); // A15, GPIO88, 0x00881002U
// 데이터 라인 설정 (D0-D15, 16비트 데이터 버스, pin_map.h 기준)
// SDRAM은 16비트 데이터 폭 지원
GPIO_setPinConfig(GPIO_85_EMIF1_D0); // D0, GPIO85, 0x00880A02U
GPIO_setPinConfig(GPIO_83_EMIF1_D1); // D1, GPIO83, 0x00880602U
GPIO_setPinConfig(GPIO_82_EMIF1_D2); // D2, GPIO82, 0x00880402U
GPIO_setPinConfig(GPIO_81_EMIF1_D3); // D3, GPIO81, 0x00880202U
GPIO_setPinConfig(GPIO_80_EMIF1_D4); // D4, GPIO80, 0x00880002U
GPIO_setPinConfig(GPIO_79_EMIF1_D5); // D5, GPIO79, 0x00861E02U
GPIO_setPinConfig(GPIO_78_EMIF1_D6); // D6, GPIO78, 0x00861C02U
GPIO_setPinConfig(GPIO_77_EMIF1_D7); // D7, GPIO77, 0x00861A02U
GPIO_setPinConfig(GPIO_76_EMIF1_D8); // D8, GPIO76, 0x00861802U
GPIO_setPinConfig(GPIO_75_EMIF1_D9); // D9, GPIO75, 0x00861602U
GPIO_setPinConfig(GPIO_74_EMIF1_D10); // D10, GPIO74, 0x00861402U
GPIO_setPinConfig(GPIO_73_EMIF1_D11); // D11, GPIO73, 0x00861202U
GPIO_setPinConfig(GPIO_72_EMIF1_D12); // D12, GPIO72, 0x00861002U
GPIO_setPinConfig(GPIO_71_EMIF1_D13); // D13, GPIO71, 0x00860E02U
GPIO_setPinConfig(GPIO_70_EMIF1_D14); // D14, GPIO70, 0x00860C02U
GPIO_setPinConfig(GPIO_69_EMIF1_D15); // D15, GPIO69, 0x00860A02U
// 데이터 핀에 풀업 및 비동기 모드 설정
// 풀업: SDRAM 데이터 입력 안정성 확보
// 비동기 입력: 동기 모드지만 데이터 핀은 비동기 처리 가능
for(i = 69; i <= 85; i++)
{
if(i == 84) continue; // GPIO84는 EMIF1_Dx에 포함되지 않음 (pin_map.h 기준)
GPIO_setPadConfig(i, GPIO_PIN_TYPE_PULLUP); // 풀업 활성화 (전기적 노이즈 방지)
GPIO_setQualificationMode(i, GPIO_QUAL_ASYNC); // 비동기 입력 모드
}
// 디버깅용 LED 설정 (GPIO31)
// GPIO31은 EMIF1_WEN과 공유 가능 (pin_map.h: 0x00081E00U, 0x00081E02U)
GPIO_setPinConfig(GPIO_31_GPIO31); // GPIO31을 일반 GPIO로 설정 (0x00081E00U)
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드 (LED 제어)
GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD); // 표준 패드 (풀업 비활성화)
GPIO_writePin(31, 0); // LED 초기 상태: 꺼짐 (testStatusGlobal로 제어)
}
// EMIF1 초기화 함수
// 역할: EMIF1을 동기 SDRAM 모드로 설정하여 데이터 읽기/쓰기 지원 (CS0, 16비트)
// 참고: TMS320F2838x TRM 섹션 15 (EMIF), Micron MT48LC32M16A2 데이터시트, C2000Ware v6.00.00.00
void initEMIF(void)
{
EMIF_SyncTimingParams tParam;
EMIF_SyncConfig sdConfig;
// EMIF1 클럭 활성화
// CPU1SYSCLK(200MHz)를 2분주하여 100MHz EMIF 클럭 생성 (SDRAM 타이밍 준수)
SysCtl_setEMIF1ClockDivider(SYSCTL_EMIF1CLK_DIV_2);
// EMIF1을 CPU1에 할당
// CPU1_G: CPU1 전용 제어 (다른 코어와 공유 없음)
EMIF_selectController(EMIF1CONFIG_BASE, EMIF_CONTROLLER_CPU1_G);
// 접근 보호 비활성화
// CPU 패치, CPU 쓰기, DMA 쓰기 허용
EMIF_setAccessProtection(EMIF1CONFIG_BASE, 0x0);
// 설정 커밋 및 잠금
// EMIF1ACCPROT0 레지스터 변경 방지
EMIF_commitAccessConfig(EMIF1CONFIG_BASE);
EMIF_lockAccessConfig(EMIF1CONFIG_BASE);
// SDRAM 타이밍 파라미터 설정
// Micron MT48LC32M16A2 기준, 100MHz 클럭(10ns/사이클)
// tRFC = 60ns (6 사이클), tRP = 18ns (1 사이클), tRCD = 18ns (1 사이클)
// tWR = 1CLK + 6ns (1 사이클), tRAS = 42ns (4 사이클), tRC = 60ns (6 사이클)
// tRRD = 12ns (1 사이클)
tParam.tRfc = 0x6U;
tParam.tRp = 0x1U;
tParam.tRcd = 0x1U;
tParam.tWr = 0x1U;
tParam.tRas = 0x4U;
tParam.tRc = 0x6U;
tParam.tRrd = 0x1U;
EMIF_setSyncTimingParams(EMIF1_BASE, &tParam);
// Self Refresh 종료 타이밍 설정
// Txsr = 70ns (7 사이클)
EMIF_setSyncSelfRefreshExitTmng(EMIF1_BASE, 0x7U);
// 리프레시 주기 설정
// Tref = 64ms/8192행, RR = 64000*100MHz/8192 = 781.25 (0x30E)
EMIF_setSyncRefreshRate(EMIF1_BASE, 781);
// SDRAM 메모리 구성
// MT48LC32M16A2: 13행 주소, 10열 주소, 4뱅크, 16비트 폭
sdConfig.casLatency = EMIF_SYNC_CAS_LAT_3; // CAS 지연 시간: 3
sdConfig.iBank = EMIF_SYNC_BANK_4; // 4뱅크
sdConfig.narrowMode = EMIF_SYNC_NARROW_MODE_TRUE; // 16비트 데이터 폭
sdConfig.pageSize = EMIF_SYNC_COLUMN_WIDTH_10; // 열 주소 10비트 (1024열)
EMIF_setSyncMemoryConfig(EMIF1_BASE, &sdConfig);
// 초기화 성공 상태 설정
testStatusGlobal = TEST_PASS;
}
// 워치독 초기화 함수
// 역할: 시스템 안정성을 위해 워치독 타이머 설정 (리셋 모드)
// 참고: TMS320F2838x TRM 섹션 8 (워치독)
void initWatchdog(void)
{
EALLOW; // 보호된 레지스터 접근 허용
// 워치독 활성화
// INTOSC1/512, 리셋 모드 활성화 (WDCR: Watchdog Control Register)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연 (안정화)
// 프리스케일러 설정
// /64 분주 (약 1.28ms 틱, 200MHz 기준)
HWREG(WD_BASE + SYSCTL_O_WDCR) = SYSCTL_WD_CHKBITS | SYSCTL_WD_PRESCALE_64;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 즉시 리셋 방지를 위해 워치독 서비스
// WDKEY 레지스터에 두 번 연속 쓰기 (ENRSTKEY, RSTKEY)
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_ENRSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
HWREG(WD_BASE + SYSCTL_O_WDKEY) = SYSCTL_WD_RSTKEY;
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
EDIS; // 보호된 레지스터 접근 비활성화
}
// SDRAM 및 로컬 버퍼 초기화 함수
// 역할: SDRAM 및 로컬 목적지 버퍼를 0x0으로 초기화
// 참고: Micron MT48LC32M16A2 데이터시트, TMS320F2838x TRM 섹션 15 (EMIF)
void clearDestDataBuffer(uint32_t memSize)
{
uint32_t i;
uint32_t memWdl = 0x0;
// SDRAM 버퍼 초기화 (far 메모리, 0x00100000)
for(i = 0; i < memSize; i++)
{
__addr32_write_uint32((uint32_t)(extSDRAMBuf + (i * 2)), 0x0);
DEVICE_DELAY_US(10); // 쓰기 안정화 지연 (10us)
}
// 로컬 목적지 버퍼 초기화
for(i = 0; i < memSize; i++)
{
localDstRAMBuf[i] = memWdl;
DEVICE_DELAY_US(10); // 쓰기 안정화 지연 (10us)
}
}
// DMA 채널 1 설정 함수
// 역할: 로컬 RAM에서 SDRAM으로 데이터 쓰기 (16비트 전송)
// 참고: TMS320F2838x TRM 섹션 14 (DMA), C2000Ware v6.00.00.00
void configDMAChannel1(void)
{
// DMA 채널 1 설정 (16비트 데이터 크기)
// 소스: localSrcRAMBuf (ramgs0), 목적지: extSDRAMBuf (SDRAM)
destDMA = extSDRAMBuf;
srcDMA = (volatile uint32_t *)localSrcRAMBuf;
DMA_configAddresses(DMA_CH1_BASE, (const void*)destDMA, (const void*)srcDMA);
DMA_configBurst(DMA_CH1_BASE, 32U, 1U, 1U); // 버스트 크기: 32, 증분: 1
DMA_configTransfer(DMA_CH1_BASE, ((MEM_BUFFER_SIZE * 2) / 32), 1, 1); // 전송 횟수
DMA_configWrap(DMA_CH1_BASE, 0x10000U, 0, 0x10000U, 0); // 랩 설정
// DMA 트리거: 소프트웨어, 원샷 모드, 연속 모드 비활성화, 16비트 전송
DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SOFTWARE,
(DMA_CFG_ONESHOT_ENABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT));
// DMA 트리거 활성화
DMA_enableTrigger(DMA_CH1_BASE);
// 불필요한 인터럽트 플래그 제거
DMA_clearTriggerFlag(DMA_CH1_BASE);
DMA_clearErrorFlag(DMA_CH1_BASE);
}
// DMA 채널 2 설정 함수
// 역할: SDRAM에서 로컬 RAM으로 데이터 읽기 (32비트 전송)
// 참고: TMS320F2838x TRM 섹션 14 (DMA), C2000Ware v6.00.00.00
void configDMAChannel2(void)
{
// DMA 채널 2 설정 (32비트 데이터 크기)
// 소스: extSDRAMBuf (SDRAM), 목적지: localDstRAMBuf (ramgs1)
destDMA = (volatile uint32_t *)localDstRAMBuf;
srcDMA = extSDRAMBuf;
DMA_configAddresses(DMA_CH2_BASE, (const void*)destDMA, (const void*)srcDMA);
DMA_configBurst(DMA_CH2_BASE, 32U, 2U, 2U); // 버스트 크기: 32, 증분: 2
DMA_configTransfer(DMA_CH2_BASE, ((MEM_BUFFER_SIZE * 2) / 32), 2, 2); // 전송 횟수
DMA_configWrap(DMA_CH2_BASE, 0x10000U, 0, 0x10000U, 0); // 랩 설정
// DMA 트리거: 소프트웨어, 원샷 모드, 연속 모드 비활성화, 32비트 전송
DMA_configMode(DMA_CH2_BASE, DMA_TRIGGER_SOFTWARE,
(DMA_CFG_ONESHOT_ENABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_32BIT));
// DMA 트리거 활성화
DMA_enableTrigger(DMA_CH2_BASE);
// 불필요한 인터럽트 플래그 제거
DMA_clearTriggerFlag(DMA_CH2_BASE);
DMA_clearErrorFlag(DMA_CH2_BASE);
}
// 메인 함수
// 역할: 시스템 초기화, EMIF1 SDRAM 설정, DMA를 사용한 데이터 쓰기/읽기 및 검증, 상태 모니터링
// 참고: TMS320F28388D, C2000Ware v6.00.00.00, Micron MT48LC32M16A2, pin_map.h
void main(void)
{
uint16_t i; // 루프 변수 선언 (C89 호환)
// 테스트 상태 초기화
testStatusGlobal = TEST_FAIL;
// 시스템 초기화
// 클럭, PLL, 주변 장치 초기화 (200MHz CPU1SYSCLK)
Device_init();
// 인터럽트 비활성화
DINT;
// GPIO 설정
// EMIF1 핀(CS0N, WEN, OEN, CLK, RAS, CAS, BA0, BA1, SDCKE, A0-A15, D0-D15) 및 LED 설정
Device_initGPIO();
initGPIO();
// PIE 모듈 초기화
// PIE 제어 레지스터 초기화 및 인터럽트 플래그 제거
Interrupt_initModule();
// 인터럽트 벡터 테이블 초기화
// 기본 핸들러로 벡터 테이블 설정 (확장 대비)
Interrupt_initVectorTable();
// 전역 및 실시간 인터럽트 활성화
EINT;
ERTM;
// 시스템 클럭 확인
// 200MHz 확인, 실패 시 오류 처리 (LED 끄기, 정지)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if(sysClockHz != 200000000)
{
testStatusGlobal = TEST_FAIL; // 클럭 오류 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지 (디버깅용)
}
// DMA 초기화
DMA_initController();
// DMA 채널 설정
// 채널 1: 로컬 RAM -> SDRAM 쓰기, 채널 2: SDRAM -> 로컬 RAM 읽기
configDMAChannel1();
configDMAChannel2();
// DMA 채널 시작
DMA_startChannel(DMA_CH1_BASE);
DMA_startChannel(DMA_CH2_BASE);
// EMIF1 초기화
// 동기 SDRAM 모드 설정 (CS0, 16비트)
initEMIF();
// 초기화 오류 확인
// EMIF 초기화 실패 시 오류 처리 (LED 끄기, 정지)
if(testStatusGlobal != TEST_PASS)
{
testStatusGlobal = TEST_FAIL; // 초기화 실패 상태 설정
GPIO_writePin(31, 0); // LED 끄기
ESTOP0; // 즉시 정지
}
// 소스 버퍼 초기화
// initData = 0x12103456, 각 워드에 0x11111111 추가
initData = 0x12103456;
for(i = 0; i < MEM_BUFFER_SIZE; i++)
{
initData = initData + 0x11111111;
localSrcRAMBuf[i] = initData;
}
// SDRAM 및 로컬 버퍼 초기화
clearDestDataBuffer(MEM_BUFFER_SIZE);
// SDRAM 쓰기 (DMA 채널 1)
DMA_forceTrigger(DMA_CH1_BASE);
EALLOW;
while((HWREGH(DMA_CH1_BASE + DMA_O_CONTROL) & DMA_CONTROL_TRANSFERSTS) != 0x0U);
EDIS;
// SDRAM 읽기 (DMA 채널 2)
DMA_forceTrigger(DMA_CH2_BASE);
EALLOW;
while((HWREGH(DMA_CH2_BASE + DMA_O_CONTROL) & DMA_CONTROL_TRANSFERSTS) != 0x0U);
EDIS;
// 데이터 검증
// localSrcRAMBuf와 localDstRAMBuf 비교
for(i = 0; i < MEM_BUFFER_SIZE; i++)
{
if(localSrcRAMBuf[i] != localDstRAMBuf[i])
{
errCountGlobal++; // 오류 카운트 증가
testStatusGlobal = TEST_FAIL; // 테스트 실패
}
}
// 테스트 결과 설정
if(errCountGlobal == 0)
{
testStatusGlobal = TEST_PASS; // 테스트 성공
}
// 워치독 초기화
// 리셋 모드, /64 프리스케일러 설정
initWatchdog();
// 무한 루프
// 테스트 상태 모니터링, 워치독 서비스, LED 상태 업데이트
for(;;)
{
GPIO_writePin(31, (testStatusGlobal == TEST_PASS) ? 1 : 0); // LED 상태 업데이트 (정상: 켜짐, 오류: 꺼짐)
SysCtl_serviceWatchdog(); // 워치독 서비스 (리셋 방지)
DEVICE_DELAY_US(1000000); // 1초 지연 (폴링 주기)
}
}
/* TMS320F2838x CPU1용 링커 스크립트 (C2000Ware v6.00.00.00 기반)
* 역할: 내부 RAM, 플래시, 외부 SDRAM 메모리 매핑 및 섹션 할당
* 수정: .farbss 섹션과 EMIF1_CS0 메모리 추가 (SDRAM용, 0x00100000)
* 참고: TMS320F2838x TRM 섹션 15 (EMIF), Micron MT48LC32M16A2 데이터시트
*/
MEMORY
{
/* BEGIN is used for the "boot to SARAM" bootloader mode */
BEGIN : origin = 0x000000, length = 0x000002
BOOT_RSVD : origin = 0x000002, length = 0x0001AF /* Part of M0, BOOT rom will use this for stack */
RAMM0 : origin = 0x0001B1, length = 0x00024F
RAMM1 : origin = 0x000400, length = 0x0003F8 /* on-chip RAM block M1 */
// RAMM1_RSVD : origin = 0x0007F8, length = 0x000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
RAMD0 : origin = 0x00C000, length = 0x000800
RAMD1 : origin = 0x00C800, length = 0x000800
RAMLS0 : origin = 0x008000, length = 0x000800
RAMLS1 : origin = 0x008800, length = 0x000800
RAMLS2 : origin = 0x009000, length = 0x000800
RAMLS3 : origin = 0x009800, length = 0x000800
RAMLS4 : origin = 0x00A000, length = 0x000800
RAMLS5 : origin = 0x00A800, length = 0x000800
RAMLS6 : origin = 0x00B000, length = 0x000800
RAMLS7 : origin = 0x00B800, length = 0x000800
RAMGS0 : origin = 0x00D000, length = 0x001000
RAMGS1 : origin = 0x00E000, length = 0x001000
RAMGS2 : origin = 0x00F000, length = 0x001000
RAMGS3 : origin = 0x010000, length = 0x001000
RAMGS4 : origin = 0x011000, length = 0x001000
RAMGS5 : origin = 0x012000, length = 0x001000
RAMGS6 : origin = 0x013000, length = 0x001000
RAMGS7 : origin = 0x014000, length = 0x001000
RAMGS8 : origin = 0x015000, length = 0x001000
RAMGS9 : origin = 0x016000, length = 0x001000
RAMGS10 : origin = 0x017000, length = 0x001000
RAMGS11 : origin = 0x018000, length = 0x001000
RAMGS12 : origin = 0x019000, length = 0x001000
RAMGS13 : origin = 0x01A000, length = 0x001000
RAMGS14 : origin = 0x01B000, length = 0x001000
RAMGS15 : origin = 0x01C000, length = 0x000FF8
// RAMGS15_RSVD : origin = 0x01CFF8, length = 0x000008 /* Reserve and do not use for code as per the errata advisory "Memory: Prefetching Beyond Valid Memory" */
/* Flash sectors */
FLASH0 : origin = 0x080000, length = 0x002000 /* on-chip Flash */
FLASH1 : origin = 0x082000, length = 0x002000 /* on-chip Flash */
FLASH2 : origin = 0x084000, length = 0x002000 /* on-chip Flash */
FLASH3 : origin = 0x086000, length = 0x002000 /* on-chip Flash */
FLASH4 : origin = 0x088000, length = 0x008000 /* on-chip Flash */
FLASH5 : origin = 0x090000, length = 0x008000 /* on-chip Flash */
FLASH6 : origin = 0x098000, length = 0x008000 /* on-chip Flash */
FLASH7 : origin = 0x0A0000, length = 0x008000 /* on-chip Flash */
FLASH8 : origin = 0x0A8000, length = 0x008000 /* on-chip Flash */
FLASH9 : origin = 0x0B0000, length = 0x008000 /* on-chip Flash */
FLASH10 : origin = 0x0B8000, length = 0x002000 /* on-chip Flash */
FLASH11 : origin = 0x0BA000, length = 0x002000 /* on-chip Flash */
FLASH12 : origin = 0x0BC000, length = 0x002000 /* on-chip Flash */
FLASH13 : origin = 0x0BE000, length = 0x002000 /* on-chip Flash */
CPU1TOCPU2RAM : origin = 0x03A000, length = 0x000800
CPU2TOCPU1RAM : origin = 0x03B000, length = 0x000800
CPUTOCMRAM : origin = 0x039000, length = 0x000800
CMTOCPURAM : origin = 0x038000, length = 0x000800
CANA_MSG_RAM : origin = 0x049000, length = 0x000800
CANB_MSG_RAM : origin = 0x04B000, length = 0x000800
RESET : origin = 0x3FFFC0, length = 0x000002
/* EMIF1 CS0 메모리 추가: SDRAM (Micron MT48LC32M16A2, 64Mbit)용 */
EMIF1_CS0 : origin = 0x00100000, length = 0x00800000 /* EMIF1 CS0, SDRAM, 8MB */
}
SECTIONS
{
codestart : > BEGIN
.text : >> RAMD0 | RAMD1 | RAMLS0 | RAMLS1 | RAMLS2 | RAMLS3
.cinit : > RAMM0
.switch : > RAMM0
.reset : > RESET, TYPE = DSECT /* not used, */
.stack : > RAMM1
#if defined(__TI_EABI__)
.bss : > RAMLS5
.bss:output : > RAMLS3
.init_array : > RAMM0
.const : > RAMLS5 | RAMLS6
.data : > RAMLS5
.sysmem : > RAMLS4
#else
.pinit : > RAMM0
.ebss : >> RAMLS5 | RAMLS6
.econst : > RAMLS5
.esysmem : > RAMLS5
#endif
ramgs0 : > RAMGS0, type=NOINIT
ramgs1 : > RAMGS1, type=NOINIT
/* .farbss 섹션 추가: EMIF1 CS0 SDRAM에 매핑 (extSDRAMBuf용) */
.farbss : > EMIF1_CS0, PAGE = 1
MSGRAM_CPU1_TO_CPU2 : > CPU1TOCPU2RAM, type=NOINIT
MSGRAM_CPU2_TO_CPU1 : > CPU2TOCPU1RAM, type=NOINIT
MSGRAM_CPU_TO_CM : > CPUTOCMRAM, type=NOINIT
MSGRAM_CM_TO_CPU : > CMTOCPURAM, type=NOINIT
/* The following section definitions are for SDFM examples */
Filter_RegsFile : > RAMGS0
Filter1_RegsFile : > RAMGS1, fill=0x1111
Filter2_RegsFile : > RAMGS2, fill=0x2222
Filter3_RegsFile : > RAMGS3, fill=0x3333
Filter4_RegsFile : > RAMGS4, fill=0x4444
Difference_RegsFile : > RAMGS5, fill=0x3333
.TI.ramfunc : > RAMM0
}
/*
//===========================================================================
// End of file.
//===========================================================================
*/
수정 내용
- MEMORY 블록:
- EMIF1_CS0 추가:
- 주소: 0x00100000
- 길이: 0x00800000 (8MB, Micron MT48LC32M16A2의 64Mbit 용량 지원)
- 주석: SDRAM 용도 명시
- 기존 메모리 정의(RAMM0, RAMD0, RAMLS0–RAMLS7, RAMGS0–RAMGS15, FLASH0–FLASH13 등) 유지.
- EMIF1_CS0 추가:
- SECTIONS 블록:
- .farbss 섹션 추가:
- 매핑: EMIF1_CS0, PAGE = 1 (데이터 페이지, EMIF1은 데이터 공간으로 사용)
- 주석: extSDRAMBuf용 SDRAM 매핑 명시
- 기존 섹션 정의(codestart, .text, .bss, ramgs0, ramgs1 등) 유지.
- .farbss 섹션 추가:
- 호환성:
- emif_sdram_dma.c의 extSDRAMBuf (__attribute__((far)), #pragma DATA_SECTION(extSDRAMBuf, ".farbss"))와 일치.
- TMS320F2838x TRM 섹션 15(EMIF): EMIF1 CS0 주소 범위(0x00100000–0x008FFFFF) 준수.
- C2000Ware v6.00.00.00 및 TI C2000 컴파일러(ti-cgt-c2000_22.6.1.LTS) 호환.
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, 비동기 모드, 동기 모드, 대기 신호, 칩 선택
'MCU > C2000' 카테고리의 다른 글
TMS320F28388D DSP CAN 사용법: DriverLib API로 CAN 설정 및 코드(수정) (0) | 2025.08.17 |
---|---|
TMS320F28388D DSP SDFM 사용법: DriverLib API로 SDFM 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP CLB 사용법: DriverLib API로 CLB 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP CLA 사용법: DriverLib API로 CLA 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP eQEP 사용법: DriverLib API로 eQEP 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP eCAP 사용법: DriverLib API로 eCAP 설정 및 코드(수정) (3) | 2025.08.17 |
TMS320F28388D DSP ePWM 사용법: DriverLib API로 ePWM 설정 및 코드(수정본) (0) | 2025.08.16 |
TMS320F28388D DSP ADC 사용법: DriverLib API로 ADC 설정 및 코드(수정) (0) | 2025.08.08 |