鳥なき里のマイコン屋(112) NucleoでArduino, PWM編

Joseph Halfmoon

STマイクロエレクトロニクス製Nucleoボードの古い機種F072RBをArduino環境に転用することにいたしたのですが、方針微修正、環境はArduinoIDEでなくVS Code(PlatformIO)利用といたしました。今回は、PWMに着目して「Arduino業界標準機」Unoとの違いを探って行きたいと思います。

まずArduino IDEからVS Code + PlatformIO への変更理由なのですが、

  1. デバッガが使える
  2. リビルドが早い

の2点であります。NucleoはオンボードでST-LINKを搭載しているので、折角のハードを有効活用しデバッグできます。また、ちょっとした修正でもかなり時間がかかるArduino IDEと比べると、VS Code環境にするだけでリビルドが凄く速くなるからであります。(Arduino Pro IDEというバージョンがありデバッガ使えるようになっているようですが、現状アルファ版ということで当面まだ見送り。昔から仕方がないとき以外はアルファ版どころかベータ版にも手を出さない保守的な性格?)

ともあれUIは異なりますが、VS Code + PlatformIOでもNucleo用のArduino環境のオブジェクトはビルドできることを確認しました。

Arduino環境で使い慣れた各種関数は「ほぼそのまま」使える感じですが、やはりハードが違う分、UnoとNucleoでは微妙な違いがあるようです。Nucleo「ファミリ」内ではかなり互換性が高そうなので小さいF072RBにモルモットになってもらって確かめて行きたいと思います。まずはこちらの回でWio Terminal(SAMD51)とUno(AVR)の差異を調べたPWMの件から。

ご存知のとおりPWMは0/1のデジタル信号ですが、Arduino環境では以下の関数などで制御されます。

Unoの場合、analogWrite()できる端子には制限があり、出力に使えるのはD3,5,6,9,10,11番の各端子です。書きこめる値は0~255の8ビット範囲。また周期は5番6番が980Hz, それ以外は490Hzとキメウチです。

Nucleo F072RBのD3, D4, D5の各端子にanalogWrite()し、その波形を観察してみました。とりあえずデフォルト設定のまま。

analogWrite(D3, 128);
analogWrite(D4, 64);
analogWrite(D5, 64);
D3端子(青)D4端子(黄)の様子

Uno的にはD3のPWM出力可能、D4は不可ですが、Nucleoでは両方可能です。STM32マイコン的にはもっとレゾリューションを上げられる(そのための関数もあり)のですが、オリジナルとの互換性のためデフォルトは引数8ビットのようです。ただ、Unoとは周期が異なりどちらも1000Hzで動作しているように見えます。あと細かいところですが、D3とD4の信号の立ち上がりがズレていることをご記憶ください。

analogWrite_D3B_D4Y

D4端子(黄)D5端子(青)の様子

D4とD5の場合、同じ値を書きこんでいるのでハイパルスの幅が同じであることは勿論、立ち上がりエッジも一緒に見えます。
analogWrite_D4Y_D5B上の2つの波形の挙動の理由は、以下のソースをみると理解できます。

packagesフォルダのパス\framework-arduinoststm32\variants\NUCLEO_F072RB\PeripheralPins.c

対応部分だけ簡単にまとめるとこんな感じ。

Aruino端子名 F072RB端子名 タイマ
D3 PB3 TIM2-CH2
D4 PB5 TIM3-CH1
D5 PB4 TIM3-CH2

D3端子にはタイマ2のCH2が割当られているけれど、D4/D5端子には同じタイマ3のCH1とCH2が割り当てられている、と。D4,D5は同じタイマを見ているので立ち上がりがそろうのだと思います。

このSTM32F072マイコンの場合、いわゆるタイマ(RTCやWatchdog等除く)は9本あり、PWM出力に使えるのはそのうちの7本です。ただし、TIM1のようにコンペアCHを4本も持っているタイマから、TIM16のようにコンペアCHを1本しかないタイマもあり能力的にはいろいろです。また、大部分は16ビットタイマですが、TIM2のみ32ビットです。TIM17などと呼ばれているものまで存在しますが、途中飛ばされている番号があります。番号が飛んでいるのは他のマイコン機種と統一した番号で呼ばれているためだと思います。

PWMを使う関数として以下も動かしてみました。

Arduino Unoの場合、D3とD11でしか動作しない関数です(Unoには1本しかない、なけなしの16ビットタイマを使う。)

tone(D10, 440);
tone(D11, 880);
D10端子(黄)D11端子(青)の様子

結果はちょっと予想と異なりました。こんな感じ。

tone_D10Y_D11BD10/D11ともタイマの割当があります。どちらも動くものと予想して試してみたのですが、D10は予定どおりほぼ440Hzの信号が出ているのに対し、Unoでも使えるD11には反応がありません。Nucleoボードの回路図を見ると、このD11という端子はちょっと特殊です。ボード裏面のハンダブリッジで接続先を選択可能ないくつかの端子の1本です。出荷時そのままで手を加えていないハンダブリッジを観察したところでは、D11はチップのPA7番に接続しているように見えます。出力される筈と思うのですが。ここは追加調査であります。

ついでにloop()関数を回る速度も測ってみました。

loop Speedトグルで約214kHzなので、loopそのものは428kHzとなります。以前測定したところ(今回と条件異なる)では、Uno(ATMega328P 16MHz) 248kHz, Wio Terminal(SAMD51P19, 120MHz) 1.8MHz, M5Stack Gray(ESP32, 240MHz) 3.8MHzという数字を得ています。Unoの倍くらい速いけれども、Wio TerminalやM5Stackよりはかなり遅いことが分かります。

VS Code + PlatformIO上でのデバッグの様子

ついでにデバッガ立ち上げたところの画面キャプチャです。立ち上げると「本物の」main.cppファイルの先頭でまずブレークがかかります。mainの中みるとユーザからみえるsetup()関数やloop()関数が呼ばれていることが分かります。

debugStartRealMainloop()関数の中にブレークポイントをセットしてRunするとこんどは「ユーザーの」main.cppファイルのloop()関数内でブレークします。VS Code + PlatformIOでは、Arduinoプラットフォームでも 拡張子 .ino ではなく、.cppであります。main.cppが2個見えてしまうのでちょっと紛らわしいです。

debuggerUserMain

ちゃんとウオッチポイントなど使えます。

debuggerWatch

PWM信号が使えるようになったので、次回は端子に何かつなげてみますか。

鳥なき里のマイコン屋(111) NUC120で28BYJ-48、1相、2相、1-2相? へ戻る

鳥なき里のマイコン屋(113) M5Stack, M5ez、本当にイージー へ進む