コンテンツにスキップ

Tang Nano 9kでLチカをやってく

最近後輩に話を聞いてFPGAをやりたいな~と思って調べてたんだけど、ついに買った.
Tang Nano 9K1というやつで、凄い小さいんだけど初めて遊ぶのには良いならいいかな~と思って購入.
20Kでもいいかなとも思ったけど、まあ高いしこっちでいいかとなったのは内緒.

さてやっぱりこういう電子工作で一番最初にやることといえばLチカ.
電子工作界のHello Worldはこれだというのが自分の認識、雑すぎる.
Arduinoを始めて弄ったときもこれをやった気がする、あれももう7年前くらいだからこういうハードは久々ね.

ということで今回は公式チュートリアル2に従って実装をやっていく.
その際に参考にしたのはここ3、非常に分かりやすかった.

まず最初は公式4に行って登録、そしてEducation5をダウンロード.
ダウンロードはEducationであることに本当に注意.
自分は最初に通常の方をダウンロードして、ライセンス認証で弾かれました.
別段そういうのはいらないのよ、楽がしたいのよ.

ダウンロードしたらexeをたたいて、File/FPGA Design Projectで適当にプロジェクトを作成.
GW1NR-LV9QN88PC6/15にデバイスを設定して、完了.

ソースコードはVerilog Fileをとりあえず作成.
名前は適当に.
そしたらVerilogを書いていくことになる.
初めてなのでそれっぽく雰囲気で読んでいく.

まず最初にmoduleで入力と出力を設定する.
inputは入力,outputは出力で、この段階ではあくまで抽象的なものである.
実際の入力はボタンだったり、出力ならLEDとか具体的なものがあるけども、プログラム内ではあくまでinput,outputであるということが大事っぽい.
とはいえ、今回はLチカである程度具体的なものはわかってる.
sys_clkはクロック、sys_rst_nはリセット用のボタン,ledはLEDとなる.
Tang Nano 9KはLEDが6個あるので、配列で書いている.

module top(
    input sys_clk,          // clk input
    input sys_rst_n,        // reset input
    output reg [5:0] led    // 6 LEDS pin
);

そして、regで値を保持するためのデータを用意しておく.
always文を書く際はこれで変数宣言するっぽい.
[23:0]とあるが、[MSB:LSB]という形らしく、最上位ビットと最下位ビットを指定してるっぽい.
今回は24ビットを設定している感じかな? [2:2]とかなら1ビットで[2:1]なら2ビットとかになるという認識.

reg [23:0] counter;

そしたらalways文.
何か信号に変更があったときにイベントを発行する処理.

always @(posedge sys_clk or negedge sys_rst_n) begin
イベントはposedge sys_clk or negedge sys_rst_nの二つ.
まずposedgeは0->1の変化が起こったときに発行.
negedgeは1->0の変化が起こったときに発行.
今回は

  • クロックが0->1になったとき
  • リセットボタンが1->0,つまりボタンが押されたとき

の二つである.
これがorとなってるので、片方が起こったときの状態がそのまま発行される.
ボタンが押されてなくてもクロックが発動したら1の状態が発行されるし、ボタンを押したままクロックが発動したら0の状態が発行されるという感じ.
あくまでイベント駆動なわけだね.

そしたら処理を見ていこう.
まずリセットボタンが押されている場合、つまり0となっているときはcounterをリセットする.
24'd0は24はビット数, 'は単純に区切り文字,dは10進数,0は代入する値となる.
つまり簡潔に言えばcounter = 0;ということだ.

    if (!sys_rst_n)
        counter <= 24'd0;

次はcounter周りの処理.

    else if (counter < 24'd1349_9999)       // 0.5s delay
        counter <= counter + 1'b1;
    else
        counter <= 24'd0;
end

基本的にカウンタはcounter + 1'b1にある通り+1をし続ける.
counter++;みたいなもんか.
そして奇怪な1349_9999.

どうもTang Nano 9Kは27MHzでクロックを行う.
そのため,1秒に27M回クロックするので、27M/2=13.5M27M/2=13.5Mと半分にすれば0.5sということが分かる.
つまり0.5秒立つまで待って、0.5秒立ったらカウンターをまたリセットしてるわけだ.

さて、alwaysでもう一つ式を書く.
verilogは上から下に順に処理を行うので,次に行う処理を書いてくことになる.
まずリセットボタンを押したときの処理,この時はLEDを1 0 0 0 0 0に初期化.
0が点灯で1が消灯.
なので1つだけ消えた状態になる訳である.

always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n)
        led <= 6'b100000;

次にカウンターが0.5sまで来たときにずらす.それ以外はLEDを継続.

    else if (counter == 24'd1349_9999)       // 0.5s delay
        led[5:0] <= {led[4:0],led[5]};
    else
        led <= led;
end

endmodule

ビットをずらしている.これhlslのfloat3 v; v.xzyみたいな感じができるってことですね.
処理としては

  • 1 00000
  • 0 00001
  • 0 00010
  • 0 00100
  • 0 01000
  • 0 10000

というループをずっとやってるだけ.

これでコードは書けたので、FPGA特有の処理をやっていく.
まずProject->Configuration->Place&Route->Dual-Purpose PinのUse DONE as regular IOをONにする.
なんかエラー回避のためとチュートリアルには書いてあるけどよくわかってない.

次にSynthesizeをダブルクリックで論理合成を行う.緑のチェックが付けば成功.
これで回路図を作りつつ、最適化をしてるっぽい.コンパイルみたいなもんかなぁ.

次にConstrainの設定.
先ほどのコードはinputとoutputという抽象的なものを用意したに過ぎないけど、ここでちゃんと設定をすることで結びつけるわけだ.
この時の結び付けはここのpdf6を見るとわかる.
Tang Nano 9Kの設計図で何がどのピンに対応してるのかが書いてある.

まずクロック,sys_clkの設定.
これはBANK1の51,52に書いてある.
51はIOR17B/GCLKC_3で52はIOR17A/GCLKT_3らしい.
Cが差動クロックのマイナス側、Tがプラス側らしい.わからん.
今回は52の方を使用するので、Locationを52へ.
また、BANK1は3.3Vらしいので、I/O TypeをLVCMOS33にする.

次はボタン,sys_rst_n.
BANK3でPIN3/4が対応するっぽい.
今回は4の方をLocationに設定する.
BANK1は1.8VなのでLVCMOS18のままでOK.

最後にLED,ledの設定.
LEDは1から6まであるが、それぞれBANK3内の10,11,13,14,15,16に相当,Locationに設定.
なんか12はLEDの先の信号に繋がってるっぽいけどこいつは何を意味してるんだ?
まあそれはいいとして、BANK3でボタンと同じなためLVCMOS18のままでOK.

ここまで出来たら次はPlace&Route,配置配線.
チップ上にどのように今まで作った回路図を配置するかを決める.
これも自動で決めてくれるので、論理合成と同じでダブルクリックするだけ.
緑のチェックが付けばOK.

ここまでできればあとは実際にTang側にダウンロード.
まずはProgrammerをダブルクリックして開く.
接続が成功したら、モードで0と1の謎の分岐があるけど1を設定.
何故か0だと固まって失敗した,理由はわからない.
SRAM ProgramにOperationがなっているのを確認出来たら、後は緑色の実行ボタンを押して実行!

tang_led_blink_01

うん、いい感じ!
今回はLチカをやった.
次はLCDとかやりたいけど、そもそも手に入れないとなぁ...