2つのマスタとのI2C通信について

お世話になります。

複数のマイコンを使ったI2C通信が実現できず、ご教授頂けないでしょうか。

現在3つのRL78/G14のR5F104PJを使いマスタを2つ、スレーブを1つとした形でI2C通信を実現しようとしています。

コードは自動生成でスレーブ側はIICA0とIICA1を生成し、マスタ側もシングルマスタでIICA0を生成しています。

大まかな処理としては連続してスレーブのデータをマスタに渡し、マスタが取得したデータに応じて各々で操作します。

送信データは最大700byteほどで、マスタが行う処理とコードはどちらも同じ内容です。

マスタ1つで単独の連続した送受信はそれぞれ実現できているようなのですが、2つで行うと実現できません。

最初の1回目はOKで、連続する2回目以降に片側がビジー状態となってしまいます。また、どのようなタイミングか不明ですが同時通信ができることがあります。データ数が少ないと再現しやすいです。

当初、単独にすると連続する通信が実現できるため、通信処理には問題なく、2つのスレーブが何かしら干渉しているのではと考えたのですが、それぞれ使用するクロック、データ・バスが異なるため影響はないようで、原因が分かりません。マスタとスレーブを逆にすることも考えているのですが、現構成でも実現できないか検討したいと思います。

これらの原因や、検証すべき内容などございましたらご教示頂けないでしょうか?よろしくお願いします。

  • チョコです。

    I2Cのちゃんとしたマルチマスタは、コード生成では対応できません。

    マルチマスタをきちんと実現するには、やはり、リソース管理や排他制御が必要でしょう。しかし、コード生成では対応できていません。

    なお、RL78/G13のサンプルコードに以下のものがあります。

    これを参考にされることをお勧めします。

  • KANさん、チョコさん、こんにちは。NoMaYです。

    これはマルチマスタ接続なのでしょうか?他に、1つのRL78/G14は2つI2Cスレーブのくちがあり、残り2つがマスタでそれぞれひとつずつそこに繋がっている、という接続のようにも受け取れるのですけれど。

  • チョコさん、NoMaYさん、ご確認頂きありがとうございます。

    難読な文章となり申し訳ございません。

    >1つのRL78/G14は2つI2Cスレーブのくちがあり、残り2つがマスタでそれぞれひとつずつそこに繋がっている

    NoMaYさんのご意見のようにスレーブの2つのくちにそれぞれマスタが繋がっている接続で、それぞれで独立した通信でマルチマスタとは別なのではないかと思っているのですが、同時に通信すると片方に影響が出る原因が分からないのです。

    ループで連続した通信において①1つのマスタ単独の通信の場合、②2つのマスタ同時通信で最初の一回目、③(タイミングによっては不可)データ数を少なくした場合(ex.700→20byte)、の3つの場合が通信できている状態です。

  • KANさん、チョコさん、こんにちは。NoMaYです。

    私は、以前、RL78 FreeRTOSのサンプルプログラムとして、RL78/G14 R5F104MLの2つあるIICAの片方をマスタにして残りの片方をスレーブにして同一マイコン上で通信させるものを作ってみたのですが、その時に、コード生成されたスレーブにパッチを当てないと(たしか高速クロック時に)うまく通信出来ませんでした。ちょっと今その時のことを思い返そうとしています。ヒントがありそうな気がしたからです。なお、パッチを当てたソースは以下にあります。([追記] すみません。行番号は将来ちょっとズレるかも。パッチが将来まったく別物に変わる可能性もあります。)

    github.com/NoMaY-jp/FreeRTOS_examples_for_Renesas_R_CPUs/blob/main/43_I2C_1Mbps_Advanced/RL78_RL78G14_FPB_Renesas_e2studio_CS%2B/src/r_cg_serial_user.c#L84
     

  • チョコです。

    申し訳ございませんでした。歯医者に飛び込みでかかろうとして慌てていたので、最初の部分しか読まないでコメントしてしまいました。

    スレーブ・チャネルは基本的に独立したハードウェアなので、干渉することは考えられません。一つ気になるのは、通信完了の確認処理をどのようにしているのでしょうか。コード生成では通信完了は割り込みの中でコールバック処理を呼ぶようになっているだけです。コールバックの中身はユーザ任せになっているので、そこがバッティングしてはいないかです。2つのスレーブ・チャネルで割り込みの優先順位はどうなっているか、割り込み処理でのレジスタバンクはどうなっているかも気にはなるところです。

    よろしければ、スレーブ処理のプロジェクトのI2Cバス関係のプログラム部分をアップしてもらうことはできないでしょうか。

  • NoMaYさん、ヒントありがとうございます。似たような現象のため効果があるかもしれません。

    コード生成した上に変更が必要だとは考えていなかったので参考にさせていただき、挙動を確認したいと思います。

  • チョコさん、歯医者だったんですね笑。お忙しい中ご確認頂けるだけでも大変助かっています。こちらも紛らわしい題で申し訳ありませんでした。

    確かにスレーブはマスタと違ってそれぞれの通信を扱うため、スレーブ側の処理に問題があるかもしれません。割り込みの優先順位はどちらも「低」です。プログラムについては段取りを整えてまたご相談させてください。よろしくお願いします。

  • KAN_i2c.zip

    チョコさん

    お世話になっております。KANです。

    先日のプログラムですが段取りができたため添付させていただきます。

    内容はi2c関連のファイルとして、r_main.c、r_cg_serial.c、r_cg_serial_user.c、です。開発環境は古いですがCA,CXを使用しております。i2cに関係しない通信箇所は削除していますが、不要な変数等残っているかもしれません。予めご了承ください。

    内容をご確認いただき、修正や変更箇所がございましたらご教示いただければ幸いです。どうぞよろしくお願いします。

  • チョコです。

    まだ、さっと眺めている段階ですが、スレーブの受信完了のコールバック処理で、結構処理をやられているようですが、そこは割り込み処理の中での処理です。この処理中にはほかの割り込みは受け付けられなくなるのですが、問題にはならないのでしょうか。

  • チョコさん

    お世話になっております。KANです。

    ご確認頂きありがとうございます。確かに割り込みの中でマスタ側に返すデータのセットと送信を行っているため、データ数が大きく、どこか他に影響があるかもしれません。割り込みの処理時間は700byteで750μSecほどかかっていました。マスタ同士の割り込み処理のタイミングも影響しているかもしれません。

    初心者質問ですみませんが、両方の割り込みタイミングが一緒になった場合、どっちかが先に処理されるのでしょうか?また、現方法でマスタとの通信処理はコード上、他に問題はないでしょうか?

  • チョコです。

    >両方の割り込みタイミングが一緒になった場合、どっちかが先に処理されるのでしょうか?

    全く同時で、なおかつ割り込み優先順位が同じ(この場合は低)で、ともにマスクされていない場合には、ディフォルト・プライオリティで決まります。

    ディフォルト・プライオリティはハードウェア マニュアルの「表21 - 1 割り込み要因一覧」の左から2番目に書かれています。

    IICA0はディフォルト・プライオリティが17で、IICA1は43になっているので、同時ならIICA0が受け付けられます。

    >また、現方法でマスタとの通信処理はコード上、他に問題はないでしょうか?

    main関数のwhileループでReceive_Send_IICA0(0U);とReceive_Send_IICA1(0U);を交互に呼び出しているようですが、それぞれの中では、受信完了を待ってループしているようです。片方の受信待ちでループしていると、反対側はその間は無視されます。それでいいのでしょうか?

    NoMaYさんのスレッドにありましたが、現在のタイミングでr_iica0_callback_slave_receiveendを処理すると、その間に受信完了の9クロック目の割り込みが発生しますが、それは問題ないのでしょうか。

    以上です。

  • チョコさん

    ご回答ありがとうございます。また、ご返信が遅くなり申し訳ありません。

    頂いた内容を参考にさせて頂き、調整して期待する動作となることができましたので次の通りご報告いたします。

    >Receive_Send_IICA0(0U);とReceive_Send_IICA1(0U);を交互に呼び出している

    >現在のタイミングでr_iica0_callback_slave_receiveendを処理すると、その間に受信完了の9クロック目の割り込みが発生

    上記2点で通信の順番、割り込みのタイミング、データの量と波形など検討していたところ、通信は必ずマスタ2がバスのビジーで落ちていることが分かりました。マスタの方で無理やり送信リトライなど出来ればいいのではないかと考えたところ「LRELn」という通信退避があることを知り、マスタの送信で使えないか試したのですがうまくいかず。。スレーブ側では使っていなかったか確認したところReceive_Send_IICA0(0U);とReceive_Send_IICA1(0U);の以下の場面で使用していることを確認。

    if (byInit)
    {
        memset(g_iica1_rx_buffer, 0, sizeof g_iica1_rx_buffer);
        g_iica1_rx_end = FALSE;
        R_IICA1_Slave_Receive(&g_iica1_rx_buffer[0], 4);
        return;
    }

    if (g_iica1_rx_end)
    {
        g_iica1_rx_end = FALSE;
        while ((FALSE == g_iica1_tx_end) || (1U != g_iica1_slave_status_flag))
        {
            HALT();
        }
        //LREL1 = 1;
        R_IICA1_Slave_Receive(&g_iica1_rx_buffer[0], 4U);
    }

    今回の処理では不要ではないかと思い、コメントアウトしたところ期待していた通信を行うようになりました。2つのマスタで片側の通信だけに影響を与えていた原因はよくわかりませんが、割り込みのタイミングとACKやトリガーなどのフラグが何かしら互いに影響していた?のではないかと思います。また、本コードはサンプルプログラムを参考に作成したものですが何故この様な位置で設定しているのか不明で、他の箇所に別の影響があるかもしれないので、もう少し調査していきたいと思います。

  • チョコです。

    >「LRELn」という通信退避があることを知り、マスタの送信で使えないか試したのですがうまくいかず。
    LRELnはスレーブが自局に関係ない通信から抜ける場合に使用するもので、シングルマスタのバスのマスタでは使うことはありません。これを使用した状態からの復帰はストップ・コンディション検出した(他のマスタがバスを話したので使用可能になった)ときか、他のマスタからスレーブとして選択された時だけですね。

    >今回の処理では不要ではないかと思い、コメントアウトしたところ期待していた通信を行うようになりました。
    そうですか。r_iica0_callback_slave_receiveendの最後でR_IICA0_Slave_Send(&bySendData[0], wLength);で送信を起動していたんですね。
    これがLRELで打ち消されていたわけですか。

    以上