google-site-verification: google3bd66dd162ef54c7.html
FC2ブログ

Arduino よもやま話-18(未使用ピンをまとめて設定する関数を作った)

◆未使用ピン
Arduinoでは未使用ピンは何もしないで放置しておくのが普通ですが、そうやると少し問題があることが判りました。特に気になるのが電源の消費電流の増加で、何も対策しないと約3mAも消費電流が増えてしまいます。そのあたりの話はよもやま話に書いてきましたが、重要と思われる記事へのリンクを以下に貼っていきます。
Arduino よもやま話-15 (未使用ピンの電圧変化の観察)
Arduino よもやま話-16 (未使用ピンの電圧と電源の消費電流の関係)

◆プログラムからの対策
この問題の対策は、未使用ピンを入力プルアップや出力LOWの状態に設定して電圧を確定してしまえば良く、居酒屋ガレージ日記さんのArduino やっぱり気になる放置ポートという記事で詳しく解説されています。
ここまでやれば完璧ですが、これまで pinMode( )なんちゃらとやって 1ピンずつ設定してきたので、いきなりこの書き方、つまりポート制御レジスタを直接いじる方式に変えるのは大変です。

◆未定義ピンを設定するプログラム
未定義のピンだけ空き端子処理することが出来れば良いので、そこに特化した関数を作ってみました。
// Arduino の空き端子処理関数 20200530uuPinSetup.ino
// uuPinOutputLow, uuPinOutputHigh, uupinInputPullup, uuPinInput
// 2020/05/30:割り込み対策追加 (居酒屋ガレージ日記さんご指摘)*1
// ラジオペンチ

void setup() {
// Serial.begin(115200);
// pinMode(13, OUTPUT);
uuPinOutputLow(0b01111111111100, 0b111111); // 未使用ピンをLOW出力に設定
// uuPinOutputHigh(0b01111111111100, 0b111111); // 未使用ピンをHIGH出力に設定
// uuPinInputPullup(0b01111111111100, 0b111111); // 未使用ピンを入力プルアップに設定
// uuPinInput(0b01111111111100, 0b111111); // 未使用ピンを入力に設定(デフォルトに戻す)
}

void loop() {
}

void uuPinOutputLow(unsigned int d, unsigned int a) { // 指定ピンを出力/LOWに設定(un used Pin set to Output Low)
// ビットパターンで該当ピンを指定(1で有効)。d:D13-D0, a:A5-A0
// PORTx=0, DDRx=1
unsigned int x;
uint8_t oldSREG = SREG; // ステータスレジスタ保存(割込状態保存)*1
cli(); // 割込み禁止*1
x = d & 0x00FF ; PORTD &= ~x; DDRD |= x; // D0-7
x = (d >> 8) & 0x3F; PORTB &= ~x; DDRB |= x; // D8-13
x = a & 0x003F ; PORTC &= ~x; DDRC |= x; // A0-5
SREG = oldSREG; // ステータスレジスタ復元(割込状態復元)*1
}

void uuPinOutputHigh(unsigned int d, unsigned int a) { // 未使用ピンを出力/HIGHに設定(un used Pin set to Output High)
// ビットパターンで該当ピンを指定(1で有効)。d:D13-D0, a:A5-A0
// PORTx=1, DDRx=1
unsigned int x;
uint8_t oldSREG = SREG; // ステータスレジスタ保存(割込状態保存)*1
cli(); // 割込み禁止*1
x = d & 0x00FF ; PORTD |= x; DDRD |= x; // D0-7
x = (d >> 8) & 0x3F; PORTB |= x; DDRB |= x; // D8-13
x = a & 0x003F ; PORTC |= x; DDRC |= x; // A0-5
SREG = oldSREG; // ステータスレジスタ復元(割込状態復元)*1
}

