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

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

  • 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は完了復帰型という記憶に塗り替えてしまい
    生成されたコードをろくに解析してませんでしたが皆様からアドバイスを頂き気づくことができました。。

    有難うございます。