커패시터에 전하를 담아 비트를 저장하는 메모리(Dynamic RAM). 전하가 새어 나가므로 주기적으로 다시 채워야 한다.
왜 리프레시가 필요한가
1비트 = 트랜지스터 1개 + 커패시터 1개
- 커패시터의 전하는 누설로 수십 밀리초 안에 사라진다
- 보통 64ms 안에 모든 행을 한 번씩 읽고 다시 써야 한다
읽는 행위 자체가 파괴적이다. 커패시터의 전하를 감지 증폭기로 읽으면 전하가 빠져나가므로, 읽은 뒤 다시 써 넣는다(restore).
접근 과정 — 왜 느린가
- ① RAS (Row Address Strobe) — — 행 주소를 보내 그 행 전체를 감지 증폭기로
- ② CAS (Column Address Strobe) — 그중 열을 골라 데이터를 꺼낸다
- ③ Precharge — — 다음 행을 위해 비트라인을 초기화
같은 행 안의 연속 접근은 빠르고(②만), 다른 행으로 가면 느리다(①③ 포함).
- CL(CAS Latency)-tRCD-tRP-tRAS 예: 16-18-18-36
- 이 숫자들이 각 단계의 클럭 수
순차 접근이 랜덤 접근보다 훨씬 빠른 물리적 이유가 이것이다. 캐시 라인 단위 전송이나 배열 순회의 이점도 여기서 나온다.
SDRAM·DDR
- SDRAM — : 클럭에 동기화(Synchronous). 파이프라인 동작
- DDR — : Double Data Rate — 클럭의 상승·하강 양쪽에서 전송 → 대역폭 2배
- DDR2~5 : 프리페치 폭을 늘려 대역폭을 계속 확대
- LPDDR — : 저전력 버전. 모바일·임베디드용
DDR이 클럭을 올리지 않고 대역폭을 2배로 만든 방법이 상승/하강 양쪽 사용이다. 클럭을 올리면 신호 무결성 문제가 커지기 때문에 나온 우회책이다.
임베디드에서 언제 DRAM이 필요한가
- MCU 내장 SRAM (수십~수백 KB) — → 대부분의 제어 애플리케이션에 충분
- 외부 SDRAM (수십 MB~) — → 아래의 경우
| 용도 | 필요 이유 |
|---|---|
| 디스플레이 프레임 버퍼 | 800×480×2바이트 ≈ 750KB. SRAM으로 불가 |
| 카메라 영상 처리 | 프레임 여러 장을 동시에 |
| 리눅스 구동 | 최소 수십 MB |
| 오디오 버퍼링 | 긴 버퍼 |
| 네트워크 패킷 버퍼 | 대량 |
연결 방법
- STM32의 FMC/FSMC (Flexible Memory Controller)
- 외부 SDRAM 을 메모리 맵의 0x60000000 또는 0xC0000000 에 매핑
- 이후에는 일반 메모리처럼 포인터로 접근
초기화가 까다롭다 — 타이밍 파라미터(tRCD, tRP, CAS latency), 리프레시 주기, 데이터 폭을 데이터시트대로 정확히 설정해야 한다. 하나만 틀려도 간헐적으로 값이 깨지는 증상이 나온다.
// 리프레시 카운트 계산 예
// COUNT = (SDRAM 리프레시 주기 × SDRAM 클럭) / 행 수 - 20
임베디드에서 DRAM을 쓸 때 주의할 점
① 지연이 일정하지 않다
리프레시 중에는 접근이 지연된다 행이 바뀌면 느려진다
- 실시간성이 중요한 코드를 DRAM에 두면 지터가 생긴다
하드 실시간 코드는 TCM이나 내장 SRAM에 배치한다.
② 캐시와의 조합
Cortex-M7처럼 캐시가 있으면 DMA와 DRAM을 함께 쓸 때 캐시 일관성을
직접 관리해야 한다(SCB_CleanDCache, SCB_InvalidateDCache).
③ 전력
리프레시 때문에 대기 상태에서도 계속 전류를 먹는다. 배터리 기기에서 저전력 모드에 들어가도 DRAM 유지 전력이 남는다. LPDDR의 self-refresh 모드로 줄일 수 있지만 0은 아니다.
④ 초기화 전에는 못 쓴다
startup 코드에서 .data를 복사할 때 DRAM은 아직 초기화 전이다.
DRAM에 배치한 변수는 초기화 이후에 별도로 세팅해야 한다 —
링커 스크립트와 startup 순서를 함께 봐야 하는 지점이다.