RL78/G13 CSIのマスタ連続送受信でオーバーランエラーが発生する

こんにちは、ユキと申します。

RL78/G13のCSIで、バッファ空き割込みを使った連続送受信をマスタとして行うときのことについて
ご教授いただけないでしょうか。
コンパイラはCC-RL、IDEはe2studioを使用しております。

現在、コード生成を使い、CSI21を以下のような設定で動作させようとしています。

転送モード:連続転送モード
データ長:8ビット
データ転送方向:MSB
データ送受信タイミング:タイプ4
転送レート:
 クロック・モード:内部クロック(マスタ)
 ボー・レート:2000000bps
通信完了割り込み優先順位:低
コールバック機能設定:すべて有効

コード生成を実行した上で、自分のコードでR_CSI21_Send_Receive()を呼び出しているのですが、
以下のような現象が起きています。

・1バイトのデータを送信した時は通信が成功する
・2バイト以上のデータを送信するとオーバーランエラーが発生する
・シングル転送モードを使った場合は、2バイト以上のデータを送信してもオーバーランエラーは発生しない

そして、r_cg_serial_user.cのr_csi21_interrupt()の、

if (g_csi21_tx_count > 0U)
{
    if (g_csi21_tx_count != (g_csi21_send_length - 1U))
    {
        *gp_csi21_rx_address = SIO21;
        gp_csi21_rx_address++;
    }

    SIO21 = *gp_csi21_tx_address;
    gp_csi21_tx_address++;
    g_csi21_tx_count--;
}

上記のコードを以下のように書き換えてみると、オーバーランエラーが発生しなくなりました。

if (g_csi21_tx_count > 0U) 
{

    *gp_csi21_rx_address = SIO21;
    gp_csi21_rx_address++;

    SIO21 = *gp_csi21_tx_address;
    gp_csi21_tx_address++;
    g_csi21_tx_count--;
}

期待通りの動作をするようになったものの、何故こうなるのか理解できておりません。
上記はコード生成でできるコードなので、私の使い方が間違っている気がするのですが……

バッファオーバーランが起きる時、送信データの1バイト目を書き込んだ後の最初のバッファ空き割込みで、
実際にはSDRにデータが存在するような動作をしているように見えます。

しかし、ハードウェアマニュアルを読むと、
送信データの1バイト目を書き込んだ後の最初のバッファ空き割込みでは、
データを受信していないし、バッファ空き割込みなのだからSDRは空いている。
何もせずに2バイト目のデータをSDRに書き込んで良い
というように読み取れました。

私の理解は正しいのでしょうか。そして、何故このような動作をするのでしょうか。
ご助言をいただけると嬉しいです。

足りない情報がございましたら、おっしゃってください。

よろしくお願いいたします。

Parents
  • ユキさん、こんにちは。NoMaYと申します。チョコさんも、こんにちは。

    横から失礼します。ユキさんはコンパイラの最適化レベルを何に設定してコンパイルされていますか? ユキさんも書かれているように

    > 転送速度が2Mbpsですから、1バイト転送するのに掛かる時間は4usですよね。

    > CPUのクロックは高速オンチップオシレータクロックで低速メインモード、周波数は8MHzですが、

    ですので、1命令=1クロックとしても

    8命令/us × 4us = 32命令

    ですね。他方、チョコさんの場合は以下になりますね。

    > RL78/G12(24MHzの動作クロック)のCSI00をタイプ4に設定して,6Mbpsの転送速度で送信して正常に送信できています

    24命令/us × 1s/6Mbps × 8bit = 32命令

    両者同じで間に合っても良さそうですが、いかんせん32命令分しかありません。コンパイラの最適化レベルの違いで、間に合う/間に合わないが変わることもあり得そう、な気がしました。(割り込み発生時のスタックへのPUSHや復帰時のスタックからのPOPもありますので、実際は、もっと少ない命令しか実行することが出来ない、と思います。)

    また、32命令という少なさで処理が間に合う/間に合わないを試行錯誤する場合は、生成されたコードをアセンブラレベルで確認しながらやらないと、うまくいかないような気がします。(と言うか、もうアセンブラ記述しないと(インラインアセンブラでも可ですが)、コンパイラの生成コードが変わった時に動かなくなったりしないか、やっぱり気になってしまいます。)

Reply
  • ユキさん、こんにちは。NoMaYと申します。チョコさんも、こんにちは。

    横から失礼します。ユキさんはコンパイラの最適化レベルを何に設定してコンパイルされていますか? ユキさんも書かれているように

    > 転送速度が2Mbpsですから、1バイト転送するのに掛かる時間は4usですよね。

    > CPUのクロックは高速オンチップオシレータクロックで低速メインモード、周波数は8MHzですが、

    ですので、1命令=1クロックとしても

    8命令/us × 4us = 32命令

    ですね。他方、チョコさんの場合は以下になりますね。

    > RL78/G12(24MHzの動作クロック)のCSI00をタイプ4に設定して,6Mbpsの転送速度で送信して正常に送信できています

    24命令/us × 1s/6Mbps × 8bit = 32命令

    両者同じで間に合っても良さそうですが、いかんせん32命令分しかありません。コンパイラの最適化レベルの違いで、間に合う/間に合わないが変わることもあり得そう、な気がしました。(割り込み発生時のスタックへのPUSHや復帰時のスタックからのPOPもありますので、実際は、もっと少ない命令しか実行することが出来ない、と思います。)

    また、32命令という少なさで処理が間に合う/間に合わないを試行錯誤する場合は、生成されたコードをアセンブラレベルで確認しながらやらないと、うまくいかないような気がします。(と言うか、もうアセンブラ記述しないと(インラインアセンブラでも可ですが)、コンパイラの生成コードが変わった時に動かなくなったりしないか、やっぱり気になってしまいます。)

Children
  • NoMaYさん
    こんにちは。コメントくださり、ありがとうございます。
    コンパイラの最適化レベルはデバッグ優先でした。
    ので、最適化レベルを速度優先にしてみましたが、それでも結果は変わりませんでした。

    割り込み処理関数に入るタイミングで適当なポートの値を変えるようにして、
    割り込み処理関数に入るタイミングと、SCKの波形をオシロで比べてみました。
    1バイト目のデータの転送が終わる少し前のタイミングで割り込み処理関数に入っているようです。
    割り込み処理関数に入ってから1バイト目のデータの送受信が終わるまでの間には1usも空いていません。
    割り込み処理関数に掛かる時間以前に、割り込み処理関数に入るのが遅すぎる気がします…。