Sipeed Tang Nanoで遊んでみる (Linux版)

# 概要

GOWINのLittleBeeシリーズFPGAが載っているFPGAボード`Tang Nano`がSipeedから出たので、Linux上に開発環境を整えてからLチカするまで試した内容を記載します。

Windows版は @tomorrow56 さんが[既に書いている](https://qiita.com/tomorrow56/items/7e3508ef43d3d11fefab) のでこちらを参考にしてください。


# 開発環境のインストール

基本的にインストール手順はSipeedの[Tang NanoのGet Startedページ](http://tangnano.sipeed.com/en/get_started/install-the-ide.html)に書いてありますが、現時点でLinux版はTODOとあります。とりあえずLinux版の開発環境バイナリがDLできるので、適当に入れてみました。

Tang Nanoの資料は[http://dl.sipeed.com/TANG/Nano](http://dl.sipeed.com/TANG/Nano) からDLできます。

1. [http://dl.sipeed.com/TANG/Nano/IDE](http://dl.sipeed.com/TANG/Nano/IDE) にある`download_link.txt` に記載されているとおり、 [http://www.gowinsemi.com.cn/faq.aspx
](http://www.gowinsemi.com.cn/faq.aspx
) のページを開く
2. `云源软件 for Linux(V1.9.2.01Beta)` を選んでLinux版のIDEをダウンロードする。
3. ダウンロードしたtar.gz形式のアーカイブを展開する。このとき、アーカイブにはトップディレクトリが含まれていないので、適宜ディレクトリを作ってその中に展開すること。

    ```bash
    mkdir gowin
    tar xf Gowin_V1.9.2.01Beta_linux.tar.gz -C gowin
    ```

4. ライセンスサーバーの設定のため、以下の環境変数を設定する。他のflexlm系ライセンスを使っている場合は、既存の`LM_LICENSE_FILE`に`:` で区切って追加する。再起動時に自動的に設定されるように `.bashrc` あたりに追加しておくとよい

    ```bash
    export LM_LICENSE_FILE=27020@45.33.107.56
    ```

5. `IDE/bin/gw_ide` を実行する。ライセンスエラーとか言われるので、`Use Floating License Server` を選んで、`Server`に`45.33.107.56`, `Port`に`10559`を入力して`Save`を押し、再度`gw_ide`を実行する。

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/6c11cde0-23f2-a79d-a42c-08763479452c.png)

6. `GOWIN FPGA Designer` の画面が表示されたら成功

これでLinuxでの開発環境のインストールは終わりです。

# Lチカする

買ってきてUSBポートに繋ぐとボード上のカラーLEDが点灯します。
動作確認用に点灯パターンを変更してみます。

## プロジェクト作成

サンプル・プロジェクトが用意されていますが、適当に回路図読みながらプロジェクトを作ってみます。

回路図は [http://dl.sipeed.com/TANG/Nano/HDK](http://dl.sipeed.com/TANG/Nano/HDK) の下にあります。

`GOWIN FPGA Designer` のトップ画面の`Quick Start`から`New Project` を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/2fa9adf5-b296-948b-73cb-1bef43d052b2.png)

表示されたダイアログで`FPGA Design Project`を選んで`OK`を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/25712e34-b23f-b04d-5128-bca6f630ae75.png)

`Project Wizard`が表示されるので、プロジェクトの保存先のパスとして `Create in:` に適当なディレクトリのパスを入力します。

`Name:` には、プロジェクト名を入力します。ここでは適当に`blinker`とでもしておきます。

入力したら `Next` を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/2c3efde6-3308-9101-653d-afd7a0779f15.png)

`Select Device` 画面が表示されるので、`Series`で`GW1N`を選んで、下の表から`GW1N-LV1QN48C6`を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/a042b6cb-4871-f3ce-75eb-dee8d05c8ede.png)

`Summary` 画面が表示されるので、 `Finish` を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/6193fdff-2a38-c3b0-1d7e-6bb01bafd430.png)

## ソースファイルの追加

プロジェクトができたので、必要なファイルを追加します。

`Design`ペインで右クリックして`New File`を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/19a5ce6e-8ac5-7fd6-3f86-12fbe340cc68.png)

表示された`New`ダイアログで`Verilog File`を選択し`OK`を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/33abfbb0-6cd5-a0b5-b535-cf1faa6a883d.png)

