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

Arduino よもやま話-15 (未使用ピンの電圧変化の観察)

◆おさらいと、今回の調査
Arduino の未使用ピン(未定義ピン)の挙動の話の続きです。前回の記事では調査用のプログラムを使って信号レベルの変化を調べました。そこで判ったのは、デバイスやピンによってかなり挙動が違っていることですが、情報は1(HIGH)か 0(LOW)しか無いので細かな挙動までは判りませんでした。

そのあたりをはっきりさせるために、今回はオペアンプを使って入力ピンの電圧変化の様子を観察してみます。

◆調査に使った回路
入力ピンのインピーダンスはものすごく高いので、テスターやオシロではその電圧は測定出来ません。そこで CMOS のオペアンプのボルテージフォロアを使って測定しました。

・測定回路
オープンピン挙動調査回路
使ったのは LMC6482 で、ボルテージフォロアで使い、出力の電圧をオシロで観察しました。インピーダンスが高いので簡単にノイズが乗ってしまうので、入力端子はシールド線を使って配線しました(この図はD10ピンの電圧を測定しているところです)。あと、オペアンプの空き端子はきちんと処置しておきます。

・実施のオペアンプ周辺の様子
入力はシールド線で配線
入力ピン (pin3) の隣が GND(pin4) なのでシールド線の配線を行うのに好都合でした。

・全体の様子
入力ピンの電圧変化
中央が被測定対象の Arduino、右がオペアンプで、左のオシロで測定します。低速波形の観察なのでこういうオシロで十分です。(背後の MDF板の裏にはノイズ対策のためにアースに接続した金属板が入っています)

◆測定方法
前の記事で使ったプログラムをそのまま使いました。動作としては、ピンを一旦電源電圧までプルアップし、その後開放状態にして10秒待機。次にピンを一旦GNDに落とし、その後開放状態にして10秒待機、と言うパターンを繰り返します。その状態をオシロで観察、記録しました。このように記録時間が長い場合はデジタルオシロでないとやる気が失せます。

以下結果を見ていきますが、前の記事のピンの状態変化一覧表と一緒に見ていくことにします。

◆測定結果-A基板(UNO純正)
ピン状態変化リスト
UNO-A
・波形 A-D2ピン
A-D2
GND と +5V の位置を矢印で示しています。
最初に+5Vまで電圧が上がっているのはプルアップしたためです。その後徐々に電圧が下がり、10秒後にGNDに接続したために電圧が急降下して0Vになります。その後は徐々に電圧が上昇し、10秒後に+5Vにプルアップというパターンを繰り返しています。以下の写真は全て同じ条件で波形を見たものです。

・波形 A-D12ピン
A-D12
デジタル測定ではこっちの方が長生きしてたのに、電圧の低下はこちらの方が速いです。ピン毎の VIH の違いも見えていたということなんでしょう。

◆測定結果-B基板(UNO純正)
・ピン状態変化リスト
UNO-B

・波形 B-D4ピン
B-4
5V から電圧が下がっていく途中の 4V 付近で波形の傾きが変わっています。シュミットトリガ回路の動作が関係している気がしますが、どうなんでしょう。

・波形 B-D10ピン
B-D10
こちらの波形には段付きはほとんどありません。2.5V を中心にきれいな上下対称な波形になっています。

◆測定結果-C基板
・ピン状態変化リスト
UNO-C

・波形 C-D5ピン
C-5
かなりはっきりした段付きがあります。これでもずっと HIGH レベルとして観測されていたということは VIH は2.8Vくらいだったということになります。

◆測定結果-D基板
・ピン状態変化リスト
UNO-D

・波形 D-D8ピン
D-8
デジタル測定ではまともだったピンですが、電圧変化もまあまともです。

・波形 D-D11ピン
D-11
電圧があっという間に1/2Vcc 付近に低下(上昇)していて、リークが大きそうな波形です。チップ内にコンタミなどがあるのでしょうか?
デジタルでは上昇/降下とも 1(HIGH) と判定されていて、アナログで見てもどちらも2.5Vくらいになっています。一見これで良さそうに思いそうですが、シュミットトリガのヒステリシスがどこかに行っちゃってる訳で、これはまずいです。

・波形 D-D12ピン
D-12
これはまあまともな波形です。

◆測定結果-Arduino NANO基板
・ピン状態変化リスト
NANO-1

・波形 1-D9 ピン
1-D9(NANO)
波形が収束するレベルが1.2V 付近になっていて、上の4つとは明らかに傾向が違っています。チップがそういう特性になっているのか、単にプリント基板の絶縁が悪いのか、この波形だけでは判断できそうもありません。

・波形 1-A0 ピン
1-A0(NANO)
数即するレベルが下がっているのは同じですが、マイナス側の時定数が短い感じです。

