レベル変換 (6) I2C その1 MOSFET
マイコンのシリアル・インターフェースには、I2C、SPI、UARTなどが使われます。その中で、センサの多くにはI2Cが利用されます。それは、
- 事象の変化が急激ではないのでデータ転送は比較的低速でもよい
- 複数のデバイスをつなげるのには単純な2線インターフェースが便利
などが大きな理由だと思います。ArduinoではWireライブラリを利用することで、比較的簡単にスケッチを書いてセンサ類を利用できます。
最近のセンサは、1.8Vもしくは3.3Vで利用する製品が多くなりました。5Vでは消費電力を下げられないのが最大の理由だと思われます。レベル変換の連載は、今回から、I2Cで利用できるデバイスを取り上げます。
●I2C信号の電圧
I2Cの論理レベルHIGHとLOWは、次のような電圧に規定されています。
規定 | 電源5V | 電源3.3V | |
---|---|---|---|
LOW Vil | 0.3*Vdd以下 | 1.5V | 0.99V |
HIGH Vih | 0.7*Vdd以上 | 3.5V | 2.31V |
Arduino UNOで使われているATMega328のI/O端子のVilは0.3*Vdd=1.5V、Vihは0.6*Vdd=3.0Vなので、HIGH電圧が少し異なります。
I2Cの信号は電源電圧へプルアップして利用します。5Vのマイコンでは5Vへ、3.3Vのセンサでは3.3Vです。したがって、2本の信号がつながるデバイスの電源電圧が異なる場合は、途中にレベル変換回路が必須です。
●信号の方向
Arduino UNOを利用するときは、マスタの役割をします。センサなどはスレーブです。クロックSCLはマスタがスレーブに対して送ります(一方向)。
I2C自体はマスタが複数バス上に存在するマルチマスタが規定されているので、SCLも双方向である必要な回路も存在します。
データのSDAはマスタとスレーブで双方の伝送が行われます。したがって、5Vと3.3Vのレベル変換では、双方向対応の回路を選びます。
●事例はArduino UNOとBME280
Arduino UNOは5Vで動作し、I/Oの電圧も5Vです。電源に3.3Vが用意されています。
温度、湿度、気圧を測れるセンサBME280の電源は3.3Vです。I/Oも3.3Vです。インターフェースはI2CもしくはSPIのどちらかが利用できます。ここではI2Cで通信します。このモジュール「BME280使用 温湿度・気圧センサモジュールキット」は、秋月電子通商から入手しました。
レベル変換には、MOSFETは4回路が実装されたモジュール「HiLetgo 10個セット IIC I2C ロジック レベル 変換 双方向モジュール 5V Arduinoに対応」をアマゾンで入手しました。
HVxと書かれたほうに高い電圧側の信号を、LVxと書かれたほうに低い電圧側の信号をつなぎます。中央付近のHVにはArduino UNOの5Vを、LVにはArduino UNOの3.3Vをつなぎます。この基板にあるGNDはどこにもつなぎません。動作を安定にするためのグラウンド・プレーンのようです。配線はしなくても、回路は動きます。
レベル変換回路は、UARTのときに使ったMOSFETの回路と同じです。
接続です。BME280ボードのジャンパJ1、J2はプルアップ抵抗(4.7kΩ)を有効にするためにショートしています。ここでの実験では、MOSFETのレベル変換回路に既に10kΩのプルアップ抵抗が入っているので、ショートする必要はありません(前の実験のままショート状態で使っている)。
J3はショートするとVddとつながり、I2Cインターフェースが有効になります。SDOはI2Cのスレーブ・アドレスの設定端子で、デフォルトの0x76にするためにGNDへつなぎます。Vddへつなぐと0x77になります。
SDIはI2CのSDA信号を、SCKはI2CのクロックSCLをつなぎます。
●スケッチ
BME280はデータを読み出しただけでは正しいデータにならず、個々のデバイスに保存されている補正データを利用して正しい温度、湿度、気圧のデータにします。ここでは、ライブラリを利用します。
ライブラリの管理からライブラリマネージャを開き、BME280で検索して出てきたGroveのライブラリを選びました。選択した理由は特にありません。
スケッチ例からbme280_exampleを読み込んで実行します。
実行結果です。
Analog Discovery2を使って、これらの実験中の波形を示します。画面の上側ブロックがアナログ信号です。オレンジ色がArduino UNOのクロックSCL波形で、青色がレベル変換したデータSDAの波形です。
下側のブロックはI2Cのデータをデコードして表示する画面です。オシロスコープのチャネル1(オレンジ色)にDIO2ピンを、オシロスコープのチャネル2(青色)にDIO1ピンをつないでいます。
Arduino UNOのSCLはLOWが0.1V、HIGHが3.8Vです。BME280側のLOWは0.2V、HIGH3.6Vです。Arduino UNOのI2CのVihは3.5Vですから、マージンは少ないですがHIGHレベルを満たしています。
●レギュレータ付きMOSFET
ebayで2回路のレベル変換回路基板を入手しました。5端子のレギュレータICが搭載されているので、3.3Vは別途電源を用意しなくて済みます。
Vin端子にArduino UNOの5Vをつなぐと、3V3端子に3.3Vが出力されるので、BME280ボードのVddへつなぎます。5A/5BにArduino UNOのSCL/SDAを、3A/3BにBME280ボードのSCK/SDIをつなぎます。
波形です。最初のMOSFETと同じレベルの電圧変換ができています。
●Arduino UNOのI/Oポートの電圧が低い?
ここまでのレベル変換の回路の実測で、5VあるはずのArduino UNOのI/Oポートの電圧が4V弱でした。ちょっと低めなので原因を考えました。
MOSFETのON時に大電流が流れれば、寄生ダイオードは無視され、オン抵抗だけの世界になる。しかし、レベル変換回路では電流がほとんど流れない。そのため寄生ダイオードの順方向電圧Vdsfが効いてくる。なので、Arduino UNO側が5Vではなく4Vぐらいになる。BSS138 だとVdsfは0.8Vくらい。 |
2N7000を使って検証しました。R1=R2=10kΩがよくみられる回路の定数です。電流を流すには、R1の抵抗値を変えればよいので、変化させました。
R1[Ω] | ドレインの電圧[V] |
---|---|
10k | 3.70 |
1k | 3.97 |
47 | 4.67 |
仮定は正しいかどうかはわかりませんが、期待した結果が得られました。
5Vに近づけるために47Ωを使うと十分な電圧が得られますが、電流が100mAも流れ、とてももったいない消費電力になります。ノイズ・マージンを確保したいときなどは、1kΩ弱の抵抗値を利用するのがよいように思えます。