UIAPduino用のArduino環境の改良

先週末は,三連休で時間があったので,最近構築しているch32funをベースにしたUIAPduino用のArduino環境をいじっていた. いくつかの進展があったので,私の目標とするところまでかなり近付いたように思う.

まず,Arduinoでコンパイルする際のやり方が書いてあるplatform.txtを全面的に見直した. 少しいじると,すぐにエラーが出ることが多く,これまでは必要になる度に,最低限の修正を加えるということを繰り返して來たために,見通しが悪くなってしまっていた. Arduinoのコンパイルでは,recipe.c.o.patternなどに基づいてC言語,C++,機械語のソースをそれぞれコンパイルして,recipe.c.combine.patternに基づいて リンクが行われる. そこに与えるオプションを,ボードの種類などによって変えられるようにするのだが,共通のオプションを使っている部分はまとめたりして,見た目をすっきりとさせた. さらに,オプションの意味を調べて,削除したり追加したりもした. その際,ch32funではch32fun.mkにコンパイルのやり方が書いてあるので,そのオプションも参考にした. 最終的なコンパイルサイズを小さくするためのいくつかの工夫が見られたが,リンクのオプションで–whole-archiveという指定を–no-whole-archiveに変えることによって,サイズがかなり小さくなった. これまでは,この指定のために,使っていない関数についても組込まれてしまっていたようだ. 例えば,blinkは768バイトとなり,ch32funだと616バイトだが,スイッチの設定などを変更する部分などを考慮すると,無難なサイズでは無いだろうか. デフォルトでは–no-whole-archiveらしいので,わざわざそれを変えているということに意味があるのならば,不都合が生じる場合もあるかも知れない. しかし,残念なことに,UIAPduinoを持って帰るのを忘れてしまったので,まだ十分な検証ができていない.

ハードに触れないので,ソフトをいじろうということで,他にもいくつか変更を加えてみた. いつか組込もうと思っていたピン割り込みは,megaAVRのコードとch32v003のマニュアルを参考に,実装してみた. ToneはPWMと共通点が多いので,その中に組込む形で取り入れてみた. ついでに,alternate functionを利用して,すべてのピンでPWMを使えるようにした. pulseはWCHのコードにch32funのコマンドを入れて実現した. shiftはWCHのコードがそのまま利用できそうだと思ったら,api/Common.h中の宣言とかち合ったので,megaAVRのコードをそのまま使った. これらも動作の確認はこれからだが. ピン割り込みにはまだバグがある気がする.

なかなか原因が分らなかったSPIのコンパイルもできるようになった. その主な原因は,api/HardwareSPI.hで

virtual ~HardwareSPI() { }

と定義されていて,これが悪さをしていた. クラス名に~を付けると,オブジェクトが削除されるときに実行されるデストラクタを意味しており,このときにdeleteが呼ばれて,それが定義されていないというエラーが起きていたのである. この行をコメントアウトしたら,コンパイルできるようになった. しかし,ArduinoCoreAPIの中身は変更しないという方針なので,他の方法を模索する必要があった. deleteは,AVRmegaではnew.cppの中で定義されている. new.hとnew.cppを持って来て, platform.txtのcppのコンパイルオプションに,

-fno-exceptions -fno-use-cxa-atexit -std=gnu++11

を加えたら,freeが無いというエラーに変わった. freeは,通常はstdlib.h中で定義されているのだが,ch32v003にはfreeが無いのかも知れない. そこで,new.cppの関数の中身を失くしたら,うまく行った. まだSPIにはバグはあるかも知れないが,一番大きな問題がクリアされただろう.

i2cのslaveも少しコードを加えたけど,割り込みの部分がmasterのコードを干渉しそうなので,それをどうするのか悩んで,そこで止まっている. これで,組込む予定だった機能で,組込めていないのは,i2cのslaveのみになった. 本体が無かったので,動作確認が出来ていないのが大きな問題なのだが,一つずつ検証して行こうと思う.

最初は,とりあえず動くものを作ろうと考えていて,Arduinoやch32funの中身を理解するつもりは無かったのだが,いろいろな問題を解決する過程で,それらを避けて通るわけにはいけなかった. 特に,ArduinoからUIAPduinoのUSBを使えるようにするために,rv003usbを組込むところでは,様々な試行錯誤が必要だった. ch32v003の細かい仕様を知らなくても,Arduinoから使えるようにするために始めたはずなのに,目的と手段が入れ替わってしまったかな.

Read more...

UIAPduino環境のコンパイルサイズの謎

私がUIAPduino用に新しく作っているArduino環境で,なぜかblink.inoのコンパイルサイズが大きくなってしまう. UIAPduinoの公式よりは三割程度は小さいのだが,明らかに大きすぎる気がする. 試行錯誤しながら,その理由を考えていたのだが,ヒントが見つかった気がするので,そのことについて説明する.

私の環境でのBlink.inoのコンパイルサイズは,AlexanderManderaさんの環境よりも2.3kバイトほど大きい. まずは冗長な処理を行っていたピンの定義などを簡略化して40バイトぐらいは小さくなったが,2kバイトには程遠い. 他の部分もいじってみたが,それほど無駄なことをしていないように見える.

ch32funの部分に無駄が無いかを調べていて,FUNCONF_TINYVECTORというパラメータを見つけた. AlexanderManderaさんの環境でも,-DTINYVECTORという指定をしていて,なんだろうと思っていたが,これに対応するようだ. このオプションを有効にしたら,私の環境でもコンパイルサイズが2kバイト以上小さくなった. 一番大きな要因はここにあったようだ. しかし,このオプションを有効にすると,割り込みが使えなくなる. 例えば,PWMなども働かなくなってしまったし,USBも使えなくなった. それでは意味が無いので,TINYVECTORは使わないことにした.

ch32v003には,40個ほどの割り込みがあり,そのベクターテーブルは,合計でも160バイト程度のはずである. TINYVECTORはそのほとんどを無くしてしまうというオプションなのだが,普通に考えると160バイト程度しか,コンパイルサイズに影響しないはずである. しかし,Arduinoでコンパイルすると,2kバイト以上の違いになる. 割り込み一つあたり50バイト程度が,何かに使われていると予想される. 少なくとも割り込み時に実行される40個ぐらいの関数を定義するのに,それぞれ多少のバイト数は必要になるだろう. Wireのコードをいじっていたときに,一つの処理を関数に置き換えるとあまりバイト数が変わらないけど,同一の二つの処理を関数に置き換えると数十バイト大きくなるということがあった. 一つの処理の場合には,最適化によって,関数としては使われず,二回使ったときに,関数として使われるとすると,一つの割り込み関数で50バイト増えるのも無難な気がする. ch32funの中では,ユーザーが定義していない割り込みは,DefaultIRQHandlerのaliasになっているので,実質一つの関数なのだが,Arduinoでは何らかの理由でalias指定が働かないとすると,2kバイト大きくなることが説明できる. これが正しいとすると,このalias指定を有効にして,その時に使用する割り込みのみを関数として使うようにすれば,2kバイト弱はサイズが小さくできる可能性があるのでは無いだろうか.

ch32funを使っているという共通点のあるAlexanderManderaさんの環境と,コンパイルサイズが違う原因が分かってすっきりした. 機能の面も合わせて考えると,ようやく私の環境がこの環境に劣っている点は,ほぼ無くなったと言える. USBを使えるという大きな利点があるものの,WireのslaveやSPIにはまだ対応できていない. 私はあまり使わないので忘れていたけど,ピン割り込みも対応するかな. 今後は,Arduino環境でのalias指定という観点に着目して,コンパイルサイズを小さくできる可能性について,もう少し調べてみたい.

Read more...

UIAPduinoでコードゴルフ

最近,Arduinoからch32funを介してUIAPduinoを使える環境を構築している. その環境でi2cとUSB serialを使ったプログラムを作ったら,flashにギリギリのサイズになってしまった. いろいろ調べていたら,ch32funのdebug printが有効になっていたので,それをオフにしたら多少は余裕ができた. もう少しバイナリのサイズを小さく出来無いかと思って,少しいじってみた. 現時点では,ArduinoCoreAPIは組込むと決めているので,その縛りの下でArduinoが組み込んでいるC言語やC++のソースをコンパイルした後のバイナリを小さくするようにするコードゴルフのようなものかな. しかし,コンパイラがある程度の最適化を行っているので,単純では無い. 例えるならば,日本語を通訳に流暢な英語にしてもらっているときに,その英語を短かくするように,日本語を作るようなものかな. 繰り返し行われている操作を,関数にして使うようにしたら,四回ぐらいしか使わない場合には,サイズが大きくなってしまうが,それより多く使うと,小さくなった. 小技を使って4バイトずつ縮めたり,USB serialの方もいじったりして,100バイト程度は短くなった. RingBufferを使うようにしたら,ソースコードは短かくなったが,バイナリは若干大きくなってしまったので,元に戻した. ついでにi2cをslaveに対応させようとして少し書き足したら,100バイトぐらい増えてしまって,元と同じぐらいに戻ってしまった. 使ってない関数は,最適化されたら関係無いと思ったけど,なんでだろう. 折角なので, UPAIduino環境で,最適化が-Osと-Os LTOのとき, 私の構築している環境で,with USB serialとwithout USBのとき, AlexanderManderaさんの環境の, 5つの場合について,コンパイルしたときに生成されるbinファイルのサイズを比較してみた. プログラムはプログラムの例から,いろいろな機能を使う場合を選んでみた. 結果は以下の通りである. overとついているのは,flashのサイズを超えた容量を示している. Xは実装されていないことを表している. condition Blink AnalogInput DigitalReadSerial AnalogInOutSerial i2c_scanner adafruit_aht10_test UIAPduino -Os 7140 8656 7616 12648 13032 11024 over UIAPduino -Os LTO 5696 6248 5872 8276 11040 error my own with USB serial 4460 4644 4440 4844 5752 1232 over my own without USB 3968 4168 3992 4338 5308 772 over AlexanderMandera 1640 1932 2132 X X X この表を見て気がついたのが,UIAPduinoでは,-Osがデフォルトになっているが,-Os LTOの方がサイズが小さくなって良さそうだということだ. UIAPduinoを使う場合には,-Os LTOで使うと良いだろう. バイナリのサイズという点では,AlexanderManderaさんの環境がかなり小さい. 私の環境は,Blinkはそれなりに大きなサイズになっているが,機能を増やしても,あまりサイズが変わらないという特徴を持っているようだ. 私の環境には最新のch32funを使っているのだが,その特徴なのかも知れない. ちなみに,シームレススイッチを組み込んでいるので,それが76バイトぐらいは大きくなっている原因だという点を考慮して欲しい. i2c_scannerはWireを使っていると言っても,ほぼ何も通信しないプログラムなので,UIAPduinoできちんとしたWireをArduinoから使えるのは,今のところ私の環境だけかも知れない. まだ,slaveが使えないが. また,adafruit_aht10_testを動かせるようにするには,かなり小さくしないといけないので,ちょっと厳しい気がする.
Read more...

UIAPduinoのHIDでターミナル

UIAPduinoでデバッグプリントするには,いくつかの方法がある. シリアルやSWIOなどに出力するのは簡単なのだが,それらを読み取るために別の機器が必要となる. ch32funや私が構築中のArduino環境では,rv003usbを介してUSB serialを使うこともでき,一つのUIAPduinoのみで済むのだが,Windowsでは使えない. そこで,rv003usbにdemo_terminalとして例のある,USB HIDを用いたデバッグプリントが重要になる. 確かめていないが,HIDを使った手法だと,Windowsでも使えるのでは無いだろうか.

今回は私が構築中のUIAPduino用Arduino環境に,この機能を追加してみた. USB serialと切り替える必要があるので,usb_config.hをincludeする際に,条件によって別のファイルを読み込むようにした. funconfig.hも少し修正した. USB serialのように,新たな関数をいろいろと定義しないといけないのかなと思っていたが,その必要も無く動くようになってしまった. 細かいところはch32funとrv003usbがやってくれているようである.

linuxでは,権限の問題をクリアするために,以下のコマンドを実行する.

echo -ne "KERNEL==\"hidraw*\", SUBSYSTEM==\"hidraw\", MODE=\"0664\", GROUP=\"plugdev\"\n" | sudo tee /etc/udev/rules.d/20-hidraw.rules
sudo udevadm control --reload-rules
sudo udevadm trigger

UIAPduinoに付属したminichlinkではうまく動かなかったので,ch32funに付属のminichlinkをつかって,以下のコマンドを実行する.

./minichlink -kT -c 0x1209d003

そして,inoの中でprintfで出力すると,その内容がターミナルに表示される.

UIAPduinoのためのch32funを使ったArduino環境は,ほぼ完成の領域に近づいたと言えるだろう. SPIはArduinoCoreAPIのHardwareSPI.hのどこかが悪さをしているみたいで,まだエラーが取れていないけど,このファイルを使うのを止めた方が早いかな. それぞれの機能が正常に作動するかや,複数の機能を使ったときにCH32V003のflashに入るかなど,検証すべき点は残されているが,大きな山は超えただろう. また,ArduinoIDEの設定については,理解していない部分が多い状態で,なんとか動く状態にしているので,無駄や美しくない部分も多いだろうから,それらを洗練していく必要はあるかも知れない. あとは,自分しか使わないのは勿体無い気がするので,どういった形で公開ができるかも考えないと.

Read more...

UIAPduinoのシームレススイッチ

UIAPduinoを書き込みモードにするには,RSTスイッチを押したままUSBに接続する必要がある. マイコンのプログラムを作るときには,何度も書き換える必要があることが多く,その度にUSBを抜き挿しするのは面倒である. UIAPduinoの公式ページには,RSTスイッチで書き込みモードと実行モードを切り換える方法が,SeamlessSwitch.inoとして以下のようなコードと共に示されている.

void setup() {
  if (FLASH->STATR & (1<<14)) NVIC_SystemReset();
  SystemReset_StartMode(Start_Mode_BOOT);
  pinMode(PD4, OUTPUT);
  // ...
}

しかし,私が構築した環境はch32funを使っており,SystemReset_StartModeという関数が無い. そこで,同等の関数を以下のように定義してみた.

void SystemReset_StartMode(uint32_t Mode)
{
  FLASH->KEYR = FLASH_KEY1;
  FLASH->KEYR = FLASH_KEY2;
  FLASH->BOOT_MODEKEYR = FLASH_KEY1;
  FLASH->BOOT_MODEKEYR = FLASH_KEY2;
  FLASH->STATR &= ~(1<<14);
  if(Mode == Start_Mode_BOOT){
    FLASH->STATR |= (1<<14);
  }
  FLASH->CTLR |= CR_LOCK_Set;
}

そして,指定したコードを実行してみたのだが,期待する挙動とならない. かなりの試行錯誤を経て,ようやくその原因が分った. ch32funでは,PD4は0x34=52という数値が割り当てられている. 一方,UIAPduinoではこのピンには14という番号がつけられており,私の環境ではその番号でピンを指定するようにしたので,PD4ではなく14をOUTPUTにする必要があったのである. このコードをmain.cppに組み込んでみたところ,無事にスイッチで書込と実行のモード切り替えできるようになった.

当たり前のことなのだが,USB serialなどを使っている場合には,USBがPD4を使うので,このPINを使うことが出来無い. そのため,スイッチによるモード切り替えも動作しない. その場合には,bootloaderに入るけどもUSBの初期化が出来無くなるのかなと思っていたが,実際にはリセット後で実行モードが立上がる. この理由が分らないが,bootloaderがUSBを認識できなかったら,実行モードに切り替わるのかな. いずれにせよ,USBを使っている場合には,やはり抜き挿しが必要となる.

2026/3/18追記 main.cppの中でUSBを組込む直前に,USBのD-に使われている14ピンを少しの間だけLOWにするようにしたら,書き込み後に自動でUSBを認識するようになった. bootloaderにもUSBの認識前に14ピンをLOWにするコードを入れられたら,USBを使っている場合でも,RSTでモード切り替えができるかもしれない. しかし,bootloaderのサイズはカツカツらしいので,難しいかも.

2026/3/31追記 usb_setup()を実行してから,その後でboot先を変更したら,USBを使っている場合でも,うまくいった. なぜだか良く分かって無いけど.

