チョコさんが以前に指摘されていたRL78コード生成機能によるCSI連続送信の終了の割り込みコードの問題を調べています

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

すみません、掲題の件、下記のスレッドでの話題ですが、コード生成されたソースの以下のコードのことでしょうか?

r_cg_serial_user.c

static void __near r_csi00_interrupt(void)
{
    if (g_csi00_tx_count > 0U)
    {
        SIO00 = *gp_csi00_tx_address;
        gp_csi00_tx_address++;
        g_csi00_tx_count--;
    }
    else
    {
        if ((SSR00 & _0040_SAU_UNDER_EXECUTE) == 0U)
        {
            r_csi00_callback_sendend();    /* complete send */
        }
        else
        {
            SMR00 &= ~_0001_SAU_BUFFER_EMPTY;
        }
    }
}

RL78/G14のEEPROMのI2C通信について
japan.renesasrulz.com/cafe_rene/f/002-2095199602/5962/rl78-g14-eeprom-i2c/33068#33068

チョコです。
鈴木さん,MAX7219をCSIで制御してLED表示を行っていて,問題を見つけました。
CSIの連続送信で最後のデータを書き込んだ後で,割り込みタイミングを書き換えてますが,転送速度とプログラムの実行速度の関係で,最後の割り込みが発生しない可能性があります。


RL78/G13 CSIのマスタ連続送受信でオーバーランエラーが発生する
japan.renesasrulz.com/cafe_rene/f/002-2095199602/5972/rl78-g13-csi/33137#33137

チョコです。
この現象については,「RL78/G14のEEPROMのI2C通信について」で少し触れていますが,次のような動作になっていると考えられます。
①最後のデータを書き込むための割り込みが発生します。
②CSIは最後のデータを送信します。
③CPUは割り込みを受け付けると,最後のデータの送信中かチェックして,最後のデータなら割り込みタイミングを転送完了に書き換えます。
ところが,③で割り込みタイミングを書き換える前に送信が完了してしまっていると,書き換えた時点では,送信完了割り込みの発生タイミングを終了しているので,期待した最後の割り込みが発生しません。
そのため,通信処理を終えることができなくなってしまいます。


なお、以下のCS+ V8.03の画面コピーは先程のソースを生成させた時のコード生成機能の設定内容です。



 

