気温データ・ロガーについて

いつもお世話になっております。

solと申します。

C-Firstという基板と「絵解き マイコンCプログラミング教科書」という教科書でマイコンの勉強をしています。

現在、以下の資料を参考に気温データ・ロガーを作成しております。

https://japan.renesasrulz.com/cafe_rene/f/002-2095199602/4975/cq

I2CでLCDと通信を試みているのですが、ACKが検出できず、困っています。

一方で、基板上の加速度センサや、リアル・タイム・クロックとは正常に通信ができており、ACKも検出できています。

 

そこで、(絵解き マイコンCプログラミング教科書のサポートページより入手可能な)気温データ・ロガーのサンプルプログラムを動かしてみたところ正常に動作したため、自分のプログラムと何が違うのか見比べてみたところ、サンプルプログラムはACKが受信できているかどうかを確認しておらず、ただ送り付けているだけだということに気づきました。

私のプログラムも同様にACKの確認をせず、ただ一方的に送り付ける形で送信してみたところ、LCDにきちんと文字列が表示され、動作しました。

ACKの受信が検出できない原因が分からないのですが、どのような理由が考えられるでしょうか。

ご回答よろしくお願いします。

  • LCDのバスドライブ能力が低いためだと考えられます。
    経験上、I2Cバスのプルアップが10kΩ以上は欲しいところです。
    しかし、そうすると通信速度を上げたり、複数デバイスを繋ぎにくくなります。

    このような場合、I2Cバスリピーター経由でつなぐような事が世間では行われています。(Raspberry Piでの対策として有名なようです)

    参考:
    akizukidenshi.com/.../goodsfaq.aspx
    strawberry-linux.com/.../619011

  • チョコです。
    >I2CでLCDと通信を試みているのですが、ACKが検出できず、困っています。

    >一方で、基板上の加速度センサや、リアル・タイム・クロックとは正常に通信ができており、ACKも検出できています。

    C-Firstでは、気温データ・ロガーはI2Cのレベル・コンバータを介して3.3Vロジックに変換したI2Cで接続するようになっています。オンボードのデバイスが正しくアクセスできており、気温データ・ロガーでLCDのACKが戻ってこないと言うことは、3.3V側のプルアップ抵抗(4.7kΩ)が小さすぎるようです。オシロがあれば、ACKのところでSDAが十分に下がりきっていないことが観測できるのはないかと思われます。
    Higetakaさんがコメントされているように、SDA信号だけでも抵抗を10kΩにでも交換してみてください。

    >サンプルプログラムはACKが受信できているかどうかを確認しておらず、

    これは、Arduinoのやり方を踏襲したからでしょう。Arduinoのスケッチは分かりやすくするためにエラー処理が手抜きされているようです。今回のLCDの場合には、ACKは必ず戻ってくるはずなので、無視しても悪影響はないと考えられます。
  • > Higetakaさん
    ご回答ありがとうございます。
    まず、I2Cバスになぜプルアップ抵抗が必要なのでしょうか。
    プルアップ抵抗を調べてみると、スイッチの説明が色々と載っており、スイッチについては必要性が分かったのですが、I2Cはスイッチではないので、なぜ必要なのかがイマイチ分かっていません…
    また、抵抗値に関して、(現在4.7kΩですが)なぜ10kΩの抵抗であればうまくいきそうなのでしょうか?
    さらにですが、プルアップ抵抗を10kΩとした場合、通信速度を上げたり、複数デバイスをつなぎにくくなるのはなぜなのでしょうか。

    あまりご負担のない範囲でご回答いただければ幸いです。
    よろしくお願いします。
  • > チョコさん
    いつもご回答いただき、ありがとうございます。
    プルアップ抵抗(4.7kΩ)が小さすぎるとのアドバイス、ありがとうございます。
    すぐには交換できませんが、またできるときに交換を試してみたいと思います!
  • チョコです。
    >まず、I2Cバスになぜプルアップ抵抗が必要なのでしょうか。

    I2Cバスはオープン・ドレイン出力でドライブするようなバスになっています。
    このようになっているのは、複数のマスタを接続して、複数のマスタのが同時にバスを使い始めようとしたときに信号がぶつかっても問題ないようにするために、ハイレベルをプルアップ抵抗で供給するようになっているからです。

     

    追記

    >また、抵抗値に関して、(現在4.7kΩですが)なぜ10kΩの抵抗であればうまくいきそうなのでしょうか?

    プルアップ抵抗値が小さいと、大きな電流を流さないと、ロウレベルにはできません。4.7kΩでは、500μA流したとすると、2.35Vの電圧降下になるので、3.3Vの電源電圧なら、0.95Vになります。ロウレベル入力電圧の閾値が0.2VDDなら0.66V以下でないとロウレベルと判断されず、ACKが検出できません。抵抗を10kΩにすると、264μA流せば、0.66Vになるので、ロウレベルと判断され、ACKが検出できます。

     

    >プルアップ抵抗を10kΩとした場合、通信速度を上げたり、複数デバイスをつなぎにくくなるのはなぜなのでしょうか。

    信号の立ち上がりはプルアップ抵抗でのI2Cバスの容量を充電することになり、抵抗値が大きいと、信号の立ち上がりがなまってしまい、タイミングが遅くなってしまいます。また、複数のデバイスが接続されると、リーク電流が大きくなり、ハイレベルを維持できなくなる可能性が出てきます。

  • チョコです。

    気になったので、NXP社のI2Cの仕様で電気的な特性を確認してみました。

    標準モードやファストモードでLOWレベル出力電流が、VOLが0.4Vでも3mA(最小)と規定されています。ファスト・モードでは、0.6Vで6mA(最小)と規定されています。

    この規格が満足されていれば、3.3Vで4.7kΩで全く問題ないはずです。

    にも拘わらず、4.7kΩをLOWレベルまでドライブできないということは、LCDモジュールのコントローラがI2Cの規格を満足できていないことになります。

    以前使った別のLCDモジュールでもI2Cバスのドライブ能力は低かったのですが、それでも3.3kΩで大丈夫でした。規格を満足しないだけでなく、その中でさらにバラつきがあることになります。そのためにデバイスのドライブ能力が明確にされていないのかもしれません。

    海外メーカのデバイスにはこういうことがよくあるようです。(それを使いこなすのがノウハウというのはおかしい気がします。何のための標準規格でしょう。)

    同じI2Cの仕様書に以下の記述もありました。

    かなり愚痴が出てしまいましたが、これがI2Cの実態かもしれません。

  • > チョコさん
    ご回答ありがとうございます。
    ずっとオープン・ドレイン出力が分からず、色々調べていましたが、
    www.picfun.com/midi2c02.html
    tool-lab.com/.../
    この二つのサイトを見て、なんとなくわかってきました。

    プルアップ抵抗値の意味も分かりました。

    ありがとうございました。
  • > チョコさん
    補足ですが、使用しているLCDモジュールのコントローラーは、恐らく strawberry-linux.com/.../ST7032i.pdf これだと思います。
    ドレイン-ソース間に流せる電流がどれなのか私にはよくわかりませんが、p.48 の Pull Up MOS Current がそれだとすると、30uA でよっぽど少ないので20kΩ以上必要なのでしょうか…?
  • チョコです。
    >p.48 の Pull Up MOS Current がそれだとすると、30uA でよっぽど少ないので20kΩ以上必要なのでしょうか…?
    おそらく違います。Pull Up MOS Currentから想像できるのは、内部のLCD制御回路のプルアップ用のPch-MOS-FETがあり、そこで流せる電流ではないかということです。
    もし、30μAなら、それで2.31V(3.3VのVDDの0.7倍)の電圧降下を発生させるには、77kΩの抵抗が必要です。20kΩでも全く不足です。(3mAの規格に対して30μAはあまりにもひどすぎますが。)
    もし、波形が確認できるなら、現状のプルアップ抵抗で何Vまで下がっているかを確認して、そこから電流を計算してそこから置き換える抵抗値を計算してみてください。
    波形が確認できないなら、抵抗を付けるところをソケットにして、抵抗を交換できるようにしてはどうでしょうか。
    それと、C-FirstのRL78IOlib_o.cを確認したのですが、SCLの設定がおかしいようです。solさんのプログラムでは、IICWL0とIICWH0の設定値はどうなっていますでしょうか。
  • > チョコさん
    内部のMOS-FETの話だったんですね。
    20kΩは、計算がおかしかったですね。

    波形はまた確認できるときに確認して、実際にどんな風になっているのかを見てみて、SDAが下がりきっていないのであれば、抵抗値を上げて試してみたいと思います!

    (ところで、以前、電源電圧5Vの波形を確認したところ、3.7V - 4.7V くらいの範囲(5Vになることはなかった)で揺れていましたが、今回の件に関係あるでしょうか)

    SCLの設定ですが、ユーザ・オプション・バイトの設定にて fCLK = 24MHz としているので、PRS0 = 1 として fMCK = fCLK/2 = 12MHz を選択しています。
    標準の 100kHz を通信クロックとしたいため、ハードウェア・マニュアルの 18.4.2 を参考に
    IICWL0 = (0.47 / 100000) * (24000000/2)
    IICWH0 = (0.53 / 100000 - 0) * (24000000/2)
    このように設定しています。
    IICWH0 の tR と tF の計算の仕方が分からず、暫定的に0としたところ、コード生成と(ほぼ)一致したためこれでやっていますが、正しいでしょうか…?