English / 日本語

Gregory J. Durnan, PhD, CEng, FIMarEST

はじめての CH32V003F4P6 と WCH-LinkE
San Diego, CA, USA · お問い合わせ · durnan.org

ベンダー製IDE不要、16キロバイトのRISC-Vチップ

CH32V003F4P6-R0-1v1 board, CH32V003C eval board, WCH-LinkE probe and spare dice

CH32V003はWCHのエントリークラスRISC-Vマイコンで、RV32EC命令セットで動くQingKe V2Aコア、16 KBのフラッシュ、2 KBのSRAMを搭載し、価格はこのサイトで既に紹介している定番の8051ボードよりも安いくらいです。STC89C52RCのような内蔵UARTブートローダは持っておらず、代わりにプログラミングとデバッグはどちらもWCH-LinkEという小さなUSBプローブ経由で行い、1本のデバッグ線でチップと通信します。

WCHがこのチップ向けに提供しているものはすべて、自社製のEclipseベースIDEであるMounRiver Studioの利用を前提としています。このページでは別の道を用意します。STC89C52RC + SDCC + Geanyのページで既に使っているのと同じ、専用IDEを使わないミニマルなワークフローです。すなわち、単体で動くGNU RISC-Vクロスコンパイラ、Makefileまたはバッチファイル、独立した2つ目のGeanyプロファイル、そして手作業で残る唯一のステップとしてWCH自身の小さな書き込みGUIを使います。

キットの中身と、見当たらないDIPソケットの謎

AVRや8051用のプログラマを使ったことがあれば、プログラマを直接差し込むZIFソケットやDIPヘッダがあるものと自然に思うかもしれません。しかしCH32V003のボードにはそのようなソケットはなく、そもそも必要ありません。 WCH自身の評価ボードマニュアルにもはっきりと書かれています。デバッグインターフェースは「ダウンロード、シミュレーションデバッグ、シングルワイヤ通信のためのものであり、SWDIOをPD1に接続するだけでよい」と。

QingKe V2Aコアが使うのは独自のシングルワイヤ・デバッグインターフェースであり、STM32系でおなじみの2線式ARM SWDプロトコルではありません。PD1という1本の信号線だけで、プログラミングとデバッグの通信をすべてまかないます。これに電源とグランドを加えれば、WCH-LinkEとボード間の接続は、ボードにすでに用意されているヘッダピンに挿す普通のジャンパ線3本だけで完成します。専用ソケットもアダプタも特別なコネクタの購入も不要です。

WCH-LinkE 側ピンボード側ピン(ヘッダ P1)用途
3V3VCC電源。両方の電源レールの電圧が一致していると確認できていない限り、USB給電と同時に行わないこと。
GNDGND共通グランド。
SWDIO / RMSPD1シングルワイヤ・デバッグ/プログラミング(SWIO)。
SWCLK / TCK接続不要未使用 — CH32V003はシングルワイヤ方式のみ。
先に知っておくべきこと: F4P6-R0-1v1ボードでは、デフォルトで水晶振動子用のパッド(R4、R5、Y1)には部品が実装されていません。以下のサンプルコードはデフォルトで48 MHzのHSE-PLLクロックを使う設定になっていますが、水晶が実装されていない場合でもWCH自身のクロック設定コードが安全に24 MHzの内蔵発振器へフォールバックするため、ボードが止まってしまうことはありません。デバッグ用UART経由で報告されるクロック値が異なるだけで済みます。

「GCC」に関する補足 — なぜもう1つ別のGCCが必要なのか

GCCのマニュアルには、対応している他のあらゆるアーキテクチャと並んでRISC-V向けのオプション(-march、-mabiなど)が記載されているため、すでに手元にあるgcc.exeにそれらのフラグを渡すだけで良いように思えるかもしれません。しかし、それはできません。GCCのバイナリは、それぞれがただ1つのターゲット向けにビルドされているからです。多くの人がgfortranなどに使っているWindows向けGNUツールチェーンはx86_64-w64-mingw32をターゲットにビルドされており、生成されるのはネイティブのWindows実行ファイルです。そこにはRISC-V用のコード生成機能はそもそも含まれていません。

必要なのは、もう1つ別のGCCビルドです。コンパイラのファミリーは同じでも、--targetがまったく異なり、riscv-none-elf-gcc.exe、riscv-none-elf-objcopy.exeのように、それぞれ固有のプレフィックスの付いたバイナリとして配布されています。ファイル名にプレフィックスが付いているため、同じPATH上にあっても普通のgcc.exeやgfortran.exeと衝突することはありません。この構成ではさらに一歩進めて、PATHそのものを使わないようにしています。以下のMakefileとバッチファイルでは、RISC-Vツールチェーンの場所を明示的な変数として指定するため、既存のGNU Toolsのインストール環境には一切手を加えません。

おすすめの配布版は、無料でスタンドアロンのxPack GNU RISC-V Embedded GCC(riscv-none-elf-gcc)です。zipを展開して、そのbinフォルダのパスを控えておけば準備完了です。

WCH-LinkUtility による書き込み

WCH-LinkUtility configured for CH32V003 in RISC-V mode

