rpine lab Tech Blog

趣味のプログラミング(Web系・バックエンド)や自宅ラボ(Homelab)構築・マイコンを使った電子工作などを雑多に扱った技術ブログです。

CH32V003マイコンの汎用実験基板にUSBでプログラムを書き込む

CH32V003マイコンの汎用実験基板にUSBでプログラムを書き込む
目次

概要

前回の記事(📄Arrow icon of a page linkCH32V003マイコンの汎用実験基板を設計・実装する)で作ったCH32V003マイコンの汎用実験基板に、rv003usbのUSBブートローダーを書き込みます。これで、WCH-Linkを使わずにUSBケーブルだけで直接プログラムを書き込めるようになります。

この記事ではUSB回路、ブートローダーの設定と書き込み、オプションバイトの変更、リセットボタンでブートローダーに入るための処理を紹介します。

rv003usbとブートローダー

CH32V003マイコンにはUSBペリフェラルが内蔵されていませんが、ソフトウェアUSB実装であるrv003usbを使うとUSBが使えるようになります(上位機種のCH32V103やCH32V203だとUSBペリフェラルが載っています)。

今回はrv003usbを使ったUSBブートローダーで、USB経由でプログラムを書き込めるようにします。

USB回路

rv003usbのREADMEに書かれているとおりにUSB周りの回路を組みます。

USB周辺回路
USB周辺回路
マイコンへの接続
マイコンへの接続

ピン割り当て

D+ピンとD−ピンの割り当てに制限があるので注意が必要です。

この2ピンはPORTA・PORTC・PORTDいずれかの0~4番(つまり、P[A,C,D]0~4)の中から選ぶ必要があります。また、2ピンは同じポート(PORTAなど)にする必要があります。

今回の基板での割り当てはREADMEどおり(D+: PD3, D−: PD4)にしています。

D−プルアップ(DPU)の制御

USBの接続状態を制御するためにD−ピンに1.5 kΩの抵抗を入れて、その先をPD5ピンに繋いでいます。常に認識状態でいいのならVCC(+3.3 V)に直接プルアップすることでDPUピンを省略できます。

CC抵抗

ホストから5 V電源を得るためにCC1・CC2ピンを5.1 kΩ抵抗でGNDにプルダウンします。

ダンピング抵抗

ノイズの低減と保護のために33 Ωの抵抗をマイコン近くに挿入しています。

ブートローダーの準備

開発環境

  • OS:Windows 11
  • IDE(ブートローダービルド用):VSCode+PlatformIO拡張機能
  • IDE(ユーザープログラムビルド用):MounRiver Studio Ⅱ

rv003usbプロジェクトのクローン

rv003usbはch32funをサブモジュールとして含んでいるので、--recursiveを付けてクローンします。

git clone --recursive https://github.com/cnlohr/rv003usb.git

WCH-Linkドライバーの入れ替え

書き込みとオプションバイトの設定には、ch32funに同梱されているminichlink(ch32fun\minichlink\minichlink.exe)を使います。

minichlinkからWCH-Linkを使うには、ZadigでWCH-LinkのドライバーをWinUSBに入れ替える必要があります。

  1. Zadigを起動し、「Options」→「List All Devices」をオンにする
    Image in a image block
  2. リストから「WCH-Link (Interface 0)」を選ぶ(Interface 0と1のうち、元のドライバーがwinserではなくWCHLink_A64になっている方)
    Image in a image block
  3. 「WinUSB」を選んで「Replace Driver」を押す
⚠️
WinUSBドライバーに入れ替えると、そのWCH-LinkはMounRiver Studio Ⅱから使えなくなります。

デバイスマネージャーでドライバーを更新することで元に戻せます。

ブートローダーの設定

ブートローダーは初期設定のままだと、電源を入れてから約5秒間動いたあとユーザープログラムを起動します。今回は、ユーザーボタン(PD2)を押しながら電源を入れたときだけブートローダーに入るよう、bootloader/bootloader.cの#defineを次のように変えます。

#define DISABLE_BOOTLOAD

#define BOOTLOADER_BTN_PORT D
#define BOOTLOADER_BTN_PIN 2
#define BOOTLOADER_BTN_TRIG_LEVEL 0 // 1 = HIGH; 0 = LOW
//#define BOOTLOADER_BTN_PULL 1 // 1 = Pull-Up; 0 = Pull-Down; Optional, comment out for floating input

#define BOOTLOADER_TIMEOUT_PWR 0

//#define BOOTLOADER_TIMEOUT_USB 0
bootloader/bootloader.cの書き換え箇所

この基板のボタンは押すとLowになり、外付けのプルアップ抵抗があるので内部プルアップは使いません。待ち時間とUSBホストの検出は無効にします。

USBのピン設定(bootloader/usb_config.h)は初期設定がこの基板と同じなので、変更しません。

ビルドとWCH-Linkでの書き込み

