DE0-Nanoボードで、SDRAMコントローラを使ってNiosからリード・ライトしてみる ハードウェア編

FPGA

FPGAボードであるTerasic社のDE0-Nanoを使っていろいろ遊んでいますが、今回はNiosからSDRAMへのリードとライトに挑戦してみました。

DE0-Nanoには、ISSI社の256-MBIT SYNCHRONOUS DRAMであるIS42S16160Bが実装されています。

SDRAMコントローラのIPを使って、NiosからこのSDRAMにリードとライトをしてみたいと思います。

今回はハードウェア編で、QuartusのPlatform Designerを使ったIPの実装から、FPGAへの書き込みまでを記事にしておきます。

なお、SDRAMコントローラの設定は、Terasic社のサンプルプロジェクト(DE0_NANO_SDRAM_Nios_Test)をコピーしています。

Terasic DE0-NANO開発ボード 【P0082】

新品価格
¥14,520から
(2020/12/7 22:14時点)

スポンサーリンク

Platform Designerを使ってIPを追加

IPの追加

Quartusでプロジェクトを作成したら、Platform Designerを起動します。

起動したら、まずは下記のIPを追加します。

  • Nios II Processor
  • On-Chip Memory (RAM or ROM) Intel FPGA IP
  • JTAG UART Intel FPGA IP

Platform Designerの起動からIPの追加までは、下記の記事を参考にしてください。

上の3つのIPは基本的な機能です。

次にSDRAMを制御するIPを追加します。

追加するIPは以下の2つです。

  • ALTPLL Intel FPGA IP
  • SDRAM Controller Intel FPGA IP

ALTPLL Intel FPGA IPは、PLLです。DE0-Nanoに実装されたFPGAには4つのPLLが内蔵されています。

そのPLLを使って、FPGAからSDRAMに供給するクロックを生成します。

SDRAM Controller Intel FPGA IPは、SDRAMをコントロールするためのIPです。

すべてのIPの追加が終わると、上の図のようになると思います。(IPの名前はわかりやすい名前に変更しています)

追加が終わったら、IPの設定をしていきます。

IPの設定

clk_0の設定

clk_0は最初から追加されていたと思います。

意味はよく理解できていませんが、下図のように赤枠内が太字になっているか確認しておきます。

DE0-Nanoに実装されている発振器の周波数は50MHzなので、Clock frequencyには”50000000″と入力しておきます。

nios2_cpuの設定

nios2_cpuの設定は、”Vectors”タブを選択し、”Reset vector memory”と”Exception vector memory”をFPGA内蔵メモリである”onchip_memory.s1″を選択しました。

ここでSDRAMを設定することもできますが、今回はFPGA内蔵メモリを選択しました。

onchip_memoryの設定

FPGA内蔵のonchip_memoryのサイズは、40960bytesにしました。

これはソフトウェア作成中にメモリ不足のエラーが出たので、メモリサイズを増やしていった結果、この値になりました。

jtag_uartの設定

ここの設定は何も変更しなかったと思います。デフォルト値のままで、以下の設定です。

SDRAMコントローラの設定

ここはTerasic社のサンプルプロジェクトをコピーして、以下の設定にしました。

altpllの設定

ここもTerasic社のサンプルプロジェクトをコピーです。

なぜ?という設定が多々ありましたが、とりあえずコピーしました。

1 of 11

“What is the frequency of the inclk0 input?”を50MHzに設定します。

その他の設定も確認し、”Next”をクリックします。

2 of 11

設定を確認し”Next”をクリックします。

Create ‘locked’ outputにチェックが入っていますが、ここはチェック無しで大丈夫かも???PLLがロックしたときに出力される信号だと思うのですが、この信号は使わなかったので。

3 of 11

設定を確認し”Next”をクリックします。

4 of 11

設定を確認し”Next”をクリックします。

5 of 11

設定を確認し”Next”をクリックします。

6 of 11

赤枠内を設定します。

赤枠内を設定後、青枠内の数値は、以下のValue(before)ようになっているかもしれません。

なぜかはわかりませんが、、、次の”7 of 11″の設定後には、Value(after)に変わっていました。

DescriptionValue(before)Value(after)
Primary clock VCO frequency (MHz)600.000600.000
Modulus for M counter1212
Modulus for N counter11
Initial VCO phase cycles for M counter12
VCO phase tap for M counter00
VCO post scale K counter22
c0 settings:
Post-scale counter66
Initial VCO phase cycles12
VCO phase tap00
High period count33
Low period count33
ModeEvenEven
7 of 11

赤枠内を設定します。

緑枠内のClock phase shiftを-60に設定することを忘れずに。Terasic社のサンプルプロジェクトをコピーしているので-60とわかりましたが、サンプルプロジェクトがなかったら私には絶対にわからない設定でした。

青枠内の数値は以下のようになっていると思います。

DescriptionValue(before)
Primary clock VCO frequency (MHz)600.000
Modulus for M counter12
Modulus for N counter1
Initial VCO phase cycles for M counter2
VCO phase tap for M counter0
VCO post scale K counter2
c1 settings:
Post-scale counter6
Initial VCO phase cycles1
VCO phase tap0
High period count3
Low period count3
ModeEven
8 of 11

