激安中華マイコンでLチカやってみた

みなさんIoTしてますか！

この度中華製HLK-W80xという謎の激安マイコンを試してみたので、簡単に紹介します。

# HLK-W80xとは
![W80x_arduino.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532340/97ca0532-d6f0-735b-f92c-f679ce0ad900.jpeg)
左から、HLK-W801、HLK-W806、Arduino Pro Micro互換（ハンダが汚くてすみません）の写真です。
この左2つが今回使ってみたマイコンです。

W80xは中国WinnerMicro社が開発しているIoT用のマイコンで、HLK-W80xがそのマイコンを搭載した開発ボードのことです。
2018年にアリババ社が買収したC-Sky社のXT804という、C-Sky ISAアーキテクチャを採用し、USBシリアルも搭載しているためArduinoのようにUSBケーブル1本で給電、書き込み、シリアル通信が可能です。
また価格が安く、開発ボードはAliExpressから5個セットで2000円以下で入手できます。

W806とW801は2.4Ghz無線機能の有無とフラッシュ容量を除いて、基本的に同じものですが、一方で、そのMCUを搭載した開発ボードであるHLK-W801とHLK-W806はW801が後発なため色々な改善が行われています。
大きい変更点はUSBコネクタがType-Cになっている、USBシリアル経由のRTS信号によりリセットが可能になった、基板上に5V VCCが追加(W806は3.3Vのみ)されたことでしょうか。

<details><summary>詳細なスペック (クリックして展開)</summary><div>

```
W801
CPU(MCU)
 WinnerMicro W801 32-bit C-SKY XT804 1コア240 MHz 
 フラッシュ: 2MB
 RAM: 288KB
 その他 DFP、暗号化エンジン内蔵

無線機能
 802.11b/g/n, STA/APモード、WPA2サポート
 Bluetooth 4.2

インタフェース
 1x SDIOホスト(SDIO 2.0, SDHC, MMC 4.2) 
 6x UART, 1x I2C, 1x I2S
 1x SPIスレーブ＠50 MHz, 1xマスター/スレーブSPI
 4x ADC (16-bit, 1KHz)
 44x GPIO(5xPWM) 
 最大で15個のタッチセンサー
 ISO/IEC 7816 スマートカードインタフェース

その他
 USBシリアルによる接続、Type-Cコネクタ
 オンボード RESET、BOOTボタン、7個のオンボードLED（うち2個がPWM対応）

W806
CPU(MCU)
 WinnerMicro W801 32-bit C-SKY XT804 1コア240 MHz 
 フラッシュ: 1MB
 RAM: 288KB
 その他 DFP、暗号化エンジン内蔵

無線機能
 なし

インタフェース
 1x SDIOホスト(SDIO 2.0, SDHC, MMC 4.2) 
 6x UART, 1x I2C, 1x I2S
 1x SPIスレーブ＠50 MHz, 1xマスター/スレーブSPI
 4x ADC (16-bit, 1KHz)
 44x GPIO(5xPWM) 
 最大で15個のタッチセンサー
 ISO/IEC 7816 スマートカードインタフェース

その他
 USBシリアルによる接続、マイクロType-Bコネクタ
 オンボード RESET、BOOTボタン、3個のオンボードLED

```
</div></details>


さて、これがどんなボードかを理解してもらうには、他の開発ボードとの比較を見てもらうといいと思います。

|  | HLK-W801 | HLK-W806 | ESP-WROOM | Raspberry Pi Pico | Arduino Pro Micro互換 |
|:-:|:-:|:-:|:-:|:-:|:-:|
|価格[^1] | 365円 | 333円  | 424円 |  493円 |  175円 |
|CPU| 32bit 1コア 240Mhz |  32bit 1コア 240Mhz |  32bit 2コア 240Mhz |  32bit 2コア 133Mhz | 8bit 1コア 16Mhz |
|フラッシュ| 2MB  | 1MB| 4MB  | 2MB  | 32KB  |
|RAM|288KB|288KB|520KB|264KB|2.5KB|
|無線| 2.4G Wi-Fi/BT<BR>技適無し  | 無し  |2.4G Wi-Fi/BT<BR>技適有り[^2]|無し|無し|
[^1]: 比較対象の価格はAliExpressである程度売上があるものを5個以下のロットの場合での価格を簡単に調査したものです
[^2]: 技適が通っているモデル(Ai Thinkerなど)を指名買いしようとすると多分値段が3倍位します