void uuPinInputPullup(unsigned int d, unsigned int a) { // 未使用ピンを入力/PULLUPに設定(un used Pin set to Input Pullup)
// ビットパターンで該当ピンを指定(1で有効)。d:D13-D0, a:A5-A0
// PORTx=1, DDRx=0
unsigned int x;
uint8_t oldSREG = SREG; // ステータスレジスタ保存(割込状態保存)*1
cli(); // 割込み禁止*1
x = d & 0x00FF ; PORTD |= x; DDRD &= ~x; // D0-7
x = (d >> 8) & 0x3F; PORTB |= x; DDRB &= ~x; // D8-13
x = a & 0x003F ; PORTC |= x; DDRC &= ~x; // A0-5
SREG = oldSREG; // ステータスレジスタ復元(割込状態復元)*1
}
void uuPinInput(unsigned int d, unsigned int a) { // 未使用ピンを入力(Hi-Z)に設定(un used Pin set to Input)
// ビットパターンで該当ピンを指定(1で有効)。d:D13-D0, a:A5-A0
// PORTx=0, DDRx=0
unsigned int x;
uint8_t oldSREG = SREG; // ステータスレジスタ保存(割込状態保存)*1
cli(); // 割込み禁止*1
x = d & 0x00FF ; PORTD &= ~x; DDRD &= ~x; // D0-7
x = (d >> 8) & 0x3F; PORTB &= ~x; DDRB &= ~x; // D8-13
x = a & 0x003F ; PORTC &= ~x; DDRC &= ~x; // A0-5
SREG = oldSREG; // ステータスレジスタ復元(割込状態復元)*1
}

居酒屋ガレージ日記さんから、「IOピンのレジスタ操作中は割り込みを禁止した方が良い」とのアドバイスを頂いたので修正しました。
なお旧版はこちら → 0528版(割り込み対策無し版)

つまり、空きピンの処理用に下記の関数を作った訳です。
・出力でLOW     uuPinOutputLow(d, a);
・出力でHIGH     uuPinOutputHigh(d, a);
・入力でプルアップ  uupinInputPullup(d, a);
・入力         uuPinInput(d, a);

空き端子を行いたいピンを引数のビットで指定する方式で、引数の d が D0~D13、引数の a が A0~A5に対応しています。 1 が指定されていればそのポートの空き端子処理を行い、0 だったら、元の設定のままで何もしないという動作を行います。

pinModeの設定が終わったあたりで未使用ピンに対してこの関数を使って空き端子処理を行えばよいと思います。あるいは最初にこの関数で全ピンの空き端子処理を行い、後でpinModeで変更するという手順でもいけると思います。どちらの場合でもグリッジが出る可能性があります。

どの空き端子処理を選択するかは好みに合わせて使えば良いと思いますが、私は居酒屋ガレージ日記さんの作法にならって、LOWを出力、つまり uuPinOutputLow を使っていこうかと思います。なお、入力 (uuPinInput) は無くても良いのですが、コードの対称性が悪くなるので作っておきました。設定を途中でにデフォルトに戻したい場合などで、あると便利かも知れません。

なお、必要なコードだけソースに書けば良く、使っていないコードは削除しても大丈夫です。(書いてあっても使っていなければコンパイラの段階で無かったことになるので悪影響はありません。)

◆効果
上記のプログラムを動かしたときのCPUの消費電流は約11mAでした。一方で、未使用ピンの処理無し、つまり uuPinOutputLow() をコメントアウトした状態の消費電流は 14mA、つまり消費電流を 3mA減らす効果が確認出来ました。
他の関数を使っても消費電流の低減効果は同じでした(デフォルト状態と同じuuPinInput() は除く)

◆電流波形
以上の確認はDMMによる測定と共に、オシロで電流波形も見たものです。オシロの波形で面白い結果が出ているので以下に示します。なお、この波形はCPUの電源ピンに入れた1Ωのシャント抵抗の電圧波形、つまり1mVは1mAに相当しています。

空き端子処理無しの状態
CPU電源電流波形の測定
約14mA流れています。

空き端子処理(OutputLow)ありの場合
出力LOWに設定
消費電流が10.5mAまで下がっています。

再び空き端子処理無しの状態
ACラインノイズの影響
I/Oコネクタに指を近付けると電源電流がACライン波形で変調されました。
空きピンがACラインの影響を受けて電位が変化し、そのために消費電流が変化しているのだと思います。空き端子処理をしていない場合の消費電流の値がフラフラするのが気になっていたのですが、どうもこういう現象が起きていて値が安定しなかったようです。