未使用なので設定項目はありません。

9 of 11

未使用なので設定項目はありません。

10 of 11

未使用なので設定項目はありません。

11 of 11

“Finish”をクリックして終了です。

PLLの数の謎

DE0-NanoにはCyclone IV E EP4CE22というFPGAが実装されていて、内蔵されているPLLの数は4つです。

しかし、altpllの設定ではc0からc4までの5つ(6 of 11から10 of 11まで)の設定をしました。

なぜ、c0からc4までの5つだったのでしょうか???謎です。

ConnectionsとExportの設定

ちょっと複雑な結線ですが、頑張って以下の画像のように結線します。

Exportの設定も忘れずに。

Terasic社のサンプルプロジェクトを参考にして上記の結線にしました。Terasic社のサンプルプロジェクトとは追加しているIPが異なるので、ここの結線もTerasic社のサンプルプロジェクトとは異なっています。

参考記事 第2回 Nios IIで遊ぼう Quartus Platform Designer編

HDLの生成

Platform Designerの設定が終わったら保存します。拡張子が.qsysで保存されると思います。

次にメニュー System -> Assign Base Addressesを選択します。

メッセージウインドウにエラーがなければ、Generate HDLをクリックします。

そして、ここで気になるメッセージが。(点線の赤枠)

SDRAM Controller will only be supported in Quartus Prime Standard Edition in the future release.

将来的に、SDRAM Controllerは有償のStandard Editionのみサポートで、無償のLite Editionでは使えなくなってしまうかもしれませんね。

話は元に戻って、”Generate HDL”をクリックすると、xxx_inst.vhdというファイルが生成されます(Generate HDLでVHDLを選択した場合)

xxxはPlatform Designerの保存時の名前です。

生成されたVHDLのファイルの中身です。

component sdram_qsys is
   port (
      altpll_areset_conduit_export : in    std_logic                     := 'X';             -- export
      altpll_locked_conduit_export : out   std_logic;                                        -- export
      altpll_sdram_clk             : out   std_logic;                                        -- clk
      clk_clk                      : in    std_logic                     := 'X';             -- clk
      reset_reset_n                : in    std_logic                     := 'X';             -- reset_n
      sdram_wire_addr              : out   std_logic_vector(12 downto 0);                    -- addr
      sdram_wire_ba                : out   std_logic_vector(1 downto 0);                     -- ba
      sdram_wire_cas_n             : out   std_logic;                                        -- cas_n
      sdram_wire_cke               : out   std_logic;                                        -- cke
      sdram_wire_cs_n              : out   std_logic;                                        -- cs_n
      sdram_wire_dq                : inout std_logic_vector(15 downto 0) := (others => 'X'); -- dq
      sdram_wire_dqm               : out   std_logic_vector(1 downto 0);                     -- dqm
      sdram_wire_ras_n             : out   std_logic;                                        -- ras_n
      sdram_wire_we_n              : out   std_logic                                         -- we_n
   );
end component sdram_qsys;

u0 : component sdram_qsys
   port map (
      altpll_areset_conduit_export => CONNECTED_TO_altpll_areset_conduit_export, -- altpll_areset_conduit.export
      altpll_locked_conduit_export => CONNECTED_TO_altpll_locked_conduit_export, -- altpll_locked_conduit.export
      altpll_sdram_clk             => CONNECTED_TO_altpll_sdram_clk,             --          altpll_sdram.clk
      clk_clk                      => CONNECTED_TO_clk_clk,                      --                   clk.clk
      reset_reset_n                => CONNECTED_TO_reset_reset_n,                --                 reset.reset_n
      sdram_wire_addr              => CONNECTED_TO_sdram_wire_addr,              --            sdram_wire.addr
      sdram_wire_ba                => CONNECTED_TO_sdram_wire_ba,                --                      .ba
      sdram_wire_cas_n             => CONNECTED_TO_sdram_wire_cas_n,             --                      .cas_n
      sdram_wire_cke               => CONNECTED_TO_sdram_wire_cke,               --                      .cke
      sdram_wire_cs_n              => CONNECTED_TO_sdram_wire_cs_n,              --                      .cs_n
      sdram_wire_dq                => CONNECTED_TO_sdram_wire_dq,                --                      .dq
      sdram_wire_dqm               => CONNECTED_TO_sdram_wire_dqm,               --                      .dqm
      sdram_wire_ras_n             => CONNECTED_TO_sdram_wire_ras_n,             --                      .ras_n
      sdram_wire_we_n              => CONNECTED_TO_sdram_wire_we_n               --                      .we_n
   );

参考記事 第2回 Nios IIで遊ぼう Quartus Platform Designer編

QuartusでSDRAMコントローラを作成

まずは生成したxxx_inst.vhdを使って、SDRAMコントローラをVHDLで作成します。

作成したVHDLがこちら。

library ieee;
use ieee.std_logic_1164.all;

