SDOTECK HOME

  • ご参考になりましたか?
    SDOTECKブログでは、みなさんからのフィードバックをお待ちしています。 説明が解らなかったり、もっと詳しく解説してほしいポイント・テーマがありましたら、お気軽にsudoteck@gmail.com までメールくださるか、記事にコメントして下さい。
  • -

RF PowerAMP なら

  • RF AMP DESIGN

HEX calc pro 1.00

  • HEX calc pro ver1.00
    エンジニア向けの16進と浮動小数点を混在して入力出来る計算機 。 Version 1.00 高機能な 16進電卓や科学計算電卓はありますが、いちいちモードを切り替えなければならず、最大の問題は16進数と小数点値を同時に使用出来ないことです。
    詳しい説明はここ
    iTunes ではここまで

ATT calc

  • ATT calc ver2.00
    iPhone 用 RF アッテネーター計算ソフトです。  RF開発エンジニアに必要な、 dBm - W 換算機能をはじめ、π型やT型の ATTを 設計する上で、必要な dB値から抵抗値を算出する機能と、 E24系列の抵抗値を 使用したときの減衰量(dB)と整合インピーダンス(Ω) が表示されますので、どの 抵抗値の組み合わせがよいか検討できます。  また、正確な値を必要とする場合に2個のE24系列抵抗を並列接続して理想の値を 求める計算機能も持っています。  操作はピッカーホイールを回すだけですので、実験中でも片手で簡単に操作 できます。

FIL Calc

  •  LPF 計算機
    RFエンジニア向けフィルター計算ソフト LPFやHPFの設計をするときに、いちいちパソコンを起動してフィルタを設計、結果をプリントアウトして、実験室に行ってネットワークアナライザで測定・実験、ちょっと修正したい時にまたパソコンの所にもどって、再計算...というのが結構面倒で、手軽にiPhone で計算できるといいいなと思って作りました。

iPhone APP

  • ATT calc ver2.00
    SDOTECK が開発した iPhone APP の紹介です。 NEWS---SWRproリリース

Amazon

  • AMAZON Books

RAKUTEN

  • RAKUTEN

mujic.jp

  • music.jp
    music.jp

サイト内検索には?

  • -------------------------------
    ◆下の検索機能でこのブログのすべての関連項目を検索出来ます。是非使ってみて下さい。
サイト内検索
ココログ最強検索 by 暴想

SCHEMATICS

BOSE

  • BOSE
    クワイアットコンフォート20
無料ブログはココログ

Google

  • Google

« RFパワーアンプのはなし | トップページ | ECLのはなし »

2010年4月23日 (金)

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でまだ動かないならば、オシロスコープが必要ですね。
I2c3最初の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 まで送受してみましょう
 また、アドレスを変えて反応が無くなることも確認して、デバイスが壊れた時の対応のチェックもしましょう。

参考書----------------------------------------------------

« RFパワーアンプのはなし | トップページ | ECLのはなし »

トラブル対策」カテゴリの記事

コメント

こんにちは。大変参考になります。

> デバイスからのACKのLowが電圧が完全に0Vにならないなど、送る側のLow電圧も高い場合、プルアップ抵抗が小さすぎるとか、デバイスの電源電圧の違いとかチェックしましょう。

送る側の Low 電圧はちゃんとゼロだけど、デバイスからの ACK の Low 電圧が完全にゼロにならない場合、どのような原因が考えられますでしょうか?

デバイスによっては出力電流が大きく取れず、完全にはゼロにならない場合があるかと思いますが、出力ポートがCMOSならば 0.1V以下、トランジスタだったら、大きくてもLow電圧は 0.3V以下ならば問題ありません、それ以上ありますか? プルアップ抵抗が1KΩ以上で使っていて動作しない場合は、デバイスの電源電圧、GND端子接続などをチェックする、他にI2Cデーターラインにデバイスが付いている場合はそれを外して単独でチェックしてみるなどの方法があります。

いつも読ませていただき勉強させていただいております。

最近何度かI2Cでの通信を行っているのですが、Read時に書き込んだアドレスがそのまま返ってきてしまうデバイスがあり困っております・・・。

同じmasterより別デバイスはwrite、Read共に問題ないのですが。

何か思い当たることありますでしょうか?