rv003usbのフォルダーをVSCodeで開き、PlatformIOの環境の切り替え(ツールバー)でenv:bootloaderを選んでビルドします。できた.pio\build\bootloader\firmware.binを、WCH-Linkでブートローダー用の領域に書き込みます。

ch32fun\minichlink\minichlink.exe -w .pio\build\bootloader\firmware.bin bootloader -B

オプションバイトの設定

電源投入時にブートローダーから起動させるにはオプションバイトも書き込みます。このとき、リセットピン(NRST、PD7)の扱いに注意が必要です。

rv003usbのbootloader/Makefileでコメントアウトされていない有効なコマンドの設定値(+a55aff00)は、NRSTを無効にします。この基板はPD7にリセットボタンを繋いでいるので、+a55aef10(NRST有効・電源投入時ブートローダー起動)を書き込むのが正しいです。

ch32fun\minichlink\minichlink.exe -w +a55aef10 option
オプションバイトの書き込み

USB経由でのプログラム書き込み

ブートローダーへの入り方

ユーザーボタン(PD2)を押しながらUSBケーブルを繋いで電源を入れます。PCにはHIDデバイス(VID:0x1209, PID:0xb003)として認識されます。

汎用基板にUSBを挿している様子
汎用基板にUSBを挿している様子

書き込むプログラムの作成

ブートローダーは通常のプログラムを書き込むフラッシュ領域とは完全に別の専用の領域に書き込まれています。そのため、ユーザープログラム側での特別なリンカスクリプトの設定変更(先頭アドレスのオフセット調整)などは必要ありません。

リセットボタンでブートローダーに入るための処理

オプションバイトの設定値が使われるのは電源投入時だけで、ユーザーボタンを押したままリセットボタンを押して離しても、そのままではブートローダーに入りません。

次のシステムリセットでどちらから起動するかは、FLASH->STATRのFLASH_STATR_MODEビット(1:ブートローダー)で決まります。ただし実際に試すと、リセットボタン(NRST)でリセットした直後はFLASH_STATR_MODEが1でもユーザープログラムが起動しました(FLASH_STATR_MODEはNRSTによるリセットでは消えません)。

そこで、ユーザープログラムのmain関数の先頭に次の処理を入れます。SystemReset_StartModeは、WCHの標準ライブラリ(ch32v00x_flash.c)の関数です。

int main (void) {
    if (FLASH->STATR & FLASH_STATR_MODE) {
        NVIC_SystemReset();
    }
    SystemReset_StartMode(Start_Mode_BOOT);

    // 以降は通常の処理
}
  1. 電源投入時はオプションバイトの設定に従いブートローダーが起動する
  2. ブートローダーはFLASH_STATR_MODEを0にしてユーザープログラムを起動するため、最初のif文はスキップされる
  3. SystemReset_StartModeでFLASH_STATR_MODEを1にする
  4. リセットボタンで再起動するとユーザープログラムが実行されるが、FLASH_STATR_MODEが1なのでif文のNVIC_SystemReset()でソフトウェアリセットされてブートローダーが起動する
  5. ブートローダーは、ユーザーボタンが押されていればそのままとどまり、押されていなければユーザープログラムを起動する

書き込み

ブートローダーに入った状態で、MounRiver Studio Ⅱでビルドしたファイル(objフォルダー内の.bin)をUSB経由で書き込みます。

.\ch32fun\minichlink\minichlink.exe -C b003boot -w [プロジェクトのフォルダー]\obj\ch32v003-bo-brd.bin flash -b

-C b003bootで書き込みにrv003usbのブートローダーを使うように指定します。省略すると、WCH-Linkが接続されている場合はそちらが優先されます。

動作確認

前回の記事(📄Arrow icon of a page linkCH32V003マイコンの汎用実験基板を設計・実装する)で使ったプログラム(一部改変)をUSB経由で書き込んだところ、Lチカプログラムを走らせることができました。

static uint8_t cnt = 0;

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

    RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOD, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init (GPIOD, &GPIO_InitStructure);  // UserLED
}

int main (void) {
    if (FLASH->STATR & FLASH_STATR_MODE) {
        NVIC_SystemReset();
    }
    SystemReset_StartMode(Start_Mode_BOOT);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    SystemCoreClockUpdate();
    Delay_Init();

    UserPins_Init();

    while (1) {
        if (cnt & 0x1) {
            GPIO_SetBits (GPIOD, GPIO_Pin_0);
        } else {
            GPIO_ResetBits (GPIOD, GPIO_Pin_0);
        }

        cnt++;
        Delay_Ms(200);
    }
}
Lチカ動作確認プログラム

まとめ

USBブートローダーをCH32V003マイコンに書き込んで、USB経由でのプログラム書き込みができるようにしました。最初にWCH-Linkでブートローダーとオプションバイトを書き込んでおけば、あとはUSBケーブルだけでプログラムを書き換えられます。

この記事が役に立ったら是非ご支援をお願いします!

支援する

※Squareの決済ページに移動します