Milk-V Duoのすゝめ

# Milk-V Duoについて

Milk-V DuoはShenzhen MilkV Technology Co., Ltd.が販売するRISC-V CPUを搭載する小型のシングルボードコンピュータ。

https://milkv.io/duo

>Milk-V DuoはCV1800Bをベースにした超小型の組み込みプラットフォームです。LinuxとRTOSが実行可能で、プロフェッショナル、産業用ODM、AIoT、DIY、クリエイターに、高信頼で高費用対効果なプラットフォームを提供します。Duo 256MはSG2002をメインコントローラーに据えたDuoのアップグレードで、256MBのメモリーを備えており、スタンダードなLinuxシステムとアプリケーション、さらにより多くのメモリを必要とするアプリケーションに対応できます。

Raspberry Pi Picoと同じサイズです。が、Linuxが動作します。Kawaii🥰
片面基盤なのもミソですね。

メモリ64MBと256MBバージョン、フォームファクタや機能が全く違いますがDuo Sという形で512MBバージョンがあります。

国内では(Duo Sを除いて)秋月電子通商で取り扱いがあります。

:::note info
先日256MB版を入手しました。
256MB版についての詳しい解説はこちら↓
https://qiita.com/niwatori_chicken/items/9f71ac83338ef08260e3/
:::

### スペック
<details><summary>Milk-V Duo 64M(クリックで展開)</summary><table>

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735779/22e21ed6-e20c-9994-a608-e32cba183462.png">
(milkv.ioより引用)
<caption>Milk-V Duo 64M</caption>
  <thead>
    <tr>
      <th></th><th>名称</th><th>備考</th>
    </tr>
  </thead>
  
  <tr>
    <td>SoC</td> <td>CVITEK CV1800B</td> <td></td>
  </tr>
  
  <tr>
    <td>CPU</td> <td>T-Head Xuantie C906</td> <td>1GHz駆動</td>
  </tr>

  <tr>
    <td>CPU</td> <td>T-Head Xuantie C906</td> <td>700MHz駆動 RTOS用</td> 
  </tr>

  <tr>
    <td>RAM</td> <td>64MB DDR</td> <td>SoCに内蔵</td> 
  </tr>

  <tr>
    <td>MCU</td> <td>8051</td> <td>8KB SRAM</td> 
  </tr>

  <tr>
    <td>TPU</td> <td>0.5TOPS</td> <td>INT8</td> 
  </tr>

  <tr>
    <td>GPU</td> <td>なし</td> <td></td> 
  </tr>

  <tr>
    <td>ストレージ</td> <td>MicroSD/SPI NAND</td> <td></td> 
  </tr>

  <tr>
    <td>ネットワーク</td> <td>Ethernet</td> <td>パッドから100Mbpsが1系統</td> 
  </tr>

  <tr>
    <td>オーディオ</td> <td>なし</td> <td></td> 
  </tr>

  <tr>
    <td>映像出力</td> <td>なし</td> <td></td> 
  </tr>

  <tr>
    <td>GPIO</td> <td>26ピン</td> <td></td> 
  </tr>

  <tr>
    <td>カメラ</td> <td>MIPI CSI</td> <td>16pin FPCコネクタ/2レーン 1系統</td> 
  </tr>
</table>

</details>