まず確認して頂きたいのは、
1) デバイスを指定するアドレス書き込みに対しACKが帰って来ているか。
これがダメならアドレス違いか相手が悪い。
ACKがOKならば
2)アドレスがそのまま帰ってくる場合は、相手がアドレスを受け取ってから返事のデーターをセット出来ないうちにマスター側の読み込みのCLKが始まってしまっている可能性があります。高級?なデバイスはこのような場合自分でCLKを変化させて(LOWをキープする)データーが用意出来ていないことを知らせます。(CLKストレッチという)
デバイスのアドレスを送信した後、再度スタートコンディションを出して読み込みモードに入るまでの時間をDelayを入れる等して多めにとってみたらどうでしょう?
相手のデバイスはどんなデバイスですか?

早急(遅くに)回答ありがとうございます。
1)デバイスアドレスのACKは返ってきます。(write、read共に)

2)デバイスアドレス(W)⇒コマンドアドレス⇒デバイスアドレス(R)⇒データ
の手順で行っています。
相手のデバイスは、デジタル照度近接センサです。(APDS-9900)
近接照度データ部分の読み込みはDelay関係あるかと思ったのですが、IDやRevが読み込めなかったので・・・。
早速Delay入れて確認してみます。

APDS-9900のデーターシート見ましたが、Standard mode では Set-up time for a repeated START condition .... min 4.7µS ってのが気になりますね。2度目の STARTコンディションに入るのに CLKを High にしてけっこう待ってから SDA をLOWにしないといけないみたいですね。

I2Cのトラブルで検索していてここを読ませて頂きました。今ADT7410でレジスタのデータを読もうとしていますがレジスタ0以外のレジストをよんでも何故かレジスタ0の内容を読みます。
データシートの手続きどうりにしてますがレジスタ2からレジスタ12にアクセスできません。RasberryPiでも読めないようです。なにかヒントを教えて頂けませんか?

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 を入れて終わるのでなく、リピートといって再度スタートコンデションを送ります。
このあたり同じように送っているか、間違いないか確認ください。

お答え有難うございます。
レジスタ0はFig17のように連続して2byte読んでます。指で触るとこの値が上昇して離すと室温まで下がるので温度を読んでると思います。レジスタのIDをFig18のように読んでますがレジスタ0の値を読んでます。
2byte目のレジスタ値を書きこめないのはSrがよくないせいでしょうか?
他のデバイス(DS1337,DS3231など)では連続してデータを読めるのでなにかSrのタイミングが違うのでしょうか?

温度レジスタ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
までどうぞ。

こんばんは
レジスタ0,1は変換して1秒間隔で表示させて温度変化みてるので間違いないと思います。
指摘された事に留意して再度コード見直してみます。
僕はForthで書いてるので多分ほとんどの人にはわからないと思います。