◆プログラム書き込み電流と同時観察
せっかくなのでCPUのフラッシュメモリーに書き込む様子と合わせて電流波形を観察してみました。

・空き端子処理無しの場合
プログラム書き込み、デフォルト
25mAくらいのスパイク電流がフラッシュに書き込みを行っているタイミングだと思います。その電流が6mAくらいまで減った後で、ユーザープログラムに制御が移り、消費電流14mAの状態で動き始めるのだと思います。小さな周期的な波は、AC電源からの誘導があるためだと思います。

・空き端子処理あり(OUTPUT LOW)
プログラム書き込み、OUTPUT LOW
こちらはユーザープログラムが動き出した後は消費電流が約11mAに減っています。これは前記した話と同じですが、さらにユーザープログラムが起動した後の波形は平坦になっています。これは空き端子処理を行ったためにノイズの影響を受け難くなった効果が表れているのだと思います。

◆まとめ
好みの問題はあるでしょうが、空き端子処理が必要な場合は、今回の記事の関数を使っていきたいと思います。何か問題があったらその時に修正したいと思います。

マイコンはデジタル処理の典型的なデバイスですが、そこにAC電源からの誘導、つまりハムが乗るとは油断が出来ないです。

Arduino NANO にはA6,A7ピンがありますが、この2つのピンにはデジタル入出力機能が無いので初期化は不要なはずです。

Arduino よもやま話-17 (アナログポートの未使用ピンの処置)

◆DIDR0 レジスタ
このところ Arduino の未使用ピンの処置方法についていろいろ調べています。ほぼ結論が出たと思っていたら、居酒屋ガレージ店主(JH3DBO)さんからコメントを頂き、アナログポートについては DIDR0 レジスタの設定でうまく処置出来るという情報を頂きました。そんな機能があるとは知らなかったので、さっそく試してみました。

◆測定の回路図
アナログ入力ピンに電圧印加
アナログポート (A0-5) を全部パラに接続し、テスト用の電圧を加えてその時のCPUの電源ピンの電流を測定しました。(CPUの電源はこの回路図には出てきません)
残りの信号ピンは、これまでの調査では何も接続せずオープンにしていたのですが、それでは電源電流が無駄に増えてしまって、良くないことが判りました。そこで、今回の調査ではプログラムで出力にアサインして LOW を出力しておきました。つまり、真面目に空き端子処理をやっておきました。

◆テスト用のプログラム
// 20200505 アナログ入力ピンのデジタル回路切り離し機能の効果測定プログラム
// DIDR0 レジスタを設定した場合の効果比較プログラム
void setup() {
// Serial.begin(115200);
pinSetup(); // D2-7, D8-13 を空きピン処理(全部LOW出力)A0-5は入力(何もしていない)
DIDR0 = 0b00111111; // digitalRead部切り離し(通常状態にするときはコメントアウト)
}

void loop() {
// Serial.println(PINC,BIN); // A0-5の状態確認
// delay(200);
}

void pinSetup() { // 空き端子処理
// 居酒屋ガレージ日記さんの書き方を真似した
// PORTBは全ピンLOW出力
PORTB = 0b00000000; // data/pull up
DDRB = 0b00111111; // I/O (0:in 1:out)
// |||||+---- PB0 IO8 out
// ||||+----- PB1 IO9 out
// |||+------ PB2 IO10 out
// ||+------- PB3 IO11 out
// |+-------- PB4 IO12 out
// +--------- PB5 IO13 out
// PORTDはTX,RD以外は全部LOW出力
// PORTCはデフォルトのまま(全部input)
PORTD = PORTD &= 0b00000011; // data/pull up (下位2ビット以外はLOW)
DDRD = 0b11111110; // I/O (0:in 1:out)
// |||||||+---- PD0 IO0 in RXD
// ||||||+----- PD1 IO1 out TXD
// |||||+------ PD2 IO2 out
// ||||+------- PD3 IO3 out
// |||+-------- PD4 IO4 out
// ||+--------- PD5 IO5 out
// |+---------- PD6 IO6 out
// +----------- PD7 IO7 out
}

