かずの不定期便ブログ

備忘録代わりに書きます

FPGA Sipeed Tang Nano 20KでSDRAMを動かす

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コントローラ部だけを抜き出したものを公開してくださっていました。

github.com

 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)

SDRAM動作波形
BL=16のread → BL=1のwrite → BL=1のread
部分を切り出しました。

参考資料