スイッチの操作でLEDを点灯させるプログラムをこちらで紹介しました。
Arduino UNO R4 MINIMAのLED_TXとLED_RXを光らせるようにしたのですが、プログラムを書き込み直後にこの2つのLEDがわずかにチラっと光ります。もし試した人がいらしたら、気がつかれましたでしょうか? チラ光りはその記事を書いた時には気づいていたのですが、とりあえず先に進んでしまいました。その後にArduinoの公式フォーラムで話題になっていたのを見つけましたので、紹介したいと思います。
つまりどういうこと?
フォーラムはこちら、post #2のvan_der_deckenさんのレスがズバリそのものになります。
Nano R4 GPIO switching - Nano R4 - Arduino Forum
「On the R4, pinMode(pin, OUTPUT); sets the output low. Even if you've done a digitalWrite(pin, HIGH); while it was in the input state. This is different than how the R3 worked.」
訳すと、「R4では、pinMode(pin, OUTPUT)は出力をLOWにセットする。INPUTの状態だった時にdigitalWrite(pin, HIGH)を実行していたとしても。これがR3の動作との違い。」
MINIMAのLED_TX、LED_RXはポート出力をLOWにしたときに光るよう回路が構成されています。また冒頭のスイッチとLEDを使ったプログラムでは、下のようにpinMode()、digitalWrite()の順でsetup()に書いています。2つのLEDは、pinMode()でLOWが出て光り、直後にdigitalWrite()でHIGHにされて消灯します。これがチラっと光る現象の正体です。
// UNO R4 MINIMA
setup() {
pinMode(LED_TX, OUTPUT);
pinMode(LED_RX, OUTPUT);
digitalWrite(LED_TX, HIGH);
digitalWrite(LED_RX, HIGH);
}
NANO R4のフルカラーLEDもポート出力をLOWにすると光る回路構成です。たぶん下のコードでチラ光りするはず……やっぱり光りますね。
// NANO R4
setup() {
pinMode(LEDR, OUTPUT);
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
digitalWrite(LEDR, HIGH);
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, HIGH);
}
pinMode() 実行の前後で起こっていることを、レジスタ内容と電圧波形で確認してみます。以下が使ったプログラムです。
//D3ピン(RA4M1 P104)の設定状態テスト
uint32_t $TEST0; uint32_t $TEST1; uint32_t $TEST2; uint32_t $TEST3; void setup() { delay(2000); //安定待ち、念のため $TEST0 = R_PFS->PORT[1].PIN[4].PmnPFS; digitalWrite(3,HIGH); $TEST1 = R_PFS->PORT[1].PIN[4].PmnPFS; pinMode(3, OUTPUT); $TEST2 = R_PFS->PORT[1].PIN[4].PmnPFS; digitalWrite(3,HIGH); $TEST3 = R_PFS->PORT[1].PIN[4].PmnPFS; Serial.begin(115200); Serial.println($TEST0, HEX); Serial.println($TEST1, HEX); Serial.println($TEST2, HEX); Serial.println($TEST3, HEX); } void loop() { digitalWrite(3, HIGH); delay(1000); digitalWrite(3, LOW); delay(1000); }
以下が配線で、D3ピンの電圧を見ます。あくまでこのテスト用として、抵抗10kΩと5kΩ(=10kΩを並列)で5VとGNDを分圧し、その中点をD3ピンにつなぎます。それによって、D3ピンが入力、出力のどちらに設定されているかも判別できるようにします。

D3ピンの入出力を設定するレジスタの変化とD3ピンの電圧波形です。


推定されるプログラム動作をD3ピンの波形に追記しました。最初ポートは入力になっていて、抵抗で分圧された約1.6Vから始まります。ポート出力データPODRは最初は0、次のdigitalWrite()で1になりますがポートは入力のまま。次のpinMode()でPODRは0になり、またおそらくこの時点でポートが出力に設定されて結果0Vが出力されます。その後digitalWrite()を実行し出力をHIGHにするまではLOWが出力されてしまいます。$TEST2の代入をコメントアウトするとLOWが続く正味時間が観測され、約1.6μsecでした。ここまでのテストで、フォーラムの情報のとおりpinMode()がLOW出力に設定するらしいというのが観測できました。
最初にHIGHから始まる設定はできないの?
出力LOWでアクチュエータが動作する回路では、最初の電源投入やリセットの直後はアクチュエータをオフするという要求もあるかと思います。RA4M1を含めて、一般的にはポートの入出力の方向とポート出力データのHIGH、LOWは別々のものです。そのためポートを出力に切り替える前にあらかじめ出力データを設定することは、ほぼ定石のように利用します。ですが、UNO R4のコアライブラリではLOWから出力を始めることを選んだようです。コアライブラリを改変するのもはばかられるので、HIGHで始めたくても一瞬LOWが出るのはやむを得ないところ。
そのほかに、レジスタ直接アクセスのR_PFS->PORT[m].PIN[n].PmnPFS = 0x04 or 0x05を使うことで、入出力方向の切り替えと出力HIGH、LOWのいずれかが一発で設定できます。ですが、その後にdigitalWrite()が不具合なく使えるかの相性は不明ですね。以降はレジスタ直接アクセスのみにする覚悟も必要かと。
とにかく、pinMode()の直後にdigitalWrite()を必ず書くのが良いでしょう。加えて、システム全体やアクチュエータの特性で工夫できるなら、それを利用してこの現象に対応するようです。
補足
公式か裏技か位置づけは不明ですが、UNO R3では最初にdigitalWrite()でHIGHに設定してからpinMode()で出力に切り替えるという方法でHIGH出力から始められるようです。それもあるために、UNO R4ではpinMode()実行の後に次のdigitalWrite()まではLOWのままになった、というケースは非常に注意が必要と思います。UNO R3と同じやり方でHIGHにしたつもりだったのに、ということになりかねません。
テストで使ったD3ピンは最初入力になっていますが、このピンのHIGH、LOWを判別する実際上のスレショルド電圧は電源電圧の半分程度と想定されます。ここに例えば分圧抵抗10kΩ、10kΩで入力すると、HIGHとLOWの間を行き来するアナログ的な動作をして悪影響を与える恐れがあります。その影響をなるべく減らすために、テストでは半分からずらして10kΩと5kΩで約1.6Vを作ってD3ピンに接続しました。