IoT何をいまさら(66) UnoとWio、TIMER、PWM違い

Joseph Halfmoon

Wio Terminalは、「Arduino Unoだと思って」使える部分も多いですが、8ビットのAVRマイコンのUnoとは違う32ビットArmコア、SAMD51マイコン機です。違う部分もチラホラあります。今回は、TIMERとTIMERによって制御される機構であるPWMについてその差を調べてみました。

※「IoT何をいまさら」投稿順Indexはこちら

1週間ほど前の「IoT何をいまさら(63)Wio Terminal、時刻と温度をSD記録」で作ったソフトですが、計測のタイミングとUIの制御が一緒になっているのはマズイなどと述べておったのであります。この「分離」にはタイマ割り込みが適当。というわけでタイマを使おうと考えました。Wio Terminalは、Arduino Unoとのソース互換性が高いです。Arduino Unoで、タイマといえば定番の

MsTimer2ライブラリ

を使えば一撃じゃないかと思ったですが、それは使えませぬ。MsTimer2ライブラリのソースの中をちょいと覗いてみましたが、AVRマイコン各種の対応はされているようでしたが、WioのSAMD51などは含まれておりませぬ。SAMD51にはSAMD51用のタイマ制御がいる、と。

WioのSAMD51を調べる前に、Unoがどうなっているのか調べてみました。Arduino Uno搭載のマイコンAtmega328Pのタイマは3本です。それぞれのタイマに2CHづつのPWM出力が可能なレジスタが付属しています。大昔の8ビットマイコンに比べたら遥かに洗練されていますが、やはり8ビットなのでささやかなハードに見えます。

    • タイマ0は8ビット
    • タイマ1は16ビット
    • タイマ2は8ビット

です。タイマ0はdelay()などでも使われているようなのであまり自由には使えないのだと思います。タイマ1のみ16ビットなので、モーターなど高精度の制御が必要な周辺ではこれを使うのだと思います。タイマ2は比較的自由で(そのためいろいろな音程を奏でられるtone()関数が使っているようです)、そのためか、タイマ2を使うMsTimer2ライブラリが定番化しているようです。

これに対して、Wio TerminalのマイコンSAMD51P19のタイマは13本、この本数にはRTCやWatchdogのようなタイマは入っていなくてこの数です。ま、でも、最近の32ビットMCUとしてはこんなものかも。タイマが必要になるような周辺装置の搭載も多いし。TIMERの中には、PWMも含め近代的なMCUとして必要そうな機能はそろっている感じ。13本の内訳ですが、

    • TCx(xは0から7)は8または16ビット、2本まとめて32ビット化も可能
    • TCC0/1は24ビット
    • TCC2/3/4は16ビット

です。TCといっている方がシンプルな「タイマ・カウンタ」で、TCCといっている方がより複雑な機能を持つ「タイマ・カウンタ・フォー・コントロール」です。こんだけあるので、どこか自由に使えるタイマがあるでしょう。ま、タイマで定周期の割り込みをかけようという「単純」な目標です。

まずは、ArduinoIDEのスケッチ例の中にきっと適当な例があるだろ~ということで調べてみました。以下にそのスクリーンキャプチャを掲げます。Wio Timer Example Fail

Seeeduino Wio Terminal用のスケッチ例という項目の中に

    • TimerTC3
    • TimerTCC0

という2つの項目があり、どちらにもタイマを使って定周期割り込みを発生させ、LEDをブリンクさせる例が掲げられています。これでOKっと思ったのですが、ちょっと嫌な予感がしました。SeeedStudioのGitHubの以下のコードを眺めていて、これ、Wio Terminal向けではないんじゃね、という疑問を持ったからです。

Seeed-Studio / ArduinoCore-samd /libraries/TimerTC3/TimerTC3.h

なお、ちょっと脱線しますが、手元のArduinoIDEはWindows Storeからインストールしたもので、ボード特有の設定などは通常権限では開けないフォルダに皆しまわれてしまうのでちょっと不便です。直ぐに開けるGitHubを見る方が早い。(※2021/1/20訂正、AVRマイコンについては通常権限で開けないパスにインストールされていますが、Wio TerminalのSAMDマイコン固有の部分は通常アクセスできるフォルダにありました。)

