- はじめに — HC-SR04をラズベリーパイにそのまま挿しました
- ロジックレベルとは何か — VIHとVIL
- 3.3V出力が5V入力で読める理由、逆がだめな理由
- 5Vが3.3Vピンに入るとシリコンの中で起きること
- ボード別ロジックレベル表
- 抵抗分圧 — 安いですが入力専用で、速い信号では破綻します
- MOSFET双方向シフターと専用IC
- I2Cはなぜ違うのか — オープンドレインバス
- 締めくくり — 電源ピンの電圧と信号ピンの電圧は違う数字です
はじめに — HC-SR04をラズベリーパイにそのまま挿しました
超音波距離センサーHC-SR04はArduino入門キットにほぼ必ず入っています。ピンは4本、VCC、GND、TRIG、ECHOです。サンプルコードも10行で終わります。
同じことをラズベリーパイでやってみることにします。5VピンにVCC、GNDにGND、GPIO23にTRIG、GPIO24にECHOをつなぎます。論理的には何も問題なさそうです。スクリプトを動かします。距離が出ます。うまくいきます。
そして数日後、あるいは数時間後、GPIO24が壊れます。値が常に0か常に1です。別のピンに移すとまたうまくいきます。そのピンもしばらくすると壊れます。
原因はコードではなく、ひとつの事実です。HC-SR04は5Vの部品で、ECHOピンは5Vで出力します。ラズベリーパイのGPIOは3.3Vの素子で、5Vに耐えられません。
この記事で扱うのは、その「耐えられない」が正確に何を意味するかです。そして耐えられるようにする方法を、それぞれの限界とともに見ていきます。
ロジックレベルとは何か — VIHとVIL
「デジタル」という言葉が誤解を生みます。ピンの内側を行き来しているのは0と1ではなく電圧であり、0と1はその電圧をある基準で解釈した結果です。
解釈の基準はデータシートに2つの数字で書かれています。
VIHは入力がHIGHと確実に認識される最小電圧です。VILはLOWと確実に認識される最大電圧です。その間は何も保証されない区間です。
出力側にも対応する2つの数字があります。VOHは出力がHIGHのときに保証する最小電圧、VOLはLOWのときに保証する最大電圧です。
2つのチップをつなぐということは結局こういう比較です。送る側のVOHが受け取る側のVIHより大きいか、そして送る側のVOLが受け取る側のVILより小さいか。この2つの条件がどちらも真であれば通信が成立します。
実際の値を見てみます。
| 素子 | 動作電圧 | VIH(HIGH最小) | VIL(LOW最大) | 基準 |
|---|---|---|---|---|
| ATmega328P(Arduino Uno) | 5V | 3.0V | 1.5V | 0.6倍/0.3倍 |
| 74HC系CMOS | 5V | 3.5V | 1.5V | 0.7倍/0.3倍 |
| 74HCT系 | 5V | 2.0V | 0.8V | TTL互換の固定値 |
| BCM2835(ラズベリーパイ) | 3.3V | 2.31V | 0.99V | 0.7倍/0.3倍 |
| ESP32 | 3.3V | 2.475V | 0.825V | 0.75倍/0.25倍 |
同じ5V素子なのにATmega328Pは3.0V、74HCは3.5Vです。この0.5Vの差が次の節の話題を分けます。
3.3V出力が5V入力で読める理由、逆がだめな理由
3.3Vから5Vへ送る — だいたいうまくいきます
3.3V素子がHIGHを出力すると、およそ3.2Vから3.3Vが出ます。この信号を5VのArduinoが受けると、
受け取った電圧3.3V vs ATmega328PのVIH 3.0V
3.3Vが3.0Vより大きいのでHIGHとして読まれます。
読めます。マージンは0.3Vです。余裕はありませんが動作します。だからESP32やラズベリーパイの出力をArduinoの入力に直接つなぐ回路は実際に多く出回っていて、だいたい問題なく動作します。
ただし「だいたい」という言葉を強調しておきたいです。表の2行目をもう一度見てください。74HC系ロジックICのVIHは3.5Vです。3.3Vは3.5Vより小さいので、規格上HIGHと認識される保証はありません。室温では運よく動いていても、温度が変わったり別のロットの部品に替えたりすると突然失敗します。74HCシフトレジスタやバッファを3.3Vボードにつないだとき「ときどきおかしい」という症状の正体がこれです。
この場合の正解は74HCT系に変えることです。HCTは入力閾値がTTL規格の2.0Vに固定されているので、3.3V入力を余裕を持って受け取ります。74AHCT125のようなバッファをひとつ挟むのが広く使われる解決策で、3.3Vボードで WS2812 LEDストリップを駆動して信号が不安定なとき、たいていこの部品で解決します。
5Vから3.3Vへ送る — 絶対にだめです
逆方向は認識の問題ではなく破壊の問題です。
3.3V素子のデータシートには絶対最大定格が書かれています。ラズベリーパイのBCMチップの場合、GPIOピンにかけられる最大電圧は次のとおりです。
絶対最大入力電圧 = VDD + 0.5V = 3.3V + 0.5V = 3.8V
3.8Vです。5Vはこの値を1.2V超えます。そして絶対最大定格という言葉は「この値を超えると性能が落ちる」ではなく「この値を超えると損傷することがあり、メーカーは何も保証しない」という意味です。
何が損傷するのかは次の節で見ます。
5Vが3.3Vピンに入るとシリコンの中で起きること
CMOS入力ピンの内側には静電気保護回路が入っています。構造はこうです。
VDD (3.3V)
│
▼ 上段クランプダイオード(ピン→VDD方向に導通)
│
ピン ────┼──── 内部ゲートへ
│
▼ 下段クランプダイオード(GND→ピン方向に導通)
│
GND
ピン電圧がVDDよりダイオードの電圧降下分高くなると、上段ダイオードが導通します。つまりピンから3.3Vレールへ電流が流れ込みます。これが本来設計された動作です。人の手から出る数千ボルトの静電気パルスを安全に逃がすために作られた回路です。
問題はそのパルスの持続時間です。静電気放電はナノ秒単位です。クランプダイオードはその短い瞬間の大電流に耐えるように設計されているだけで、持続的な電流を流すようには作られていません。
HC-SR04のECHO出力をつなぐとどうなるか計算してみます。ECHOがHIGHのとき5Vを出力し、その出力トランジスタの抵抗はおよそ50オームです。ダイオードの順方向電圧を0.7Vとすると、
ダイオードに流れる電流 = (5V - 3.3V - 0.7V) / 50オーム
= 1.0V / 50オーム
= 0.02A = 20mA
20mAがクランプダイオードを通して3.3Vレールへ流れ込み続けます。このダイオードは幅数マイクロメートルの薄い構造で、20mAを持続的には耐えられません。繰り返されると、シリコンと金属配線の接合部で原子が電流に沿って移動するエレクトロマイグレーションが起き、最終的に切れるか短絡します。
ここまでが最初の損傷経路です。2つ目のほうがもっと悪いです。
注入された20mAは3.3Vレールに入ります。レギュレータは電流を送り出すように作られていて、受け入れるようには作られていません。他の回路がその分を消費しなければ3.3Vレールの電圧が上がります。そうするとそのレールにつながっているすべての素子が規格外の電圧を受け取ります。損傷がGPIOピンひとつで終わらない理由です。
3つ目が決定的です。ラッチアップです。
CMOS構造の中には設計者が意図しなかった寄生トランジスタ対が常に存在します。p型とn型の領域が交互に配置されて自然に作られるpnpn構造で、これはサイリスタです。普段はオフですが、ピンに十分な電流が注入されるとオンになります。そしてサイリスタの性質上、一度オンになると電源を切るまで自分では消えません。
オンになった瞬間、電源と接地の間に低抵抗経路ができます。数百ミリアンペアからアンペア単位の電流がチップ内部を貫通します。症状はこうです。ラズベリーパイが急に熱くなり、止まり、電源を入れ直さないと生き返りません。生き返っても、そこにはすでに溶けた配線が残っていることが多いです。
まとめると、5Vが3.3Vピンに入ったときに起きることは3つです。クランプダイオードがじわじわ摩耗して切れるか、3.3Vレールが押し上げられて他の部品まで規格外に押しやるか、ラッチアップでチップが即死するかです。そして3つとも元に戻せません。
ひとつ付け加えると、この損傷がすぐに現れないことがかえって危険です。数日間よく動いていた回路がある日死ぬと、原因を配線に求めなくなります。最初からよく動いていたという事実は、配線が正しいことの証拠にはなりません。
ボード別ロジックレベル表
自分のボードがどちら側かを知ることが出発点です。ここでは3列目がこの記事の核心です。
| ボード | ロジック電圧 | 5V入力に耐えるか | ピンあたり最大電流 | GPIO合計 | ADC |
|---|---|---|---|---|---|
| Arduino Uno R3/Nano/Mega | 5V | 該当なし(自身が5V) | 20mA(絶対最大40mA) | 200mA | あり |
| Arduino Pro Mini 3.3V | 3.3V | いいえ | 20mA | 200mA | あり |
| Arduino Due | 3.3V | いいえ | 3mA(推奨)、15mA(最大) | 130mA | あり |
| ラズベリーパイ40ピンヘッダー | 3.3V | いいえ | 16mA | 50mA | なし |
| ラズベリーパイPico | 3.3V | いいえ | 12mA | 50mA | あり |
| ESP32 DevKit v1 | 3.3V | いいえ | 12mA | 120mA | あり |
| ESP8266(NodeMCU) | 3.3V | いいえ | 12mA | 不明 | あり(1チャンネル) |
| Teensy 4.x | 3.3V | いいえ | 4mA(推奨) | 制限あり | あり |
3つ確認します。
第一に、3.3Vボードの中で5Vに耐えるものはこのリストにひとつもありません。昔のTeensy 3.xや一部のSTM32系には5V耐性ピンがありましたが、最近よく使われるボードでは例外だと考えるほうが安全です。
第二に、ラズベリーパイにADCがないことがよく事故を起こします。アナログ出力のセンサーをパイにつなぐにはMCP3008のような外部ADCが必要ですが、この事実を知らずにアナログセンサーをGPIOに直接つなぐと値も出ず、5Vセンサーならピンも失います。
第三に、5V電源ピンがあるからといってGPIOが5Vという意味ではありません。ラズベリーパイヘッダーの2番、4番ピンは5Vを出力しますが、それは部品に電源を供給するためのものです。その5Vを使う部品の信号線をGPIOに直接つないだ瞬間、この記事の冒頭に戻ります。
配線を描いてこの組み合わせが安全か確認したければ、このサイトの配線検証ツールにボードと部品を載せてみてください。HC-SR04のように5Vだけで動作して5Vロジックを出力する部品を3.3Vボードにつなぐとロジックレベルの危険としてエラーが出て、ピンあたりの電流とレールごとの合計も一緒に計算してくれます。
抵抗分圧 — 安いですが入力専用で、速い信号では破綻します
もっとも安い解決策は抵抗2本です。前回の記事で見た電圧分割器そのままです。
5V信号 ──[ R1 ]──┬── 3.3Vボードの入力ピン
│
[ R2 ]
│
GND
出力電圧はこう出ます。
出力 = 入力 × R2 / (R1 + R2)
R1を1キロオーム、R2を2キロオームにすると、
出力 = 5V × 2000 / (1000 + 2000) = 5V × 0.667 = 3.33V
3.33Vです。3.3Vピンに安全な値です。よく使われる別の組み合わせは1.8キロオームと3.3キロオームです。
出力 = 5V × 3300 / (1800 + 3300) = 5V × 0.647 = 3.24V
3.24Vで、パイのVIHである2.31Vより十分高いのでHIGHとしてよく読めます。
この方式の利点は明確です。抵抗2本で済み、部品は数円で、ブレッドボードに直接挿せます。HC-SR04のECHOピンにはこの方法が事実上の標準です。
欠点は3つあり、それぞれ正確に理解して使う必要があります。
欠点1 — 一方向にしか動作しません
分圧器は高い電圧を下げるだけで、低い電圧を上げることはできません。つまり5V部品の出力を3.3Vボードが受け取るときにしか使えません。3.3Vボードの出力を5V部品に送る必要があるなら、この回路は何の役にも立ちません。
幸い、ほとんどの場合逆方向はシフティングなしで通ります。HC-SR04のTRIGはパイの3.3V出力をそのまま受けてもよく認識します。しかし先ほどの74HCの例のように、相手のVIHが高ければ通りません。
欠点2 — 常時電流を使います
信号がHIGHの間、R1とR2を通して電流が流れ続けます。
1キロオーム + 2キロオーム → 5V / 3000オーム = 1.67mA
1.67mAはUSB電源では無視できますが、バッテリー機器でこの回路が8つあると13mAになり無視できません。
電流を減らそうと抵抗を大きくすると、次の欠点が大きくなります。この2つはトレードオフの関係にあります。
欠点3 — 速い信号では破綻します
これがもっとも重要で、もっとも見落とされがちです。
分圧器の出力から回路を見た抵抗、つまり出力インピーダンスは2つの抵抗の並列値です。
1キロオーム || 2キロオーム = (1000 × 2000) / 3000 = 667オーム
ここに入力ピンと配線の静電容量約30ピコファラドが加わり、RC低域通過フィルタが作られます。
時定数 = 667オーム × 0.00000000003F = 0.00000002秒 = 20ナノ秒
信号が10パーセントから90パーセントまで上がる時間は時定数の2.2倍です。
立ち上がり時間 = 20ns × 2.2 = 44ナノ秒
HC-SR04のECHOは数ミリ秒単位で変化する信号なので、44ナノ秒はまったく問題になりません。だからこの組み合わせはうまく動作します。
今度は抵抗を大きくしてみます。電流を節約しようと10キロオームと20キロオームを使ったとすると、
出力インピーダンス = 10000 || 20000 = 6667オーム
時定数 = 6667 × 30pF = 200ナノ秒
立ち上がり時間 = 440ナノ秒
440ナノ秒です。1MHzのSPI信号の1ビットの長さは1000ナノ秒なので、信号が半分ほど上がったところですでに次のビットが始まっています。波形が三角形に潰れてデータが壊れます。抵抗分圧器をSPIや速いUARTに使ってはいけない理由がこれです。
まとめると抵抗分圧器の適用範囲はこう整理されます。
| 信号 | おおよその周波数 | 抵抗分圧器の適合性 |
|---|---|---|
| ボタン、リレーの状態 | 数Hz | 非常に適している |
| HC-SR04 ECHO | 数百Hz | 適している |
| UART 9600bps | 9.6kHz | 適している |
| UART 115200bps | 115kHz | 低い抵抗値なら可能 |
| I2C 100kHz | 100kHz | 不適合(オープンドレインで構造が異なる) |
| SPI 1MHz以上 | 1MHz以上 | 不適合 |
| WS2812データ | 800kHz、厳密なタイミング | 不適合 |
MOSFET双方向シフターと専用IC
BSS138 2抵抗回路
もっとも広く使われる双方向シフターはNチャンネルMOSFETひとつとプルアップ抵抗2つで作られます。ブレイクアウト基板として売られている4チャンネルレベルシフターの内部はほとんどがこの回路です。
動作原理を知っておくと限界も一緒に理解できます。MOSFETのゲートを低いほうの電圧である3.3Vに固定し、ソースを3.3V側の線に、ドレインを5V側の線につなぎます。両方の線にはそれぞれの電圧でプルアップがかかっています。
両方の線が放置されていると、3.3V側は3.3V、5V側は5Vにそれぞれ上がります。ゲートとソースの電圧が同じなのでMOSFETはオフです。
3.3V側がLOWに引き下げられると、ソースが0Vになります。ゲートは3.3Vなのでゲートとソースの間に3.3VがかかりMOSFETがオンになり、5V側も一緒に引き下げられます。
5V側がLOWに引き下げられると、まずMOSFETの寄生ダイオードが導通して3.3V側を0.7V付近まで引き下げ、するとゲートとソースの間に電圧が生まれてMOSFETが完全にオンになります。結局両方ともLOWになります。
どちら側から始まってもLOWが伝わり、HIGHはそれぞれのプルアップが作ります。方向を指定する必要がありません。
ここで限界が見えてきます。この回路は本質的にオープンドレイン方式です。HIGHへ上がる速度はプルアップ抵抗と静電容量が決め、MOSFETはその過程に何の助けもしません。10キロオームのプルアップに50ピコファラドなら立ち上がり時間は1マイクロ秒を超えます。だから実用的な上限はおよそ400kHzから1MHzの間です。I2Cには完璧ですが高速SPIには使えません。
専用レベルシフターIC
速度が必要か、チャンネルが多い場合は専用ICへ移ります。部品ごとに性格がはっきり異なるので、選ぶ基準を知っておく必要があります。
| 部品 | 方向 | 出力方式 | おおよその速度 | I2C使用 | 特徴 |
|---|---|---|---|---|---|
| 抵抗分圧器 | 単方向(降圧) | 受動 | 100kHz以下 | 不可 | もっとも安い、部品2つ |
| BSS138回路 | 双方向 | オープンドレイン | 400kHz〜1MHz | 適している | 方向指定不要 |
| 74LVC245 | 単方向(ピンで指定) | プッシュプル | 100MHz以上 | 不可 | 8チャンネル、非常に速い |
| 74AHCT125 | 単方向(昇圧) | プッシュプル | 50MHz以上 | 不可 | 3.3Vを5Vへ上げるとき |
| TXB0104/TXB0108 | 自動方向検出 | プッシュプル | 数十MHz | 不適合 | プルアップと衝突する |
| TXS0102/TXS0108 | 自動方向検出 | オープンドレイン対応 | 数MHz | 適している | I2C専用に近い |
| PCA9306 | 双方向 | オープンドレイン | 400kHz | 適している | I2C専用2チャンネル |
この表で必ず覚えておくべき行がTXB系です。TXB0104は自動方向検出機能があり便利に見えますが、I2Cには使ってはいけません。このチップは信号が変わる瞬間を検知して一瞬強く押す回路を内蔵していますが、I2Cバスのプルアップ抵抗がその検知を妨げて方向判定が乱れます。データシートにもオープンドレイン信号には使うなと明記されています。同じメーカーのTXS系がその用途向けです。名前が1文字違うだけで用途は正反対なので、注文するときは注意が必要です。
I2Cはなぜ違うのか — オープンドレインバス
I2Cを別に扱う理由は、このバスが上で見たすべての方法と前提が異なるからです。
I2CのSDAとSCLはオープンドレインです。バスにつながったどの機器も線をHIGHへ押しません。引き下げるか手を離すかのどちらかで、HIGHはプルアップ抵抗が作ります。
ここですぐに問題がひとつ見えてきます。プルアップがどの電圧につながっているかがバス全体の電圧を決めます。5Vセンサーモジュールには基板上にすでに5Vプルアップが付いていることが多いです。そのモジュールをラズベリーパイのSDAとSCLにそのままつなぐと、バスが休んでいる間も両方の線が5Vになります。パイのGPIO2とGPIO3に5Vが常時かかるということです。先ほどのクランプダイオードの話が、信号があるときだけでなく常に起きます。
だからI2Cのレベルシフティングは選択ではありません。そして方法も限られます。抵抗分圧器は使えません。オープンドレイン線に分圧器を付けると、その抵抗がプルアップと相互作用してLOW電圧が0Vまで下がりません。プッシュプルシフターも使えません。先ほど見たTXB系の問題です。残るのはBSS138回路かTXS系、PCA9306です。
プルアップ抵抗値の計算
I2Cを扱うとき知っておくべき計算がもうひとつあります。プルアップ抵抗値の上限と下限です。
下限は機器が線を引き下げられる能力が決めます。I2C規格は、出力がLOWのとき0.4V以下を維持しながら3mAを吸収できなければならないと定めています。
最小プルアップ抵抗 = (3.3V - 0.4V) / 0.003A = 967オーム
967オームより小さいプルアップを使うと、機器が線を十分に下げられません。
上限は立ち上がり時間が決めます。標準モード100kHzで許容される最大立ち上がり時間は1000ナノ秒で、バス静電容量を100ピコファラドと仮定すると、
最大プルアップ抵抗 = 1000ns / (0.8473 × 100pF) = 11803オーム ≈ 11.8キロオーム
400kHzの高速モードなら許容立ち上がり時間が300ナノ秒に減るので、
最大プルアップ抵抗 = 300ns / (0.8473 × 100pF) = 3541オーム ≈ 3.5キロオーム
だから標準モードには4.7キロオーム、高速モードには2.2キロオームが慣例として定着しています。根拠のない習慣ではなく、この計算の中間値です。
ラズベリーパイでよく出る落とし穴
パイのGPIO2とGPIO3には基板上に1.8キロオームのプルアップが固定で付いています。ところが市販のI2Cモジュールにもたいてい自前のプルアップが付いています。これらは全部並列です。
モジュール2個をつなぎ、それぞれ10キロオームのプルアップを持っているとすると、
合成抵抗 = 1 / (1/1800 + 1/10000 + 1/10000) = 1 / 0.000756 = 1324オーム
LOW維持に必要な電流 = (3.3V - 0.4V) / 1324オーム = 0.00219A = 2.19mA
2.19mAで、3mA規格の範囲内です。動作します。
今度は4.7キロオームのプルアップを持つモジュール4個をつなぐと、
合成抵抗 = 1 / (1/1800 + 4/4700) = 1 / 0.001406 = 711オーム
必要な電流 = (3.3V - 0.4V) / 711オーム = 0.00408A = 4.08mA
4.08mAで規格を超えます。どれかの機器が線を0.4V以下に下げられず、バスが断続的に壊れます。症状は「機器を3個までは大丈夫だが4個目からおかしい」です。解決策はモジュールのプルアップ抵抗を物理的に取り除くことです。ほとんどのモジュールでその抵抗は基板上の小さな部品で、はんだごてで外せば済みます。
実際のコードでの姿
HC-SR04に戻ります。ECHOに1キロオームと2キロオームの分圧器を入れると、コードは普通になります。
# HC-SR04をラズベリーパイに接続します。
#
# 配線:
# VCC -> 5V (2番ピン)
# GND -> GND (6番ピン)
# TRIG -> GPIO23 (パイの3.3V出力をそのまま受けます。シフティング不要です。)
# ECHO -> 1k抵抗を経由してGPIO24、そしてGPIO24から2k抵抗でGNDへ
#
# 分圧結果: 5V * 2000 / 3000 = 3.33V
# ECHOをGPIO24に直接つなぐとピンが損傷します。
from gpiozero import DistanceSensor
from time import sleep
sensor = DistanceSensor(echo=24, trigger=23, max_distance=2.0)
while True:
# distanceはメートル単位です。
print(f"{sensor.distance * 100:.1f} cm")
sleep(0.2)
コードには分圧器の痕跡がまったくありません。ソフトウェア側から見れば何も起きていないからです。これがハードウェアの問題をコードで探す羽目になる理由でもあります。配線が間違っていてもコードは正常に見え、うまく動作しているように見えることさえあります。
締めくくり — 電源ピンの電圧と信号ピンの電圧は違う数字です
この記事の結論は短いです。部品をつなぐ前に2つを別々に確認する必要があります。この部品が何ボルトで動作するか、そしてこの部品が出力する信号が何ボルトかです。
2つの値はたいてい同じですが、必ずしも同じではありません。HC-SR04は5Vで動作し5Vを出力します。PIRセンサーHC-SR501は5Vで動作しますが出力は3.3Vです。同じ5V部品でもひとつはパイを壊し、ひとつは安全です。データシートで確認すべきなのは電源電圧ではなく出力ロジックレベルです。
そしてこの確認は回路が動作するかどうかで代用できません。5VのECHOをパイに直接つないだ回路は最初はよく動作します。よく動作するという事実が安全であることの証拠にならない領域がハードウェアにはあり、ロジックレベルはその中でもっとも代表的な場所です。
次回は電圧ではなく電流が問題を引き起こす場合に移ります。モーターをGPIOにつなぐとなぜボードが再起動するのかを扱います。
현재 단락 (1/166)
超音波距離センサーHC-SR04はArduino入門キットにほぼ必ず入っています。ピンは4本、VCC、GND、TRIG、ECHOです。サンプルコードも10行で終わります。