レジスタ1が読めていれば、1℃以下の変化が表示できるはずですので、ご確認ください。
Forth ですか..
30年前に Apple][で GraForth ってグラフィックメインの Forth いじってました。
中身は..もう忘れたかな...

RepeatedStartをクロックストレッチ対応にしたらレジスタを全部読めました。ありがとうございました。
もう一つ質問なのですが
はじめにクロックを384kHzから100kHz,10kHz,1kHzと遅くした時はレジスタを読めませんでした。
単にクロックを遅くしたらクロックストレッチしないわけではないのですか?

今は384kHzでレジスタ読めてます。

原因はクロックストレッチでしたか。
CLK 端子の説明によく見ると clock-Outとも書いてありますね。
12個もレジスタがあると、アドレスのデコードが必要で、レジスタが決定されてから、送信バッファに転送する時間がかかるのでしょうね。(特に低消費電力のデバイスは内部動作クロックが低いのでしょう)
時間が足りないので、デフォルトのアドレス0の値のままになっていたのですね。
オシロで見ればどのくらいCLK 待たされているか判るのですが、処理が開始するのはアドレス確定後なので、結局最後のACKを出した後の時間ですから、1KHz時でも 1mS では足りなかったのでしょうね。

おはようございます。訂正です。
クロックストレッチの部分を外してみてもレジスタを正常に読めました。
実はI2CデバイスのコマンドはForthに入ってるものを使ってたんですがsclはプルアップされてるのに出力ポートを使ってました。今回ついでにscl-hiはポートを入力にscl-loはloをポート出力に出すように修正しました。
これはどういう理由でレジスタ値を書きこめない事になるのでしょうか?

またクロックストレッチというのは1byte書き込みのACK(マスター <-- スレーブ)でもありえるのでしょうか?

CPU側SCLが出力ポート(CMOSでプッシュプル)タイプではHigh出力時にデバイスがCLKストレッチを行おうと LOWに引っ張った際に禍電流が流れて自己リセットしたのかもしれませんね。通常は出力ポートでも Open-Drainタイプで行うのでそのような問題は起きないでしょう。
1Byte 書き込みでも、前回の処理が終わっていないとありえます。EEPROM 書き込みなどは デバイスによってはバッファサイズを超えた場合に書き込み完了まで10mS程度かかる場合があります。16バイトまで連続して1バイトづつ書いて大丈夫なのに、17バイト目でエラーになるなんてことがあります。

CPUの出力ポートはOpen-Drainじゃないので自己リセットかもしれません。
色々と勉強になりました。有難うございました。

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のままです。
長々と書いてしまいすみません。
なにかアドバイスを頂けますでしょうか。
よろしくお願いします。

一度問題を切り分けた方が良いですね。
 EEPROM のデーターをプログラム上の ROM として配列等で配置して、まずそれのデーターで問題無く正弦波など普通の波形がPWMで再生できるかを確認ください。
 オシロがあるのでしたら波形を見て正常になるかは確認できるかと思います。
 次に音声データーの読み込みですが、EEPROMから読み込む動作が遅延無く出来るかどうかですが,リアルタイムが難しそうなら一度バッファメモリーのようにEEPROMからRAMエリアに読み出して、順次使うなどの方法が採れるかと思います。
 まず最初に PWM をきちんと動作させるのが要でしょう。

SUDOTECK様
早いレスありがとうございます。
正弦波の1周期分のデータを配列に入れてテストして見ますと全部PWMしました。
波形は汚いですが正弦波です。
そうなるとI2Cの取りこぼれ?
そもそも私のプログラムに無理があるのではと思えて仕方ないです。
それはEEPROMへのアクセスタイミンク"をタイマー2の周期で割り込みをかけ割り込みルーチンでI2CでEEPROMにアクセスしています。ほかのタイマーを使った方が良いのでしょうか。
いずれにしても質問に答えて頂きありがとうございました。

データーの取り込みの問題ならば、やはりデーターをバッファリングしたほうが良いですね。PWMデーター更新を割り込みでやっているならば、読み出しバッファ量が足りなくなったら(リングバッファなどで読み出しポインタが書き込みポインタに近くなったら)今のタイマー2割り込みで良いので連続して数バイトバッファに貯めるなどの手法が必要かと思います。 I2C は相手がありますので、いつも同じ速度で出来るとは限りません。余裕をもった読み出しが必要と思います。

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){

部分的で申し訳ありません。
なにか致命的な間違えをやっているでしょうか?
何度もすみません。アドバイスをお願いします。

プログラム上ではおかしな所は無いですね。
EEPROMの先読みを init_I2C(); の直後にやれば、割り込み中の if(yomikomi==1){ は不用になり、少し処理が早くなりますね。
EEPROM上のデータが何かおかしいとしか考えられないですね。
例えば、EEPROMデータが unsigned でない signed 型で、0 の後の -1 が 0xFF になっていませんか?
あるいは、SetDCOC1PWM()には全ての8Bitデーターを渡しても大丈夫ですか?0 とか 0xFF が来るとおかしくなるとか..
そのくらいかな

SUDOTECK様
解決しました!!

驚きでした。というか、自分の勉強不足、経験不足を強く感じました。
EEPROMの読込、SetDCOC1PWM()の変数はなぜかint型でした。
(ほとんど気にもしていませんでした。)
これをunsigned intにしてみたら全波PWMになりました。
もちろん、音声も改善しました。
この壁を乗り切ることができて本当に感謝です。
ありがとうございました。

よかったですね。PICのコンパイラはシリーズによって int char の変換も仕様が違がったりするので、まずは変換データーを確認してみるのが一番ですね。

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/556493/48158484

この記事へのトラックバック一覧です: I2Cのトラブルのはなし:

« RFパワーアンプのはなし | トップページ | ECLのはなし »