◆測定結果
DIDR0レジスタの効果(入力電圧vs電源電流)
横軸がアナログポート(A0-5) に加えた電圧で、縦軸が CPU の電源ピンの電流です。

青色のプロットが DIDR0 レジスタに何も設定しない状態、つまり前の記事と同じ状態を再測定したものです。この場合 1/2Vcc を中心に消費電流が増えます。なお、今回の測定では残りのピンは全部LOW出力に設定して空きピン処理を行っているので、電流の値は前の記事より 1.5mAくらい少なくなっています。

オレンジ色のプロットが DIDR0 レジスタを設定 (0b00111111) した場合で、こちらは、入力ピンの電圧が変わっても電源電流には全く影響が出ていません。DIDR0 レジスタの目的は、アナログ入力ピンに、デジタル入力のシュミットトリガ回路の影響が出て、電圧/電流特性に非線形な影響が出ることを防ぐことで、そのためにアナログスイッチを使ってデジタル回路への接続を絶つと共に、デジタル入力を LOW レベルにクランプしています。

このような操作を行ったことによる別の効果として、電源電流が無駄に増加するという現象が解消出来る、ということになろうかと思います。ただ細かい話をすると、入力電圧がゼロの場合の電源電流を比較すると、DIDR0レジスタを使うより、LOW にクランプしておいた方が、電源の消費電流は約1mA 少なくなっています。

そんなことで、省電流化を狙う場合は出力 LOW で空き端子処理を行った方が良いのかも知れません。ただアナログ電圧の測定を行うピンではそんなことは出来ないので、やはり DIDR0 レジスタを設定するしか対策方法は無いでしょう。なお、Arduino で analogRead(An) とやる場合はおそらくそういう状態を作っているのだと思います。

◆データーシート
今回 DIDR0 レジスタの効果についてコメントで教えて頂きましたが、こういうことはデーターシートに書いてあるはずなので原文を確認してみました。("DIDR0" でPDFを文字列検索すると関係した部分を手早く発見出来ます)
datasheet of ATmega328P

すると、
ATmega328Pのデーターシート、9.10.6項

ATmega328Pのデーターシート、23.9.5項
確かにいろいろ書いてありました。

ここの説明は、アナログ入力ピンにパラに入っているデジタル入力回路の影響についての言及であって、デジタル入力ピンについては何も触れられていません。デジタル入力ピンの場合は切り離したりする機能は無いので、ここに書いてある影響がそのまま出るということだと思います。

◆まとめ
Arduino の空きピン処理も詳しく見るといろいろ難しいものです。ブレッドボードで一時的に組んで動作を試すような場合、空きピン処理などは気にしないで楽しんでしまえば良いと思います。この場合、CPUの消費電流が数mA増えているかも知れません。

一方で電池で長期間動かすような場合は、消費電力は重要なのできちっと空き端子処理を行った方が良いでしょう。あと、仕事で使うような場合は誘導ノイズなどで誤動作しては困るので、きっちりと空き端子処理を行っておく必要があります。

ところで、今回の記事では pinSetup() という関数を作って、ここでまとめて空き端子処理を行いました。しかし、この関数の中身を書くのがちょっと面倒です。例えば空き端子処理をしておきたい端子名を引数に列挙して呼び出せば、空き端子処理 (例えば出力で LOW) をやってくれるライブラリ、あるいは関数を作れば便利かも知れません。まあ逆に判りづらくなって変な問題のタネを蒔くだけになりかねないのですが。

Arduino よもやま話-16 (未使用ピンの電圧と電源の消費電流の関係)

◆ふたたび未使用ピンの話
未使用ピンをオープンのままにした場合の電圧の変化について、一つ前の記事で測定結果を示しています。簡単にまとめると、電源電圧の中央付近にゆっくりと電位が変化していく傾向があります。ただ、インピーダンスがものすごく高いので普通に使っている分にはあまり気にしなくても良いでしょう、というのがその時点での私の結論でした。