entity nios_sdram is
   port(
      CLK50M		: in std_logic;
      A_RST		: in std_logic;
      CLK_RST		: in std_logic;
      PLL_LOCK		: out std_logic;		
      DRAM_CLK		: OUT STD_LOGIC; 
      DRAM_CKE 	        : OUT STD_LOGIC;
      DRAM_ADDR 	: OUT STD_LOGIC_VECTOR(12 DOWNTO 0);
      DRAM_BA 		: OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
      DRAM_CS_N	        : OUT STD_LOGIC; 
      DRAM_CAS_N	: OUT STD_LOGIC; 
      DRAM_RAS_N	: OUT STD_LOGIC;
      DRAM_WE_N	        : OUT STD_LOGIC;
      DRAM_DQ		: INOUT STD_LOGIC_VECTOR(15 DOWNTO 0);
      DRAM_DQM		: OUT STD_LOGIC_VECTOR(1 DOWNTO 0)
   );
end nios_sdram;

architecture rtl of nios_sdram is

   component sdram_qsys is
      port (
         altpll_areset_conduit_export : in    std_logic                     := 'X';             -- export
         altpll_locked_conduit_export : out   std_logic;                                        -- export
         altpll_sdram_clk             : out   std_logic;                                        -- clk
         clk_clk                      : in    std_logic                     := 'X';             -- clk
         reset_reset_n                : in    std_logic                     := 'X';             -- reset_n
         sdram_wire_addr              : out   std_logic_vector(12 downto 0);                    -- addr
         sdram_wire_ba                : out   std_logic_vector(1 downto 0);                     -- ba
         sdram_wire_cas_n             : out   std_logic;                                        -- cas_n
         sdram_wire_cke               : out   std_logic;                                        -- cke
         sdram_wire_cs_n              : out   std_logic;                                        -- cs_n
         sdram_wire_dq                : inout std_logic_vector(15 downto 0) := (others => 'X'); -- dq
         sdram_wire_dqm               : out   std_logic_vector(1 downto 0);                     -- dqm
         sdram_wire_ras_n             : out   std_logic;                                        -- ras_n
         sdram_wire_we_n              : out   std_logic                                         -- we_n
      );
end component sdram_qsys;
	
	

begin
		
u0 : component sdram_qsys
   port map (
      altpll_areset_conduit_export => A_RST,		-- altpll_areset_conduit.export
      altpll_locked_conduit_export => PLL_LOCK,		-- altpll_locked_conduit.export
      altpll_sdram_clk             => DRAM_CLK,		-- altpll_sdram.clk
      clk_clk                      => CLK50M,		-- clk.clk
      reset_reset_n                => CLK_RST,		-- reset.reset_n
      sdram_wire_addr              => DRAM_ADDR,	-- sdram_wire.addr
      sdram_wire_ba                => DRAM_BA,		--           .ba
      sdram_wire_cas_n             => DRAM_CAS_N,	--           .cas_n
      sdram_wire_cke               => DRAM_CKE,		--           .cke
      sdram_wire_cs_n              => DRAM_CS_N,	--           .cs_n
      sdram_wire_dq                => DRAM_DQ,		--           .dq
      sdram_wire_dqm               => DRAM_DQM,		--           .dqm
      sdram_wire_ras_n             => DRAM_RAS_N,	--           .ras_n
      sdram_wire_we_n              => DRAM_WE_N		--           .we_n
   );
		
		
end rtl;

VHDLの作成が終わったら、メニュー File -> Create / Update -> Create Symbol Files for Current Fileを選択して、回路図で使えるようにシンボルを作成します。

別にシンボルは作成しなくても良いのですが、プロジェクトのトップは回路図にするのが好きなので、私はシンボル化しておきました。

作成したプロジェクト階層トップの回路図です。ピン番号も割付け済です。

参考記事 第2回 Nios IIで遊ぼう Quartus Platform Designer編
参考記事 FPGAボードDE0-Nanoを使ってみる:ピン割付けからRAMへの書き込みまで
参考記事 Quartusを使って、回路図とHDLの混在でFPGAを設計する

コンパイル

ここまできたらコンパイルしますが、Platform Designerで作成したqsysをプロジェクトに追加することを忘れずに。

プロジェクトへの追加は、メニューProject -> Add/Remove Files in Projectを選択します。

すると、以下のウインドウが開きます。

Platform Designerで作成したqsysファイル、プロジェクト階層トップの回路図ファイル、SDRAMコントローラのVHDLファイルの3つが入っています。

これでコンパイル実行です。

エラーがでなければ、FPGAに書き込みを行います。

参考記事 Quartus入門
参考記事 FPGAボードDE0-Nanoを使ってみる:ピン割付けからRAMへの書き込みまで

まとめ

Terasic社のサンプルプロジェクトをコピーさせていただきましたが、けっこうな作業量でした。

EclipseでSDRAMにリード・ライトするniosのプログラムは以下の記事をご参照ください。Terasic社のツールを使った検証もしています。

タイトルとURLをコピーしました