<details><summary>Milk-V Duo 256M(クリックで展開)</summary><table>
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735779/9edb2e3a-9b4d-022c-62fe-f9d80dc1d015.png">
(milkv.ioより引用)
<caption>Milk-V Duo 256M</caption>
  <thead>
    <tr>
      <th></th><th>名称</th><th>備考</th>
    </tr>
  </thead>
  
  <tr>
    <td>SoC</td> <td>SOPHGO SG2002</td> <td></td>
  </tr>
  
  <tr>
    <td>CPU</td> <td>T-Head Xuantie C906</td> <td>1GHz駆動</td>
  </tr>

  <tr>
    <td>CPU</td> <td>T-Head Xuantie C906</td> <td>700MHz駆動 RTOS用</td> 
  </tr>

  <tr>
    <td>CPU</td> <td>ARM Cortex-A53</td> <td>C906@1GHzとは排他利用</td> 
  </tr>

  <tr>
    <td>RAM</td> <td>256MB DDR</td> <td>SoCに内蔵</td> 
  </tr>

  <tr>
    <td>MCU</td> <td>8051</td> <td>6KB SRAM</td> 
  </tr>

  <tr>
    <td>TPU</td> <td>1TOPS</td> <td>INT8</td> 
  </tr>

  <tr>
    <td>GPU</td> <td>なし</td> <td></td> 
  </tr>

  <tr>
    <td>ストレージ</td> <td>MicroSD/SPI NAND</td> <td></td> 
  </tr>

  <tr>
    <td>ネットワーク</td> <td>Ethernet</td> <td>パッドから100Mbpsが1系統</td> 
  </tr>

  <tr>
    <td>オーディオ</td> <td>GPIO経由で対応</td> <td></td> 
  </tr>

  <tr>
    <td>映像出力</td> <td>なし</td> <td></td> 
  </tr>

  <tr>
    <td>GPIO</td> <td>26ピン</td> <td></td> 
  </tr>

  <tr>
    <td>カメラ</td> <td>MIPI CSI</td> <td>16pin FPCコネクタ/2レーン 1系統</td> 
  </tr>
</table>
</details>

<details><summary>Milk-V Duo S(クリックで展開)</summary><table>
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735779/fdfe8ddd-3320-7901-1c29-3292718fc921.png">
(milkv.ioより引用)
<caption>Milk-V Duo S</caption>
  <thead>
    <tr>
      <th></th><th>名称</th><th>備考</th>
    </tr>
  </thead>
  
  <tr>
    <td>SoC</td> <td>SOPHGO SG2000</td> <td></td>
  </tr>
  
  <tr>
    <td>CPU</td> <td>T-Head Xuantie C906</td> <td>1GHz駆動</td>
  </tr>

  <tr>
    <td>CPU</td> <td>T-Head Xuantie C906</td> <td>700MHz駆動 RTOS用</td> 
  </tr>

  <tr>
    <td>CPU</td> <td>ARM Cortex-A53</td> <td>C906@1GHzとは排他利用</td> 
  </tr>

  <tr>
    <td>RAM</td> <td>512MB DDR</td> <td>SoCに内蔵</td> 
  </tr>

  <tr>
    <td>MCU</td> <td>8051</td> <td>6KB SRAM</td> 
  </tr>

  <tr>
    <td>TPU</td> <td>0.5TOPS</td> <td>INT8</td> 
  </tr>

  <tr>
    <td>GPU</td> <td>なし</td> <td></td> 
  </tr>

  <tr>
    <td>ストレージ</td> <td>MicroSD/eMMC</td> <td></td> 
  </tr>

  <tr>
    <td>ネットワーク</td> <td>Ethernet/WiFi6/Bluetooth 5.4(オプション)</td> <td>RJ45対応</td> 
  </tr>

  <tr>
    <td>オーディオ</td> <td>3.5mmジャック経由で対応</td> <td></td> 
  </tr>

  <tr>
    <td>映像出力</td> <td>GPIO経由で対応</td> <td>MIPI DSI 4レーン</td> 
  </tr>

  <tr>
    <td>GPIO</td> <td>39ピン</td> <td>26ピン×2中 一部ディスプレイに使用</td> 
  </tr>

  <tr>
    <td>カメラ</td> <td>MIPI CSI</td> <td>16pin FPCコネクタ/2レーン 1系統</td> 
  </tr>
</table>

</details>

めちゃくちゃヘテロジニアスな構造。
組み込み向けを謳っているだけあり、8051を内蔵しています。電力状況次第でC906を寝かせておき、8051に動いてもらうこともできそう。
エッジAIを意識してか、TPUも搭載しています。SG2002のが一番強力なようです。
残念なことにC906はコア間連携には対応しておらず、Linuxから扱えるのは1GHz(C906B)の方のみになります。
追記:
    小さい方のコア(C906L)にはMMUがないようです。
    なので通常のLinuxカーネルは動作しませんが、もし仮にμCLinuxをC906Lで動かせたら面白いことになりそう...