◆居酒屋ガレージ日記さんの追加調査
そうこやっているうちに、こういう調査をやることになった居酒屋ガレージ日記さんの記事に追加情報が出て、5月2日の記事ではArduino 放置したポートが及ぼす電源電流変化という記事で、入力ピンの電圧とチップの電源電流波形の関係を示されています。

これが以前から危惧されている、「空きピン処理が不適切な場合に消費電流に影響を与える現象」のようです。これを読むと結構影響がありそうで、あまり気にしなくても良いでしょう、なんてのんきなことを言っていられなくなりました。

ということで心配になってきたので私も測定してみました。

◆電源電流測定用のゲタ
電流波形の測定
CPUの電源電流測定はハイサイドで測定するのが楽なので、昔作ったATmega328の電源電流測定用のゲタを引っ張り出してきて、居酒屋ガレージさんと同じ測定を試みました。

この測定で同じような傾向の結果は得られたのですが、手持ちの測定器の組み合わせでは残念ながら精度の良い測定は出来ませんでした。(ハイサイドのシャント抵抗の電圧波形を見ながら同時に信号ピンの波形を観察するのはひと工夫必要です)

そこで、オシロによる測定は諦め、直流測定でやることにしました。

◆測定方法
測定のためには全ピンを入力に設定する必要があり、そのためのテストプログラムを作りました。と書くと大変そうですが、Arduinoのプログラムに中身が何もない setup と loop を書くだけです。つまり、

  void setup() {
  }
  void loop() {
  }

こんなふうに中に何も書かなければ全ピンが入力にアサインされます。Arduinoでこれ以上簡単なプログラムは無いでしょう。

・測定回路例
入力ピン電圧vs電源電流測定の回路
予備実験の結果から1ピン単位で測定すると誤差が大きくなりそうだったので、この回路図のように、ポートのグループ単位でまとめて測定することにしました。

つまり、パラに接続したグループ単位で電圧を加え、その時の電源電流の測定を行うという方法でやってみました。上の回路図は全部のピンを一つにまとめていますが、これ以外にPB0-4(D8-12), PD2-7(D2-7), PC0-5(A0-5)のグループ単位でも測定を行っています。なお、グループ単位の測定では測定対象以外のピンはオープンにしておきました。

・測定の様子
入力ピンにまとめて電圧印加
ブレッドボードの電源の列を使ってピンを並列に接続しました。

◆測定結果
測定の生データーは下記の通りです。
測定結果
グループでまとめて(ショートさせて)電圧を加えた時の電源電流の値 (mA) です。右端は全ピンに電圧を加えています。
(TX、RXとD13ピンは電圧印加の対象から外しています)

・グラフ
入力電圧vs電源電流特性
横軸が入力電圧で、縦軸が電源電流です。
両端は電流が少なく、中央付近で電流が大きくなる特性になっていました。(普通のCMOSロジックでこういうことをやると、貫通電流で素子を痛めるのでやってはいけません)
D8-12の振れ幅が小さいのはピン数が5ピンと少ないためだと思います(ほかのグループは6ピンです)
全17ピンをまとめた測定では、電圧が中央付近では消費電流が20mAにもなっていて、これはちょっとまずい感じです。一方で、電圧が0Vあるいは5Vなら消費電流は12mAまで減っています。本来はこういう状態で使うべきなんでしょう。

17ピンまとめて駆動した場合の電源電流の差は8mAあるので、平均すると1ピン当たり0.47mA消費電流が無駄に増えることになります。これはもったいないです。

ともかく、このグラフが居酒屋ガレージ日記さんが問題提起されていた現象を判り易く示していると思います。

◆まとめ
これまでも Arduino の CPU のATmega328P の消費電流を測っていますが、その値が数mAくらい違うことがありました。これって、チップの当り外れなのかと思っていたのですが、そうでは無くて空き端子処理の影響もあったのかも知れません。

入力ピンの空き端子処理をしていない場合、その電位は2.5V付近に集まるようになっていますが、こうなると電源に流れる無駄な電流も大きくなってしまうので好ましくありません。

入力ピンの空き端子処理をやらないと消費電流が8mAも増える可能性がある訳で、電池で動かす回路などでは、真面目に空き端子処理をやっておかないといけないです。
カレンダー
05 | 2020/06 | 07
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード