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

    送信モード時のこの対策としては,現在投稿の準備中ですが,割り込み処理の中で残り転送データ数が0になっていたら,SSRレジスタのTSFビットが0になったら通信は完了しているとして最後のデータを読み出して通信を完了すればいいと思います。
    MAX7219に対して,RL78/G12(24MHzの動作クロック)のCSI00をタイプ4に設定して,6Mbpsの転送速度で送信して正常に送信できています。
  • チョコさん

    お返事ありがとうございます。

    最後に送信完了割り込みが来ることを期待して割り込みタイミングを書き換えるコードになっているのですが、
    送信完了割り込みが発生しない場合があるということですね。

    ご助言を基に、残り転送データ数が0の時にSSRレジスタをポーリングで見て、
    TSFビットが0になったらデータを読み出して抜けるようにしてみましたが、
    まだオーバーランエラーが発生しております。
    以下が変更後の割り込み処理のコードです。間違いがあると思うのですが、ご指摘いただけないでしょうか。

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

    static void __near r_csi21_interrupt(void)
    {
    volatile uint8_t err_type;
    err_type = (uint8_t)(SSR11 & _0001_SAU_OVERRUN_ERROR);

    SIR11 = (uint16_t)err_type;

    if (1U == err_type)
    {
    r_csi21_callback_error(err_type); /* overrun error occurs */
    }
    else
    {
    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--;
    }
    else
    {
    r_csi21_callback_sendend(); /* complete send */
    *gp_csi21_rx_address = SIO21;
    gp_csi21_rx_address++;

    while ((SSR11 & _0040_SAU_UNDER_EXECUTE) != 0U)
    {
    NOP();
    }
    *gp_csi21_rx_address = SIO21;
    r_csi21_callback_receiveend(); /* complete receive */
    }
    }
    }
  • チョコです。
    基本的に,SIO21の読出しタイミングの問題だけのようです。そこで,SIO21からの読出しそのものは処理の頭でやるようにして,最初のバッファ空き割り込みでは読み出したデータを格納するポインタを更新しないようにしてみました。
    割り込み処理での時間をできるだけ早くするには,レジスタ・バンク機能を使うことが考えられます。CSI00の例を下に示します。この例では,レジスタ・バンク1を使うように設定しています。
    #pragma interrupt r_csi00_interrupt(vect=INTCSI00,bank=RB1)

    今は,手元に動作環境がないので,論理的に考えただけですが,こんな風に直してみました。この例では,CSI21の割り込みタイミングも書き換えています。

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

    *gp_csi21_rx_address = SIO21; /* 受信データの読出し */

    err_type = (uint8_t)(SSR11 & _0001_SAU_OVERRUN_ERROR);

    SIR11L = err_type; /* エラーフラグのクリア */

    if (1U == err_type)
    {
    r_csi21_callback_error(err_type); /* overrun error occurs */
    }
    else
    {
    if (g_csi21_tx_count > 0U)
    {
    if (g_csi21_tx_count != (g_csi21_send_length - 1U))
    {
    gp_csi21_rx_address++;
    }
    SIO21 = *gp_csi21_tx_address;
    gp_csi21_tx_address++;
    g_csi21_tx_count--;

    if ( g_csi21_tx_count == 0 ) /* 最後の送信データ書き込み */
    {
    SMR11 &= ~0x0001; /* 転送完了割り込みに設定 */
    if ((SSR11 & _0040_SAU_UNDER_EXECUTE) == 0U)
    { /* 最終データ送信完了 */
    r_csi21_callback_sendend(); /* complete send */
    CSIIF21 = 1; /* 念のために割り込みを要求 */
    }
    }

    }
    else
    {
    *gp_csi21_rx_address = SIO21; /* 最終受信データの読出し */
    SMR11 |= 0x0001; /* バッファ空き割り込みに */
    r_csi21_callback_receiveend(); /* complete receive */

    }
    }
    }
  • チョコです。
    追加のコメントです。
    >通信完了割り込み優先順位:低
    そもそも,オーバーラン・エラーが発生して問題になるのなら,優先順位は最優先にしておくべきです。
    その上で,多重割り込みを使うなりの対策を行ってください。それでもだめなら,DMAの使用を考えてください。
Reply
  • チョコです。
    追加のコメントです。
    >通信完了割り込み優先順位:低
    そもそも,オーバーラン・エラーが発生して問題になるのなら,優先順位は最優先にしておくべきです。
    その上で,多重割り込みを使うなりの対策を行ってください。それでもだめなら,DMAの使用を考えてください。
Children
No Data