SPIの制御はこれまで作ってきた回路に任せます。全体のシーケンシャルな制御はFPGA内に組み込むマイコンで制御します。IntelのFPGAではNiosIIというマイコンコアを組み込むことができます。
まず、第3回で作ったプロジェクトをコピーします。
まず、今回はniosii_swd_study5_logicsimをコピーして、niosii_swd_study5_implを作ります。
Open Project
そして、開く。
Tools-->Platform Designer
こういうのが出てくるので、clk_0をダブルクリックする。
パラメタでClock Frequencyを100MHz(100000000Hz)にする。PLLで作った100MHzを使うので。
いったんここでCtrl+Sを押して、保存しておく。
いちいちこんなのが出る。のでClose。
NiosIIコアを追加。
Nios II/eを選択し、エラーは無視してFinish。Nios II/fはお金もかかるしFPGAのリソースも食うらしい。
そして、結線。
Flashを追加。
Configuration Mode : Single Compressed Image wirh Memory Initialization
SectorID3 : Access Mode --> Hidden
としてFinish。
結線。
RAMを追加。
Total memory sizeを32768にしてメモリ内容初期化を無効化してFinish。
結線。
System IDを追加。これがないと、JTAGデバッガからNiosIIへの接続の確認ができないらしい。なきゃないで回避もできるけど入れておく。
いじらずFinish。
結線。
JTAG UARTを追加。これがあると、printfでデバッグコンソールに表示できるので、何かと便利。
いじらず、Finish。
結線。
sys_clk用にインターバルタイマを追加。
いじらずFinish。
結線。
timestamp_timer用にもう一つInterval Timerを追加する。設定はsys_clk用のtimer_0と同じでよい。
こうなる。
GPIOを追加する。今回は自作SPI回路の動作確認が目的なので、自作SPIとGPIOを内部で結線する。
実際の実装は後ですが、こんな感じにするので、8ビットの出力のGPIOを2つ、8ビットの入力のGPIOを2つ組み込む。
8bit, outputにしてFinish。
結線。external_connectionはQSYS_COREの外側に引き出しすので、Double-click to exportをダブルクリックする。
こうなる。
これをもう一つ組み込む。
こうなる。
次は8bit input。Inputを選択すると、割り込みとかオプションがいろいろあるけど、今回は使わない。
こうなる。
ビューの右側で割り込み番号を設定できるけど、今回は成り行きで。
モジュールのアドレスを設定する。
まぁこんなんで。
モジュール表示に戻る。
nios2をダブルクリックして設定タブを表示する(最初から表示されていることもある)。
ベクタタブを表示させる。
リセットベクタ、例外ベクタをRAMに配置する。
エラーがすべてなくなる。
Ctrl+Sでセーブ。
Closeおす。
Generate HDLおす。
VHDL派を主張してGenerateを押す。
だいぶ長いこと勝手に何かをやる。
おわたようなので、Closeを押す。
Platform DesignerのFinishを押す。
これが出来上がったと教えてくれる。あとで実装に追加して組み込む。
Assignments-->Settings...
...を押す。
Platform Designerの成果物を選ぶ。qipだけでいいらしい。
こうなるのでOKを押す。
ちなみにPlatform Designerで出来上がったものの中に*_inst.vhdlってファイルがあり、これは上位のモジュールに組み込む際のひな型になっている。
component QSYS_CORE is port ( clk_clk : in std_logic := 'X'; -- clk reset_reset_n : in std_logic := 'X'; -- reset_n pio_0_external_connection_export : out std_logic_vector(7 downto 0); -- export pio_1_external_connection_export : out std_logic_vector(7 downto 0); -- export pio_2_external_connection_export : in std_logic_vector(7 downto 0) := (others => 'X'); -- export pio_3_external_connection_export : in std_logic_vector(7 downto 0) := (others => 'X') -- export ); end component QSYS_CORE; u0 : component QSYS_CORE port map ( clk_clk => CONNECTED_TO_clk_clk, -- clk.clk reset_reset_n => CONNECTED_TO_reset_reset_n, -- reset.reset_n pio_0_external_connection_export => CONNECTED_TO_pio_0_external_connection_export, -- pio_0_external_connection.export pio_1_external_connection_export => CONNECTED_TO_pio_1_external_connection_export, -- pio_1_external_connection.export pio_2_external_connection_export => CONNECTED_TO_pio_2_external_connection_export, -- pio_2_external_connection.export pio_3_external_connection_export => CONNECTED_TO_pio_3_external_connection_export -- pio_3_external_connection.export );
今回はこんな感じ。これを参照することで、上位のモジュールで同記述すればいいのかわかる。
最上位のモジュールを編集する。表示されていなければProject Navigatoでトップモジュール=FPGAをダブルクリックする。
LIBRARY ieee; USE ieee.std_logic_1164.ALL; LIBRARY altera; USE altera.altera_syn_attributes.ALL; ENTITY FPGA IS PORT ( EN : out std_logic; INIT : out std_logic; BUSY : out std_logic; SCK : OUT STD_LOGIC; MOSI : OUT STD_LOGIC; MISO : IN STD_LOGIC; clk48 : IN STD_LOGIC ); END FPGA; ARCHITECTURE ppl_type OF FPGA IS SIGNAL res_n : STD_LOGIC; SIGNAL por_n : INTEGER RANGE 0 TO 1; SIGNAL por_count : INTEGER RANGE 0 TO 65535; CONSTANT POR_MAX : INTEGER := 127; COMPONENT MySPI IS PORT ( NSEND : IN STD_LOGIC_VECTOR(2 DOWNTO 0); NCLKDIV : IN STD_LOGIC_VECTOR(2 DOWNTO 0); CLKIN : IN STD_LOGIC; CLKOUT : OUT STD_LOGIC; CLKSYS : IN STD_LOGIC; BUSY : OUT STD_LOGIC; INIT : IN STD_LOGIC; WDATA : IN STD_LOGIC_VECTOR(7 DOWNTO 0); RDATA : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); OUTP : OUT STD_LOGIC; INP : IN STD_LOGIC; EN : IN STD_LOGIC ); END COMPONENT MySPI; SIGNAL MySPI_CONF : STD_LOGIC_VECTOR(7 DOWNTO 0) := "01111111"; SIGNAL MySPI_STAT : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL MySPI_WDATA : STD_LOGIC_VECTOR(7 DOWNTO 0) := "00000000"; SIGNAL MySPI_RDATA : STD_LOGIC_VECTOR(7 DOWNTO 0); COMPONENT PLL IS PORT ( inclk0 : IN STD_LOGIC := '0'; c0 : OUT STD_LOGIC; c1 : OUT STD_LOGIC ); END COMPONENT PLL; SIGNAL clk100 : STD_LOGIC; SIGNAL clk2 : STD_LOGIC; component QSYS_CORE is port ( clk_clk : in std_logic := 'X'; -- clk reset_reset_n : in std_logic := 'X'; -- reset_n pio_0_external_connection_export : out std_logic_vector(7 downto 0); -- export pio_1_external_connection_export : out std_logic_vector(7 downto 0); -- export pio_2_external_connection_export : in std_logic_vector(7 downto 0) := (others => 'X'); -- export pio_3_external_connection_export : in std_logic_vector(7 downto 0) := (others => 'X') -- export ); end component QSYS_CORE; signal PIO0 : std_logic_vector(7 downto 0); signal PIO1 : std_logic_vector(7 downto 0); signal PIO2 : std_logic_vector(7 downto 0); signal PIO3 : std_logic_vector(7 downto 0); BEGIN MySPI_CONF<=PIO0; MySPI_WDATA<=PIO1; MySPI_STAT(7 downto 1)<="0000000"; PIO2<=MySPI_STAT; PIO3<=MySPI_RDATA; EN<=MySPI_CONF(7); INIT<=MySPI_CONF(0); BUSY<=MySPI_STAT(0); MySPI_inst : COMPONENT MySPI PORT MAP( NSEND => MySPI_CONF(6 DOWNTO 4), NCLKDIV => MySPI_CONF(3 DOWNTO 1), CLKIN => clk2, CLKOUT => SCK, CLKSYS => clk100, BUSY => MySPI_STAT(0), INIT => MySPI_CONF(0), WDATA => MySPI_WDATA, RDATA => MySPI_RDATA, OUTP => MOSI, INP => MISO, EN => MySPI_CONF(7) ); PLL_inst : PLL PORT MAP( inclk0 => clk48, c0 => clk100, c1 => clk2 ); u0 : component QSYS_CORE port map ( clk_clk => clk100, -- clk.clk reset_reset_n => res_n, -- reset.reset_n pio_0_external_connection_export => PIO0, -- pio_0_external_connection.export pio_1_external_connection_export => PIO1, -- pio_1_external_connection.export pio_2_external_connection_export => PIO2, -- pio_2_external_connection.export pio_3_external_connection_export => PIO3 -- pio_3_external_connection.export ); --internal reset PROCESS (clk48) BEGIN IF clk48'event AND clk48 = '1' THEN IF por_count = POR_MAX THEN por_n <= 1; por_count <= por_count; ELSE por_n <= 0; por_count <= por_count + 1; END IF; END IF; END PROCESS; res_n <= '1' WHEN por_n = 1 ELSE '0'; END;
こんなかんじ。EN, INIT, BUSYは内部をモニターするために外に引き出す。
TasksのAnalysis & Synthesisを右クリックしてStartをクリック。
なにかやり始めるので、とりあえず、祈る。
ウォーニングはあるけどエラーはない。ホビーユーザはウォーニングまではほじらない。
Tools-->Netlist Viewers-->RTL Viewer
として回路を見てみる。
とりあえず、未結線がないかどうか確認する。NiosIIのGPIOの方向とか不一致だとしても、論理合成でなぜかエラーにならなくて最後まで悩むことがあるので。
端子を実際のデバイスに割り当てる。
電源ドメインが色分けされているので、同じ用途のものはできるだけ同じ電源ドメインで割り当てることにする。
実際のブツはこうなっていて、トップレベルのポートから6ポート必要なのでpin_60,59,58,57,56,55を使うことにする。
で、こうする。このボードは48MHzのクリスタルオシレータがpin_27に接続されています。割り当ての操作は、ピン名を上の絵にずりずりっとやる方法もあるけど、Locationカラムに直接打ち込んだほうが早い。
で、Close。
デバイスのコンフィグレーションの設定をPlatformDesignedのon chip Flashの設定と合わせるため、デバイスの設定を開く。
Device and Pin Options...を押す。
GeneralカテゴリにConfiguration modeというのがあるので、
Single Compressed Image with Memory Initialization
(on chip Flashと同じもの)
を選んでOKを押す。前のダイアログに戻るのでOKを押す。
TasksのCompile Designを右クリックしてStartをクリック。フルコンパイルを実行。
何かがとり行われ。
そして、終わる。、、、無事。
書き込みます。
モノはこんな状態です。ロジアナつなぎすぎやろ、、、すみません、今回に合わせて一部外すのが正解だったと思いますが、何しろめんどくさいので。MAX10の上に死んでるって書いてますが、過去に書いたもので、今回試したら動きました。うちではUSB-Blasterを使ってます。USB-Blaster2が発売されてお値打ちになっています。
Programmerが起動すると、だいたいあとはStartを押すだけの状態になっています。ライターが認識されていないと、Hardware Setup...を押して出てくる画面でなんとかします。
Startを押すとすぐに右上のPrograssが100%になって書き込みが終わったことがわかります。ちなみに現在Programmerに登録されているファイルの拡張子がsofなので、RAMに書き込まれます。電源切ると消えます。MAX10は不揮発メモリも実装されているので、pofを選ぶとFlashに書き込まれて、電源切っても消えません。が、何かと確認事項が増えるので、今回はRAMでいいんです。
、、、とんでもなく長いのでいったん切ります。
コメントをお書きください