◆気付いた点
・リークの状態がかなり違っていて、極端に悪い物(多分絶縁が悪い物)も混ざっているようです。(偽物のCPUもある?)
・上下対称な波形になっていて欲しいのですが、下側にずれている物が多い印象です。
・正負で波形の収束する電圧に差があるものと、ほとんど同じ値に収束するものがあるようです。
・+5V から電圧が降下していく時、4V 付近でそのカーブが変化するものがある。
・LMC6482 を使ったボルテージフォロアはこの測定を行うのに十分な性能(入力抵抗)があったようです。ちなみに、単体の挙動を調べてみると、特定の電圧に向かって収束していくような傾向は認められませんでした。(数分の程度のスパンでは)

◆まとめ
デジタルで見ると何が起きているか判らなかったのですが、アナログ測定ではいろいろな違いが見えてきました。入力スレッショルドレベル (VIH, VIL) はかなりばらついているようです。

入力ポートに充電された電圧はゼロボルトに向かって低下していく(放電していく)のではないかと予想していたのですが、2.5V 付近に向かって収束するような挙動になっていました。やっぱり実際に確かめてみないとダメですね。これは CMOS 入力の上下2つのゲートのリークが案分されるような感じになるのでしょうか。

放電カーブの時定数は5秒程度なので、入力容量が 10pF と仮定すると、リーク抵抗の値は10^11Ωオーダーになりそうです。

収束する電位が上下2つに分かれていることがありましたが、これはシュミットトリガのヒステリシス電圧と関係がありそうな気がしますが、どうなんでしょう。あと、放電カーブの傾斜が途中で変化したりしてます。このあたりはデバイス特性に詳しい方の意見を伺いたいものです。

ということで、Arduino の CPU の ATmega328P に対する理解が深まったかも知れません。いや逆に謎が深まったかも知れませんが、まあ知らないより知っていた方が良いことは間違いないでしょう。ともかく勉強になりました。

#コロナウィルスで外出できない日は、家で回路の測定をやろう。

Arduino よもやま話-14 (未使用ピンの挙動をプログラムで調査)

◆未使用ピンをどうする
Arduino の未使用ピンの処置について居酒屋ガレージ日記さんが、Arduino やっぱり気になる放置ポートという記事を書かれています。Arduino の世界では未使用ピンは何もしないで放置しておくのが普通ですが、プロの目から見るとそんな危ないことをしてはダメ。ピンのレベルが HIGH あるいは LOW になるようにプログラムで設定、あるいは回路で接続しておくべきなんだそうです。

確かに空きピンの処置は回路設計の行儀作法みたいなもので、言われなくてもちゃんとやっておくものです。私の設計ではありませんが、大昔に誰かが空きピン処置を怠ったために原因不明の誤動作が発生し、2日くらい悩んだ経験があります。

◆マイコンの空きピン処置
Arduino のようなマイコンは、入力ピンがシュミットトリガになっているので空きピンは何も処置しなくても良いという話をどこかで聞いたことがあります(出典不明)。そうは言っても居酒屋ガレージ日記さんが指摘されているように、シュミットトリガ入力の閾値付近で消費電流が増えるのは困ります。

あと、これは個人的な見解ですが、プリント基板の絶縁抵抗は高くても 10^10Ω程度なので、たとえ電荷が存在したとしても時間経過と共に放電してしまうはず、つまり空きピン処理は不要と考えていました。(正確にはその空間の電荷分布に倣う)

◆隣接ピンのスイッチングノイズ
そうは言っても、居酒屋ガレージ日記さんのコメント欄で教えて頂いたPWM出力の隣接ピンへの誘導ノイズの例を見ると、空きピンにははあたかも盗聴器のように信号が漏れている訳で、これはちょっと嫌な状態です。

これは平行配線長が短ければ顕在化しない問題なのかも知れません。でもやはり気になるのでもう少しまじめに調べてみることにしました。何しろ新型コロナウィルス騒動で外出は出来るだけ避けろということで、こういう時は家で暇つぶししているのに限ります。

◆ネタはある
Arduinoのボード
測定に使えそうな基板を引っ張り出してみたら、これだけありました。内容としては、純正品のUNOが2枚、互換品のUNOが2枚、互換品のNANOが1枚あります。なお写真上にA,B,Cなどの文字を書きましたが、これは以下の測定結果と対応しています。

◆調査方法
I/Oピンの電圧を測定することが出来れば手っ取り早いのですが、相手はものすごいハイインピーダンスなので簡単ではありません。それに基板の枚数も多いので1ピンずつ電圧測定なんてやってられません。ということで、調査用のプログラムを書きました。

