こんにちは、ユキと申します。
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)
{
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に書き込んで良いというように読み取れました。
私の理解は正しいのでしょうか。そして、何故このような動作をするのでしょうか。ご助言をいただけると嬉しいです。
足りない情報がございましたら、おっしゃってください。
よろしくお願いいたします。
チョコさん
お返事ありがとうございます。
最後に送信完了割り込みが来ることを期待して割り込みタイミングを書き換えるコードになっているのですが、送信完了割り込みが発生しない場合があるということですね。
ご助言を基に、残り転送データ数が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 */ } }}
チョコさん 多くのご助言ありがとうございます。 ■ソースコードについて データの読み出しを間に合わせるために、読み出しを処理の頭でやるようにしたということですね。 しかし、これでもオーバーランエラーは解消しませんでした。 データの読み出し(*gp_csi21_rx_address = SIO21;)の場所を変えて、 if (1U == err_type) { r_csi21_callback_error(err_type); /* overrun error occurs */ } else { if (g_csi21_tx_count > 0U) { *gp_csi21_rx_address = SIO21; ← ここでデータを読み出す 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--; } ...(以下省略) こちらのようにするとエラーが発生しなくなります。 しかし、これは単にSDRへのデータの取り込みとデータの読み出しのタイミングが 絶妙に噛み合っただけということですよね。 ちなみに、レジスタバンクは既に使用しております。 ■追加のコメントについて ・割り込みの優先度を高にする ・CSI21以外の割り込み処理の先頭でEI()を実行する を試してみましたが、それでも駄目でした。DMAを使うしかないでしょうか……
チョコさん そうですよね…実際のプロジェクトはちょっと公開できないので、 いただいたヒントを基にもう少しこちらで調べてみます。色々とご助言くださり、ありがとうございました。何か分かりましたら、こちらに投稿させていただきます。
使っているのはCC-RL78です。 気になるコードに展開される可能性というのには当てはまらなさそうですね。