UIAPduinoでtoneとinterrupt


構築中のUIAPduino用のArduino環境に対して, 先週末に実装したつもりだったtoneとinterruptには,やはりバグがあった. なんとか,一応は動くようになったので,どのようなバグがあったかを説明したい.

まず,toneについてだが,32bitのCPUなので,timerも32bitだろうと思ってコードを書いたのだが,実はtimerは16bitだったので,その部分の修正が必要だった. prescalerが16bitだったので,実質的にはほぼ32bitとして扱えるので,比較的広い周波数の指定ができる状態を保持したまま,無難なコードに書き直した. その過程で,最初は挙動が思った通りにならなかったが,それはArduinoCoreAPIでtoneという関数が宣言されているためだった. また,durationというパラメータを誤って解釈していたのだが,何ms後に自動で音の発生を止めるという意味だった. 最初はdelayで誤魔化していたが,PWMを作っているタイマーで,波の数をカウントして止めることにした. しかし,タイマー割り込みのやり方の情報があまり見つからなかったので,試行錯誤が必要だった. update時の割り込みを許可して,updateをoverflowまたはunderflowに限定して,割り込み関数を有効にしたら,一つの波が終わったときに割り込みがかかる.

TIM1->DMAINTENR |= TIM_UIE;
TIM1->CTLR1 |= TIM_URS;
NVIC_EnableIRQ( TIM1_UP_IRQn );

そして,割り込みの中で,以下のようにupdateをクリアしないと何度も割り込みがかかってしまう.

TIM1->INTFR &= ~( TIM_UIF );

1を書き込んだらクリアされると思ったら,0を書き込む必要があった. 別の割り込みでは1の方だったので,そっちを試していたら,なかなかうまく行かなかった.

次に,interruptだが,二つの大きなバグがあった. 一つは,rv003usbの中でピンのinterruptを使っているので,USBを使っているときには使えないということだ. バグを発見するために,USB serialを使って動作を確認していると,何だか変な挙動をすることから,そのことに気が付いた. そこで,USBを使っているときには,interruptのコードは取り込まないようにしたが,これは仕方無いだろう. USBを使っていないときには,きちんと動くようにするためには,もう一つのバグを解決する必要があったが,それはC言語とC++の共存に関係する問題だった. attachInterruptなどの関数は,ArduinoCoreAPIで宣言されているので,それらの関数はC++で書かないといけないが,割り込み処理の関数はch32funで定義されているので,C言語で書かないといけないのである. それを意識して,少しだけ修正したら,無事に動くようになった. 気付いてみると当たり前なのだが,これらの事に気が付くのに時間がかかった. こちらは,プログラムの本質的な部分には問題は無かったのだが,上記のような相性の問題だった.

連休中に組み込んだあと2つの機能のshiftとpulseは,それほど複雑では無いので,バグは無いと思いたいが,あるかも. と思ってArduinoCoreAPIを確認したら,2つとも関係する関数の宣言が行われていたので,それに合わせて少し調整を行った. しかし,これらの機能の動作を確かめるのは面倒なので,あまり使わないだろうし,後回しにして良いだろう.

rv003usbも使えるようになったし,コンパイルしたサイズはかなり小さくなったし,目指していたUIAPduino用のArduino環境の条件は,ほぼ満たすものが出来てきたように思う. そういえば,ic2のslaveがまだだった. これもあまり使わないし,動作確認も面倒なんだよな. SPIもとりあえず書いたけど,動作確認していない. ほぼ出来上がってくると,興味がだんだんと薄れてしまうので,今後どこまで仕上げるかな.

[2025/3/25追記] rv003usbのフォルダを眺めていたら,demo_extiという名前で,USBとピンinterruptを共存させる例があった. 仕様上,USBで使っているピンと同じ番号のピンは使えないが,それ以外のピンなら, RV003_ADD_EXTI_MASKでマスクを指定して, RV003_ADD_EXTI_HANDLERで処理を行うことができるようだ. しかし,機械語を使って書かなければならなくて,attachInterruptを実現するのは難しそうなので,今は諦めよう.