◆未使用ピンの挙動調査プログラム
全ピンをプルアップ(INPUT_PULLUP)してHIGHの状態にし、その後入力ピンにアサインして一定の時間間隔でピンの状態を読み出して、その結果をシリアルに出力しています。HIGH が終わったら次は全ピンに LOWを出力 (digitalWrite(n,HIGH)) し、同じことを繰り返しています。
このプログラムでは多数のピンの設定と変更を行う必要がありますが、一つづつ pinMode と digitalWrite とやるのは大変です。そこで、居酒屋ガレージさんのコードを流用させていただいて、ポートレジスタ単位でまとめていじることにしました。

少し長いですが、コードを見える形で置いておきます。
* Arduino I/O pin leak test
force High(INPUT_PULLUP) and relese, then watch level by digitalread
force LOE(digitalWrite(LOW) and relese, the watch level bay digital read
2020/04/29 radiopench
*/
#include <MsTimer2.h>

#define TIMESTEP 1000 // 測定周期(ms)(適当に設定)
#define N_TEST 10 // 測定回数(適当に設定)

long t = 0; // 開始からの時刻(ms)
char buff[10]; // 文字列操作バッファ
volatile boolean tUp = false; // 時刻同期フラグ

void setup() {
Serial.begin(115200);
Serial.println();
MsTimer2::set(TIMESTEP, MsTimer2IRQ); // 指定時間間隔で割り込み
MsTimer2::start();
}

void loop() {
Serial.println();
Serial.println("Set all pin High and relese. then watch dicharge of pins");
Serial.println(" time, D2,D3,D4,D5,D6,D7, D8,D9,10,11,12, A0,A1,A2,A3,A4,A5");
allPullUp(); // 全ピンハイレベル(INPUT_PULLUP)
delay(20);
allPinInput(); // 全ピン入力
t = 0;
syncTimer(); // タイマー同期
pinDump(t); // 初期値測定(t=0)
for (int n = 0; n < N_TEST; n++) { // 指定回数繰り返し
syncTimer(); // タイマー同期
t += TIMESTEP; // 時刻更新
pinDump(t); // 状態をシリアルに出力
}

Serial.println();
Serial.println("Set all pin Low and release. then watch charge up of pins");
Serial.println(" time, D2,D3,D4,D5,D6,D7, D8,D9,10,11,12, A0,A1,A2,A3,A4,A5");
allPinLow(); // 全ピンLowレベル(OUTPUT, LOW)
delay(20);
allPinInput(); // 全ピン入力
t = 0;
syncTimer(); // タイマー同期
pinDump(t);
for (int n = 0; n < N_TEST; n++) { // 指定回数
syncTimer(); // タイマー同期
t += TIMESTEP; // 時刻更新
pinDump(t); // 状態をシリアルに出力
}
}

void pinDump(long t) { // pinの情報を出力
dtostrf((t / 1000.0), 6, 1, buff); Serial.print(buff);
Serial.print(", "); printC(digitalRead(2));
Serial.print(", "); printC(digitalRead(3));
Serial.print(", "); printC(digitalRead(4));
Serial.print(", "); printC(digitalRead(5));
Serial.print(", "); printC(digitalRead(6));
Serial.print(", "); printC(digitalRead(7));
Serial.print(", "); printC(digitalRead(8));
Serial.print(", "); printC(digitalRead(9));
Serial.print(", "); printC(digitalRead(10));
Serial.print(", "); printC(digitalRead(11));
Serial.print(", "); printC(digitalRead(12));
// Serial.print(", "); printC(digitalRead(13));
Serial.print(", "); printC(digitalRead(A0));
Serial.print(", "); printC(digitalRead(A1));
Serial.print(", "); printC(digitalRead(A2));
Serial.print(", "); printC(digitalRead(A3));
Serial.print(", "); printC(digitalRead(A4));
Serial.print(", "); printC(digitalRead(A5));
Serial.println();
}

void printC(int k) { // 状態を指定文字で出力
if (k == 0) { // ゼロなら、
Serial.print(" "); // スペース出力
} else { // ゼロ以外なら
Serial.print(k); // その値(1しか来ないので1を出力)
}
}

void allPullUp() { // 全ピンプルアップ
// 居酒屋ガレージ日記さんの書き方を真似した
PORTB = 0b00111111; // data/pull up
DDRB = 0b00000000; // I/O (0:in 1:out)
// |||||+---- PB0 IO8 in
// ||||+----- PB1 IO9 in
// |||+------ PB2 IO10 in
// ||+------- PB3 IO11 in
// |+-------- PB4 IO12 in
// +--------- PB5 IO13 in
PORTC = 0b00111111; // data/pull up
DDRC = 0b00000000; // I/O (0:in 1:out)
// |||||+---- PC0 AD0 in
// ||||+----- PC1 AD1 in
// |||+------ PC2 AD2 in
// ||+------- PC3 AD3 in
// |+-------- PC4 AD4 in
// +--------- PC5 AD5 in
PORTD = 0b11111111; // data/pull up
DDRD = 0b00000010; // I/O (0:in 1:out)
// |||||||+---- PD0 IO0 in RXD
// ||||||+----- PD1 IO1 out TXD
// |||||+------ PD2 IO2 in
// ||||+------- PD3 IO3 in
// |||+-------- PD4 IO4 in
// ||+--------- PD5 IO5 in
// |+---------- PD6 IO6 in
// +----------- PD7 IO7 in
}

void allPinLow() { // 全ピン LOW出力
PORTB = 0b00000000; // D13-8 data/pull up
DDRB = 0b00111111; // I/O (0:in 1:out)
PORTC = 0b00000000; // A5-0 data/pull up
DDRC = 0b00111111; // I/O (0:in 1:out)
PORTD = 0b00000000; // D7-0 data/pull up
DDRD = 0b11111110; // I/O (0:in 1:out)
}

void allPinInput() { // 全ピン 入力
PORTB = 0b00000000; // D13-8 data/pull up
DDRB = 0b00100000; // I/O (0:in 1:out) Pin13だけ出力
PORTC = 0b00000000; // A5-0 data/pull up
DDRC = 0b00000000; // I/O (0:in 1:out)
PORTD = 0b00000000; // D7-0 data/pull up
DDRD = 0b00000010; // I/O (0:in 1:out) Txだけ出力
}

void syncTimer() { // タイマー同期
while (tUp == false) {
}
tUp = false;
}

void MsTimer2IRQ() { // MsTimer2 割り込みハンドラ
tUp = true;
}
◆結果
以下に測定結果を画面のハードコピーの形で示します。実際の測定は60秒行っているのですが、意味のある部分だけ抜き出しています。なお1行は1秒に相当しています。
Arduino UNO -A
UNO-A
事前に全ピン HIGH を書いているので2秒までは全ピンが1(HIGH)になっています。その後は櫛の歯が抜けるようにビットが落ちていって、12秒後には全ビットが0(LOW)になっています。(見づらいので 0 の時はスペースを出力しています)
後半は全Pin にLOWを書いているので、時間が経っても LOWのままです。

よしよし、この結果は予想通りです。A0 ピンがHIGHの状態を11秒維持しているのは、このピンの絶縁が優秀なんだろうな、と思ってました。

Arduino UNO-B
UNO-B
こっちはもっと優秀で、D10 と A4 はこの先60秒経っても 1 のままでした。優秀なんだけどこんなに長持ちするのはちょっと変かも?

Arduino-UNO-C
UNO-C
これは AliExpress で買った互換品で、CPUは32ピンのQFPです。
前半の HIGH を書いた後の挙動は予想通りなのですが、後半の LOW を書いた後の挙動がなんだか変です。そのまま LOW の状態で寝ていてくれれば良いのですが、D10とD11が何故かHIGHに変化しています。ゾンビかおまえは?

・Arduino UNO-D
UNO-D
これはもっと変で、LOWを書いた後多くのピンで電圧が上昇しています。D11なんて1秒も経たないうちにHIGHになっています。これは変です。何か予想外の現象が起きているようです。

・Arduino NANO-1
NANO-1
HIGHを書いても保持時間が短いようです。パチ物なので絶縁が悪いのかも?なんて思っていました。LOWを書いた後の挙動は普通で、勝手にHIGHになったりはしていません。なお、この基板のCPUも32ピンQFPです。

◆ここまでの整理
プログラムを書いたおかげで、多くのチップの全てのピン (5チップ×17ピン) の特性を効率良く測定することが出来ました。これで問題が大きそうなピンや、優秀(そう)なピンに目星を付けることが出来ました。

私の頭の中では、ピンの静電容量に溜まった電荷が、基板などの部品の絶縁抵抗を通して徐々に放電していくモデルを想定していました。多くの測定結果はそういうモデルで説明出来そうですが、LOWを書いたのに徐々に電圧が上がって行く現象はそのモデルでは説明が付きません。なんだか電荷が染み出している感じなので、CMOS入力の上下のゲートのリークが見えているのかも知れません。

こうなるとデジタルな測定では手に負えないので、電位の測定が必要になります。こういう測定は、プロならエレクトロメーターの出番ですが、アマチュアならCMOSオペアンプのボルテージフォロワーを使った測定でやるのが定番だと思います。

実はその測定は終わっていて結果は整理中なので、次回の記事で公開予定です。

あと、こういう場合の測定方法や現象の解説などで情報があれば教えて頂けると幸いです。

#コロナウィルスで外出できない日は、家でコードを書こう
カレンダー
03 | 2020/04 | 05
- - - 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コード