`New Verilog`ダイアログが表示されるので、`Name`に`blink`と入力して`OK`を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/98683d32-b3ea-e786-ec09-b4f869a68741.png)

`blink.v` がエディタで開かれた状態になるので、下のコードをコピペして保存します。

`clock`と負論理の`resetn`入力を受け取り、カラーLEDのR, G, Bに対応する信号を出力する回路です。

Tang Nanoのデータシートによると`24[MHz]`の発信回路がボード上に搭載されているので、その発信回路を`clock`の入力とします。
また、ボード上にはアクティブローのプッシュボタンが2つ搭載されているので、そのうちの一つを`resetn`の入力にします。

内部では`divider`という名前の24bit幅のカウンタ、つまり`2^24-1 = 16,777,215`までカウントできるカウンタを持っており、このカウンタでクロックを`DIVIDER_UPPER = 1200000 - 1` までカウントします。よって`divider`は `1200000/24[MHz] = 1200000/2400000 = 0.5[s]`ごとに0に戻ります。

`divider`が0に戻る前のサイクルで`led_out`の値を1ずつ加算して、0.5[s]ごとにLEDの点灯パターンを変化させます。
計8パターンのLEDの点灯パターンを順に繰り返すようにします。

```blink.v
module blink (
    input wire clock,
    input wire resetn,
    output wire led_r,
    output wire led_g,
    output wire led_b
);

reg [23:0] divider;
reg [2:0] led_out;
localparam [23:0] DIVIDER_UPPER = 24'd12_000_000 - 24'd1;

assign led_r = !led_out[0];
assign led_g = !led_out[1];
assign led_b = !led_out[2];

always @(posedge clock) begin
    if( !resetn ) begin
        divider <= 0;
        led_out <= 0;
    end
    else begin
        divider <= divider == DIVIDER_UPPER ? 0 : divider + 1;
        led_out <= divider == DIVIDER_UPPER ? led_out + 1 : led_out;
    end
end 

endmodule
```

## 合成とIO制約の追加

ここでIO制約を追加するため、一旦合成を行います。

右側のペインで`Process`タブを開き、`Synthesize` をダブルクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/c324242f-18f2-d4aa-2324-60acb50038b1.png)

ダブルクリックすると、`Synthesize` の左側のアイコンがぐるぐる回転する矢印に代わります。合成完了すると、以下のような画面画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/2233299a-c010-3724-fc06-1e0f612a4253.png)

合成完了後、`Process`タブで`FloorPlanner`をダブルクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/66323ec4-3a00-fa79-f329-ffe3cde32c95.png)

`FloorPlanner`の初回実行時はIO制約ファイル(*.cst)がないため、新しく作成するかどうかを確認するダイアログが表示されますので、`OK`を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/90d69528-044e-498c-098b-0448b281c66c.png)

FloorPlannerは起動直後は以下のような画面になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/452a98bb-148e-f73b-162c-9e9d64e0ebde.png)

今回はIO制約を追加したいので、右上のペインで`Package View`タブを開き、下のペインで`I/O Constraints`タブを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/7f7192a1-d405-db13-825a-a19348c20064.png)

現在のところ、合成した論理回路の各入出力ポートがFPGAのピンに割り当てられていませんので、Tang Nanoの回路図を見ながらピンを割り当てます。

ピンを割り当てるには、`I/O Constraints`タブで割り当てを行いたいポートを選択し、`Location`列のセルを`Package View`に表示されている割り当てたいピンにドラッグ&ドロップします。

![gowin_floorplanner_assign_pin.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/4848fd86-8daa-db38-84c3-e985a07ee74b.gif)

各ポートのピン割り当ては以下の通りです。

| Port | Location | 備考 |
|:--|:--|:---|
| clock | 35 | CH552と共用の24MHz水晶発振子の信号 |
| resetn | 15 | ボタンA (アクティブ・ロー) |
| led_r | 18 | カラーLEDの赤 (アクティブ･ロー) |
| led_g | 16 | カラーLEDの緑 (アクティブ･ロー) |
| led_b | 17 | カラーLEDの青 (アクティブ･ロー) |

回路図より、各ピンの属するIOバンクの電源電圧は3.3Vになっているので、`IO Type`列を`LVCMOS33`に変更します。

設定が完了したら保存してFloorPlannerを閉じます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/cfb2345a-023a-0cc1-90bd-ff5774b05925.png)

## タイミング制約の追加

