CH32VのオレオレArduino環境を作ろう その2 ボードマネージャーの基礎知識

概要

前回は環境だけとりあえず立ち上げましたが、ボードマネージャーで管理するために必要な項目を確認していきたいと思います。

ボードマネージャーのURL

上記のファイルになります。jsonファイルで定義されています。

正式な資料は上記になると思います。

{
    "packages": [
        {
            "name": "ch32-riscv-noneos",
            "platforms": [
            ],
            "tools": [
            ]
        }
    ]
}

ざっくりとした構造としてpackagesの中に全体のnameなどの設定と、コードなどが入っているplatformsと、ビルドに必要なtoolsが定義されています。

platformsはバージョンにより複数定義が存在しており、一番上が一番新しいバージョンを書いている場合が多いです。toolsもバージョンを複数指定することもできますが、通常は最新バージョンのみ入れておく場合が多いです。

            "platforms": [
                {
                    "name": "CH32 RISC-V noneOS",
                    "architecture": "ch32riscv",
                    "version": "1.1",
                    "category": "Contributed",
                    "url": "https://github.com/ch32-riscv-ug/arduino_core_ch32_riscv_noneos/releases/download/1.1/arduino_core_ch32_riscv_noneos.1.1.zip",
                    "archiveFileName": "arduino_core_ch32_riscv_noneos.1.1.zip",
                    "checksum": "SHA-256:a83929c3a74aa6e9e3a521ec051c04604b85b8f083badfd985e40e62ed30aac4",
                    "size": 1145553,
                    "boards": [
                        {
                            "name": "CH32L103"
                        },
                        {
                            "name": "CH32X035"
                        },
                        {
                            "name": "CH32V30x"
                        },
                        {
                            "name": "CH32V20x"
                        },
                        {
                            "name": "CH32V103"
                        },
                        {
                            "name": "CH32V003"
                        }
                    ],
                    "toolsDependencies": [
                        {
                            "packager": "ch32-riscv-noneos",
                            "name": "riscv-none-embed-gcc",
                            "version": "1.91"
                        },
                        {
                            "packager": "ch32-riscv-noneos",
                            "name": "openocd",
                            "version": "1.91"
                        },
                        {
                            "packager": "ch32-riscv-noneos",
                            "name": "beforeinstall",
                            "version": "1.91"
                        }
                    ]
                },

platformsは上記の構造になっており、ダウンロードするファイルのURLとサイズ、チェックサムなどがはいっています。boardsはあまり重要ではなく、インストール時の目安となるボード一覧になります。toolsDependenciesが重要でriscv-none-embed-gccとopenocd、beforeinstallを指定しています。

ここではWindowsなどのHostに関する設定はありません。

            "tools": [
                {
                    "name": "riscv-none-embed-gcc",
                    "version": "1.91",
                    "systems": [
                        {
                            "host": "i686-mingw32",
                            "url": "https://github.com/ch32-riscv-ug/MounRiver_Studio_Community_miror/releases/download/1.91-toolchain/riscv-none-embed-gcc-8-win-1.91.zip",
                            "archiveFileName": "riscv-none-embed-gcc-8-win-1.91.zip",
                            "checksum": "SHA-256:b3d6b85a54d85819e0a6c999ccfaff85238858133d900e4de0b10cf4c63935af",
                            "size": "245111177"
                        },
                        {
                            "host": "x86_64-linux-gnu",
                            "url": "https://github.com/ch32-riscv-ug/MounRiver_Studio_Community_miror/releases/download/1.91-toolchain/riscv-none-embed-gcc-8-linux-1.91.zip",
                            "archiveFileName": "riscv-none-embed-gcc-8-linux-1.91.zip",
                            "checksum": "SHA-256:45e53264c7f2e27de8876b8e500da2a95e5976efe7d0c1d51ef3bc7c03293ca7",
                            "size": "253087380"
                        },
                        {
                            "host": "x86_64-apple-darwin",
                            "url": "https://github.com/ch32-riscv-ug/MounRiver_Studio_Community_miror/releases/download/1.91-toolchain/riscv-none-embed-gcc-8-mac-1.91.zip",
                            "archiveFileName": "riscv-none-embed-gcc-8-mac-1.91.zip",
                            "checksum": "SHA-256:f274b8afe5307f38541548b8534946d3cdffeaeec33d5c599f461a4021aa60d3",
                            "size": "165175099"
                        }
                    ]
                },

こちらがtoolsのriscv-none-embed-gccの部分です。こちらにhost別で3種類のツールが定義されています。

OS flavourhost regexp valuehost suggested value
Linux 32i[3456]86-.*linux-gnui686-linux-gnu
Linux 64x86_64-.*linux-gnux86_64-linux-gnu
Linux Armarm.*-linux-gnueabihfarm-linux-gnueabihf
Linux Arm64(aarch64|arm64)-linux-gnuaarch64-linux-gnu
Windows 32i[3456]86-.*(mingw32|cygwin)i686-mingw32 or i686-cygwin
Windows 64(amd64|x86_64)-.*(mingw32|cygwin)x86_64-migw32 or x86_64-cygwin
MacOSX 32i[3456]86-apple-darwin.*i686-apple-darwin
MacOSX 64x86_64-apple-darwin.*x86_64-apple-darwin
MacOSX Arm64arm64-apple-darwin.*arm64-apple-darwin
FreeBSD 32i?[3456]86-freebsd[0-9]*i686-freebsd
FreeBSD 64amd64-freebsd[0-9]*amd64-freebsd
FreeBSD Armarm.-freebsd[0-9]arm-freebsd

対応しているHostは上記のようです。今回はi686-mingw32でWindows 32、x86_64-linux-gnuでLinux 64、x86_64-apple-darwinでMacOSX 64が指定されていますね。MacがIntel版になっているのでArm版に変更したほうが良さそうです。ツールを見た限りIntelとArmの両対応な気がしますが、Macは動作確認が取れないのでちょっと後回しです。

                {
                    "name": "beforeinstall",
                    "version": "1.91",
                    "systems": [
                        {
                            "host": "i686-mingw32",
                            "url": "https://github.com/ch32-riscv-ug/MounRiver_Studio_Community_miror/releases/download/1.91-toolchain/beforeinstall-win-1.91.zip",
                            "archiveFileName": "beforeinstall-win-1.91.zip",
                            "checksum": "SHA-256:d3a5bcc9823a0d431b5881aa988b12a2aa7af3a9d2c613459ae3765b00682251",
                            "size": "284"
                        },
                        {
                            "host": "x86_64-linux-gnu",
                            "url": "https://github.com/ch32-riscv-ug/MounRiver_Studio_Community_miror/releases/download/1.91-toolchain/beforeinstall-linux-1.91.zip",
                            "archiveFileName": "beforeinstall-linux-1.91.zip",
                            "checksum": "SHA-256:12258d52dc8e715a8be5c038621417bdd020bd68ef00298eb2daa4af4f0ddb73",
                            "size": "1300776"
                        },
                        {
                            "host": "x86_64-apple-darwin",
                            "url": "https://github.com/ch32-riscv-ug/MounRiver_Studio_Community_miror/releases/download/1.91-toolchain/beforeinstall-mac-1.91.zip",
                            "archiveFileName": "beforeinstall-mac-1.91.zip",
                            "checksum": "SHA-256:2bdb487bcf97622c50321f69f44445bf1ec18831b9a6678e9187071f9fcdc910",
                            "size": "284"
                        }
                    ]
                }

気をつけないといけないのはbeforeinstallです。こちらはLinuxのみで必要なファイル群なのですが他のHostでも必ず指定する必要があります。そのためサイズを見てみるとわかるのですが284バイトと小さい空に近いファイルを読み込ませています。

openwchがWindowsにもLinuxのファイルが指定してあって、シンボリックリンクをはろうとしてエラーになっていたりしています。

platform.txt

上記のファイルが一番重要なファイルになります。コンパイラやリンカに対するパラメータを設定しており、かなり設定が面倒なファイルです。

上記に説明がありますが、似たplatform.txtをベースに書いていく方が楽だと思います。今回はopenwchのファイルをベースにしましたが、MounRiverでビルドしたときの設定と極力同じになるようにパラメータを結構触っています。特に追加されていたけれど利用していないdefine宣言などはすべて取り外しました。

ビルドツールのバージョンは「tools.WCH_linkE.path={runtime.tools.openocd-1.0.0.path}/bin/」のように指定することができますが、指定するのはおすすめできません。バージョンが上がったときに変更し忘れるんですよね。そしてバージョン指定をしてそのバージョンが自分のtoolsの中にない場合には他のボードマネージャーから探しに行きます。そこでバージョン違いのものを使ったりしておかしなことになるので無指定が安全だと思います。「tools.WCH_linkE.path={runtime.tools.openocd.path}/bin/」と指定することで自分のtoolsにあるopenocdを探してくれます。

toolsが他のボードと共有しているのがちょっと気持ちの悪い感じでした。ESP32などでも指定の仕方がおかしくて、他のボードマネージャーのtoolsを実行してしまい、esptoolのバージョンが古いと新しいボードに対応していないなどの問題が起こったと思います。

boards.txt

上記に実際の開発ボードの設定を行います。ここが悩みのタネでして、どこまで細かくボード定義をするかは難しいところです。

たとえばCH32X035だと上記の7パッケージがあります。使えるGPIOなどが違いますがFlashとSRAMの容量は同じです。そして一番下にはCH32X033と違う型番もあります。

CH32V103だと4パッケージしかありませんが、FlashとSRAMの容量が違うものが混じっています。

メインのボードはEVT単位にした

いろいろな考え方がありますが、私はwchから提供されているSDK相当のEVT単位に分けることにしました。

openwchch32-riscv-noneos
CH32V00xCH32V003
CH32X035CH32V103
CH32V10xCH32V20x
CH32V20xCH32V307
CH32V30xCH32X035
CH32L103

現状上記の差があります。CH32L103は新規追加なのですが、名称にも差がありますがch32-riscv-noneosではEVTのファイル名に合わせてあります。なぜかCH32V20XのみXになっていました。

openwchだと上記のようにCH32V20xの中に実際のパッケージ違いがあります。ただ全部ではないですし、実際型番みても差がよくわかりません。

そこでch32-riscv-noneosはFlashとSRAMのみ指定するようにしました。デフォルト値はチップの仕様書にのっている値にしています。すべてのパッケージを列挙したメニューも作ってみたのですがどうも多くなりすぎてよくわからないのでこんなかんじにまずはしてみました。パッケージ違うにすると実際には利用できないPINなどもコンパイルエラーにすることが可能ですが、そこまでやるとかなり面倒なのでピンは自己責任で利用する方針にしました。

またboards.txtだけはArduino15フォルダにある実ファイルを編集しても反映されないバグが数年前からあり、治る気配がありません。おそらく2系のArduino IDEは再読込しない仕様だと思います。platform.txtは直接ファイルを編集してArduino IDEを再起動することで最新のを読み込むのですがboards.txtはキャッシュされており、更新されません。

  • C:\Users\%USERNAME%\AppData\Roaming\arduino-ide\Local Storage\leveldb

Windowsだと上記のフォルダを消して再起動することで再読込をするのですが、言語設定もクリアされて英語にもどってしまいます。英語のままクリアして編集を繰り返すか、パッケージごと消してから再インストールすることでリロードされます。

フォルダ構造

こちらも結構重要です。

  • packages\WCH\hardware\ch32v\1.0.4\cores\arduino

一般的には上記のような構造になっています。

共通ベンダー共通メンテナーバージョン共通アーキテクチャ
packagesWCHhardwarech32v1.0.4coresarduino
packagesesp32hardwareesp322.0.16coresesp32
packagesm5stackhardwareesp322.1.1coresesp32
packagesarduinohardwareavr1.8.6coresarduino
packagesarduinohardwarerenesas_uno1.1.0coresarduino

分解すると上記の構造になります。WCHがハードウエアを作っているベンダーで、ch32vがメンテナンスをしている人、arduinoがアーキテクチャです。

ESP32だと複数のアーキテクチャがあるのですが、すべてesp32でビルドのときに読み込む場所を変えてESP32やESP32-S3などを切り替えています。

arduinoだとメンテナーがavrとrenesas_unoの2種類あります。これはボードマネージャーが違うので別パッケージになっている影響だと思います。

共通ベンダー共通メンテナーバージョン共通アーキテクチャ
packagesch32-riscv-noneoshardwarech32riscv1.1coresCH32L103
CH32V003
CH32V006
CH32V20x
CH32V103
CH32V307
CH32X035

今回は上記のような構成にしてみました。アーキテクチャはboards.txtでボード別に指定できます。今回はEVT別に「CH32V003_EVT.build.core=CH32V003」のようにcoreを変更して切り替えています。

coreを切り替えるメリットはソースコードのディレクトリが分離できるからです。Arduinoの場合にはcores、libraries、variantsの3種類のディレクトリからソースコードを探して自動的にコンパイルとリンクをしてしまいます。

librariesは全部共通のコードを入れるところで、coresとvariantsはボードや環境単位でディレクトリが分離されています。ただしvariantsはピン配置などを定義するところであまり大きなコードを入れるのは適していないはずです。

#ifdef CH32V00x
#include "ch32v00x_gpio.c"
#endif

#ifdef CH32X035
#include "ch32x035_gpio.c"
#endif

#ifdef CH32V10x
#include "ch32v10x_gpio.c"
#endif

#ifdef CH32V20x
#include "ch32v20x_gpio.c"
#endif

#if defined(CH32V30x) || defined(CH32V30x_C)
#include "ch32v30x_gpio.c"
#endif

openwchはsystemという、管理外のフォルダの中にEVTのcore別コードを入れて、cores配下には上記のようにincludeで実ファイルを読み込む方式になっています。ただ上記のようなファイルが60個以上あり、coreによって対応しているファイルが違うのでかなり乱雑な管理になっています。

今回はアーキテクチャ別にcoresを分離したことによってEVTに相当する部分をそのまま入れて動かすことが可能になりました。

ちなみにESP32の場合にはcore別の処理はinclude pathで読み込むヘッダファイルを切り替えるのと、ビルド済みのライブラリを使って、最後のリンク時に切り替えていますのでソースコードは全coreで共通のものになります。

実際の開発方法

開発環境

localhostでもよいので、http経由でファイルダウンロードできる環境が必要になります。私は自宅に非公開のhttpsでアクセスできるサーバーがあるので、そこを利用しました。普通のレンタルサーバーなどでも構わないと思いますが、シェル上でzipなどのコマンド実行できるサーバーが好ましいです。

ch32_riscv_noneosの場合には上記のスクリプトから公開用ファイル一式を生成しています。EVT/getEVT.shを使ってEVTを別途ダウンロードして展開しておいてから、update.phpを動かすと以下の手順でファイルを生成しています。

  1. 生成物を入れるフォルダを削除してから新規作成する
  2. EVTから必要なファイルをコピーしてくる
  3. copyフォルダから必要なファイルを上書き転送する
  4. .patchファイルがあればpatchを適応する
  5. ZIPで保存する
  6. 保存したZIPのファイルサイズとチェックサムでjsonを更新する

今回はEVTそのまま動かすため、なるべくオリジナルのファイルを自動的にArduino IDE向けのファイル構成に再配置しています。ただそのままだとビルドが通らなかったり警告がでるファイルがあるのでpatchを当てています。

そして6が重要なのですがjsonファイルを検索してから、最初のplatformsのファイルサイズとチェックサムを更新しています。複数のjsonファイルを検索するようにしているので本番用のpackage_ch32-riscv-noneos.jsonと、開発環境用のpackage_ch32-riscv-noneos-dev.jsonを準備しておき、開発環境用のファイルはGitHubにはコミットしない運用にしています。

このファイルサイズとチェックサム更新はかなり面倒なので自動化しておくことをおすすめします。

RMDIR /S /Q C:\Users\%USERNAME%\AppData\Local\Temp\arduino

あと重要なのは上記のビルドキャッシュなどが保存されているフォルダを定期的に消すことです。ここにキャッシュが残っているとplatformsのファイルを更新してもリビルドされない場合があります。

RMDIR /S /Q C:\Users\%USERNAME%\AppData\Local\Arduino15\packages\ch32-riscv-noneos-dev
RMDIR /S /Q C:\Users\%USERNAME%\AppData\Local\Arduino15\packages\ch32-riscv-arduino-dev
RMDIR /S /Q C:\Users\%USERNAME%\AppData\Local\Temp\arduino
DEL /Q C:\Users\%USERNAME%\AppData\Local\Arduino15\*-dev.json

"C:\Users\%USERNAME%\AppData\Local\Programs\Arduino IDE\Arduino IDE.exe"

実際には上記のようなバッチファイルを準備して、パッケージごと全部消しています。重要なのはjsonファイルも消しておかないと新しいファイルを再ダウンロードしないので反映されません。最後にArduino IDEを起動していると裏側で流れているログを確認したり、バッチファイルを終了すると一緒にArduino IDEも落ちたりして便利でした。

また、パッケージを消して再起動すると前回選択されているボードがない場合には自動的に対象となるボードをダウンロードするかを聞かれるのでboards.txtの編集確認などはこちらの方法を取っていました。

まとめ

Arduino IDEの場合にはソースコードの検索対象を選ぶことができませんので、最初のフォルダ構成を色々試しながら作り込むのがよいと思います。coresとlibrariesの使い分けや、どこまでvariantsで細かい設定をいれるかなどが後々後戻りができなくなってくると思います。

単独ボードであればシンプルにできるとは思いますが、その後に拡張性などを考えて最初にグランドデザインをしたほうがよいでしょう。とはいえ、いろいろ想定外のことが発覚するので今作っている構成も今後変わるかもしれません。

コメント