FPGA Sipeed Tang Nano 20KでSDRAMを動かす
はじめに
Tang Nano 20Kには64MbitのSDR-SDRAMが内蔵されています。今回は、このメモリを制御するSDRAMコントローラーを作成しました。
設計方針
GOWIN IDEにはSDRAMコントローラのIP(SDRAM Controller HS)が用意されています。よってこれを使えば、(TangNano9KのPSRAMの様に)簡単に制御できると思っていました。
https://www.gowinsemi.com/en/support/ip_detail/5/
ここにあるUser Guideを読むと、"簡単に"と言うにはかなり厳しいインターフェース仕様でした。
SDRAMを直に触るよりは少し楽できそうかな?という印象です。
更に、IPを呼び出すと、SDRAMのACパラメータtRP,tWR,tRCDなどなどを入力しないといけないのですが、これらのパラメータ値が分かりません。。。ドキュメントを探しましたが見つけられず。
また、ここにある"RefDesign"なのですが、IP generatorから出てくるものと端子構成もIP名も異なっていて、リファレンスになっていなくて、これまた心を折りに来ています。
GOWINのIPを使う上で、難しいことは、IPが暗号化されているので、論理SIMが出来ないという点です。簡単なインターフェースであれば、自分でIPの代替モデルを作るなどしてSIMを行いますが、インターフェースが複雑だとIPの代替回路を作るのが難しく、オレオレ代替回路で検証を行ったところで、実際に動くかどうかは分からないという状態になります。
.vo(ネットリストらしい)を扱えるシミュレータであれば、IPをSIMすることが出来そうですが、無料で使えるシミュレーターでは無理なので。。。
ここで、tang nano 20kでSDRAMを使ってい方達の参考になりそうな回路を探す事にしました。
TangNano-20Kのexampleにも入っているNESTangの作者さん(nand2marioさん)が、sdramコントローラ部だけを抜き出したものを公開してくださっていました。
byteアクセスのみに対応しているようです。
この回路のSDRAMを制御するコア部分を流用して、byte転送以外の転送を可能な様に拡張する方が見通しがよさそうなので、この方向性で進める事にします。
残りの課題は、SDRAMのACパラメータが不明という事です。Micronのデーターシートを参考にして仮決めする事にします。(微調整は実機で行う)
改造内容
- 周波数を最大の166MHz化
- バースト転送対応
- AutoPrechargeをやめてPrechargeコマンド投入型へ
- Logical side interfaceをTangNano9KのPSRAMコントローラへ似せる
- AutoRefresh投入をSDRAMコントローラへ内蔵
バースト転送対応とPrechargeコマンドの投入について
BurstLength=1設定とし、ACTIVEコマンドに続くWRITE/READコマンドの数でバースト転送数を調整します。
TangNano9KのPSRAMコントローラの時はバースト数が固定でしたが、可変とします。
AutoPrechargeだとModeRegisterに設定したBurstLengthの転送が終わると自動的にSDRAM内でPreChargeが発生してしまうため、バースト長の可変を実現できないので、自前PreChargeコマンド投入としました。
Logical side interface仕様
バースト転送数を可変にしたので、バースト数を設定するLEN端子を追加します。
PSRAMインターフェースでは、コマンドとコマンドの最小間隔が決まっていました。バースト数が可変なので、決まった最小間隔ではなく、SDRAMコントローラへ転送要求をだすと、受付可能なタイミングでACKを返す仕様としました。
複数の要求元(最大3)に対応
SDRAMコントローラのLogical side interfaceは1チャネルのみですが、前段にスイッチを挟むことで3チャネルに対応してます。
ブロック図
赤枠の部分を作りました。
cmd i/f 端子一覧
pin name | I/O | active | description |
---|---|---|---|
system | |||
resetn | I | N | reset |
clk | I | - | main clock |
clk_sdram | I | - | main clock(*1) |
clk_capdq | I | - | DQ capture clock(*2) |
command i/f | |||
cmd_en | I | P | request for transaction |
cmd | I | - | 0: Read, 1:Write |
addr[22:0] | I | - | address in byte |
cmd_len[3:0] | I | - | burst length |
cmd_ack | O | P | accept for transaction |
rd_data[31:0] | O | - | read data |
rd_data_valid | O | P | read data valid |
wr_data[31:0] | I | - | write data |
wr_mask[3:0] | I | P | write data mask |
*1 : clk端子に入力するクロックと同一のものを入力してください。
*2 : 166MHz動作(近辺)においてはclk端子に入力するクロックと同一のものを入力してください。周波数を遅くした場合にはclkより位相をずらしたものをPLLで生成してDQを正しく取り込めるタイミングを調整する必要があります。
cmd i/f タイミング図
SDRAMのACスペックについて
MicronのDatasheetを参考にすることとしました。以下になります。 https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/dram/64mb_x32_sdram.pdf?rev=0af7f6403bf14075ab6b3984f549fc15
この資料によるとSpeedGradeが-6
で166MHzで動作可能ですが、TangNano20Kで動かしてみたところ、うまく動きませんでした。
tCKが166MHzに対してスペック割れしていますが、-7
だと色んなスペックが緩和されているようなので、試しに166MHzのままで、tRPなどのスペックを-7
に合わせたところ動作出来ました。
あまり深追いせず、とりあえずこのパラメータでRTLを作りました。
RTL
SDRAMコントローラ及びcmd i/fのスイッチをgithubへ置きました。
exampleとしてテストベンチも置いています。
tangnano20k/sdramc at main · kazuokada/tangnano20k · GitHub
動作波形(SDRAM I/F)
BL=16のread → BL=1のwrite → BL=1のread
部分を切り出しました。
参考資料
nand2marioさんのSDRAMCのコードを参考にしました。
https://github.com/nand2mario/sdram-tang-nano-20kSDRAMの仕様(Micron社のSDRAMデータシート)
https://media-www.micron.com/-/media/client/global/documents/products/data-sheet/dram/64mb_x32_sdram.pdf?rev=0af7f6403bf14075ab6b3984f549fc15