GY-521(MPU-6050)との通信時、ランダムにI2Cバスエラーが発生してフリーズする現象に遭遇しました。この原因をつきとめ、解消しましたので紹介します。
原因と対策
いきなりですが原因と対策です。
ランダムにフリーズする原因は AD0ピンをGNDに接続していない ことでした。
AD0はMPU-6050のデバイスアドレスを変更するポートですが、これがGY-521の中でプルダウン(またはプルアップ)されていないため、自分で接地なりしてやらないと不安定な動作になるようです。(AD0がハイインピだとしても、どっちかには振れるんだろうから、NAK返すなりすりゃあいいだけで、不安定になる理由はないだろうって気はしますが)
まあ、わかってしまえば「いかにも素人っぽいミス」なのですが、正直、AD0なんて眼中にありませんでしたよ。。。
その他試行錯誤したメモ
GY-521(MPU-6050)とのI2C通信において、試行錯誤した内容を以下にメモしておきます。
尚、ここで使用したマイコンはATSAMD21G18(SparkFun SAMD21 ミニブレイクアウト)で、フレームワークとしてASF4.0を使用しております。Arduinoは冗長かつ痒いところに手が届かないので使っておりません。
400KHzで通信する場合
GY-521付属の4.7KΩプルアップ抵抗のままで400KHz通信すると、通信波形がとても汚く、時々通信エラーが発生します。(波形はキャプチャし忘れたので無い) 対策として、SCL/SDAを外付け1KΩでプルアップ してやったところ、とても綺麗な波形になり、正しい通信を維持できるようになりました。
ただし1KΩでプルアップした場合、SCL/SDAそれぞれの消費電流が3mAくらいになります。これが許容できるかどうかは検討する必要があります。
その他検討した邪道(?)なこと
「外付け抵抗を追加せずとも、マイコンの内蔵プルアップを併用すれば、GY-521との合成抵抗によって抵抗値が下がって、結果的に通信波形も綺麗になるんじゃね?」と考えたのですが、全然駄目でした。大抵のマイコンの内蔵プルアップ抵抗は抵抗値がかなり高めだからです。例えばSAMD21の場合、内蔵プルアップの抵抗値はTYP:40kΩです。抵抗値が高すぎて全然ダメです。ATMEGA328などのプルアップ抵抗値も似たようなものでした。
起動時のエラー対策
マイコン起動時に、時々I2Cバスエラーが発生することがありました。 調査した結果、電源の瞬断などによって マイコンだけリセットして、GY-521は生き残った場合に発生する ということがわかりました。ウォッチドッグなどによってマイコンがリセットした場合も同様です。
この問題の対策として、マイコンからGY-521の電源を制御できるようにし、起動時にGY-521をパワーオンリセットすることで解決しました。
具体的なパワーオンリセット手順は・・・
1) GY521_ON を 500ms間 LOWにする(GY-521が完全に放電するのを待つ)
2) GY521_ON を 700ms間 HIGHにする(MPU-6050が完全に起動するのを待つ)
3) I2C通信設定をし、通信を開始する
これで完全にエラーが発生しなくなりました。500ms/700msはオシロで電圧波形を確認しながら決定した値です。かなり安全めの値で設定していますので、実際はこの半分くらいの時間でも大丈夫な気はします。
実行中に通信エラーが発生した場合も、同じ手順で復帰させてやれば完璧だと思います。
尚、MPU-6050からNAKが返った場合はパワーオンリセットしてはいけません。MPU-6050はNAKを返すことがあるからです。なぜNAKを返すかはデータシートにも書いていないので不明なのですが、実際に時々返ってきます。
まぁ、、I2C的に考えればさほど非常識なことでもない気はします。何かしら忙しいとかデータが揃ってないとか色々なMPU-6050事情があるんでしょう。しらんけど。
NAKが返ってきた場合は、数ミリ~数10ミリ置いて優しくリトライしてあげればデータが取れます。
ちなみに、INTピンを使って、FIFOに溜まったときだけデータを取りに行く仕組みにした場合でも、NAKを返してくることがあります。なんだかなー、、という気持ちにはなります。
とりあえず今日はここまで。
購入したものと使用した道具