実際に例を開いてビルドしてみました。

TimerTC3の例、TimerTCC0の例、ともにコンパイルでエラー

 

やっぱりというか駄目でしたね。自力で原因究明とも思ったのですが、基本的なことなので、既にどなたか解決されている筈、ということでネットを調べたらありました。ciniml殿に感謝。

ciniml/ISRBlink.ino WioTerminal TC3 sample

ここにTC3で定周期割り込みを発生させるためのクラスが定義されてありました。上記をダウンロードさせていただいたものは、問題なくビルドして動作しました。オリジナルは、オンボードのUSER LEDをTC3割り込みで1秒周期で点滅させていたのですが、以下の改造を施してハード的に周期を確認してみました。

D0端子(Grove右ソケット)接続のLEDを10ms毎で点滅

10msは人の目では分かりませんが、例によってAnalog Discovery2で波形を観察して確かめます。その様子を先頭のアイキャッチ画像に。ちゃんと周期確認できました。ダウンロードしただけで目的は果たせました。しかし同時にムクムクと気になったのが、Wio Terminalの

analogWrite()どうなっているの?

という疑問です。Wio Terminalのご本家Webの解説ページみても、analogRead()のことは書いてあるのだけれど、TIMER使った analogWrite()については説明がないように見えるからです。

こちらもまずArduino Unoの場合を記述します。analogWrite()可能な端子とPWMの関係は以下のとおりです。analogWrite()といいつつ、実体はデジタルなTIMERなので、Arduino UNO端子番号欄の端子はデジタル側の端子です。

Arduino UNO端子番号 ATmega328P端子番号 PWM
3 PD3 TIMER2_B
5 PD5 TIMER0_B
6 PD6 TIMER0_A
9 PB1 TIMER1_A
10 PB2 TIMER1_B
11 PB3 TIMER2_A

各タイマに2本づつあるPWMが各端子に割り当てられていることが分かります。また発生できる周波数が端子によって制限があることも上の関係から理解されます。

さて、Wio Terminalの場合、

デジタル端子のD0はアナログ「入力」のA0でもある

というシンプルな関係です。D0(A0)とD1(A1)のみはGroveポートにも出力されていますが、他は本体背面の拡張端子に出力です。

Wio(Arduino)アナログ入力 PWM
D0 A0 PWM0
D1 A1 ※訂正参照
D2 A2 PWM1
D3 A3
D4 A4
D5 A5
D6 A6 PWM3
D7 A7
D8 A8 PWM4

ここで注意が必要なのは、Arduino UNOのデジタル端子番号と同じ端子にPWM出力がアサインされている分けではない、ということです。UNOであれば、3, 5, 6, 9, 10, 11番端子がPWM可能ですが、Wioの方は、0, 2, 6, 8です。(※2021/1/20訂正、実際には1番もPWM使用可、くわしくはこちら記事)他にSPIの端子にもPWMがMUXされています。それを確かめるために以下の3端子にanalogWrite()(繰り返しますがデジタル出力)してみました。特にビルドでエラーは報告されません。なお、ここで書いているピン番号は、raspberry Pi互換配列の40ピン拡張端子の端子番号とは異なります。「Arduino」ソフトの上でコードできる番号です。

0番、3番、6番

0番はUnoではPWM対象でない端子、3番はUnoではPWM対象ですがWioではそうでない、6番はUnoでもWioでもPWM対象です。わざわざPWM波形を観察しなくても音で分かるのでPassive型のブザーを該当端子に接続してみました。

WioのD6番端子にパッシブ・ブザーを接続しているところ

PassiveBuzzerPIN6OK今回はWioの3.3V電源ピンに接続したので、「蚊が鳴くような」か細い声ではありますが、6番に繋いだブザーは鳴ります。そして3番では鳴りません。

GroveポートのD0端子にブザーを接続したところ

PassiveBuzzerPIN0OK当然、Unoでは対象外の0番に接続したGrove端子でもブザーは鳴ります。

多少、スッキリしたかな。。。

IoT何をいまさら(65) WioからUnoへ、IR通信 へ戻る

IoT何をいまさら(67) ようやく納得、Wio Terminalのピンアサイン へ進む