CH55xをArduinoIDEで使う

※この記事の内容をベースに、解説を加えた書籍（[薄い本](https://techbookfest.org/product/5803512929714176) / [CH55xでどうでしょう](https://www.amazon.co.jp/dp/4899775318)もありますので、あわせてご覧ください。

# CH55xというマイコン

[WCH(南京沁恒微电子股份有限公司)](http://wch-ic.com/)という中国のICメーカの製品に、CH55xというシリーズの8ビットマイコンがあります。8051という古いコアで、それほど性能は高くないのですが、びっくりするぐらい値段が安いシリーズです。しかもUSB機能がついていたり（キーボードなどのHIDデバイスにもなる）、タイマやSPIなどの周辺も充実していて、小さものは3mm角パッケージのものもあります。（もともと、米粒マイコンことATtiny10が入手困難になって、その代替品を探していて、これを使うことを思いついたのでした）

ラインナップを整理すると、こんな感じです。ちなみにUSB機能が内蔵されているだけあって、内蔵オシレータの精度も±1.5%あります。
![table.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/4a4fee62-51ba-7e50-2dbd-3f8ad639310c.png)
現時点で、このマイコンが載ったボードが日本で入手しにくいのが玉に瑕ではあるのですが、例えばスイッチサイエンスで[CH551のボード](https://www.switch-science.com/catalog/6932/)の取り扱いがあります。AliExpressでは、もっといろいろなボードが販売されています。
今回は、NT鯖江で購入した[Ksylitoli](https://github.com/creeper0723/Ksylitoli)なども使いました。

# CH55xをArduinoIDEから使う

このCH55xのプログラム開発は、当初はKeilの有料コンパイラを使う方法などが紹介されていたのですが、さすが古い8051コアだけあって、[SDCC](https://sourceforge.net/projects/sdcc/files/latest/download?source=files)などのオープンソースなコンパイラもいろいろあります。

そして、ArduinoIDEに統合できる[chH55xduino](https://github.com/DeqingSun/ch55xduino)があります。これを使えば、ArduinoIDEでプログラム開発ができるので、ずっと取りかかりやすくなりそうです。
ただこのch55xduinoは、ちょっとクセがあったので、その情報をまとめておこうと思います。

## 準備

### ArduinoIDEの準備

まずはArduinoIDEに、ch55xduinoを組み込みます。他のボードを追加するときと同様に、以下の手順で進めます。

1. ArduinoIDEを起動し、ファイル→環境設定を開き、「追加のボードマネージャのURL」に以下を追加します。
https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json
2. ツール→ボード→ボードマネージャ、を開き、検索窓で"ch"と入力して出てくる"ch55xduino"を選んでインストール
3. ツール→ボードから、使うマイコン(CH551など)を選ぶ

ちなみにピン番号は、「CH55xのポート番号が10の位、ポート内の番号が1の位」になります。例えばP3.2は32番として扱います。


### ドライバのインストール

※(2023/2/20追記)最近のバージョンではこのドライバのインストールと差し替えは不要のようです。一応、記録として残しておきますが、イタリック表記になっているところは、スキップして大丈夫なはずです。

最初に1回だけ、ドライバを入れておく必要があります。ちょっと挙動がわかりにくいので、USBデバイスの接続状況を確認する[USB Tree Viewer](https://www.uwe-sieber.de/usbtreeview_e.html)などのツールを用意しておいたほうが安心だと思います。

続いて、ドライバを準備します。以前にWCHのマイコンを使ったことがあれば、WCH純正ドライバが入っているはずなのです。
_しかしそのドライバはch55xduinoでは使えず、別のドライバ(libusb-win32)に差し替える必要があります。そこで、まず[Zadig](https://zadig.akeo.ie/)というツールをダウンロードしておきます。zadig-2.7.exeをダブルクリックして起動し、つながっている全USBデバイスが表示されるようにOptionsの"List All Devices"にチェックを入れておきます。
![Zadig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/47ab3daa-bf0d-3456-e839-32fdf5a38294.png)_

### Bootloadモード(DFUモード)での設定

まずCH55xボードをBootloadモード(DFUモード)でUSB接続します。大半のボードには"Bootload"ボタンがあると思いますので、それを押したままUSBケーブルをつないで、少し待ってから離せばOKです。（USB D+と+3.3Vを10kΩの抵抗を介して接続すると、このモードになります）

この状態では、"USB Device"という名称のデバイスが一覧に出てくるはずです。（ちなみにこの状態でのVenderID/ProductIDは0x4348/0x55e0）
![bootload.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/0c602d40-402e-22a9-ff13-5cd6cbc4a210.png)

_ここで、Zadigのデバイス一覧から"USB Module"を選び、それで使うドライバ（緑の矢印の右側）に"libusb-win32"を選んで、"Reinstall Driver"ボタンを押して、使うドライバを差し替えます。_
![bootload_driver.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/158bda4f-8ffd-ab14-173c-2f77666620ce.png)

### まずは1回、ArduinoIDEからの書き込み

適当なプログラムを用意し（例えばスケッチ例→0.Basics→Blink）、ボードに付いているLEDのピン番号を、先程のルール(P3.2→32、など）に変更して、普通のArduinoと同じように書き込みます。こんな感じで、書き込みが完了し、動作が始まります。
![upload.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/b952952c-46c0-2609-dcd6-c1a9b18642c9.png)
ここで"no CH55x found"などと出る場合は、Bootloadモードになっているか、_ドライバをlibusb-win32に差し替えているか_、を確認しましょう。

書き込みが完了すると、USBデバイス名が"Deqing CH55xduino"に変わるはずです。（ちなみにVendorID/ProductIDは0x1209/0xc550）
![CH55xduino.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/f1b177be-9649-4686-6ffb-ee4005b12cc0.png)

_ここで、CH55xduinoのドライバを、Zadigでlibusb-win32またはCDCに差し替えておきます。_
![CH55xduino_driver.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/ad6e9d4d-f7f1-a7d9-e83d-22a784bae8df.png)


## 2回め以降の書き込み

AduinoIDEのCOMポートを、CH55xduinoのCOMポート番号に選んでおけば、2回目以降は、Bootloadモードにしなくても、そのまま書き込みができます。楽ちんでいいですね。ただしCH55xのフラッシュメモリは一応データシート記載の書き換え上限数が200回と比較的少ないので書き換えすぎには注意しましょう。

なおUSBでシリアル通信を行うCDCを使わない場合は、COMポートが現れませんので、書き換えはDFUモードに設定してから行います。


## シリアル通信

実はch55xduinoで使っているコンパイラのSDCCはC++のコンパイラではないので、いわゆる"polymorph"関数が使えません。これは、引数の型に応じて関数を選ぶというC++の仕様で、例えばArduinoのSerial.print()関数が該当します。Serial.print(int i);ならば数値、Serial.print(char *s);ならば文字列、のように、関数の実体が引数に応じて変わります。
SDCCではこれは使えないので、[ch55xduinoのREADME](https://github.com/DeqingSun/ch55xduino#no-polymorph-functions)にあるように、引数の型に応じて使う関数を変える必要があります。例えばint型の変数の値を表示するのであればUSBSerial_print_i(P) を使うわけです。
この点だけ気をつければ、シリアル通信で文字列の送受信ができますので、デバッグに便利そうですね。



## AppleSilicon(M1)Macでの書き込みツール

※この問題は現在のバージョン(v0.0.12)では解決されていますので、ここに記載の手順は不要です。

AppleSilicon(M1)のMacでは、書き込みツールが動作しません。そこでM1用にビルドした書き込みツール(vnproch551)を用意してありますので、これに差し替えて使ってください。（書き込み検証できました）
https://github.com/akita11/vnproch551

（ちなみに、この問題はGitHubでissueとしてあげて、解決策を教えてもらっていました→https://github.com/DeqingSun/ch55xduino/issues/61 ）

## さいごに・・・

びっくりするくらい安価で、ATtiny10のような極小サイズマイコンの置き換えにも十分ぐらいなスペックをもったCH55xマイコンですが、入手しやすいボードが少ないのが悩ましいところです。そこでいま、こちらの3種類のボードを設計して製造中です。機会をみて、委託販売などをできればと思います。

- CH552Xiao (マイコンはCH552P(QFN16)、SeeeduinoXiaoとフットプリントが同じ。ちなみにピン互換のCH554を使えばUSBホストにもなる）
- ProMicroCH552 (マイコンはCH552T(TSSOP20)、自作キーボードでよく使われるProMicroとフットプリントが同じ）
- CH558Pico (マイコンはCH558L(QFP48)、RaspberryPi Picoとフットプリントが同じ。ちなみにピン互換のCH559を使えばUSBホストにもなる）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/a28483c1-4618-449b-2e83-e2fdc2453f3a.png)