ch32funでCH32V003を使ってみた
WCH社のマイコンCH32を使うようになったが,以前はarduinoのWCH CH32Vサポートを使った. しかし,コンパイルしたときのサイズが大きくなるらしく,フラッシュの小さなマイコンで,複雑なプログラムをする場合には,適切ではないようだ. また,対応していない機能などもあるそうである. そこで,ch32funを試してみることにした. ch32funはもともとはch32v003用に開発されたようだが,他のマイコンにも徐々に対応して来ているが, フラッシュの小さなch32v003には特に有用だろう.
まずはインストールであるが,debianでは思ったよりも簡単だった. 必要なパッケージを以下のようにしてインストールする.
sudo apt-get install build-essential libnewlib-dev gcc-riscv64-unknown-elf libusb-1.0-0-dev libudev-dev
そして,ch32funのサイトからzipをdownloadする. コマンドラインでやりたいときは,下のようにする.
wget -O ch32fun-master.zip https://github.com/cnlohr/ch32fun/archive/refs/heads/master.zip
そして,それを展開したらインストールは完了である. 書き込みソフトであるminichlinkを使えるようにするためには,権限の問題を解決するために,以下を実行する.
sudo cp minichlink/99-minichlink.rules /etc/udev/rules.d/ sudo udevadm control --reload sudo udevadm trigger
うまくインストール出来たかを確かめるために,examplesには,ch32v003用のプログラムの例があるので,そのどれかのフォルダに行って,コンパイルを試してみると良い. make buildとすると,コンパイルされて,やり直すときには,make cleanとしてから再度実行すれば良い. 単にmakeとすると,minichlinkを使ってマイコンへの書き込みまでやってくれる. 実行する前に,WCH-Link Eなどで接続しておけば良い.
新たなプログラムを作るときには,exampleの中のtemplateをコピーして使うと良い. Makefileでは,TARGETをc言語のファイル名として,includeはch32fun.mkのファイルの場所を指定する. プログラム中では,以下の順で実行する. まずは,初期化としてSystemInit();を実行する. 次に,使う機能を有効化する. 例えば,GPIOをすべて有効にするには,funGpioInitAll();とし,PDだけを使うならfunGpioInitD();とする. そして,やりたいことを記述する. 入力モードにして読み取って,出力モードにして出力するのは,以下のような感じ.
uint8_t v; funPinMode( PD0, GPIO_CFGLR_IN_FLOAT ); v=funDigitalRead(PD0); funPinMode( PD0, GPIO_CFGLR_OUT_10Mhz_PP ); funDigitalWrite( PD0, FUN_HIGH ); funDigitalWrite( PD0, FUN_LOW );
入力はアナログ(ANALOG),pull-up pull-down(PUPD),高インピーダンス(FLOAT)が選べる. 出力は周波数として2Mhz,10Mhz,50Mhzが,モードとしてpush-pull(PP)とopen drain(OD)が選べる. レジスタなどをあまり意識しないで,arduinoのように書くことが出来るようになって来ている.
PD1とPD7はそれぞれSWIOとNRSTに割り当てられているので,そのままではGPIOとしては使えないので,注意が必要である. PD7を使えるようにするには,flashのユーザーoptionのRST_MODEを変更しなければならない. これは,./minichlink -Dとすれば実現でき,./minichlink -dとすれば元に戻せる. PD1を使うには,プログラムからalternate function IOを有効化してR32_AFIO_PCFR1レジスタの値を変更しなければならない. 上のコマンドでGPIOを有効にするとAFIOも有効になっているので,以下のようにすると良い.
AFIO->PCFR1&=~AFIO_PCFR1_SWCFG; AFIO->PCFR1|=AFIO_PCFR1_SWCFG_2;
しかし,これを実行すると,SWIOからのプログラムが出来なくなる. 電源を入れて数秒後にSWIOを無効になるようにして,必要ならその前にプログラムを書き込むようにすれば,便利である.
20pinのCH32V003F4P6でGNDと電源以外の18pinでLチカを試してみた. といっても,LEDを繋がずに,電圧の変化を見ただけだが. そのプログラムが以下とおりである. PD1とPD7が無事に動いて安心したが,PA1とPA2がうまく行っていないことに気がついたが,PAを使うつもりが無かったので,有効にしていなかっただけだった. PA1とPA2はクロックに使うこともできるが,dafaultだとそのままGPIOとして使える. 18pinをGPIOとして使えると,用途が広がるだろう.
#include "ch32fun.h"
#include <stdio.h>
int main()
{
SystemInit();
funGpioInitAll();
funPinMode( PA1, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PA2, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC0, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC1, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC2, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC3, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC4, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC5, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC6, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PC7, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PD0, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PD2, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PD3, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PD4, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PD5, GPIO_CFGLR_OUT_10Mhz_PP );
funPinMode( PD6, GPIO_CFGLR_OUT_10Mhz_PP );
// disable NRST to use PD7, by ./minichlink -D
funPinMode( PD7, GPIO_CFGLR_OUT_10Mhz_PP );
// disable SWIO to use PD1
Delay_Ms(5000);
AFIO->PCFR1&=~AFIO_PCFR1_SWCFG;
AFIO->PCFR1|=AFIO_PCFR1_SWCFG_2;
funPinMode( PD1, GPIO_CFGLR_OUT_10Mhz_PP );
while(1)
{
Delay_Ms(1000);
funDigitalWrite(PA1,FUN_HIGH);
funDigitalWrite(PA2,FUN_HIGH);
funDigitalWrite(PC0,FUN_HIGH);
funDigitalWrite(PC1,FUN_HIGH);
funDigitalWrite(PC2,FUN_HIGH);
funDigitalWrite(PC3,FUN_HIGH);
funDigitalWrite(PC4,FUN_HIGH);
funDigitalWrite(PC5,FUN_HIGH);
funDigitalWrite(PC6,FUN_HIGH);
funDigitalWrite(PC7,FUN_HIGH);
funDigitalWrite(PD0,FUN_HIGH);
funDigitalWrite(PD1,FUN_HIGH);
funDigitalWrite(PD2,FUN_HIGH);
funDigitalWrite(PD3,FUN_HIGH);
funDigitalWrite(PD4,FUN_HIGH);
funDigitalWrite(PD5,FUN_HIGH);
funDigitalWrite(PD6,FUN_HIGH);
funDigitalWrite(PD7,FUN_HIGH);
Delay_Ms(1000);
funDigitalWrite(PA1,FUN_LOW);
funDigitalWrite(PA2,FUN_LOW);
funDigitalWrite(PC0,FUN_LOW);
funDigitalWrite(PC1,FUN_LOW);
funDigitalWrite(PC2,FUN_LOW);
funDigitalWrite(PC3,FUN_LOW);
funDigitalWrite(PC4,FUN_LOW);
funDigitalWrite(PC5,FUN_LOW);
funDigitalWrite(PC6,FUN_LOW);
funDigitalWrite(PC7,FUN_LOW);
funDigitalWrite(PD0,FUN_LOW);
funDigitalWrite(PD1,FUN_LOW);
funDigitalWrite(PD2,FUN_LOW);
funDigitalWrite(PD3,FUN_LOW);
funDigitalWrite(PD4,FUN_LOW);
funDigitalWrite(PD5,FUN_LOW);
funDigitalWrite(PD6,FUN_LOW);
funDigitalWrite(PD7,FUN_LOW);
}
}