Duo 256MとDuo SのA53は本当に必要なんだろうか...

### ちょこっとベンチマーク/消費電力測定
EEMBC Coremarkを回してみました。
結果はだいたい2500Coremarkくらいになり、駆動周波数の1000MHzで割るとだいたい2.5Coremark/MHzくらいです。
この値がどれくらいかで言えば、同周波数の初代ラズパイ/初代ラズパイZeroくらいですね。
まあ、このサイズ感でこの性能なら十分でしょう。
消費電力については単体の場合で最大500mW程度、アイドル時200mW程度でした。マイコンとして見れば高いですが、Linuxが動作するSBCであることを考えれば低いと思います。(当然、周辺機器を接続すればその分増えます)
近年作られたチップだけあり、消費電力性能に関しては秀でているといえるでしょう。

# 起動してみる
### 用意するもの
**・PC(Ubuntuの22.04LTS以降を推奨)**
**・MicroSDカード**
**・SDカードリーダー**
**・Milk-V Duo**

起動させるだけなら[公式のGithubリポジトリ](https://github.com/milkv-duo/duo-buildroot-sdk/releases)から完成済みのBuildroot Linuxのイメージがダウンロードできるのでそれを使います。

使用するハードウェアにあったイメージファイルをダウンロードします。

### MicroSDカードに書き込む
DDコマンドやRaspberry Pi ImagerないしEtcherのような書き込みツールを用います。

SDカードリーダーにカードを挿入し、書き込みます。

:::note alert
**ドライブの指定には十二分に注意しましょう**
:::

### 起動して接続する

Duoに先ほど書き込んだMicroSDカードを挿入し、Type-Cケーブルを接続します。
Linuxが正常に起動すると、USB-Cポート付近の青色のLEDが点滅します。

:::note warn
#### LEDが点滅しない場合
LEDが点滅しない場合、Linuxが正常に起動していません。
MicroSDカードに正常にイメージが書き込まれているか確認してください。
一部カードでの相性問題も確認しています。後者に関しては諦めて別のSDカードを使うが吉です。
私の確認した限りでは、SanDisk製カードは安定して利用できることを確認しています。
:::

### RNDISを使用しての接続
RNDISはUSB経由のネットワークアダプター用の規格です。
Windowsの場合デバイスマネージャ経由でRNDISドライバのインストールが必要になります。
MacOSに関してはかなり面倒くさいので説明を省きます。
圧倒的Linux推奨。

### 用意するもの
**・先ほど書き込んだSDカード**
**・Type-C↔Type-A USBケーブル(電源・通信用)**

Linuxの場合、特別な設定は必要ありません。
ネットワークアダプターとして認識されるので、SSHで接続します。
```sh
root@192.168.42.1
```
(途中、ホストが正しいか聞かれるのでyesと入力します。)
パスワードは`milkv`です。

問題なく接続できれば、shのプロンプトが表示されます。
```
[root@milkv-duo]~#
```

`/proc/cpuinfo`でも覗いてみましょう。

```title: root@192.168.42.1
[root@milkv-duo]~# cat /proc/cpuinfo
processor	: 0
hart		: 0
isa		: rv64imafdvcsu
mmu		: sv39

[root@milkv-duo]~#
```

ちゃんとRISC-Vプロセッサが手元で動いています。MMUも居座っています。

### UARTを使用しての接続
こっちのほうがオススメです。
起動時のログなどもすべて確認できるので、起動しない場合の問題の切り分けにも役立つでしょう。

### 用意するもの
**・先ほど書き込んだSDカード**
**・Type-C↔Type-A USBケーブル(電源用)**
**・USB↔UART 変換モジュール**
**・ピンヘッダ**

ピンヘッダはハンダ付けしてください。
DuoのRXチャネルは17番ピン、TXチャネルは16番ピンです。(内側の灰色の数字)
これに従って、USB↔UART 変換モジュールと接続します。(TXチャネルとRXチャネルはクロスさせます。)

<img width=300 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735779/fc8ec643-a77b-2299-ebbe-137f9f85ff86.png" title="Duoのピンアサイン" alt="Duoのピンアサイン 左上から数えてPin 1, 2, 3... 16番, 17番は左下。">
(milkv.ioより引用)

ターミナルからならpicocomやscreenが便利です。GUIのツールはGTKTermやTera Termが有名どころでしょう。

ttyUSB0などの形で認識されるはずなので、それに接続します。パーミッションの設定が必要な場合もあるので、`sudo chmod 666 /dev/ttyUSB0`のように書き換えておきます。
シリアルなのでログインはいりません。

```title: /dev/ttyUSB0
[root@milkv-duo]~# cat /proc/cpuinfo
processor	: 0
hart		: 0
isa		: rv64imafdvcsu
mmu		: sv39

[root@milkv-duo]~#
```

:::note info
RAMが28MBしか認識されていないのは一部がカメラのアルゴリズム用のメモリに割り当てられているためです。すべてのメモリをLinuxで使いたい場合は**イメージをビルドしてみる**セクションの**メモリをフル活用する**の項目に従って変更します。
:::


# イメージをビルドしてみる
アプリケーションパッケージなどを同梱してBuildrootイメージをビルドすることができます。

### 用意するもの
**・Ubuntu 22.04 LTS以降をインストールしてあるPC**
**・MicroSDカード**
**・SDカードリーダー**
**・Milk-V Duo**

### ソースをクローンする
どこか適当なわかりやすいディレクトリに移動し、
```
git clone https://github.com/milkv-duo/duo-buildroot-sdk
```
でクローンします。(ちょっと時間がかかります)
`cd duo-buildroot-sdk`でディレクトリに入っておきます。

### 必要なパッケージ
公式ドキュメント曰く：
`pkg-config`
`build-essential`
`ninja-build`
`automake`
`autoconf`
`libtool`
`wget`
`curl`
`git`
`gcc`
`libssl-dev`
`bc`
`slib`
`squashfs-tools`
`android-sdk-libsparse-utils`
`jq`
`python3-distutils`
`scons`
`parallel`
`tree`
`python3-dev`
`python3-pip`
`device-tree-compiler`
`ssh`
`cpio`
`fakeroot`
`libncurses5`
`flex`
`bison`
`libncurses5-dev`
`genext2fs`
`rsync`
`unzip`
`dosfstools`
`mtools`
`tcl`
`openssh-client`
`cmake`
`expect`
以上のパッケージ類が必要なようです(多いな)
```
sudo apt install pkg-config build-essential ninja-build automake autoconf libtool wget curl git gcc libssl-dev bc slib squashfs-tools android-sdk-libsparse-utils jq python3-distutils scons parallel tree python3-dev python3-pip device-tree-compiler ssh cpio fakeroot libncurses5 flex bison libncurses5-dev genext2fs rsync unzip dosfstools mtools tcl openssh-client cmake expect
```
でもこれをコピペしてしまえば楽でしょう(依存関係を破壊しないように注意)。


### ビルド

`./build.sh`をそのまま実行するとヘルプが表示されます。
`./build.sh`の引数にボードの名前を入力すればそれに適した設定でビルドされます。
または、引数に`lunch`と入れれば対話形式で選択できます。
```title: ボード名一覧
milkv-duo
milkv-duo-spinand
milkv-duo-spinor
milkv-duo256m
milkv-duo256m-spinand
milkv-duo256m-spinor
milkv-duos-emmc
milkv-duos-sd
```

筆者はDuo(64MB)を使用しているので、引数に`milkv-duo`をつけてコンパイルしました。

初回のコンパイル時にツールチェーン(800MBくらい)が自動でダウンロードされます。
ビルドには時間がかかります。

ビルドが完了すると`./out`ディレクトリ直下に`milkv-****.img`のようなフォーマットでファイルが出てきます。
ファイル名の途中に日付と時刻が入るので、ビルド日時順で見分けがつきます。

出てきたファイルを**起動してみる**セクションと同様にSDカードに焼いて起動できたら成功です。
機能的には標準のイメージと全く変わりません。

### WSL2を用いてビルドする
WSL2(Windows Subsystem for Linux 2)を用いてビルドする場合、Linux側に追加の設定が必要です。
`/etc/wsl.conf`に以下を追記します。
```title:/etc/wsl.conf
[前略]

[interop]
appendWindowsPath = false
```

この設定をしないと、
```
make: *** [Makefile:597: br-rootfs-pack] Error 2
Error: Build board milkv-duo256m-sd failed!
```
というエラーを吐かれます。このエラーが出る場合は`/etc/wsl.conf`を確認してください。

### メモリをフル活用する
**起動してみる**セクションで先述した通り、RAMの半分がカメラのアルゴリズム用に持っていかれており、Linuxでは28MBしか使えません。
使えるだけの全部のメモリを使いたいなら、`duo-buildroot-sdk/build/boards/cv180x/cv1800b_milkv_duo_sd/memmap.py`の43行目にある
```python title:memmap.py
ION_SIZE = 26.80078125 * SIZE_1M
```
の`26.80078125`を0に書き換えてビルドします。

<details><summary>Duo 256Mの場合</summary>
Duo 256Mの場合はパスが
<code>duo-buildroot-sdk/build/boards/cv181x/cv1812cp_milkv_duo256m_sd/memmap.py</code>
になります。
追記；Duo 256Mではビデオエンコーダ系のメモリ割り当ても同様に切る必要があります。ビルド時にエラーになります。
</details>

### パッケージを入れてみる

Buildrootには動的なパッケージ管理システムがありません。
なので、ビルド時にすべて同梱してしまう仕組みになっています。
BuildrootはTUIベースでの設定が可能になっており、難解な操作無しにパッケージを追加できます。
ただしBuildrootに関してはQiitaだけでもたくさんの記事が偉大なる先人たちによって書かれているので、ここで説明することは最低限、本質的なことについては割愛させてもらいます...

:::note info
必要なファイル類を揃えるためにも、**ビルド**セクションを参考に一回ビルドを終わらせておきます。
:::

設定ファイルのディレクトリに移動します。
```
cd buildroot-2021.05/output/milkv-duo_musl_riscv64/
```

設定画面を開きます。
```
make menuconfig
```
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2735779/44a35176-fc61-3f38-44d2-69919b69c182.png"><br>
ここでは試しにCoremarkを入れてみます。(お好きなパッケージをどうぞ)

設定を保存します。(ちょっと時間がかかります)
```
make savedefconfig
```

`cd /path/to/duo-buildroot-sdk`でBuildroot SDKのディレクトリにもどり、`./build.sh`を実行してビルドします。

出てきたファイルを**起動してみる**セクションと同様にSDカードに焼き、電源を投入します。

シェルにログインして先ほどビルドしたEEMBC Coremarkを走らせてみます。
```
[root@milkv-duo]~# coremark
2K performance run parameters for coremark.
CoreMark Size    : 666
Total ticks      : 12782
Total time (secs): 12.782000
Iterations/Sec   : 2347.050540
Iterations       : 30000
Compiler version : GCC10.2.0
Compiler flags   : -O2   -lrt
Memory location  : Please put data memory location here
			(e.g. code in flash, data on heap etc)
seedcrc          : 0xe9f5
[0]crclist       : 0xe714
[0]crcmatrix     : 0x1fd7
[0]crcstate      : 0x8e3a
[0]crcfinal      : 0x5275
Correct operation validated. See readme.txt for run and reporting rules.
CoreMark 1.0 : 2347.050540 / GCC10.2.0 -O2   -lrt / Heap
[root@milkv-duo]~# 
```
動きました。
...ちょっと値が低いのはコンパイラのツメが甘いからです。多分。(別のコンパイラでビルドした際は2500程度出ました。)

なにわともあれ、パッケージを追加することができました。

# いろいろ作ってみる

### ネットワーク
ネットワークに関しては別で記事を書いてあります。

https://qiita.com/niwatori_chicken/items/92089e4b9ccc0227edeb

https://qiita.com/niwatori_chicken/items/54bef0d6630c4865a697

### 電子工作
時間と材料と体力があれば書きます...

追記：V4L2のサポートが今後数週間のうちに開始されるとのことです。そうなれば、映像方面でより応用の幅が広がりそうです。