Read more...

ArduinoでUIAPduinoのUSB serialを使う

少し前から取り組んでいたUIAPduinoのUSB機能をrv003usbを通してArduinoから使うという試みが,ようやく一部は動くようになったので,それについて説明したい. 今回,これまでに構築してきたUIAPduino用のArduino環境に対して,rv003usbを組み込むことによって, USBの機能として最も有用であろうUSB serialを,Arduinoから動かすことに成功した. 動きそうなコードを書くのは,それほど苦労はしないのだが,それがArduino上で動くようにするまでには,いくつものバグを取り除く必要があり,かなり時間がかかってしまった.

まず行ったのが,USBを使うオプションを追加するために,boards.txtにメニューを加えることである. Suzuduinoなどのコードを参考にして,usb_flagsのパラメータを変更できるようにした. rv003usbのファイルは,cores/arduino/rv003usbに配置し,usb_config.hもここに入れた. rv003usbが参照している USBのライブラリは, cores/arduino/libに置いた. この段階で,rv003usb.Sをコンパイルする時にエラーが出たが,platform.txtでSファイルに対するオプションをうまく設定したら,このエラーは解決したが,次のエラーが出た. rb003usbのファイルは変更したくなかったが, rv003usb.hについては, _Static_assertがうまく動かなかったので,それを含む二行をコメントアウトして, 外部のコードから呼び出す三つの関数 usb_handle_user_in_requestとusb_handle_other_control_messageとusb_handle_user_dataの宣言の前にexternを加える という二つの変更が必要だった.

ch32funやrv003usbは主にC言語で書かれている. そのため,C++のArduinoにそれらの定義をincludeするときには,extern “C”{ }で囲んでおく必要がある. その辺りを誤魔化しながらクリアしていたのだが,改めてC言語のソースとC++のソースを意識して,必要な部分に宣言を加えたら,なんとかコンパイルが通るようになった.

megaavrなどを参考にして,CDC.hとCDC.cppを定義して,上で触れたrv003usbの三つの関数を呼び出すことにより,ようやくUSBでのserialを実現することができた. 通常のserialとUSB serialはArduino.hで判断して切り替えている. Serial1で通常のserialも使えるようにしたので,同時にも使えるはずである.

通常のserialとADCを使ったプログラムのbinファイルが4.4kバイトなのに対して, USB serialとADCを使ったプログラムのbinファイルは4.9kバイトと, それほど変らないので,十分実用に耐えるだろう. ただ,残念なのがWindowsからはrv003usbのCDCが使えないことである.

ArduinoからUSBが使えるようになったことで,私の目指していたUIAPduinoの環境は,完成にかなり近付いたと言えるだろう. 今後に改良したい点としては, 公式ページを参考にして,リセットで書き込みモードになるようにすることと, HIDでのデバッグを可能にすることかな. SPIもまだバグが残っているし.

2025/3/26追記 ソースコードもいろいろと手を加えたので,チェックしてみたら,rv003usb.hの内容を変更しないでもUSBが使えるようになっていた. ArduinoとC言語とC++の関係は,難しい.

Read more...

environment of the Arduino, by the ch32fun, for the UIAPduino

先日から,UIAPduinoのためのch32funによるArduinoの環境の開発を進めている. AlexanderManderaさんの環境は, そのような環境の一つであるので,そのコードを調べてみたところ,以下のようにして作られていることが分かった. まず,その中心となる開発環境の ch32funは,古いversionであるch32v003funを使っている. そして, ArduinoCoreAPIを組み込んでいるが,特にその中のHardwareSerialを書き換えて,Serialを実現している. コンパイルのオプションなどを指定しているplatform.txtなどは arduino-wch58x を参考にして作られている. i2c関係はhalというフォルダに入っているので,hardware abstraction layerのことだろうが,そのコードの起源は分からなかった.