コマンドライン用の書き込みツールがビルドに組み込まれるまでの間は、WCH-LinkUtilityの小さなGUIで書き込みを行います:

  1. WCH-LinkUtility.exeを起動し、Core: RISC-V、Series: CH32V003、Addr: 0x8000000を設定する。
  2. Erase All、Program、Verify、Reset and Runはすべてチェックしたままにする(標準的な「書き込んですぐ実行」の組み合わせ)。
  3. Target Fileで、下記のビルドで生成される.hexファイルを指定する。
  4. 上表の通りにWCH-LinkEを配線してUSBに接続し、ステータス行にConnected RISC-V mode WCH-Link Cnt:1と表示されることを確認する。
  5. 一連の操作を実行し、Result CollectにSucceed:1 | Total:1と表示されるのを確認する。

ツールチェーン構成

STCの場合と同様、構成要素は3つです:

ツールチェーンのフラグと、それぞれが必要な理由

CH32V003がRV32ECであるという情報だけでは、GCCに渡す設定としては不十分です:

このMakefileとフラグの組み合わせは、単にドキュメントを元に書いただけでなく、実際に最初から最後まで動作確認済みです。xPackのriscv-none-elf-gcc 14.2.0でエラーなくコンパイル・リンクでき、ターゲットの16 KB/2 KBという容量制限にも十分な余裕を残して収まる、実際に動作するイメージが生成されました。

+-------------------------+
| Write main.c (GPIO,     |
| pulled from WCH's own   |
| GPIO_Toggle example)    |
+-------------------------+
           |
           v
+-------------------------+
| riscv-none-elf-gcc      |
| -march=rv32ec_zicsr_    |
|   zifencei -mabi=ilp32e |
| --specs=nano.specs      |
| -> .elf -> .hex          |
+-------------------------+
           |
           v
+-------------------------+
| WCH-LinkUtility:        |
| Erase All / Program /   |
| Verify / Reset and Run  |
+-------------------------+
           |
           v
+-------------------------+
| PD0 toggles every       |
| 250 ms                  |
+-------------------------+

サンプルコード:GPIO点滅(Blink)

void GPIO_Toggle_INIT(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
}

int main(void)
{
    u8 i = 0;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    SystemCoreClockUpdate();
    Delay_Init();
    USART_Printf_Init(115200);
    GPIO_Toggle_INIT();

    while(1)
    {
        Delay_Ms(250);
        GPIO_WriteBit(GPIOD, GPIO_Pin_0, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));
    }
}

CH32V003EVT.ZIP\EVT\EXAM\GPIO\GPIO_Toggleからそのまま持ってきたものです。WCHのパッケージに含まれる423個のサンプルソースファイルすべてを確認したところ、無関係な2つのSPIサンプルにわずかな非英語の句読点が紛れ込んでいた(修正済み)以外は特に問題は見つかりませんでした。このサンプルにはそうした問題もありません。WCH自身のサンプルソースはもともと英語で書かれており、ここで実際に行った作業は、それを取り巻く独自のスタンドアロン・コマンドラインビルドシステムを構築することでした。

Geany のビルドコマンド設定

STCのワークフローと同様、Geanyはビルドコマンドをシェルを介さず直接呼び出すため、バッチファイルの実行には同じくcmd /cプレフィックスが必要です:

任意設定:printf出力を見る(UARTデバッグ)

サンプルコード内のprintf呼び出しはUSART1(PD5 TX、115200 8N1)経由で出力され、実際に見るにはUSB-シリアル変換アダプタが必要です(点滅そのものはアダプタの有無に関係なく動作します)。おすすめの部品は正規のFTDI FT232RLで、CH340系のモジュールは避けます。理由は、このサイトで既に紹介しているSTC89C52RCボードのCH340用VSPドライバのときと同じです:

これはこのチップに限った選択ではなく、このサイトのガイド全体を通じた一貫した方針です。

詳細な解説の入手

完全版ガイドでは、xPack GCCのインストール、注釈付きの完全なMakefileとbuild_ch32v003.bat、Geanyのビルドコマンドの正確な設定、スクリーンショット付きのWCH-LinkUtility操作手順、そしてこのツールチェーンの組み合わせを初めて使ったときに実際に発生するビルドエラー(zicsr/zifencei不足、フル版newlibによるフラッシュ容量オーバーなど)をもとにしたトラブルシューティングを扱っています。

この先の展開

このページでは意図的に「書き込みはGUIツール、ビルドはコマンドライン」という段階で止めています。自然な次のステップは、STC89C52RCのページでSTC-ISPをスクラッチから書いたCフラッシャーに置き換えたのと同様に、WCH-LinkE用のコマンドライン書き込みツールを用意し、make flashをmake allと同じくらい実用的なターゲットにすることです。WCH-LinkUtility自体のプロトコルは公開文書化されていませんが、コミュニティのプロジェクト(特にオープンソースのch32v003funプロジェクトに含まれるminichlink)がすでにこれをリバースエンジニアリングしてオープンソース化しており、この最後のループを閉じる価値が出てきたときの論理的な次の一手となります。