SDRAM
작업 중
ULX3S와 OrangeCrab의 SDRAM 칩과 통신해 봅시다! 현재 이 페이지에는 정리되지 않은 메모가 담겨 있으며, 저는 지금 정보를 모으면서 몇 가지 설계를 시도하고 있습니다. 진행 상황은 이곳에 보고하겠습니다.
목표 1: 640x480(이후 풀 HD) 24비트 RGB 프레임버퍼를 갖추고, 간단한 writer 회로(이후에는 FemtoRV32)가 생성한 간단한 움직이는 패턴을 표시하는 그래픽 보드입니다. WIP 프로젝트는 여기에 있습니다.
목표 2: FemtoSOC에 통합하여 FemtoRV32에서 완전히 접근할 수 있도록 합니다.
기타 메모
- 주소: 뱅크, 행, 열
- 명령: 행 열기(activate), 읽기/쓰기, 행 닫기(precharge 오해의 소지가 있음: pre-charge는 행을 닫는다는 뜻입니다)
- 리프레시: 자동 리프레시를 사용하거나 행에 접근합니다
- FPGA4Fun 예제: 그래픽 보드에 이상적입니다(듀얼 포트, 읽기 에이전트가 리프레시를 수행합니다)
- DDR RAM
- ULX3S 데이터시트: 32MB SDRAM, 166MHz, 16비트 Micron
MT48LC32M16
- 하지만 제 ULX3S에는: ALLIANCE AS4C32M16SB-7TCN
- ... 그리고 다른 변형도 있습니다(sylefeb의 Silice 메모리 컨트롤러에 있는 주석을 참고하십시오)
핀
- clk : 143MHz 클록(7TCN 시리즈)
- cke : 클록 활성화(1에 연결)
- csn : 칩 선택(high: 모든 동작이 금지됨)
- 명령: [wen, rasn, casn]
- wen : 쓰기 활성화(읽기/쓰기 비트)
- rasn : 행 주소 스트로브(하지만 스트로브는 아님)
- casn : 열 주소 스트로브(하지만 스트로브는 아님)
- a[12:0] : 주소(+ 버스트/자동 닫기 및 뱅크 내 닫기, 모든 뱅크 닫기 동작을 선택하는 라인 1개)
- ba[1:0] : 뱅크
- dqm[1:0] : 데이터 마스크(high: 데이터 I/O 억제). 8비트당 라인 하나입니다.
- d[15:0] : 양방향 데이터 버스
명령
- nop
- load mode
- 행 열기(activate)
- 읽기
- 쓰기
- 행 닫기(precharge)
- 리프레시
상태 기계
- 유휴(Idle)
- 전이 시 행 열기(activate)
- 읽기/쓰기
- 행 닫기(precharge)
- Nop
FPGA4fun 설계에는 '작은 글씨'로 된 제약 조건이 있으므로 주석을 주의 깊게 읽으십시오:
- CAS(Column Address Strobe, 열 주소 스트로브) 지연 시간=2와 유효한 버스트 모드 중 하나로 초기화해야 합니다
- 읽기 에이전트가 RAM을 리프레시할 만큼 충분히 자주 동작해야 합니다.
이 조건이 충족되지 않으면 다음도 필요할 수 있습니다:
- 읽기 측이 충분히 자주 동작하지 않는 경우를 위한 타이머와 '리프레시 상태'
- CAS가 2보다 큰 경우 행을 열고 닫은 뒤의 추가 'nop' 상태
질문
- Q1: 모드 레지스터는 어떻게 올바르게 초기화합니까?[OK, 데이터시트 14쪽]
- Q2: 어떤 모드들이 있습니까? [OK]
- Q3: 데이터 읽기와 비디오 신호 생성은 어떻게 동기화합니까?
- Q4: 버스트 모드를 선택하는 '특수' 주소 라인은 어느 것입니까? [OK, A10입니다]
- Q5: 타이밍은 어떻습니까? CAS와 주파수는 어떤 관계입니까? 데이터시트 15쪽과 21쪽의 표를 참고하십시오. [OK]
- Q6: 자동 프리차지, 자동 리프레시, 셀프 리프레시란 무엇입니까? [OK]
- Q7: 그 주파수에서는 래치된 IO 핀을 위한 전용 FPGA 블록이 필요할 것입니다.
- Q8: 초기화 시퀀스는 어떻게 구현합니까? 하드와이어드 방식입니까? BRAM에 마이크로프로그래밍하는 방식입니까? CPU로 제어하는 방식입니까? [OK: 작은 카운터]
- Q9: ULX3S에 사용된 모든 칩의 최대 공통 부분집합은 무엇입니까? [OK]
칩 데이터시트를 읽으십시오(제 보드의 경우: ALLIANCE AS4C32M16SB-7TCN)
- 빠른 클록 속도: 166/143 MHz
- 512 Mbits(64 MBytes): 8M 워드 x 16비트 x 4뱅크
- 모드
- CAS 지연 시간: 2 또는 3
- 버스트 길이: 1, 2, 4, 8 또는 전체 페이지
- 버스트 유형: 순차(sequential) 또는 인터리브(interleaved)
- 버스트 정지 함수
- 자동 리프레시 / 셀프 리프레시
- 8192 리프레시 사이클 / 64 ms
- 뱅크 활성화(Bank Activate): 행 주소 = A[12:0]
- 읽기/쓰기: 열 주소 = A[9:0], 자동 프리차지 = A[10]
- 모드 레지스터 설정: 연산 코드 = A[..:..]
- 7페이지: 명령 목록(명령이 19개나 됩니다!)
모드 레지스터 비트맵:
| BA1 | BA0 | A12 | A11 | A10 | A09 | A08 | A07 | A06 | A05 | A04 | A03 | A02 | A01 | A00 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| X | 0 | X | X | X | WBL | Tst | Tst | CAS | CAS | CAS | BT | Bst | Bst | Bst |
| 필드 이름 | 필드 설명 |
|---|---|
| WBL (Write Burst Len) | 0: 버스트 1: 단일 비트 |
| 테스트 모드 | 0 0 (그 외 설정은 벤더 전용) |
| CAS 지연 시간 | 010 (2클록) 또는 011 (3클록) |
| BT (Burst Type) | 0: 순차 1: 인터리브 |
| 버스트 길이 | 000:1 001:2 010:4 011:8 111:전체 페이지 (순차) |
질문에 대한 답변
Q1,Q2,Q8: 모드 레지스터와 초기화 시퀀스는 어떻게 됩니까?
| BA1 | BA0 | A12 | A11 | A10 | A09 | A08 | A07 | A06 | A05 | A04 | A03 | A02 | A01 | A00 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| X | 0 | X | X | X | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
- WBL: 0: 버스트 1: 단일 비트 이것이 무슨 뜻인지 모르겠습니다
- CAS 지연 시간: 010: 2 클록 FPGA4Fun 설계에서 요구됨
- BT: 0: 순차 1: 인터리브 이것이 무슨 뜻인지 모르겠습니다
- 버스트 길이: 001: 2 32비트를 위해 2로 설정합니다
초기화 시퀀스(데이터시트 14쪽)
- CKE는 high, DQM은 low, DQ는 Z가 됩니다
- 1사이클 대기합니다
- 전체 프리차지(precharge all)
- tRP만큼 대기
- 모드 레지스터 설정
- tMRD(1사이클)만큼 대기
- 이제 첫 번째 명령을 보낼 수 있습니다
참고: 여기에 설명된 초기화 시퀀스는 더 복잡합니다. 제가 무언가를 놓쳤을 수도 있습니다. Silice, Lawrie, stffrdhrn의 컨트롤러에 있는 초기화 시퀀스를 살펴보면 위의 초기화 시퀀스로도 충분할 것으로 보입니다(다만 모든 SDRAM 칩에서 동작할지는 확신하지 못합니다). 초기화 시퀀스 동안 동작하는 간단한 사이클 카운터를 사용하려고 합니다(그리고 전원 인가 시 칩이 충분한 시간을 가질 수 있도록 이 카운터는 전역 리셋 신호로 억제합니다).
Q3: 데이터 읽기와 비디오 신호 생성을 어떻게 동기화합니까?
*Q6: 자동 프리차지(auto-precharge), 셀프 리프레시(self-refresh), 자동 리프레시(auto-refresh)란 무엇입니까? MICRON 기술 문서가 더 읽기 쉽습니다. 무엇이라고 쓰여 있는지 살펴봅시다.
- 자동 프리차지: 버스트 읽기나 버스트 쓰기가 끝나면 행을 프리차지합니다(닫습니다).
- 자동 리프레시: 주소는 내부 리프레시 컨트롤러가 생성합니다. 정기적으로 하나씩 신호를 보내거나, 더 드물게 전체를 버스트 리프레시하기만 하면 됩니다.
- 셀프 리프레시: 시스템의 나머지 부분의 전원이 꺼져 있을 때 데이터를 유지합니다.
Q9: ULX3S에 사용되는 모든 SDRAM 칩을 아우르는 최대 공통 부분집합(largest common subset)은 무엇입니까?
| 제조사 | 모델명 | 용량 | 폭 | 뱅크 | 행 | 열 |
|---|---|---|---|---|---|---|
| Micron | MT48LC32M16 | 64 MB | 16비트 | 4 | 8192 | 1024 |
| ALLIANCE | AS4C32M16SB | 64 MB | 16비트 | 4 | 8192 | 1024 |
| ALLIANCE | IS42S16160G | 32 MB | 16비트 | 4 | 8192 | 512 |
| ALLIANCE | AS4C16M16SA | 32 MB | 16비트 | 4 | 8192 | 512 |
Q5: 타이밍, 그리고 CAS와 주파수의 관계는 무엇입니까?
AS4C32M16SB-7TCN의 타이밍(데이터시트 21쪽 표 16): 7-TCN은 tCK3=7ns = 143MHz를 뜻하지만, CL=2에서는 10ns(100MHz)로 떨어집니다.
가장 중요한 매개변수는 tRCD(RAS에서 CAS까지), CL(CAS 지연 시간), tRP(precharge에서 리프레시 행까지)입니다.
| 시간 | 값 | 설명 |
|---|---|---|
| tCK | 10ns | 클록, CAS 레이턴시=2일 때 |
| tRC | 63ns | 행 사이클 시간 |
| tRCD | 21ns | RAS에서 CAS까지, 동일 뱅크 |
| tRP | 21ns | precharge에서 리프레시/행 활성화까지, 같은 뱅크 |
| tRRD | 14ns | 행 활성화에서 행 활성화까지, 다른 뱅크 |
| tMRD | 14ns | 모드 레지스터 설정 |
| tRAS | 42ns | 행 활성화에서 precharge까지. max=120K |
| tWR | 14ns | 쓰기 복구 시간 |
| tREFI | 7.8us | 평균 리프레시 간격 시간 |
| tDAL | 25ns | tDAL = tWR + tRP |
Q: 다른 칩에서는 이 타이밍들이 어떻게 됩니까? Micron MT48LC32M16-75(데이터시트 33쪽의 표)를 살펴봅시다. 좋은 소식은 SDRAM 제조사가 달라도 타이밍 기호는 같은 것으로 보인다는 점입니다:
| 시간 | 값 | 설명 |
|---|---|---|
| tCK | 7.5ns | 클록, CAS 레이턴시=2 또는 3, 속도 등급 7E 또는 75 |
| tRC | 66ns | 행 사이클 시간 |
| tRCD | 20ns | RAS에서 CAS까지, 동일 뱅크 |
| tRP | 20ns | precharge에서 리프레시/행 활성화까지, 같은 뱅크 |
| tRRD | 15ns | 행 활성화에서 행 활성화까지, 다른 뱅크 |
| tMRD | 2clk | 모드 레지스터 설정 |
| tRAS | 44ns | 행 활성화에서 precharge까지. max=120K |
| tWR | 2clk | 쓰기 복구 시간 |
| tREFI | 7.81us | 평균 리프레시 간격 시간 |
| tDAL | 35ns | tDAL = tWR + tRP |
리프레시: 64ms(tREF)마다 AUTO REFRESH 사이클 8192회를 버스트로(tRC 간격으로) 수행하거나, 7.81 us마다 AUTO REFRESH 사이클을 1회 수행합니다.
Q7: 그 주파수에서는 아마 특수 IO 블록이 필요할 것입니다. 어떤 블록이 필요합니까?
Alchetry용 이 예제에 매우 잘 설명되어 있습니다. 세 가지가 있습니다:
- SDRAM 클록을 반전해야 합니다
- SDRAM 클록을 지연시켜야 합니다
- 모든 신호를 동시에 수신/송신할 수 있도록 다음 신호의 입출력
레지스터를 IO 버퍼 안에 내장해야 합니다:
- cle (클록 인에이블)
- dqm (2비트 데이터 마스크)
- cmd (3비트 명령)
- ba (2비트 뱅크 주소)
- a (주소)
- q (데이터 출력)
- qi (데이터 입력)
다음 사항에 맞게 수정해야 합니다:
- 우리 SDRAM은 16비트이며(예제는 8비트입니다), 모든 타이밍도 다를 가능성이 큽니다
- ECP5 전용 프리미티브는 All Lattice blocks를 참고하십시오
- Yosys ECP5
- TRELLIS_IO
필요한 것은 다음과 같습니다:
- IO 핀에 연결된 래치(입력)와 플립플롭(출력)(ECP5에서는 어떻게 합니까?
BB,IB,OB를 씁니까?). 그 자리에 래치를 어떻게 둘 수 있습니까? Ice-40에서는SB_GB_IO입니다. ECP5에서는 nextpnr이 IO 안에 패킹하는IFS1P3BX,OFS1P3BX인 것 같습니다. 여기의 논의를 참고하십시오. - 상승 에지 대신 하강 에지마다 SDRAM에 클록 전송(아마 상수 비트 0과
1을 넣은
ODDRX1F사용) - 클록 지연(ECP5에서는 어떻게 합니까?
DELAYF,DELAYG를 씁니까?) IFS1P3BX,OFS1P3BX(이것이 무엇입니까? 매뉴얼을 제대로 읽어 봐야겠습니다...) 이들은 PIC(Programmable IO Cell)입니다. 관련 정보는 여기와 여기에 있습니다BB를 사용한 예는 여기에 있습니다
좋습니다. 방법은 IFS1P3BX와 BB를 하나의
PIC(programmable IO Cell) 안에 결합하는 것입니다. 원래대로라면
nextpnr-ecp5가 이를 지원합니다(여기의 최근
게시물에 따르면 그렇습니다).
SDRAM에 프레임버퍼를 둘 수 있겠습니까? HDMI 640x480 타이밍
이 방법으로 설계를 테스트하는 것이 맞는지는 잘 모르겠습니다. valid/busy/ready 프로토콜을 쓰는 범용 컨트롤러를 만들어 FemtoRV32의 주소 공간에 매핑하는 편이 더 쉬워 보입니다. 두고 보겠습니다...
리프레시
- 800x525x60Hz - 픽셀 클록 = 25MHz
- 각 픽셀 행에는 140픽셀의 hblank 구간 = 5.6us가 있습니다. 여기서 '분산 리프레시(distributed-refresh)'를 할 수 있습니다
- vblank 구간 = 1.44ms 여기서 '버스트 리프레시(burst-refresh)'를 할 수 있습니다
프레임버퍼 읽기
픽셀 한 행을 BRAM에 보관해 두고, 이를 버스트 읽기(버스트 길이 = 전체 페이지)로 읽어 올 수 있을지도 모릅니다. 문제는 이것이 SDRAM의 단일 행 하나에 들어가느냐입니다. 답은 '아니오'입니다(칩에 따라 행당 1kB 또는 2kB입니다). 하지만 이것이 문제가 되지 않을 수도 있습니다. SDRAM은 100MHz로 동작하고 화면의 픽셀 클록은 25MHz이므로, 아마 라인 버퍼를 두 개 두고 현재 버퍼를 표시하는 동안 다음 버퍼를 읽는 것이 가장 좋은 방법일 것입니다. 이렇게 하면 픽셀당 4바이트를 읽을 수 있습니다. 사실 그렇게 하면 AUTO REFRESH 사이클을 수행할 필요조차 없을 것입니다.
프레임버퍼에 쓰기
그렇다면 프레임버퍼에는 언제 쓸 수 있을까요? 계획대로 읽는다면, 쓰기가 가능한 시간은 스캔라인의 마지막 1/4 구간과 hblank 시간, 그리고 vblank 시간뿐인 것 같습니다. 저는 좀 더 세밀하게 제어할 수 있는 방식을 원합니다. 아니면 SDRAM 칩을 두 개 두고 그래픽 페이지를 두 개 사용하여, 하나는 읽기 전용 모드로, 다른 하나는 쓰기 전용 모드로 쓰는 것이 가장 좋은 방법일 수도 있습니다(쓰기 전용 칩이 리프레시를 수행합니다). 하지만 이것을 같은 칩에서 할 수 있을까요? 그럴 가능성은 그다지 높아 보이지 않습니다.
잠깐만요, 웹에 참고할 만한 자료가 있지 않을까요? 네, 이 강의가 있습니다. Z버퍼까지 다루고 있다니 훌륭합니다! 여기서 무엇을 배울 수 있는지 살펴봅시다... 이 강의에서는 여기에 있는 기성 SDRAM 컨트롤러를 사용합니다. 매우 정교해 보이지만(FIFO가 있습니다), 저는 더 단순한 것이 좋습니다...
이 StackExchange 답변도 있는데, 제 생각과 대체로 일치하는 것 같습니다(기적은 없습니다. 같은 칩에서 읽기와 쓰기를 동시에 할 수는 없습니다).
여기에도 흥미로운 아이디어가 있으며, 노스브리지가 어떻게 동작하는지에 관한 정보를 제공합니다. 일부 칩은 여러 행을 동시에 열 수 있는 것 같습니다(하지만 여기서 사용하는 칩은 아마 그렇지 않을 것입니다).
프레임버퍼와 일반 RAM을 같은 SDRAM 칩에 둘 수 있을까요?
아마 가능하겠지만, 그러려면 다음이 필요합니다.
- 리프레시 사이클을 직접 관리해야 합니다. 프레임버퍼는 지속적인 읽기로 리프레시되고, 나머지는 다른 I/O 작업과 함께 스케줄링된 리프레시 사이클로 리프레시됩니다.
- I/O 작업은 HBlank/VBlank 동안 수행됩니다.