I2Cのトラブルのはなし
I2Cの続編です
WEBではかなりI2Cの規格・プログラミングが公開されていますので、実際のトラブルに対する経験を書いてみたいと思います。
ハード的には
1)ウンともスンとも動かない時
テスターがあったら、動作させる前(電源入れた直後)にデバイス側とマイコン側のSCL,SDAの電圧を測ってみましょう。両方とも Highになっていますか?両方ともLowの場合はデバイス側の電源か、マイコン側のプルアップ抵抗をチェックしましょう。「デバイスのVdd端子を間違えて、動いてなかった」なんてことはよくあります。もちろんデバイスのアドレスデーター設定端子が合っているかチェックしましょう。アドレスが違うと反応しません。また送るアドレスデーターは間違えていませんか?
アドレスデーターの最下位ビットは Read(1)/Write(0)の区別のため実際のアドレスより送るデータは2倍の値になります。
2) どちらかのラインがLowのままの時
電源・プルアップ関係がOKならば、電源を切ってテスタでGNDとのショートチェックをしましょう。バスラインがどこかで半田くずかゴミでショートしていませんか?テスタはできれば導通でブザーが鳴る機能を使うとわかり易いですね。デバイスの接続端子ミスも可能性があります。
3) デバイスを繋ぐと動かない
マイコンから個別にラインを操作できるならば、SCLがHighのままにしてSDAをLowにしてみる。
ちゃんとラインが Lowになりますか?OKならSCLもLowにしてみてCLKラインがLowに制御できますか?
これがOKでまだ動かないならば、オシロスコープが必要ですね。
最初の8ビットアドレスデーターを送ってみて、ACKがデバイスから返ってきますか?デバイスからのACKのLowが電圧が完全に0Vにならないなど、送る側のLow電圧も高い場合、プルアップ抵抗が小さすぎるとか、デバイスの電源電圧の違いとかチェックしましょう。バスライン・クロックラインのの波形はOKですか?
4) アドレスデーターはACKが来るけど、その後動かない
CPUからの9ビット目のCLK処理はタイミング合ってますか?デバイスがACKを出したままCPUのCLKを待っている状態で止まっている可能性があります。
5) 時々動かない
デバイスがEEPROMなど書き込みに時間がかかるデバイスを使っていませんか?
書き込み時は数10mSかかる場合があるので、最後の書き込みからある程度時間がたたないとBUSY状態になって連続して書き込めません。EEPROMでも、あるアドレスから数バイト(8バイトぐらいが多い)は連続書き込み出来るが、それ以上は完了時間が必要な時がありますので、デバイスの規格表をチェックしましょう。
また、ラインにノイズ防止のためのコンデンサ、EMIフィルタ等入れている場合に波形がなまって送るデーターの値によってエラーになる場合があります。CLOCKスピードを下げて実験するかコンデンサEMIフィルタの値を小さくしてみます。プルアップ抵抗の値を小さくしても効果のある場合があります。
6) CPUは 3.3Vなのにデバイスは 5Vなのでどうしよう?
PICなどは入力電圧が 3.3V Vdd でも 5.5V入力を保障していますので問題ないですが、専用のレベル変換ICなどを利用するのも良いでしょう。
7) 連続読み込みが出来ない
デバイスからデーター読み込み時に ACKを返してますか?ACKを返さないと1バイトで終了と思って通信が終わってしまします。詳細はI2C Readのはなしで...
ソフト的には
1)まず開始時にバスラインを確認しましょう。
CLKは通常値を読めないので仕方がありませんが、DATAは読めるので Idle状態( CLOCK/DATAともHigh)の設定時に DATAが Lowだったら、どれかのデバイスがCLK待ちかも知れません。STARTとSTOPコンディションを送るつもりでまずDATA を Lowにして次にCLOCKをLowに、そして先にCLOCKを立ち上げ、その後DATAをHignにします。DATAはHighに戻りましたか?
2)ステータスフラグはOKか
ハードウエアを利用したI2Cドライバの場合は、ステータスフラグのリセットなどきちんとおこなっているかどうか確認しましょう。
H8用のサンプルプログラムを紹介します。
unsigned char set_device ( unsigned char dev ,unsigned short Addr )
{
int n ;
n = 100 ;
while (IIC2.ICCR2.BIT.BBSY); //【1】I2Cバスがフリーになるまで待つ
IIC2.ICCR1.BYTE = (IIC2.ICCR1.BYTE & 0xCF) | 0x30;//【2】マスタ送信モードに設定(MST=1, TRS=1)
do {
IIC2.ICCR2.BYTE = 0xBD; //【3】開始条件を発行(BBSY=1, SCP=0)
IIC2.ICDRT = SLA | Wbit; //【4】コントロールバイトを送る
while(! IIC2.ICSR.BIT.TEND); //TEND をチェックし、送信が完了するまで待つ
--n ;
if( n < 0 ){
return( 0 ) ; // 一定期間で完了しなかったら Errorを出して抜ける
}
} while ( IIC2.ICIER.BIT.ACKBR ); //【5】ACKの返送を確認
IIC2.ICDRT = (unsigned char)( Addr & 0x00FF ); //【7】下位メモリアドレスを送信
while(! IIC2.ICSR.BIT.TEND); //TEND をチェックし、送信が完了するまで待つ
return(1) ; // OK
}
3) エラーが出た時の対策をしましょう。
ACKが来なかった時、ACK待ちで止まってしまうことがあります。止まってしまってOKなら良いですが、一定時間(一定回数)リトライしてダメならデーター0xffをとりあえず返すなど待ちループに入ってしまうのを回避するようにしましょう。
4) 必要以上速いスピードを追求しない
デジタルのHigh/Lowパルスは雑音を伴いますし、高速にすればハード的に伝送品質が落ちます。必要な速度を考慮してマージンのあるスピードで制御しましょう。ソフト的待ち時間を使ってCLOCKを作っている場合など、High期間とLow期間が同じになるような波形を作ったほうが、ハード的デバッグなどタイミングがチェックしやすくなります。
5)データーは 0x00 から 0xFF まで送受してみましょう
また、アドレスを変えて反応が無くなることも確認して、デバイスが壊れた時の対応のチェックもしましょう。
参考書----------------------------------------------------
| 固定リンク
「トラブル対策」カテゴリの記事
- SwitchBot スマートプラグ 修理のはなし(2024.08.02)
- ソーラ発電その後のはなし(2024.03.28)
- シリアル通信トラブル集( インターフェイス2024年3月号)のはなし(2024.02.29)
- パワーアンプ PROTECT故障のはなし(2023.11.16)
- ダイナミックマイクのロー抜け修理のはなし(2021.05.24)
コメント
こんにちは。大変参考になります。
> デバイスからのACKのLowが電圧が完全に0Vにならないなど、送る側のLow電圧も高い場合、プルアップ抵抗が小さすぎるとか、デバイスの電源電圧の違いとかチェックしましょう。
送る側の Low 電圧はちゃんとゼロだけど、デバイスからの ACK の Low 電圧が完全にゼロにならない場合、どのような原因が考えられますでしょうか?
投稿: CO | 2010年6月18日 (金) 15時33分
デバイスによっては出力電流が大きく取れず、完全にはゼロにならない場合があるかと思いますが、出力ポートがCMOSならば 0.1V以下、トランジスタだったら、大きくてもLow電圧は 0.3V以下ならば問題ありません、それ以上ありますか? プルアップ抵抗が1KΩ以上で使っていて動作しない場合は、デバイスの電源電圧、GND端子接続などをチェックする、他にI2Cデーターラインにデバイスが付いている場合はそれを外して単独でチェックしてみるなどの方法があります。
投稿: SUDOTECK | 2010年6月19日 (土) 10時07分
いつも読ませていただき勉強させていただいております。
最近何度かI2Cでの通信を行っているのですが、Read時に書き込んだアドレスがそのまま返ってきてしまうデバイスがあり困っております・・・。
同じmasterより別デバイスはwrite、Read共に問題ないのですが。
何か思い当たることありますでしょうか?
投稿: | 2012年2月 2日 (木) 15時06分
まず確認して頂きたいのは、
1) デバイスを指定するアドレス書き込みに対しACKが帰って来ているか。
これがダメならアドレス違いか相手が悪い。
ACKがOKならば
2)アドレスがそのまま帰ってくる場合は、相手がアドレスを受け取ってから返事のデーターをセット出来ないうちにマスター側の読み込みのCLKが始まってしまっている可能性があります。高級?なデバイスはこのような場合自分でCLKを変化させて(LOWをキープする)データーが用意出来ていないことを知らせます。(CLKストレッチという)
デバイスのアドレスを送信した後、再度スタートコンディションを出して読み込みモードに入るまでの時間をDelayを入れる等して多めにとってみたらどうでしょう?
相手のデバイスはどんなデバイスですか?
投稿: SUDOTECK | 2012年2月 2日 (木) 22時05分
早急(遅くに)回答ありがとうございます。
1)デバイスアドレスのACKは返ってきます。(write、read共に)
2)デバイスアドレス(W)⇒コマンドアドレス⇒デバイスアドレス(R)⇒データ
の手順で行っています。
相手のデバイスは、デジタル照度近接センサです。(APDS-9900)
近接照度データ部分の読み込みはDelay関係あるかと思ったのですが、IDやRevが読み込めなかったので・・・。
早速Delay入れて確認してみます。
投稿: | 2012年2月 3日 (金) 13時07分
APDS-9900のデーターシート見ましたが、Standard mode では Set-up time for a repeated START condition .... min 4.7µS ってのが気になりますね。2度目の STARTコンディションに入るのに CLKを High にしてけっこう待ってから SDA をLOWにしないといけないみたいですね。
投稿: SUDOTECK | 2012年2月 3日 (金) 23時36分
I2Cのトラブルで検索していてここを読ませて頂きました。今ADT7410でレジスタのデータを読もうとしていますがレジスタ0以外のレジストをよんでも何故かレジスタ0の内容を読みます。
データシートの手続きどうりにしてますがレジスタ2からレジスタ12にアクセスできません。RasberryPiでも読めないようです。なにかヒントを教えて頂けませんか?
投稿: tak | 2013年12月31日 (火) 17時26分
takさんこんにちは
温度センサなので、まず
1) レジスタ0のデーターは正しいか?
気温と比べて正しいかどうかわかりますね。
ここが読めていれば大丈夫。
2) レジスタ1のデーターの読み方は?
Fig18のように連続で読んでいますか?
(連続とは間に STOP が入ったりしないこと)
データーシートによると、温度データーなど 16Bit のレジスタは連続2バイト読み出しでないと読めない様ですね。
2番目のデーターが同じように読めない場合、1回目の ADT7410への ACKの処理が悪い可能性があります。
読み込みの場合、1バイト読んだ後こちら側で ACKを出して次のデーターを要求します。何もしないと終了してしまいます。
明確に終わる場合は STOP コンディションを出します。
ライブラリを使っている場合などソフト的に問題ないと思われる場合はオシロスコープなどのハードに頼るしかないです。
3) 1個づつ読んでいる場合
Fig17のようにレジスタアドレスを指定して、1バイトだけ読む場合ですが、問題は2バイトめに送る P0〜P7のデーターです。この場合例えばステータスバイトの指定は 0x02 ですね。ここを変えてもダメなら、この指定が伝わっていないことです。
(1バイトのデーターは1バイト読み込み)
I2C の読み方は読むと自動的に内部レジスタをインクリメントするものもありますが、1バイトづつ読む場合はインクリメントしないのが普通です。Fig17の2バイト
書き込んですぐ読ように指定されていますね。fig17のFRAME3の最初のようにリピートスタートといって、FRAME2まで送った後に STOP を入れて終わるのでなく、リピートといって再度スタートコンデションを送ります。
このあたり同じように送っているか、間違いないか確認ください。
投稿: SUDOTECK | 2014年1月 1日 (水) 10時19分
お答え有難うございます。
レジスタ0はFig17のように連続して2byte読んでます。指で触るとこの値が上昇して離すと室温まで下がるので温度を読んでると思います。レジスタのIDをFig18のように読んでますがレジスタ0の値を読んでます。
2byte目のレジスタ値を書きこめないのはSrがよくないせいでしょうか?
他のデバイス(DS1337,DS3231など)では連続してデータを読めるのでなにかSrのタイミングが違うのでしょうか?
投稿: tak | 2014年1月 2日 (木) 12時52分
温度レジスタ0は読めている様ですが、同時に読んでいるレジスタ1も変化しますか?Bit7..3 が細かく変化していますか?
Fig18 と Fig17 の図の解釈が逆かも知れませんので、実際の通信データーで確認です。
温度データーのレジスタ0,1を読むには、連続2バイト読みが必要です。
スタートを[ST],ストップを[SP],
書き込みデーターを[W0x??]、リード時、相手にACK出す場合は [R0x??+A] 出さない場合は[R0x??]と書くことにします。A0=low.A1=Low のアドレス設定の場合。
レジスタ0,12バイト読み込みは
Fig18のように
[ST][W0x90][W0x00]
[ST][W0x91][R0x??+A][R0x??]
と3バイト送信、2バイト受信になります。最後はACKを返さなくて終了
IDレジスタを読む場合は
Fig17のように
[ST][W0x90][W0x0B]
[ST][W0x91][R0x??][SP]
と3バイト送信1バイト受信となります。
これらは途中で止まらず連続して送受します。このとおりですか?
I2C受信ルーチンは私の使っているpic 用の MPLAB IDEではライブラリ関数で
getsI2C(temp_buffer,2)
と2バイトと指定すればバッファに入ってくるので楽です。
自分で作っていた頃は受診後ACK を返すところがCLKのHigh/Low制御と関係してなかなか難しかったのですが、上記の点では1バイト読むには ACKを返す必要がないので、IDは問題なく読めるはずです。
レジスタ8,9を温度と同じように2バイト連続して読んでみたらどうなりますか?
それでまだ温度データーのようならば、2バイト目の書き込みがうまくいっていない様ですね。
このあたりのプログラムを送って頂ければチェック出来るかも知れません。コメントでの公開が不都合でしたら
sudoteck@gmail.com
までどうぞ。
投稿: SUDOTECK | 2014年1月 2日 (木) 17時13分
こんばんは
レジスタ0,1は変換して1秒間隔で表示させて温度変化みてるので間違いないと思います。
指摘された事に留意して再度コード見直してみます。
僕はForthで書いてるので多分ほとんどの人にはわからないと思います。
投稿: tak | 2014年1月 2日 (木) 21時52分
レジスタ1が読めていれば、1℃以下の変化が表示できるはずですので、ご確認ください。
Forth ですか..
30年前に Apple][で GraForth ってグラフィックメインの Forth いじってました。
中身は..もう忘れたかな...
投稿: SUDOTECK | 2014年1月 2日 (木) 22時01分
RepeatedStartをクロックストレッチ対応にしたらレジスタを全部読めました。ありがとうございました。
もう一つ質問なのですが
はじめにクロックを384kHzから100kHz,10kHz,1kHzと遅くした時はレジスタを読めませんでした。
単にクロックを遅くしたらクロックストレッチしないわけではないのですか?
今は384kHzでレジスタ読めてます。
投稿: tak | 2014年1月 4日 (土) 06時09分
原因はクロックストレッチでしたか。
CLK 端子の説明によく見ると clock-Outとも書いてありますね。
12個もレジスタがあると、アドレスのデコードが必要で、レジスタが決定されてから、送信バッファに転送する時間がかかるのでしょうね。(特に低消費電力のデバイスは内部動作クロックが低いのでしょう)
時間が足りないので、デフォルトのアドレス0の値のままになっていたのですね。
オシロで見ればどのくらいCLK 待たされているか判るのですが、処理が開始するのはアドレス確定後なので、結局最後のACKを出した後の時間ですから、1KHz時でも 1mS では足りなかったのでしょうね。
投稿: SUDOTECK | 2014年1月 4日 (土) 09時20分
おはようございます。訂正です。
クロックストレッチの部分を外してみてもレジスタを正常に読めました。
実はI2CデバイスのコマンドはForthに入ってるものを使ってたんですがsclはプルアップされてるのに出力ポートを使ってました。今回ついでにscl-hiはポートを入力にscl-loはloをポート出力に出すように修正しました。
これはどういう理由でレジスタ値を書きこめない事になるのでしょうか?
またクロックストレッチというのは1byte書き込みのACK(マスター <-- スレーブ)でもありえるのでしょうか?
投稿: tak | 2014年1月 4日 (土) 09時56分
CPU側SCLが出力ポート(CMOSでプッシュプル)タイプではHigh出力時にデバイスがCLKストレッチを行おうと LOWに引っ張った際に禍電流が流れて自己リセットしたのかもしれませんね。通常は出力ポートでも Open-Drainタイプで行うのでそのような問題は起きないでしょう。
1Byte 書き込みでも、前回の処理が終わっていないとありえます。EEPROM 書き込みなどは デバイスによってはバッファサイズを超えた場合に書き込み完了まで10mS程度かかる場合があります。16バイトまで連続して1バイトづつ書いて大丈夫なのに、17バイト目でエラーになるなんてことがあります。
投稿: SUDOTECK | 2014年1月 4日 (土) 10時23分
CPUの出力ポートはOpen-Drainじゃないので自己リセットかもしれません。
色々と勉強になりました。有難うございました。
投稿: | 2014年1月 4日 (土) 10時46分
I2C が悪いのかPWMがおかしいのかわからずネットを見てましたらこちらにたどり着きました。
問題なのはEEPROMからの音声品質が悪いので質問させてください。
マイコンはdspic30F4012です。8倍で動かしていますので80Mhzです。
音源は8ビット サンプリング周波数は8Khz キャリア周波数は12.5khz (PWMの周期です)I2Cは1Mbpsモードで動かしてみました。
PICのアウトプットコンペアPWMで動かしています。
オシロで波形を確認しますと確かにPWMしていますが、必ず5Vから0VへはPWMしますが(半周期)その後は5Vのままです。この平の部分のおかげで音声品質が悪いと思っています。マニュアルを見ますとデューティーがPWMのPRy(?)より大きくなると強制的にHになると書いてあったので、プログラムでレジスタをチェックしてデューティーがPRyより大きくなったら-1でかわしてみたところ、全部PWM波形になったのですが全然音にならず雑音だけになってしまいました。
多分セッティングが悪いのと思うのですが、さっぱりわからなくなりました。
さらに不思議なのはPWMの周期(タイマー2)はI2Cの転送速度に合わせたつもりですがオシロで見るとSCLの周期は(スタートコンディションから次のスタートコンディションまで)全然大きく、仕方ないので波形の長さを測ったところPWM周期6個分と分かりましたのでEEPROMのメモリーアクセスはPWM周期6回に1回にしたところだいぶ音は改善されました。でも半周期データはHのままです。
長々と書いてしまいすみません。
なにかアドバイスを頂けますでしょうか。
よろしくお願いします。
投稿: kiku | 2016年9月19日 (月) 12時18分
一度問題を切り分けた方が良いですね。
EEPROM のデーターをプログラム上の ROM として配列等で配置して、まずそれのデーターで問題無く正弦波など普通の波形がPWMで再生できるかを確認ください。
オシロがあるのでしたら波形を見て正常になるかは確認できるかと思います。
次に音声データーの読み込みですが、EEPROMから読み込む動作が遅延無く出来るかどうかですが,リアルタイムが難しそうなら一度バッファメモリーのようにEEPROMからRAMエリアに読み出して、順次使うなどの方法が採れるかと思います。
まず最初に PWM をきちんと動作させるのが要でしょう。
投稿: SUDOTECK | 2016年9月19日 (月) 13時18分
SUDOTECK様
早いレスありがとうございます。
正弦波の1周期分のデータを配列に入れてテストして見ますと全部PWMしました。
波形は汚いですが正弦波です。
そうなるとI2Cの取りこぼれ?
そもそも私のプログラムに無理があるのではと思えて仕方ないです。
それはEEPROMへのアクセスタイミンク"をタイマー2の周期で割り込みをかけ割り込みルーチンでI2CでEEPROMにアクセスしています。ほかのタイマーを使った方が良いのでしょうか。
いずれにしても質問に答えて頂きありがとうございました。
投稿: kiku | 2016年9月19日 (月) 14時07分
データーの取り込みの問題ならば、やはりデーターをバッファリングしたほうが良いですね。PWMデーター更新を割り込みでやっているならば、読み出しバッファ量が足りなくなったら(リングバッファなどで読み出しポインタが書き込みポインタに近くなったら)今のタイマー2割り込みで良いので連続して数バイトバッファに貯めるなどの手法が必要かと思います。 I2C は相手がありますので、いつも同じ速度で出来るとは限りません。余裕をもった読み出しが必要と思います。
投稿: SUDOTECK | 2016年9月19日 (月) 16時34分
SUDOTECK様
返事ありがとうございます。
残念ながら未だ解決出来ていません。とても不思議なのですが、
プログラム内の配列に初期値で正弦波データを入力した場合はPWMは連続します。(それでもおおよそ1.3sに一度すべて同じビットが一瞬並びます。)
main関数内部でタイマー2の割り込みを無視するフラグを立てて音声データの先読みを実行(最大1500バイト試しました)そのあと、フラグを下ろしてタイマー2の割り込みルーチンで先ほどの配列を呼び出しPWMデューティー値をセットしてみました。結果は最初と全く同じでした。オシロで見ますとやはり波形の下半分がギザギザとなりその後はHになるので急激に立ち上がります。その後Hのまま割り込みが3回分ぐらいでまたPWMしだすような感じとなります。
問題と思える部分をお見せします。
void _ISR _T2Interrupt(void)
//割り込み関数です。
{
IFS0bits.T2IF=0;
if(yomikomi==1){
if (dd<=490){
SetDCOC1PWM(sakiyomi[dd]);
dd=dd+1;
return;
}
dd=0;
return;
}
return;
}
//Main Function
int main(void) {
init_I2C();
//Setup OUtput Compare to PWM Mode
OpenOC1(OC_IDLE_CON & OC_TIMER2_SRC & OC_PWM_FAULT_PIN_DISABLE,0,0);
OpenTimer2(T2_ON & T2_GATE_OFF & T2_PS_1_1&T2_SOURCE_INT,160-1);
ConfigIntTimer2(T2_INT_PRIOR_1 & T2_INT_ON);
yomikomi =0;
//先読み部です。
for(t=0;t<=490;t++){
sakiyomi[t] =EEPROM_read_DOG(addd);
addd=addd+1;
}
yomikomi =1;
while(1){
}
部分的で申し訳ありません。
なにか致命的な間違えをやっているでしょうか?
何度もすみません。アドバイスをお願いします。
投稿: kiku | 2016年9月20日 (火) 21時12分
プログラム上ではおかしな所は無いですね。
EEPROMの先読みを init_I2C(); の直後にやれば、割り込み中の if(yomikomi==1){ は不用になり、少し処理が早くなりますね。
EEPROM上のデータが何かおかしいとしか考えられないですね。
例えば、EEPROMデータが unsigned でない signed 型で、0 の後の -1 が 0xFF になっていませんか?
あるいは、SetDCOC1PWM()には全ての8Bitデーターを渡しても大丈夫ですか?0 とか 0xFF が来るとおかしくなるとか..
そのくらいかな
投稿: SDOTECK | 2016年9月20日 (火) 21時32分
SUDOTECK様
解決しました!!
驚きでした。というか、自分の勉強不足、経験不足を強く感じました。
EEPROMの読込、SetDCOC1PWM()の変数はなぜかint型でした。
(ほとんど気にもしていませんでした。)
これをunsigned intにしてみたら全波PWMになりました。
もちろん、音声も改善しました。
この壁を乗り切ることができて本当に感謝です。
ありがとうございました。
投稿: kiku | 2016年9月20日 (火) 22時57分
よかったですね。PICのコンパイラはシリーズによって int char の変換も仕様が違がったりするので、まずは変換データーを確認してみるのが一番ですね。
投稿: SUDOTECK | 2016年9月21日 (水) 08時56分
初めまして。
picからイメージセンサのレジスタを制御して画像を取り込もうとしています。
電源を入れた直後はscl,sdaともにhighなのですが、pic18f45j10にプログラムを書き込むと両ピンともlowとなってしまいi2cができません。
アドバイスをいただけると幸いです。よろしくお願い致します。
投稿: beginner | 2020年1月24日 (金) 14時53分
beginnerさんこんにちは
書き込むとというと、動作させるとの意味ですね?
ポートの入出力設定 TRIS は入力になっていますか?
I2C 端子は基本入力設定のようです。
RC3 ...SCL1 , RC4...SDA1
を使うなら、
TRISC = 0x18 ; もしくは 設定後 TRISC |= 0x18 ;
で治りませんか?
投稿: SUDOTECK | 2020年1月24日 (金) 16時10分
迅速なご回答ありがとうございます。
左様でございます。
ご指摘の通りコンフィギュレーション設定を見直した所、書き込み後も両線共にhighとなりました。
しかし、実際にデータを1byte送るとSCLがlowとなってしまいます。その際、SDAはhighとなっております。
00,ff等いずれのデータでも試しましたが上記のような動作となってしまいます。
重ねての投稿となりますがよろしくお願い致します。
投稿: beginner | 2020年1月24日 (金) 17時29分
SCL が LOW になるのは、相手が Lowにしているのでしょうか?
相手が SCL を LOWにする場合は Clock ストレッチの場合ぐらいです。
オシロで見ているようでしたら、こちらが CLOCK を送り終えて9個目が終わった後にこちらが Hig ( Open 状態)にしているのに、相手が Lowにしている場合は、Highになるまで、こちらが待たないとなりません。
最初のアドレスを送るだけでもそうなりますか?
CLOCK と DATA のラインが間違っているとか?
こちらが LOWにしている場合は、相手のACK を見るために9個目のクロックが必要です。ライブラリで作っているなら、そのあたりは問題ない気がしますが。
投稿: SUDOTECK | 2020年1月24日 (金) 17時41分
I2C通信についてお尋ねします。2台の機器を接続して使う計画にしています。単体であればきちんと動作するのですが2台同時接続すると動作しません。波形を見るとひどい波形になっています。データ信号がLOWになっていない気がします。これは2台の機器のタイミングの問題でしょうか。
投稿: | 2020年9月22日 (火) 16時26分
2台使うという事は、片方がマスターでもう片方がスレーブということでしょうか?それともどちらもマスターになりうる動作ですか?
全く同じ機器でどちらもマスターになり得る通信の場合は、優先順位をきめないとぶつかってしまいます。単体では動作するという事は、PCか何かで実験すると上手くいくという事ですか?
ひどい波形というと、マスター同士でぶつかっているみたいですね。
投稿: SUDOTECK | 2020年9月22日 (火) 17時38分
お世話になります。早速、ご回答いただきありがとうございます。マイコン(マスター)にLCDとセンサーをI2Cで接続しています。LCDのみ接続、センサーのみ接続の単体ならプログラム通り動作します。両方を同時につないだ状態でプログラムを動作させると上手くいきません。BUS busy reinit のエラーが表示されます。何がおきているのでしょうか?
投稿: | 2020年9月23日 (水) 11時55分
いつも拝見させていただいております。ありがとうございます。
書き込み及び読み込みともに成功する時もあるのですが、2回に1回ほどDATAラインのみ0Vとなってしまい、書き込み及び読み込みができないといった不具合が生じております。
何かアドバイスを頂けないでしょうか。
投稿: | 2021年8月10日 (火) 15時55分
DATAラインが 0V となるのは、最後のCLOCKが伝わっていない可能性があります。もしくはこのコメントライン2020年1月24日にある、クロックストレッチが起きているかもしてません。そのあたりを確認ください。
データーを読む場合、コマンドを出してある程度時間が経たないと IC がデーターを準備出来ない場合があります。その場合、ICによっては本来は受信だけのクロックラインを自分でLOWレベルに引き延ばして時間をかせいでいる機能があります。この場合これを確認するのはライブラリが対応してないと難しいし、自分でクロックをソフトで出力している場合やハード的にクロックラインが出力状態だけの場合などは、最初のアドレスを含む命令の後ACK が帰ってきたら、そこでしばらく時間待ち(数 mS のループ処理)してから読み込んだりすると間に合う場合が多いです。
ライブラリで、I2Cのステータス( OK , 衝突,反応無し)が判ればそれに応じて OK 以外は一度 STOP を送って初期化して、再度次の時にアクセスするなどの工夫が必要です。オシロで見ることが出来ればクロックストレッチなどの状況は判りやすいかと思います。
投稿: SUDOTECK | 2021年8月10日 (火) 20時13分
いつもお世話になります 現在TIのCPUとPICを接続してTI側をマスターで動作させています
3つ問題があります
1.ライト
アドレスと1バイト目は正常なのに2バイト目が7クロック分しか出ない
(スレーブをつけても外しても同じ)
2.リード
データが化ける
2バイトしか読めない
以上で困っています。
EEPROMはリードライトできています
ちなみにリードライトともマスター TI側から見てです
EEPROMが読めているので悩んでいます
何か思い当たることがあればよろしくお願い申し上げます。
投稿: 自由 | 2022年6月23日 (木) 18時47分
ご質問見逃していました。
もう解決いたしましたか?
7クロック分しか出ないのはのは PICのほうですね?
PICのスレーブはやったことがないのですが、PIC側が2バイト目の最初のクロックを STOP コンデションかSTART コンデションかに勘違いしているのではないでしょうか?PIC側の1バイト目の ACK 返信が悪いとか?
投稿: SUDOTECK | 2023年12月31日 (日) 12時00分