いつもお世話になっております。
下記の現象についてご教授ください。
【発生現象】
スマートコンフィグレータで生成した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 */ }}
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は完了復帰型という記憶に塗り替えてしまい生成されたコードをろくに解析してませんでしたが皆様からアドバイスを頂き気づくことができました。。
有難うございます。