この環境の利点を活かしつつ,UIAPduinoが使い易くなる環境を作りたいと考えていたが,少しずつ形になって来たので,そのことについて説明したい. 今回,新たな環境を構築するにあたって, 最新のch32funを使い,Arduinoの基本的な機能をArduinoと同じように使えるようにすることを,基本的な目標とした. また, 部品として使うch32funやArduinoCoreAPIなどのファイルは,できるだけ変更せずそのまま利用して,手を加えたファイルがどれかが分かりやすいようにする方針とした.

個人的に使うArduino環境は,~/Arduino/にファイルを置くことによって作ることができる. UIAPduinoに書き込みができるように, ~/Arduino/tools/minichlink/に,UIAPduinoのminichlinkを置き, ~/Arduino/hardware/wch/001/の下に,様々なファイルを配置して,Arduino IDEから使えるようにした. platform.txtは主にarduino-wch58xなどを,boards.txtはUIAPduinoなどを参考にして,作成した. cores/arduino/ch32fun/とcores/arduino/api/には,オリジナルのフォルダの内容をそのまま使った. ch32funが参照するcores/arduino/funconfig.hの中には,

#define FUNCONF_SYSTICK_USE_HCLK 1

を指定すると,以前起こったdelayなどが1/8になる問題が解消された. variants/CH32V003/pins_arduino.hには,ch32funのピンの定義を活かしつつ,Arduinoのピンの指定方法への橋渡しをするように記述した. コンパイルの後のリンクのときに,定義の一部が参照できないというエラーが出て,Arduino.hなどをいろいろといじって動くようになったが,よく理解できていない. cores/arduino/wiring_digital.cppやwiring_analog.cppは,ch32funのarduino-likeな書き方を最大限活用して,比較的コンパクトに書くことが出来た. その中で,以前の環境では使えなかったADCやPWMを実装した. ADCを簡単に使うためのコードは,extralibs/ch32v003_GPIO_branchless.hにも含まれているのを見つけたが,他の部分が干渉しそうだったので,funAnalogReadなどを使う方が無難だと判断した. PWMは,ピンのsetting変更は行わずに,とりあえず十個ぐらいのピンで使えるように書いたが,pinのmodeをOUTPUTでは無く,OUTPUT_AFにしないといけないことに気がつくのに,時間がかかってしまった. UIAPduinoでは,PWMは3つのピンで出来ると書いてあって,USBやRSTやSWIOで使うピンを除外しても7つは使えると思うけど,さらに相補的な出力を除いても4つになるのに,なぜA1がPWMを使えないことになっているのかな. 相補的な出力も,単独で使う場合には普通に使えるっぽいので,活用すれば良いように思うけど,何か理由があるのかも知れない. Serialはch32fun.cなどのコードを参考にしてcores/arduino/SerialUART.cppを作って,api/HardwareSerialとapi/RingBufferを活用して実現した. rv003usbのuart_cdc.cで作ったシリアル変換をつかって動作チェックをしたのだけど,そこに残ったバグに気が付くのにも苦労した. i2cについては,ArduinoCoreAPIを使っているmageavrのWire.cppから, ch32funのextralibs/ssd1306_i2c.hを参考に作った関数を呼び出すようにして,それらのファイルをlibraries/Wire/の中に入れた. SPIについては,同様にmegaavrのSPI.hとSPI.cppを変更して,ch32funのextralibs/ch32v003_SPI.hの関数を呼び出すようにした. しかし,リンクのときに, undefined reference to `operator delete(void*, unsigned int)' と出てしまう. あと少しで動きそうだけど,Arduinoのversionのせいかも知れない.

新たに作った環境の十分な動作チェックはまだだが,最低限の機能についてはArduinoとほぼ同じ感覚で使えるようになったと考えている. 以前の環境に比べて,以下の点が進歩したと思う. まず,ADCとPWMが新たに使えるようになり,i2cがWireから使えるようになった. SPIも,あと一歩だと思うけど,私はあまり使わないので,今は許して下さい. 細かい点では,ADCなどの指定がArduinoと同じようにできるようになったし, SerialはArduinoCoreAPIを変更しないで実現した. 欠点としては,少しコンパイルサイズが大きくなった点が気になるが,ch32funを新しくした影響なのかな. 新たに作った環境でblink.inoをコンパイルしたときの,binファイルのサイズは2040byteとなり,以前に比べて二割ほど大きくなったが,WCHの環境よりはるかに小さいので,十分使えるレベルだと思う. serialとi2cを使うプログラムは,13.9kだったので,まあflashには収まるサイズになった. 多数の機能を使ったら,flashのサイズを超えるかも知れないので,今後の検証が必要だろう.

次のステップとして,rv003usbを使えるようにできないかを模索する予定である. それには,ArduinoIDEのファイルの扱いについて,さらに理解を深めないといけないだろう. メニューからオプションでUSBを使う指定をしたときだけ,rv003usbを組み込むようにしたいけど,そのためには,どこにどうファイルを配置すれば良いのかを調べる必要がある. CDCまたはHIDを使ったprintを使えるようになれば,実用性が非常に大きくなるだろう. バグが減ってきたら,いずれは何らかの形で公開したいが,githubの使い方を覚えるのも面倒なので,どうしようかな.

Read more...

Arduinoからch32fun

Arduino IDEからch32funを使ってCH32V003を使う方法を探している. AlexanderManderaさんの環境は,arduino IDEからch32funを使えるようにしたものなので,これを使うと,Arduino IDEからch32funを通して,UIAPduinoを使うことができる. しかし,しばらく更新されておらず,古いversionのch32funを使っているし,まだ実装されていない機能も多いので,改良が必要である. 似たようなやり方で,最新のch32funをArduino IDEから使えるようにできないかと考えている. 特にrv003usbをArdiuno IDEから使えるようになれば望ましい.

そこで,ch32funとArduino IDEのコンパイルの仕方を少し調べてみた. ch32funでは,Makefileの中でincludeされているch32fun.mkに従ってコンパイルが行われる. 一方,Arduino IDEでは,arduino-builderが,platform.txtに書かれている情報に基づいて,C++のコードの生成とコンパイルが行われる. つまり,ch32funでmake buildを行ったときの出力を見て,それそplatform.txtに移植すれば,Arduino IDEを使ってコンパイルできるようになる.

純粋なarduinoについての設定は,/usr/share/arduino/hardware/arduino/avr/の中でされている. ユーザー独自の環境を作るときには,~/Arduino/hardware/wch/001/などを作って,そこに似たような構造のファイルを配置すれば良い. そこに,AlexanderManderaさんやUIAPduinoやch55xduinoのファイルを参考にして作ったファイルを配置して,最新のch32funを組み込んで,blink.inoのコンパイルはできるところまではできた. 書き込んで見ると,delayの時間が1/8ぐらいになっている気がするけど,まあいいか. 後でソースを少しずつ読み解いて,原因を調べよう.

rv003usbも組み込めないかなと思って, ~/Arduino/hardware/wch/001/librariesにrv003usb関係のファイルを入れたら,多少の進展はあったが,エラーが出てしまう. rv003usb.Sの処理のところで,うまく他のファイルを参照することが出来ていないようだが,もう少しいじれば,なんとかなりそうな気がする. 時間が出来たら,ch32funやarduinoの設定を検証して,また挑戦してみよう.

Read more...

UIAPduinoでADC

先日,UIAPduinoでserialとi2cを使ったら,flashの容量オーバーになってしまった. 一方,serialとADCを使った適当なプログラムをコンパイルしたら,9kバイト程度だったので,これなら十分にflashに書き込めた. 少し戸惑ったのがピンの指定で,例えば,analogRead(1)だと,ピン番号が1のA0では無くA1になるようだ. analogRead(A1)などとしても動くのだろうが,内部ではA1は0xc1などと表されているようだ. ADCを使うプログラムなら,容量が小さくできるch32funやAlexanderManderaさんの環境を使わずにすむのだが,それらではどの位のサイズになるのか知りたくなるものである. しかし,AlexanderManderaさんの環境では,ADCは実装されていない. 仕方が無いので,自分で書いてみた. 以下の内容の~/.arduino15/packages/alexandermandera/hardware/wch/0.0.2/cores/arduino/wiring_analog.cppというファイルを作る. #include "Arduino.h" #include "ch32v003fun.h" #include "wiring_private.h" static int write_resolution = 8; static int read_resolution = 10; void analogWrite(pin_size_t pin, int val){} void analogWriteResolution(int bits){} int analogRead(pin_size_t pin) { uint8_t adc2gpio[] = {0,0,2,3,3,3,3,3}; uint8_t adc2pin[] = {2,1,4,2,3,5,6,4}; uint8_t gpio = adc2gpio[pin & 0x07]; GPIO_TypeDef* port = gpioRegister(gpio); uint8_t p = adc2pin[pin & 0x07]; // ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2 RCC->CFGR0 &= ~(0x1F<<11); // Enable GPIO* and ADC RCC->APB2PCENR |= (0x04 << gpio) | RCC_APB2Periph_ADC1; // P*p is analog input chl n port->CFGLR &= ~(0xf<<(4*p)); // CNF = 00: Analog, MODE = 00: Input // Reset the ADC to init all regs RCC->APB2PRSTR |= RCC_APB2Periph_ADC1; RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1; // Set up single conversion on chl n ADC1->RSQR1 = 0; ADC1->RSQR2 = 0; ADC1->RSQR3 = pin; // 0-9 for 8 ext inputs and two internals // set sampling time for chl n ADC1->SAMPTR2 &= ~(ADC_SMP0<<(3*pin)); ADC1->SAMPTR2 |= 7<<(3*pin); // 0:7 => 3/9/15/30/43/57/73/241 cycles // turn on ADC and set rule group to sw trig ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL; // Reset calibration ADC1->CTLR2 |= ADC_RSTCAL; while(ADC1->CTLR2 & ADC_RSTCAL); // Calibrate ADC1->CTLR2 |= ADC_CAL; while(ADC1->CTLR2 & ADC_CAL); // start sw conversion (auto clears) ADC1->CTLR2 |= ADC_SWSTART; // wait for conversion complete while(!
Read more...

UIAPduinoでI2C

AHT10という温度と湿度を読み取れるセンサーを,UIAPduinoを使ってI2Cから読み取って,Serialに出力させるプログラムを作ってみた. センサーの使い方を調べていたら,ArduinoにAdafruitのライブラリがあって,データシートを読むよりも,これを参考にやってみることにした. まずは,UIAPduinoの環境でAdafruit_AHT10を使ってやってみようとしたら,プログラムはコピペですぐに書けたが,プログラムのサイズがflashに入らないとエラーが出た. 噂には聞いていたが,WCHのArduinoはかなり大きくなってしまう. それではと,Adafruitのライブラリを外して,SerialとWireを初期化して,コンパイルしたら,もうサイズがギリギリになっている. センサーに初期化コマンドを送るところまで書いたら,サイズオーバーである. 仕方が無いので,ch32funを使うのはややこしいので,AlexanderManderaさんの環境を使うことにした. I2Cの使い方は,標準的なArduinoとは違うのだが, ~/.arduino15/packages/alexandermandera/hardware/wch/0.0.2/cores/arduino/hal にI2Cのサブルーチンがあり, ~/.arduino15/packages/alexandermandera/hardware/wch/0.0.2/examples/CH32V003-I2C-1 にある例を参考にしたら,それほど苦労せずにプログラムすることができる. それより,AHT10のライブラリを読み解いて,移植する方が面倒かな. 湿度と温度を読み取ってシリアルに出力すプログラムを書いて,コンパイルしたら12kバイトぐらいである. 思ったよりも大きくなったが,十分なサイズである. そのプログラムが以下のものである. calibrationはうまくいかなかったので,その終了判定はコメントアウトしている. #include "hal/wch-hal-i2c.h" #define AHT10_I2CADDR_DEFAULT 0x38 ///< AHT10 default i2c address #define AHT10_CMD_CALIBRATE 0xE1 ///< Calibration command #define AHT10_CMD_TRIGGER 0xAC ///< Trigger reading command #define AHT10_CMD_SOFTRESET 0xBA ///< Soft reset command #define AHT10_STATUS_BUSY 0x80 ///< Status bit for busy #define AHT10_STATUS_CALIBRATED 0x08 ///< Status bit for calibrated #define LED_BUILTIN 2 uint8_t data[10] = {0}; void setup() { delay(20); Serial.
Read more...