Parents
  • こんにちは。NoMaYです。

    今回の割り込みコードの問題はCSI連続送信でしたが、他のタイプの連続転送に関しても、コードを生成させて、生成コードを確認してみました。不具合原因のコードから推測すると、問題点の(2)の該当/非該当は以下の表のようになると思います。なお、問題点の(1)は、コードの複雑さとボーレートの上限から推測すると、CSI連続送信しか該当しないのではないかと思います。←[訂正] 再検討中です。

    問題点(再掲):

    (1) CPU動作周波数(MHz)とCSIボーレート(Mbps)の比が4:1ぐらいの場合(例えば24MHz:6Mbpsとか32MHz:8Mbpsとか)には、コンパイラの種類とかバージョンとか最適化レベルとか(或いはコード生成されたコードを改造した内容とか)のバランス次第では、(常に)送信終了のコールバック関数呼び出しがスッポ抜ける(コールバック関数が呼び出されない)

    (2) 上記の(1)の場合よりCSIボーレートが低い場合でも、割り込み禁止区間(他の割り込みや明示的なDI/EIによるもの等)が絶妙なタイミングでくだんの割り込み要求の発生とオーバーラップしてしまった時には、送信終了のコールバック関数呼び出しがスッポ抜ける(コールバック関数が呼び出されない)

    問題点の(2)の該当/非該当の推測:

    SAU CSI連続送信モード 該当(此処までの本スレッドの案件)
    SAU CSI連続受信モード 該当?
    SAU CSI連続送受信モード 該当?
    SAU UART受信 非該当(連続転送モード自体が無い)
    SAU UART連続送信モード(繰り返し送信モード) 該当?
    SAU 簡易IIC 非該当(連続転送モード自体が無い)
    IICA 非該当(連続転送モード自体が無い)

    以下にプロジェクトのファイル一式を添付します。(CS+ V8.03でコード生成しています。なお、今回はビルドをしていません。)

    プロジェクトのファイル一式:
    issue_20200228_2_0310.zip

    r_cg_serial_user.c

    SAU CSI連続送信モード(此処までの本スレッドの案件)

    static void __near r_csi00_interrupt(void)
    {
        if (g_csi00_tx_count > 0U)
        {
            SIO00 = *gp_csi00_tx_address;
            gp_csi00_tx_address++;
            g_csi00_tx_count--;
        }
        else
        {

            if ((SSR00 & _0040_SAU_UNDER_EXECUTE) == 0U)
            {
                r_csi00_callback_sendend();    /* complete send */
            }
            else
            {
                SMR00 &= ~_0001_SAU_BUFFER_EMPTY;
            }
        }
    }

    SAU CSI連続受信モード

    static void __near r_csi10_interrupt(void)
    {
        volatile uint8_t err_type;

        err_type = (uint8_t)(SSR02 & _0001_SAU_OVERRUN_ERROR);
        SIR02 = (uint16_t)err_type;

        if (1U == err_type)
        {
            r_csi10_callback_error(err_type);    /* overrun error occurs */
        }
        else
        {
            if (0U == g_csi10_rx_count)
            {
                SIO10 = 0xFFU;    /* write dummy */
                g_csi10_rx_count++;
            }
            else
            {
                if (g_csi10_rx_count < (g_csi10_rx_length - 1U))
                {
                    *gp_csi10_rx_address = SIO10;
                    gp_csi10_rx_address++;
                    g_csi10_rx_count++;
                    SIO10 = 0xFFU;    /* write dummy */
                }
                else
                {
                    if ((SMR02 & _0001_SAU_BUFFER_EMPTY) == 0x0001U)
                    {
                        *gp_csi10_rx_address = SIO10;
                        gp_csi10_rx_address++;
                        g_csi10_rx_count++;

                        if ((SSR02 & _0040_SAU_UNDER_EXECUTE) == 0U)
                        {
                            *gp_csi10_rx_address = SIO10;
                            r_csi10_callback_receiveend();    /* complete receive */
                        }
                        else
                        {
                            SMR02 &= ~_0001_SAU_BUFFER_EMPTY;
                        }
                    }
                    else
                    {
                        *gp_csi10_rx_address = SIO10;
                        r_csi10_callback_receiveend();    /* complete receive */
                    }
                }
            }
        }
    }

    SAU CSI連続送受信モード

    static void __near r_csi20_interrupt(void)
    {
        volatile uint8_t err_type;

        err_type = (uint8_t)(SSR10 & _0001_SAU_OVERRUN_ERROR);
        SIR10 = (uint16_t)err_type;

        if (1U == err_type)
        {
            r_csi20_callback_error(err_type);    /* overrun error occurs */
        }
        else
        {
            if (g_csi20_tx_count > 0U)
            {
                if (g_csi20_tx_count != (g_csi20_send_length - 1U))
                {
                    *gp_csi20_rx_address = SIO20;
                    gp_csi20_rx_address++;
                }
                
                SIO20 = *gp_csi20_tx_address;
                gp_csi20_tx_address++;
                g_csi20_tx_count--;
            }
            else
            {
                if ((SMR10 & _0001_SAU_BUFFER_EMPTY) == 1U)
                {
                    r_csi20_callback_sendend();    /* complete send */
                    *gp_csi20_rx_address = SIO20;
                    gp_csi20_rx_address++;    
                    
                    if ((SSR10 & _0040_SAU_UNDER_EXECUTE) == 0U)
                    {
                        *gp_csi20_rx_address = SIO20;
                        r_csi20_callback_receiveend();    /* complete receive */
                    }
                    else
                    {
                        SMR10 &= ~_0001_SAU_BUFFER_EMPTY;
                    }
                }
                else
                {
                    *gp_csi20_rx_address = SIO20;
                    r_csi20_callback_receiveend();    /* complete receive */
                }
            }
        }
    }

    SAU UART連続送信モード(繰り返し送信モード)

    static void __near r_uart3_interrupt_send(void)
    {
        if (g_uart3_tx_count > 0U)
        {
            TXD3 = *gp_uart3_tx_address;
            gp_uart3_tx_address++;
            g_uart3_tx_count--;
        }
        else
        {

            if ((SSR12 & _0040_SAU_UNDER_EXECUTE) == 0U)
            {
                r_uart3_callback_sendend();
            }
            else
            {
                SMR12 &= ~_0001_SAU_BUFFER_EMPTY;
            }
        }
    }

     

  • チョコです。

    NoMaYさん,
    SAU CSI連続受信モードはあり得ないですね。
    連続するかどうかは送信側の処理の問題で,受信側はきたものを受信して受信完了したら,割り込みを発生するだけです。割り込みのタイミングを変更するような処理はないので,非該当です。
    スレーブの場合に,処理が遅れた時には,オーバーラン・エラーになるだけです。
  • チョコさん、こんにちは。NoMaYです。

    リプライ有難う御座います。

    > SAU CSI連続受信モードはあり得ないですね。
    。。。
    > 割り込みのタイミングを変更するような処理はないので,非該当です。

    生成コードを確認すると、ソース上には、割り込みのタイミングを変更する、以下の行(赤字箇所)が存在していますので、後で動作を追い掛けてみます。(何だろう、、、) どうも有難う御座いました。

    SAU CSI連続受信モード

    r_cg_serial.c

    MD_STATUS R_CSI10_Receive(uint8_t * const rx_buf, uint16_t rx_num)
    {
        MD_STATUS status = MD_OK;

        if (rx_num < 1U)
        {
            status = MD_ARGERROR;
        }
        else
        {
            if (1U == rx_num)
            {
                SMR02 &= (~_0001_SAU_BUFFER_EMPTY);
            }
            else
            {
                SMR02 |= _0001_SAU_BUFFER_EMPTY;
            }

            g_csi10_rx_length = rx_num;    /* receive data length */
            g_csi10_rx_count = 0U;         /* receive data count */
            gp_csi10_rx_address = rx_buf;  /* receive buffer pointer */
            SIO10 = 0xFFU;    /* start receive by dummy write */
        }

        return (status);
    }

    r_cg_serial_user.c

    static void __near r_csi10_interrupt(void)
    {
        volatile uint8_t err_type;

        err_type = (uint8_t)(SSR02 & _0001_SAU_OVERRUN_ERROR);
        SIR02 = (uint16_t)err_type;

        if (1U == err_type)
        {
            r_csi10_callback_error(err_type);    /* overrun error occurs */
        }
        else
        {
            if (0U == g_csi10_rx_count)
            {
                SIO10 = 0xFFU;    /* write dummy */
                g_csi10_rx_count++;
            }
            else
            {
                if (g_csi10_rx_count < (g_csi10_rx_length - 1U))
                {
                    *gp_csi10_rx_address = SIO10;
                    gp_csi10_rx_address++;
                    g_csi10_rx_count++;
                    SIO10 = 0xFFU;    /* write dummy */
                }
                else
                {
                    if ((SMR02 & _0001_SAU_BUFFER_EMPTY) == 0x0001U)
                    {
                        *gp_csi10_rx_address = SIO10;
                        gp_csi10_rx_address++;
                        g_csi10_rx_count++;

                        if ((SSR02 & _0040_SAU_UNDER_EXECUTE) == 0U)
                        {
                            *gp_csi10_rx_address = SIO10;
                            r_csi10_callback_receiveend();    /* complete receive */
                        }
                        else
                        {
                            SMR02 &= ~_0001_SAU_BUFFER_EMPTY;
                        }
                    }
                    else
                    {
                        *gp_csi10_rx_address = SIO10;
                        r_csi10_callback_receiveend();    /* complete receive */
                    }
                }
            }
        }
    }

     

  • チョコです。
    意味不明ですね。
    デバイスのマニュアルにも,受信動作時には,レジスタ設定は明確に,「0:転送完了割り込み」と記載されています。
    ここらが,私がシリアル関係のコード生成されたコードを使わない理由でもあります。
Reply
  • チョコです。
    意味不明ですね。
    デバイスのマニュアルにも,受信動作時には,レジスタ設定は明確に,「0:転送完了割り込み」と記載されています。
    ここらが,私がシリアル関係のコード生成されたコードを使わない理由でもあります。
Children
No Data