表を見て薄々感づいているかもしれませんが、IoT系で有名なESP-32と比較すると、安いくらいしか良い点はありません。
あえてメリットを上げるのであれば
* フラッシュがオンチップ、基盤実装面積が小さい[^5]
* チップ単価が130円くらいと激安
* 新しい。特にW801は2021年11月発売
[^5]: ボード上に水晶、CH330Nと3.3Vの3端子レギュレータ以外は抵抗とダイオードしかない。GPIOが多いので余裕を持って配線しているが、切り詰めれば相当小さくなりそう。

対してデメリットは
* JTAGとか無いので趣味以上には使いづらい
* 技適通している開発ボードがないので趣味では使いづらい
* AliExpressとかでしか売っていないので配送に時間がかかる
* **多分日本では誰も使ってない**
* **ドキュメントが中国語のみ**
* **Web上の日本語情報はゼロ。掲示板の書き込みとかも全く引っかからない**
* 英語もほとんどない


[WinnerMicro社の公式サイト](http://www.winnermicro.com/)では英語表記も選べますが、中国語にしないとW801,806の情報は出てきません。
それどころか、**このチップ名でググっても日本語の情報は一切引っかかりません**[^4]。英語についても同じような記事ばかりで具体的な内容に触れているものはフォーラムくらいで公式ドキュメントも中国語のみで提供されます。
[^4]: https://i.gyazo.com/f1ce8a62d830cb8752a4aa8034c22a73.png 証拠写真です

でもきっと、ESP-32を頼んだのにお父さんがHLK-W801を買ってきたとか、国外在住で技適関係ないとか、とにかく新しいもの好きとかの方もきっといると思うんです。
せっかくW806/W801を触ってみたので、たとえこのマイコンがこのまま誰にも使わず忘れ去られて埋もれる運命でも、証を残すためにもここにログを残させてください。

# Arduino IDE利用編 (HLK-W806のみ)
HLK-W806を選択した方は賢明です。技適問題も無いですし、このボードはArduino IDEで簡単に動作を試すことが出来ます。
ただし、Arduinoの標準インタフェースへの対応が全然完了していないので、単純に開発環境、フラッシュへの書き込みにArduino IDEを使うだけですが、
開発は活発に進んでいるようですので今後に期待ですね。

GitHubのプロジェクトページは下記の通りです。（ボードの開発元であるHi-Linkのサポートを受けているようです）
[GitHub W80x-arduino](https://github.com/Hi-LinkDuino/w80x_arduino)

前提条件：
* Windows 10環境を前提に記載しています
* W806はCH330Nを使用してUSBシリアル変換しています。必要に応じてCH330NのドライバをPCにインストールしてください。
  私の環境はCH341のドライバで動作していました。なお、USBのIDは"PID_7523&REV_8131"でした。
* Arduino IDEがインストールされている必要があります

### Lチカまで
1. GitHubのREADME.mdにはボードマネージャにjsonを読み込む、とありますがそれはうまくいきません。
理由として中に記載されているURLがcnpmjs.orgという[グレートファイアウォール内専用GitHubプロキシ](https://theblackcat102.github.io/weird-github-entry-point/)が指定されており、盾に守られていない我々はアクセスできません。
1. そのため、GitHubプロジェクトページからpackage_w80x_proxy_index.jsonをダウンロードし、URL中に含まれる.cnpmjs.orgをすべて置換（削除）してください
1. 書き換えが終わったjsonファイルを **アクセス可能な適当なWebサーバにjsonを配置し** 、そのURLをArduino IDEの追加ボードマネージャURLに指定してください。(他にいい方法がありそうですが、簡単なのはなさそうでした)
1. ボードマネージャからW80x_Boardsをインストールすると、Arduino IDEからコードを書けます。

JSON書き換えのイメージ：
```text:package_w80x_proxy_index.json
書き換え前
"url": "https://github.com.cnpmjs.org/Hi-LinkDuino/w80x_arduino/releases/download/v0.0.1/w80x_arduino-0.0.1.zip",
書き換え後
"url": "https://github.com/Hi-LinkDuino/w80x_arduino/releases/download/v0.0.1/w80x_arduino-0.0.1.zip",
```

IDEからシリアルポートを選択し、下記のコードをIDEにペーストすればLチカが動くはずです。
なお、フラッシュへの書き込み、及び書き込み後に手動で基板上のリセットスイッチを押す必要があります。
![Arduino_IDE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532340/3626d8d6-fe1a-3462-4af2-124a2cd81588.png)



サンプルコード：
```c:sample.c
 #include <stdio.h>
 #include <Arduino.h>

void setup() {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // GPIO PINの初期化
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
}

void loop() {
    printf("Hello, World!\r\n");
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, (GPIO_PinState)0);
    HAL_Delay(500);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, (GPIO_PinState)1);
    HAL_Delay(500);
}
```
簡単にLEDチカチカできますね！また、シリアルモニタを開くとHello, Worldの出力も確認できます。（シリアルの初期化が不要なんですね）
![LCHIKA_W806.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532340/34d1dda9-57ed-f1b0-6e87-ae9aa261b685.gif)

もちろん、GPIOはいっぱいありますから、ブレッドボードに差し込んでもっと複雑な制御も出来ます。


# MSYS2環境編 (HLK-W801/HLK-W806)
::: note alert
日本国内で技適マークの無い無線機の設置は違法です。

ただし、[技適未取得機器を用いた実験等の特例制度](https://exp-sp.denpa.soumu.go.jp/public/)を用いれば180日以内の検証であればWeb上から届け出が可能です。実験の際は必ず事前に届け出て、商用用途なら技術適合証明を取得するか、物理的に対策を講じて[微弱無線局の範囲まで電波強度が落ちれば問題ない](https://qiita.com/maclineto/items/0a1e7e56a002aeb858f9)そうです。
:::

HLK-W801は残念ながらArduino IDEに対応していないようです。SDKをインストールし自分でコンパイル、リンク、フラッシュする必要があります。
なお本手順は色々と手探りでやったため、もっと効率がよい/モダンな方法もあると思います。是非コメントで教えて下さい。

事前準備：
1. 日本国内の場合、特例申請をします
1. [MSYS2](https://www.msys2.org/)をインストールします
1. ビルドに用いるライブラリをダウンロードするのですが、C-Sky公式からのダウンロードが中国国外から出来ないため、W806編の[GitHubのReleaseページ](https://github.com/Hi-LinkDuino/w80x_arduino/releases)から下記のファイルをダウンロードしてきます。
 csky-elfabiv2-tools-mingw-minilibc-20210423.tar.gz

### 1. MSYS2での環境設定
MSYS2触ったことなかったのですが、中国語のガイドがMSYS2だったのでそのまま進めます。
まず、MSYS2コンソールを開き、pacmanでパッケージ更新及び必要なパッケージのインストールを行います。
```shell:MSYS2
 // パッケージリストの更新
pacman -Syu

 // 各種パッケージのインストール
pacman -S msys/make
pacman -S msys/automake
pacman -S msys/autoconf
pacman -S msys/gcc
pacman -S msys/git
pacman -S msys/ncurses-devel
pacman -S msys/gettext-devel
```
MSYS2のターミナルからWindows環境にアクセスする場合、/etc/fstabの末尾にローカル側のパス、MSYS2側のパスの順で書いておきます。
その後ターミナルを一度終了し、再度開けばルートにディレクトリが見えていると思います。

```shell:/etc/fstab
C:/work_w801 /work
```
### 2. ライブラリの展開
次に、ダウンロードしておいたライブラリを解凍します。自分は/workをプロジェクトフォルダにしたので、work_w801内にcsky-elfabiv2-tools-mingw-minilibc-20210423.tar.gzをコピーしておきます。その後、MSYS2のターミナルからライブラリを適当なパスに展開します。
```shell
 // 適当なディレクトリを作る
$ cd /work
$ mkdir csky-elfabiv2-tools
$ tar xvf csky-elfabiv2-tools-mingw-minilibc-20210423.tar.gz -C csky-elfabiv2-tools
```
これで/work/csky-elfabiv2-toolsにライブラリが展開できました。

### 3. SDKのClone
中華GitHubであるところのGiteeで、W801のSDKを公開してくださっている方がいます。
[https://gitee.com/iosetting/wm-sdk-w80x](https://gitee.com/iosetting/wm-sdk-w80x)から、SDKをcloneしていきます。
```shell
$ cd /work
$ git clone https://gitee.com/iosetting/wm-sdk-w80x
```

### 4. リセットシグナルの変更（W801のみ）
これで環境が出来たのですが、W801はリセット時にRTSを用いるため、Makeに用いるrule.mkを修正します。
（atがrtsになっているのと、monitorを追加しています）

ちなみに、W801のRTSシグナルの扱いに問題がありLinux(POSIX標準)では問題が発生するそうです。詳細は下記サイトをご参照ください。
[https://www.cnblogs.com/milton/p/15621540.html](https://www.cnblogs.com/milton/p/15621540.html)

```diff:/work/wm-sdk-w80x/tools/w800/rules.mk
...
run:all
-        @$(WM_TOOL) -c $(DL_PORT) -rs at -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).fls -sl str -ws 115200
+        @$(WM_TOOL) -c $(DL_PORT) -rs rts -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).fls -sl str -ws 115200

list:
        @$(WM_TOOL) -l

down:
-        @$(WM_TOOL) -c $(DL_PORT) -rs at -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).fls
+        @$(WM_TOOL) -c $(DL_PORT) -rs rts -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).fls
+ 
+ monitor:
+        @$(WM_TOOL) -c $(DL_PORT) -sl str -ws 115200

image:all
        @$(WM_TOOL) -c $(DL_PORT) -rs at -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).img

flash:all
-        @$(WM_TOOL) -c $(DL_PORT) -rs at -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).fls
+        @$(WM_TOOL) -c $(DL_PORT) -rs rts -ds $(DL_BAUD) -dl $(FIRMWAREDIR)/$(TARGET)/$(TARGET).fls

erase:
        @$(WM_TOOL) -c $(DL_PORT) -rs at -eo all
...
```

### 5. ライブラリパスの指定
次に、menuconfigを用いてライブラリを指定してあげます。
```shell
$ cd /work/wm-sdk-w80x/
$ make list # 接続されているシリアルポートをリスト表示
COM10

$ make menuconfig
```
menuconfig上でライブラリパスとCOMポートを変更します。
* Toolchain Configuration -> Toolchain path に /work/csky-elfabiv2-tools/**bin/** を指定します
* Download Configuration -> download port にW801のCOMポートを COM1 などと指定します
Windowsのデバイスマネージャでも確認出来ます

### 6. Lチカっ！
それでは早速、Lチカをやっていきましょう！
ユーザプログラムはapp/main.cに記述します。
```c:app/main.c
 #include "wm_include.h"

void init(void)
{
        tls_gpio_cfg(WM_IO_PB_05, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
        return;
}

void UserMain(void)
{
        // initialize
        init();

        // loop
        while(1)
       {
                tls_gpio_write(WM_IO_PB_05, 0);
                printf("0\n");
                tls_os_time_delay(500);
                tls_gpio_write(WM_IO_PB_05, 1);
                printf("1\n");
                tls_os_time_delay(500);
        }
}
```

その後、/work/wm-sdk-w80x/でmake flashします。

```text
$ cd /work/wm-sdk-w80x
$ make flash
... <snip> ...
generate compressed image completed.
build finished!
connecting serial...
serial connected.
wait serial sync...
serial sync sucess.
mac 28-6D-CD-XX-XX-XX.
start download.
0% [##################################################################] 100%
download completed.

 // シリアルポートを見てみる
$ make monitor
0
1
0
1
...
```
うまく動きましたか？
![LCHIKA_W801.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2532340/b2b795a3-69c6-f427-5c16-f1fbae3eab8c.gif)

とりあえず動いてしまえば、あとはコーディングするだけです。
SDKのdemoにサンプルとして、HTTPSサーバやSDカードの読み書き、無線AP、クライアント等色々入っています。

# 終わりに
大変長くなってしまいました。
Raspberry Pi PicoやArduinoでマイコンをいじった気になっても、結局先人のサンプル通りに動かしているだけじゃない？実力ってなんなの？という気持ちが強くなり、未知のマイコンを触ってみようと酒に酔ってAliExpressで注文し、届くまでに調べようとしたら一切情報がなく焦ったのを覚えています。
マイコン歴が浅い僕にはとても難しかったのですが、まぁでもなんとかフラッシュ通ったので、ちゃんとしたプロジェクトを作ろうと思います！

もし興味を持って頂いたり、なにか誤りを見つけたり、ご要望、もっといい方法や面白いものをご存知でしたらぜひコメントで教えて下さい。

本当にありがとうございました。最後まで読んでいただきありがとうございます。

# 参考にしたサイト
* https://www.cnblogs.com/milton/p/15534747.html HLK-W806のチュートリアル。中国語。最重要サイト。
* https://reposhub.com/cpp/miscellaneous/IOsetting-wm-sdk-w806.html 貴重な英語サイト。でも、上のサイトの翻訳

***