I2Cバスビジー状態になる時がある(RX231/CS+/Config_RIIC0)

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

下記の現象についてご教授ください。

 

【発生現象】

スマートコンフィグレータで生成したConfig_RIIC0でマスターからの送受信をした際にかなり頻度で

送信時に★バスビジー状態となる現象が発生します。

尚、★時にICSR2のSTARTビットをみても0で、Step実行で実行する限りは発生しません。

 

MD_STATUS R_Config_RIIC0_Master_Send(uint16_t adr, uint8_t * const tx_buf, uint16_t tx_num)
{
        :

if (1U == RIIC0.ICCR2.BIT.BBSY)
{
   status = MD_ERROR1;                     ★

 

 

【発生環境】

・CS+

・スマートコンフィグレータ生成のConfig_RIIC0

・SCLは200kHz

・SDA/SCL波形をみる限りBBSYフラグ=1条件であるスタートコンディションおよびIICRST発生はみられません。

・割込要因はALI/STI/SPI/NAKI

※生成された割込ハンドラはr_Config_RIIC0_error_interrupt()/r_Config_RIIC0_transmit_interrupt()/r_Config_RIIC0_transmitend_interrupt()/r_Config_RIIC0_receive_interrupt()

 

【ご質問】

Q1:

waitで回避する事は可能ですが、どの関数にいれるべきか?(割込ハンドラにwaitなどいれたくないのが本音です)

頭を悩ませております。

 

Q2:

他に何をどうやって確認すればよいのか、お恥ずかしながらわかりません。

(http://japan.renesasrulz.com/cafe_rene/f/forum11/1425/r5f61644a-h8sx-iic-busy#pi4368=3

 は拝見しましたがノイズがのってる訳ではないので、同じ現象ではないように思えます)

Parents
  • bunbunさん、こんにちは。NoMaYです。

    この場合、(私なら、) どれか空いているポートを使って、オシロの波形のどこで以下のif文の条件が成立してしまうのか、それを確認したいかな、と思います。

    if (1U == RIIC0.ICCR2.BIT.BBSY)
    {
       この位置で、どれかのポートを0出力→1出力に変化させ、オシロのSCL/SDAの波形と一緒に観測してみる
       status = MD_ERROR1;                     ★

     

  • NoMaYさん、こんにちは。
    いつもお世話になっております。

    現在、2CHオシロしかない為、3CHオシロが借用でき次第試してみます!!
    いつもいつもご教授ありがとうございます。
  • bunbunさん、こんにちは。NoMaYです。

    3CHがなかなか借用出来ないようであれば、2CHで、くだんのポート出力とSCLの2つでも何かしら分かるかもしれないです。あまり、先のことを書いても最初の状況からして既に想定外だったということもあるかとは思われますが、今、私の頭の中に浮かんでいることを書いておきます。

    (1) if文の条件が成立している箇所が、それこそ通信真っ最中の箇所だった場合
    ⇒ bunbunさんのプログラム内に待ち時間の見積もりを間違えた箇所があるのでは?という可能性が気になります

    (2) stop conditionが生成されたあたりで発生していた場合

    ⇒ (2-1) bunbunさんのプログラム内にぎりぎりで待ち時間の見積もりが足りてなかった箇所がある可能性
    ⇒ (2-1-1) 本来は「見積もる」という大まかな方法では無くてコールバック関数内で通信完了フラグを立ててそれを見て判断する

    (3) 上記の(2-1-1)の通信完了フラグを立ててそれを見て判断することをしていた場合

    ⇒  RX231のRIIC0のハードウェア&RXスマートコンフィグレータの生成コードのあるべき状況としては、通信完了のコールバック関数が呼ばれた時点で、既にBBSYは1→0に変化した後であるべきだと思われるが、そうなっているかどうか?

    (3-1) 通信完了のコールバック関数が呼ばれた時点で、まだBBSYは 1 のままである場合
    ⇒ RX231のRIIC0のハードウェアが誤判定している? or RXスマートコンフィグレータの生成コードに何か足りない?

    (3-2) 通信完了のコールバック関数が呼ばれた時点で、既にBBSYは1→0に変化した後である場合
    ⇒ う~ん、、、と考え込みます、、、

Reply
  • bunbunさん、こんにちは。NoMaYです。

    3CHがなかなか借用出来ないようであれば、2CHで、くだんのポート出力とSCLの2つでも何かしら分かるかもしれないです。あまり、先のことを書いても最初の状況からして既に想定外だったということもあるかとは思われますが、今、私の頭の中に浮かんでいることを書いておきます。

    (1) if文の条件が成立している箇所が、それこそ通信真っ最中の箇所だった場合
    ⇒ bunbunさんのプログラム内に待ち時間の見積もりを間違えた箇所があるのでは?という可能性が気になります

    (2) stop conditionが生成されたあたりで発生していた場合

    ⇒ (2-1) bunbunさんのプログラム内にぎりぎりで待ち時間の見積もりが足りてなかった箇所がある可能性
    ⇒ (2-1-1) 本来は「見積もる」という大まかな方法では無くてコールバック関数内で通信完了フラグを立ててそれを見て判断する

    (3) 上記の(2-1-1)の通信完了フラグを立ててそれを見て判断することをしていた場合

    ⇒  RX231のRIIC0のハードウェア&RXスマートコンフィグレータの生成コードのあるべき状況としては、通信完了のコールバック関数が呼ばれた時点で、既にBBSYは1→0に変化した後であるべきだと思われるが、そうなっているかどうか?

    (3-1) 通信完了のコールバック関数が呼ばれた時点で、まだBBSYは 1 のままである場合
    ⇒ RX231のRIIC0のハードウェアが誤判定している? or RXスマートコンフィグレータの生成コードに何か足りない?

    (3-2) 通信完了のコールバック関数が呼ばれた時点で、既にBBSYは1→0に変化した後である場合
    ⇒ う~ん、、、と考え込みます、、、

Children
  • NoMaYさん、こんにちは。

    ご教授有難うございます。

    >3CHがなかなか借用出来ないようであれば、2CHで、くだんのポート出力とSCLの2つでも何かしら分かるかもし>れないです。あまり、先のことを書いても最初の状況からして既に想定外だったということもあるかとは思わ>れますが、今、私の頭の中に浮かんでいることを書いておきます。

    借用できない場合も考慮して頂きありがとうございます。

    2CHでやっても意味ないかと思いましたが後程トライしてみます(案の定、当面3CHは使えそうもないので自前で購入しようかとおもってました。。)

    >(1) if文の条件が成立している箇所が、それこそ通信真っ最中の箇所だった場合

    >⇒ bunbunさんのプログラム内に待ち時間の見積もりを間違えた箇所があるのでは?という可能性が気になりま>す

    >(2) stop conditionが生成されたあたりで発生していた場合

    >⇒ (2-1) bunbunさんのプログラム内にぎりぎりで待ち時間の見積もりが足りてなかった箇所がある可能性

    スマートコンフィグレータで生成したI2C APIを使用している為、自分で待ち時間を設定、追加等はしておりません。

    >⇒ (2-1-1) 本来は「見積もる」という大まかな方法では無くてコールバック関数内で通信完了フラグを立ててそれを見て判断する

    自動生成されたコードでその辺が自己完結が一応されているコードとなっております。

    ④でnop()を4回ほどコールしてみましたが挙動はかわりませんでした。(4つでは足りないとは思いますが)

    R_Config_RIIC0_Master_Send()

    {

                                  :

           /* Issue a start condition */

           R_Config_RIIC0_IIC_StartCondition();                                                                                  ①

           /* Set flag for generating stop condition when transmission finishes */

           g_riic0_stop_generation = 1;

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    static void r_Config_RIIC0_transmitend_interrupt(void)

    {

       if (_06_IIC_MASTER_SENDS_END == g_riic0_state)

       {

           if (1U == g_riic0_stop_generation)

           {

               RIIC0.ICSR2.BIT.STOP = 0U;

               RIIC0.ICCR2.BIT.SP = 1U;                                                                                                          ②

               g_riic0_state = _07_IIC_MASTER_SENDS_STOP;

           }

           else

           {

               RIIC0.ICSR2.BIT.TEND = 0U;

               r_Config_RIIC0_callback_transmitend();               ③

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    static void r_Config_RIIC0_callback_transmitend(void)

    {

       /* Start user code for r_Config_RIIC0_callback_transmitend. Do not edit comment generated here */

       /* End user code. Do not edit comment generated here */          ④ 

    }

     

    >(3) 上記の(2-1-1)の通信完了フラグを立ててそれを見て判断することをしていた場合

    >⇒  RX231のRIIC0のハードウェア&RXスマートコンフィグレータの生成コードのあるべき状況としては、通信

    >完了のコールバック関数が呼ばれた時点で、既にBBSYは1→0に変化した後であるべきだと思われるが、そうな

    >っているかどうか?

     

    コールバック関数r_Config_RIIC0_callback_transmitend()内、上記を確認してみます。

     

    >(3-1) 通信完了のコールバック関数が呼ばれた時点で、まだBBSYは 1 のままである場合

    >⇒ RX231のRIIC0のハードウェアが誤判定している? or RXスマートコンフィグレータの生成コードに何か

    >足りない?

     

    RIIC0コンポーネントの設定は以下としております。

     

    >(3-2) 通信完了のコールバック関数が呼ばれた時点で、既にBBSYは1→0に変化した後である場合

    >⇒ う~ん、、、と考え込みます、、、

     

    いずれにしろ、上記を確認後、ご報告させて頂きます。

    色々、ありがとうございます。

  • とりあえずの結果、ご報告です

     

    >>2CHでやっても意味ないかと思いましたが後程トライしてみます(案の定、当面3CHは使えそうもないので自前で購入しようかとおもってました。。)

    >>(3) 上記の(2-1-1)の通信完了フラグを立ててそれを見て判断することをしていた場合

    >>⇒  RX231のRIIC0のハードウェア&RXスマートコンフィグレータの生成コードのあるべき状況としては、通信

    >>完了のコールバック関数が呼ばれた時点で、既にBBSYは1→0に変化した後であるべきだと思われるが、そうな

    >>っているかどうか?

    >コールバック関数r_Config_RIIC0_callback_transmitend()内、上記を確認してみます。

     

    異常は特にみられませんがこの波形は次の送信データを送信する際の一発目のクロック(スタートコンディション)発行時なので、1つ前の送信終了があやしそうです。

    またコールバック関数r_Config_RIIC0_callback_transmitend()ではBBSYフラグはたっておりました。(STAR/STOPビットは0)

     

     

  • bunbunさん、こんにちは。NoMaYです。

    > 1つ前の送信終了があやしそうです。

    そのようですね。(1つ前の送信終了というより、このスタートコンディションを生成したR_Config_RIIC0_Master_Send()による送信が完了するよりも前に、というかこのスタートコンディションを 生成した)R_Config_RIIC0_Master_Send()を呼び出したすぐ後にもう次のR_Config_RIIC0_Master_Send()を呼び出してしまっている箇所があって、この後者の呼び出し時にBBSYフラグチェックでエラーになっている感じですかね。

    > またコールバック関数r_Config_RIIC0_callback_transmitend()ではBBSYフラグはたっておりました。(STAR/STOPビットは0)

    う~ん、そうでしたか、、、何だろう、、、

  • bunbunさん、こんにちは。NoMaYです。

    > RIIC0コンポーネントの設定は以下としております。

    ビットレートを10kbps→200kbpsとした箇所以外はRXスマートコンフィグレータのConfig_RIIC0のデフォルトと同じ設定ですね。

    > またコールバック関数r_Config_RIIC0_callback_transmitend()ではBBSYフラグはたっておりました。(STAR/STOPビットは0)

    これから推測されるトラブルの可能性は、r_Config_RIIC0_callback_transmitend()で次のR_Config_RIIC0_Master_Send()を呼び出してもBBSYフラグチェックでエラーになってしまう可能性ですね。(ここでR_Config_RIIC0_Master_Send()を呼び出してBBSYフラグチェックの箇所に至るまでにBBSYフラグが1→0に変化するタイミング設計になっていなければ、、、)

    RX231のハードウェアマニュアルは後で見るつもりで、まずRXスマートコンフィグレータが生成したソースを見ていて、気になる箇所がありました。r_Config_RIIC0_callback_transmitend()を呼び出している箇所が、r_Config_RIIC0_transmitend_interrupt()とr_Config_RIIC0_error_interrupt()の両方にあるのですが、どう使い分ける意図なのだろうか?と、、、もう少し考えてみます。

    Config_RIIC0_user.c

    static void r_Config_RIIC0_transmitend_interrupt(void)
    {
        if (_06_IIC_MASTER_SENDS_END == g_riic0_state)
        {
            if (1U == g_riic0_stop_generation)
            {
                RIIC0.ICSR2.BIT.STOP = 0U;
                RIIC0.ICCR2.BIT.SP = 1U;

                g_riic0_state = _07_IIC_MASTER_SENDS_STOP;
            }
            else
            {
                RIIC0.ICSR2.BIT.TEND = 0U;
                r_Config_RIIC0_callback_transmitend();
            }
        }
    }
    static void r_Config_RIIC0_error_interrupt(void)
    {
        volatile uint8_t dummy;

        if ((1U == RIIC0.ICIER.BIT.ALIE) && (1U == RIIC0.ICSR2.BIT.AL))
        {
            r_Config_RIIC0_callback_receiveerror(MD_ERROR1);
        }
        else if ((1U == RIIC0.ICIER.BIT.TMOIE) && (1U == RIIC0.ICSR2.BIT.TMOF))
        {
            r_Config_RIIC0_callback_receiveerror(MD_ERROR2);
        }
        else if ((1U == RIIC0.ICIER.BIT.NAKIE) && (1U == RIIC0.ICSR2.BIT.NACKF))
        {
            if (_0D_IIC_MASTER_TRANSMIT == g_riic0_mode_flag)
            {
                RIIC0.ICSR2.BIT.STOP = 0U;
                RIIC0.ICCR2.BIT.SP = 1U;
                while (1U != RIIC0.ICSR2.BIT.STOP) ← 余談ですが此処は短時間で終わるループなのかな?
                {
                    nop();
                }
                RIIC0.ICSR2.BIT.NACKF = 0U;
                RIIC0.ICSR2.BIT.STOP = 0U;
            }
            else if (_0C_IIC_MASTER_RECEIVE == g_riic0_mode_flag)
            {
                RIIC0.ICSR2.BIT.STOP = 0U;
                RIIC0.ICCR2.BIT.SP = 1U;

                /* Dummy read the ICDRR register */
                dummy = RIIC0.ICDRR;
                while (1U != RIIC0.ICSR2.BIT.STOP) ← 余談ですが此処は短時間で終わるループなのかな?
                {
                    nop();
                }
                RIIC0.ICSR2.BIT.NACKF = 0U;
                RIIC0.ICSR2.BIT.STOP = 0U;
            }

            r_Config_RIIC0_callback_receiveerror(MD_ERROR3);
        }
        else if (_0D_IIC_MASTER_TRANSMIT == g_riic0_mode_flag)
        {
            if ((_01_IIC_MASTER_SENDS_ADR_7_W == g_riic0_state) || (_02_IIC_MASTER_SENDS_ADR_10A_W == g_riic0_state))
            {
                RIIC0.ICSR2.BIT.START = 0U;
                RIIC0.ICIER.BIT.STIE = 0U;
                RIIC0.ICIER.BIT.SPIE = 1U;
            }
            else if (_07_IIC_MASTER_SENDS_STOP == g_riic0_state)
            {
                RIIC0.ICSR2.BIT.NACKF = 0U;
                RIIC0.ICSR2.BIT.STOP = 0U;
                RIIC0.ICIER.BIT.SPIE = 0U;
                RIIC0.ICIER.BIT.STIE = 1U;

                r_Config_RIIC0_callback_transmitend();
            }
            else
            {
                 /* Do nothing */
            }
        }
        else if (_0C_IIC_MASTER_RECEIVE == g_riic0_mode_flag)
        {
            if ((_00_IIC_MASTER_SENDS_ADR_7_R == g_riic0_state) || (_02_IIC_MASTER_SENDS_ADR_10A_W == g_riic0_state))
            {
                RIIC0.ICSR2.BIT.START = 0U;
                RIIC0.ICIER.BIT.STIE = 0U;
                RIIC0.ICIER.BIT.SPIE = 1U;
            }
            else if (_0E_IIC_MASTER_RECEIVES_RESTART == g_riic0_state)
            {
                RIIC0.ICSR2.BIT.START = 0U;
                RIIC0.ICIER.BIT.STIE = 0U;
                g_riic0_state = _03_IIC_MASTER_SENDS_ADR_10A_R;
            }
            else if (_0B_IIC_MASTER_RECEIVES_STOP == g_riic0_state)
            {
                RIIC0.ICMR3.BIT.RDRFS = 0U;
                RIIC0.ICMR3.BIT.ACKWP = 1U;
                RIIC0.ICMR3.BIT.ACKBT = 0U;
                RIIC0.ICSR2.BIT.NACKF = 0U;
                RIIC0.ICSR2.BIT.STOP = 0U;
                RIIC0.ICIER.BIT.SPIE = 0U;
                RIIC0.ICIER.BIT.STIE = 1U;

                r_Config_RIIC0_callback_receiveend();
            }
            else
            {
                 /* Do nothing */
            }
        }
        else
        {
             /* Do nothing */
        }
    }

     

  • >ビットレートを10kbps→200kbpsとした箇所以外はRXスマートコンフィグレータのConfig_RIIC0のデフォルトと同じ設定ですね。

    はい。SCKをみるとだいたい200kHzなのでそこはスマートコンフィグレータ生成通りです。


    >これから推測されるトラブルの可能性は、r_Config_RIIC0_callback_transmitend()で次の
    >R_Config_RIIC0_Master_Send()を呼び出してもBBSYフラグチェックでエラーになってしまう可能性ですね。(ここ

    今、ちょうどそこをみてたのですが実際にBBSYエラーになる現象をみてます。

    R_Config_RIIC0_Master_Send()はstopコンディションを発行したら抜け、後は割込ハンドラで処理
    そしてすぐ次のR_Config_RIIC0_Master_Send()はよべる状態です。


    >でR_Config_RIIC0_Master_Send()を呼び出してBBSYフラグチェックの箇所に至るまでにBBSYフラグが1→0に変化するタイミング設計になっていなければ、、、)

    スマートコンフィグレータの指針?として、生成されたソースは完成されている認識なので
    何も追加しておりません。( /* Start user code for user init. Do not edit comment generated here */
    /* End user code. Do not edit comment generated here */
    以外はUpdateで消されてしまうので。。。。。)


    そもそも「生成されたソースは完成されている」認識はまちがっているのでしょうか?
    WAITなども自身で追加しないといけないのでしょうか。。。
    対抗機器によっての制限は自己対応する必要があるとは思いますが、
    CPUユニークなこの辺はそうなっていないのであれば、他にスマートコンフィグレータで生成した方が
    騒がない筈がないとおもっていますので、まず自環境に問題があるとは思っておりますが。。。

    『BBSYフラグチェックの箇所に至るまでにBBSYフラグが1→0に変化するタイミング設計』はスマートコンフィグレータ生成コードからいじってない為、ソース上はそのような処理はありません。
    もっと低レイヤーでどうなってるかはわかりませんが。。。。



    尚、ご指摘のwhileループには通常はいりませんでした。
  • 皆様
    いつもお世話になっております。

    NoMaYさんのご指摘を受け、そもそも私が間違ってる部分に一点気づきました。

    スマートコンフィグレータで生成されたI2CのAPIは完了復帰型ではないので
    完了したのを自分で確認してから次のものをAPIをコールしないといけない点です。
  • bunbunさん、こんにちは。NoMaYです。

    > 今、ちょうどそこをみてたのですが実際にBBSYエラーになる現象をみてます。

    ひょっとして、r_Config_RIIC0_callback_transmitend()が呼び出されるタイミング自体が私達が想定していたものと異なっている場合があるのかな?

    これを(この仮説を)2CHのオシロで引っ掛けるには、どうするとよいだろうか、、、(何か手はないものか、、、)

    [余談]

    一般論ですが、送信終了割り込みは(ドライバ設計者が)適切に設計しないと、意図しないタイミングで発生してしまうことが少なくないものだと、私は、そんな気がします、、、(他品種の例では、RZ/A2Mですが、危ないのでは、と実際に感じたものがあります、、、)

    Software PKG で SCIFAn を半2重通信したい (RZ/A2M)
    japan.renesasrulz.com/cafe_rene/f/103__-_forum/5902/software-pkg-scifan-2-rz-a2m/32730#32730
    これは、自身が長時間の割り込み禁止区間を作っていた例ですが、長時間の割り込みの後でも起きるかも、と思っています、、、

  • bunbunさん、こんにちは。NoMaYです。

    > スマートコンフィグレータで生成されたI2CのAPIは完了復帰型ではないので
    > 完了したのを自分で確認してから次のものをAPIをコールしないといけない点です。

    ああ、そちらでしたか、、、(まだ何かありそうな予感もしなくも無いですので、そちらも、というところかも知れませんが、、、)

  • NoMaYさん、皆さん
    いつもお世話になっております。


    皆様のおかげで無事解決する事ができました、本件、クローズ致します。
    ご教授有難うございます。

    一応、下記に原因と対処を記載しておきます。

     

    【原因】
    スマートコンフィグレータで生成されたR_Config_RIIC0_Master_Send/R_Config_RIIC0_Master_Receive関数を
    完了復帰型だと思い込んで送受信が完了しない内に次のSend/Receive関数を呼んでしまってました。

    (現象としては、1パケットの送受信が完了しない内(BBSY中もしくはBBSY間近)に
     次のSend関数が読ばれ際に冒頭のチェックで引っ掛かる。
     連続送受信した時は、タイミングにもよりけりですが高頻度でBBSYになるという症状でした)

    【対処】
    Sendの例ですが完了復帰型ではないR_Config_RIIC0_Master_Send()にWrapperを一段かませ
    その中で下記のコードを追加し、送信完了は送信完了コールバック関数の中でフラグを追加。


    MD_STATUS u_Config_RIIC0_send(uint16_t s_adr, uint8_t *const tx_buf, uint16_t tx_num)
    {
    MD_STATUS status;


    if((status = R_Config_RIIC0_Master_Send(s_adr, tx_buf, tx_num)) == MD_OK)
    {
    while(!u_Config_RIIC0_tx_snd_end); // 送信完了待ち
    while(RIIC0.ICCR2.BIT.BBSY); // Busyからの復帰待ち
    u_Config_RIIC0_tx_snd_end = 0;
    }
    else
    {
    LOG(U_LOG_ERROR, U_LOG_TAG_I2C, "\n", NULL);
    }
    return status;
    }

     


    RL78でも同様の処理を追加してたのですが
    それがいつのまにかルネサスのAPIは完了復帰型という記憶に塗り替えてしまい
    生成されたコードをろくに解析してませんでしたが皆様からアドバイスを頂き気づくことができました。。

    有難うございます。