必須ではありませんが、一応タイミング解析を行えるようにタイミング制約を追加します。

Processタブから`Timing Constraints Editor`をダブルクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/678ad13b-cb20-4822-9525-49022bdbfe0b.png)

IO制約の時と同様に制約ファイル(*.sdc)が無いため新規作成するか確認されるので、OKを選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/a81bcf74-78a2-75bc-0093-a5f7b18e4c96.png)

`Gowin Timing Constraints Editor` が表示されるので、右側の画面で右クリックし、`Create Clock`を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/0f09e221-70af-0869-c352-c35d47260fdf.png)

`Create Clock`ダイアログが表示されるので、`Clock name`に`clock`、`Frequency`に`24`[MHz]を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/0c989758-cc27-e2ae-66f2-6f592a0ed91a.png)

`Objects`横の`...`を押して`Select Objects`ダイアログを表示します。

`Collection`で`get_ports`、`Filter`に`*`を入力した状態で`Search`ボタンを押します。`Matches&Selected`リストにポート一覧が表示されるので、`clock`を選んで`>`を押します。その後、`OK`を押して`Select Objects`ダイアログを閉じます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/949c419f-15ee-ba49-d431-1e016f9d18bb.png)

`Create Clock`ダイアログに戻ると、`Objects`に`[get_ports {clock}]`が入力されるので、`OK`を押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/2f672c50-6341-bd8f-142d-c766358dec81.png)

保存して Timing Constraints Editor を閉じます。

## 配置配線とビットストリームの生成

Processペインで`Place & Route`をダブルクリックします。しばらくすると配置配線が終わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/2fd526ec-992e-1f58-6844-b4ddf06e2aba.png)

`Place & Route Report`をダブルクリックすると、配置配線結果のレポートが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/26390f09-3da8-edae-3ee1-03d740add836.png)

`Timing Analysis Report`をダブルクリックすると、タイミング解析結果が表示されます。とりあえずタイミング制約違反は無いようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/f88ca022-1e34-b77b-df3b-7a419d754b4c.png)

## ビットストリームの書き込み

ボードに書き込むためのビットストリームを作り終わったので、実際にボードに書き込んで動かしてみます。チュートリアルではFlashへの永続的なコンフィグレーション手順が記載されていますが、とりあえず実験用にSRAMにコンフィグします。(電源を落とすともとに戻ります)

ここで注意しないといけないのは、書き込みに管理者権限が必要なため、Programmerを手動で起動することです。

`Programmer/bin/programmer`を管理者で起動します。

```bash
sudo Programmer/bin/programmer
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/d88b418b-cfb0-2293-fb5e-6e786a11b51f.png)

起動したら右クリックして`Configure Device`を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/77e23ae6-6526-f9bb-cb29-cf9595bace7f.png)

`Device configuration`ダイアログが表示されるので、`Access Mode`で`SRAM Mode`、`Operation`で`SRAM Program`を選びます。
また、`Programming Options`の`File name`右にある`...`を押して、
`(プロジェクトのディレクトリ)/impl/pnr/blinker.fs` を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/7de8f74b-bf5d-c16c-0bd3-aedc912f8d6d.png)

`Save`を押してDevice configurationダイアログを閉じ、さらに右クリックメニューから`Program/Configure`を選ぶと、ビットストリームの書き込みが始まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58388/31f6358b-36bc-fddd-8245-d6292d449d48.png)


# Programmerを一般ユーザーでも使えるようにする

いちいち管理者で起動するのは面倒なので、udevの設定をして管理者で起動しなくても良いようにします。

以下のファイルを作成します。

```/etc/udev/rules.d/50-tang-nano.rules
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", ATTRS{product}=="Sipeed-Debug", GROUP="users", MODE="0666"
```

udevの設定を再読込します。

```
sudo udevadm control --reload
```

Tang NanoをUSBポートから抜いて挿し直します。
その後、`ftdi_sio`ドライバをアンロードします。

```
sudo modprobe -r ftdi_sio
```

これで一般ユーザーでもTang Nanoにアクセスできるようになります。
試しにコマンドライン版Programmerを実行してみます。

```
$ Programmer/bin/programmer_cli --channel 0 --device GW1N-1 --operation_index 0
 "Read Device Codes" starting on device-1...
 ID code is: 0x0900281B
 User code is: 0x00004951
 Status code is: 0x0001F020
 Cost 1.04 second(s)
```