スマートコンフィグレータのCG で生成した SCI 調歩同期のコードで、連続複数回の送信が出来ません

●RX72N e2studio でスマートコンフィグレータ(以下 スマコン)のCG(コード生成) を使って、『SCI 調歩同期通信の送信』のコードを作成し、送信関数 R_Config_SCI0_Serial_Send ( ) (以下、Send 関数)を連続して複数回使うと、文字列を正しく送信できません。

●スマコン生成コードは、ユーザーズマニュアル・ハードウェア編(以下、マニュアル)の動作例とは違う動作法を使用してたので、割込み関数をマニュアルに基づいて書き換えたものも試しましたが、同じ動作をしました。●連続送信を行う理由は、センサで得たデータと数値計算結果を一度に100文字以上パソコンに表示したいけれど、一つの文字列にして1回で送信するのはメモリに負担をかけそうなので、分割・連続して送信する手法を確保しておきたいからです。●ちなみに以前 RX63N-SAKURA で SCI を使用した事があります。この時は RX マイコン用 SCI 通信のアプリケーションノートを参考にしました。これは1つの Send 関数の中で、文字列の連続送信を行わず、1文字送信するたびに 『TEND エンドフラグが立つのを待つ』方法を使うので、今回の問題の参考にしていません。

●今回の不都合に関しては、ごく初歩的な間違いも考えられます

・そもそも、スマコン生成関数の使い方が間違っている。

・そもそも、連続送信を行う時に必要な動作があるのに、それをしていない。

・そもそも、送信文字列の型が間違っている。

等々。が、自分では解決できません。

●私の間違いが分かる方、或いは解決方法をご存じの方がおられれば、どうぞご指導願います。

●以下、長くなりますが
 ・正しく動作しない実行例を示してから、
 ・プロジェクト作成詳細を示し
 ・その後で、マニュアルに基づいた割込み関数を示します。


正しく動作しない実行例 (GNU C++11 の例)
●main 関数

#ifdef CPPAPP
extern "C" {
    #endif
    #include "r_smc_entry.h"
    #ifdef CPPAPP
}
#endif

中略

int main(void) {
    R_Config_SCI0_Start( );

    uint8_t txt_1[] = "0ABCD\r\n";
    uint8_t txt_2[] = "1abcd\r\n";
    uint8_t txt_3[] = "2EFGH\r\n";
    uint8_t txt_4[] = "3efgh\r\n";

    R_Config_SCI0_Serial_Send(txt_1, 7);
    R_Config_SCI0_Serial_Send(txt_2, 7);
    R_Config_SCI0_Serial_Send(txt_3, 7);
    R_Config_SCI0_Serial_Send(txt_4, 7);
    while(1) {

        // TODO: add application code here
    }
    return 0;
}


●実行結果 

03dfgh (改行)

●上記以外にも複数の実験をして分かった『間違いパターン』は

『 1回目の Send 関数の引数文字列の 最初の1文字』と、『最後の Send 関数の引数文字列を全て』を送信する。改行は実行する。

●ストップビット数、送信ビットレートを変更しても、同じ文字列が表示される。(詳細条件は後述)

●他に以下の様な実験を行いましたが、正しく動作しません。

・2つのSend 関数の間にデータ送信に関係の無い動作として数値計算(実数の足し算)を入れても結果は同じ。

・1つのSend 関数が完了しないうちに、次のSend 関数をコールしている可能性を考え、

    while (SCI0.SSR.BIT.TEND < 1 ) { }

 という『送信エンド待ちループ』を入れたが、結果は同じ。

●CC-RX C プロジェクトの場合

●CC-RX C のプロジェクトを作成しメイン関数で同じコードを実行すると、出力が文字化けをしており何らかの規則性を見つけるのが困難でした。

 ・実行結果(16進)          :  31 91 24 c0 ff 02 00 00 h(改行)

 ・参考:GNU C++ 出力の16進表示    : 30 33 65 66 67 68 0d 0a h(改行)

プロジェクト作成条件 詳細
●MCU: RX72N 176pin (北斗電子製ボード)

●SCI 通信条件
 ・送信のみ 受信コードは作成せず
 ・チャネル SCI0(TXD0)
 ・データ長 :8bit
 ・パリティ :禁止
 ・ストップビット :主に 1 bit
     他に、2bit も試したが、結果は同じ
 ・データ転送方向 :LSB ファースト
 ・ビットレート :主に 115,200 bps
     他に、57,600 bps, 38,400 bps を試したが、結果は同じ

●受信側 :SCI-USB 変換キット(秋月電子)を介して、
  Windows 10上の『 Tera Term』または『シリアルデバッグツール2』で表示

●スマートコンフィグレータ・コード生成条件
 ・IDE :e2studio 2021-07
 ・ソフトウェアコンポーネント :SCI(SCIF)調歩同期式モード コード生成 1.10.0

●参照したマニュアル :ユーザーズマニュアル ハードウェア編 Rev. 1.11  2021.02

スマコン生成・割込み関数のコード

●GNU C++ , CC-RX C 両プロジェクトで共通

static void r_Config_SCI0_transmit_interrupt(void)
{
    if (0U < g_sci0_tx_count)
    {
        SCI0.TDR = *gp_sci0_tx_address;
        gp_sci0_tx_address++;
        g_sci0_tx_count--;
    }
    else 
    {
        SCI0.SCR.BIT.TIE = 0U;
        SCI0.SCR.BIT.TEIE = 1U;
    }
}


デバッグ
●E2 lite を使ってデバッグをしましたが、私が未熟なため明確な事が伝えられません。

●なんとなくわかっているのは

・Send 関数ごとに1回割込み関数に入り、

・if 分岐 true を1回実行しただけで、

・次の if 分岐無し(文字列の文字数回 true のはず)、

・falese で else を実行することも無しに、

・次の Send 関数に移動するようでした。

・if true 時の  g_sci0_tx_count の値等は分かりません(まだデバッガを使いこなせていない為)


マニュアルの動作例とスマコン生成関数の動作が違い

●マニュアルの動作例

●マニュアルでは『 41.3.8 シリアルデータの送信(調歩同期式モード)』で下の図を使って、『複数バイトデータの連続送信の終盤』を説明しています。●送信文字列データの最後の3文字がTSR シフトRg. から送出され、最後に『TEND 送信エンド割込みフラグ』が立つところまでが描かれています。

    

●これだけでは分かりにくかったので、TDR 送信データRg.、TIE 送信割込みイネイブルbit、TEIE 送信エンド割込みイネイブル等の動作を描き足しました。ここでは
・『送信データ文字列』の『文字数を n 個』とし、
・『文字データの番号』を #0, #2, ,#(n-2), #(n-1) とし、
・『TDR データRg. に [データ #k] を 書き込む TXI 割込み要求』を、 『割込み #k 』 と名付けました。

※ 以下、SCI 通信を理解された方には釈迦に説法なのでこの図は出さないつもりでした。しかし私の解釈が間違っていて、この図も間違っているかもしれないと思い、一応添付します。

※ この図の各レジスタの動作は、『マニュアルに明記されている事』に基づいて描いたものではありません。●『この様に動作するならマニュアルに書かれた送信動作が実現するはずだ』という憶測に基づいて描かれています。

※ 特に TDR トランスミット・データ・レジスタに書き込まれたデータがいつまで残っているのか、私はマニュアルの記述では理解できていません。●動作説明に『前回のフレームのストップビットを送出するタイミングで、TDR に次のデータが有れば連続転送をする』旨の記述が有るので、『次のデータがライトされるまで前のデータが残っている』という憶測に基づいています。

    

●[TXI 割込み- #(n-1) ] の割込み関数で、

  ・[最終データ #(n-1) ]を TDR データRg. にライトした後、

  ・TIE=0, TEIT=1 とする。

  ・この間に TSR シフトRg.から1つ前の [データ #(n-2)] が送出され、

  ・続いて [最終データ #(n-1) ]の送出が終わると、TEND エンドフラグが立つ。

●スマコン生成・割込み関数の動作(GNU C++, RX-CC C 共通)

●マニュアルの説明文に即して、スマコン生成・割込み関数の動作図を描いてみました。●この図も『このように動作すれば、スマコン生成関数が動作するはずだ』という憶測に基づいて描かれています。

 

・割込み #(n-1) で
  TDR に [データ #(n-1)  を書き込み
  送信データのポインタを一つ進める。
  tx_count を 1 ⇒ 0 にデクリメントする

※ 送信データ番号 は #0 から始まり、#(n-1) は最後のデータなので、ここからポインタを進めると、未定義領域のアドレスを指すと思います。ただ、後にこの Send 関数ではポインタを操作しないので、実害は無いだろうと希望的憶測をしています。

・[割込み #n ]では
  tx_cout=0 なので、if 分岐は false
  else で TIE = 0; TEIE = 1; に設定する

●マニュアルの動作例と、スマコン関数動作の 相違点

●n+1 回目の TXI 割込み要求 #n の発生の有無
・マニュアルの図 :発生しない
・スマコン関数 : 発生する

● TIE=0, TEIE=1 設定のタイミング
・マニュアルの図 : [割込み #(n-1) ] の割込み関数内
・スマコン関数  : [割込み #n ] の割込み関数内

●私としてはマニュアルとスマコンのどちらの動作も間違いは無い、だろうと思いました。(でも正しく動作しません)

●マニュアルの動作例に基づく割込み関数を試しました

●一応、マニュアルの動作に即した『割り込み関数』も試してみましたが、まったく同じ正しくない結果が出力されました。

static void r_Config_SCI0_transmit_interrupt(void)
{
    SCI0.TDR = *gp_sci0_tx_address;
    g_sci0_tx_count--;

    if (0U < g_sci0_tx_count)
    {
         gp_sci0_tx_address++;
    }
    else
    {
        SCI0.SCR.BIT.TIE = 0U;
        SCI0.SCR.BIT.TEIE = 1U;
         // while (SCI0.SSR.BIT.TEND < 1 ) ← エンドフラグ待ちループを入れてもダメでした

    }
}

●以上、長くなりましたが、よろしくお願いいたします。

  • gNuco ぬこ です

    追記あります。

    ●Send 関数とSend 関数の間に、ダミーで数値計算(整数の足し算)を挟んでも同じ結果になったので、今後 Send 関数の連続使用でなくても突然 SCI 送信不良が起きる可能性がある事が心配なので、ぜひともこの件を解決したいです。

    ●オシロスコープは持っていません。使わせてくれる知人もいません。この点だけはご容赦下さい。

  • チョコです。

    RXは使ったことはありませんが、RL78でコード生成の時代から共通した問題です。

    これは、生成された"R_Config_SCI0_Serial_Send"関数は送信を起動しているだけだからです。"R_Config_SCI0_Serial_Send"関数から戻ってきた段階では、1バイト目のデータの送信を開始しただけです。全てのデータが送信完了しているわけではありません。

    RXの環境はないので、RL78/G23でスマート・コンフィグレータで調歩同期通信での送信処理を行う関数は以下のようになっています。

    これからも、最初のデータをUARTに書き込んだだけで戻ってきます。1キャラクタ送信割り込みの処理内容を以下に示します。

    ここでは、すべてのデータの送信が完了したら、"r_Config_UART0_callback_sendend"関数を呼び出しています。しかし、"r_Config_UART0_callback_sendend"関数は中身が全くありません。本当は、ここに、送信が完了したことを示すフラグを準備しておき、そのフラグをセットするようにしてください。また、"R_Config_SCI0_Serial_Send"関数を呼び出す前にそのフラグをクリアしてから呼び出し、戻ってきたら、フラグがセットされるのを待つようにしてください。

    この問題は、コード生成のころから、通信系のAPIで共通的な内容です。

    以上

  • チョコさん

      gNuco ぬこ です。

    ●ありがとうございます。無事に問題が解決しました。

    ●ただ、いくつかの疑問が残るのですが、よろしければ教えていただけないでしょうか。

    1,SSR.TEND フラグがこの追加フラグの役割を担っているものと思っていたのですが、別物なのでしょうか?●確かに自分で割込み関数の最終処理の後に while ( SCI0.SSR.BIT.TEND <1) { }   という、TEND エンドフラグ待ちループを入れてもうまくいかなかったのですが、ちょっと気にかかっています。

    2,このノウハウ(でしょうか?)は、他の通信、I2C, SPI でも必要なのでしょうか?

    3,こういうノウハウは、どこかに文書が有るのでしょうか? API 関数のマニュアルにも書いてないようなのですが、皆さんはどこから情報を得られているのでしょうか? ぜひ、お教えください。

  • チョコです。

    >1,SSR.TEND フラグがこの追加フラグの役割を担っているものと思っていたのですが、別物なのでしょうか?●確かに自分で割込み関数の最終処理の後に while ( SCI0.SSR.BIT.TEND <1) { }   という、TEND エンドフラグ待ちループを入れてもうまくいかなかったのですが、

    RXは使ったことはないですが、「SCI0.SSR.BIT.TEND」はRX72NのSCI のフラグなので、1キャラクタの送信完了しか示していないのではないでしょうか。ここでは、すべての送信データの完了なので、その情報はソフトでしかもっていません。つまり、ハードのフラグでは使えません。

    >2,このノウハウ(でしょうか?)は、他の通信、I2C, SPI でも必要なのでしょうか?

    今まで調べた範囲では、すべての通信関係のAPIで共通の問題です。したがって、この方法は、I2Cでも、SPIでも必要です。また、RL78のI2Cには、他にもいろいろと気に入らないところがあります。

    こんなのがノウハウとは言いたくないですね。

    >3,こういうノウハウは、どこかに文書が有るのでしょうか?API 関数のマニュアルにも書いてないようなのですが、皆さんはどこから情報を得られているのでしょうか? ぜひ、お教えください。

    かふぇルネの中には、この件についての私のボヤキがいくつも見つかるのではないかと思います。(ルネサスさんには無視されているようですが)。

    私は自前の関数を使ってI2Cをよく使っているので、問題は発生していないのですが、たまに生成されたコードをチェックして問題点を指摘しています。トラブルの情報は、かふぇルネを眺めているとわかります。

    基本的にRL78の世界で遊んでいますが、RXでも同じような問題があることに気が付きました。RXでもRL78と同じ問題があることがかふぇルネへの書き込みでわかりましたので、RXにもちょっかいを出し始めているところです。

    真面目な情報はかふぇルネのトップページの上の方にある「サンプルプログラム等」にアップしています。

    https://japan.renesasrulz.com/cafe_rene/m/sample_program

    以上

  • チョコさん

     gNuco ぬこ です。

    ●ご指導ありがとうございます。

    1、『1文字の送信終了』と『全文字の送信終了』の違いは全く考慮していませんでした。●ただ、最初の質問に添付したマニュアル記載の説明図では、TEND フラグは『連続送信の開始で下がり、連続送信の終了で上がって』います。●チョコさんのアドバイスをいただいてからそれを参考にして、TEND フラグを利用した修正を試したところ、少し改善できる方法もありました。『少し改善』というのは、4連続送信をすると、『2回目と4回目は正しく出力』するという奇妙なものですが。SCIx.SSR. 管理のフラグと、ICU 管理のフラグの違いも考慮すべきかと思い始めていもいます。●しかし実際はチョコさんの方法が定着しているという事は、それが正解で、他のアイディアは何らかの問題があったのだろうという事ですね。●本当に良い方法を教えていただき、ありがとうございます。

    2,これも本当に参考になります。色々情報発信して頂いているようですね。これからは『RL』も検索対象に含めます。

    3,このような情報は、本来メーカーが定期的にまとめて、更新するべきですよね。●ただ私もルネサスの情報発信には不満があります。マニュアルが間違っているのです。正確にはマニュアルの『て に を は』が間違っていて日本語になっていないので、正しい情報が分からないのです。RX63N と RX71M と RX72T の SCI レジスタの説明箇所に『て に を は』が間違った全く同じ文章が使われていました。●幸い RX72N の当該箇所が『正しい日本語』に修正されていた為、他のMPUも『レジスタの技術情報を推測する』事が出来ました。

    ●『サンプルプログラム等』も参考にさせていただきます。ありがとうございました。

  • チョコです。

    >マニュアル記載の説明図では、TEND フラグは『連続送信の開始で下がり、連続送信の終了で上がって』います。

    マニュアルをダウンロードして眺めてみましたが、確かにそのよう書かれていました。そこで気になったのが、連続送信ができなかったら、途中でも立ち上がってしまうということです。これが、ハードの限界でしょうね。ほとんどの場合には、次のデータの書き込みがそこまで遅れることはないと考えられるので、途中で立ち上がるようなことはないとは思われますが。実際、gNucoさんの確認でも、そのような状態が発生していることから(おそらく、他の割り込みで邪魔されて応答時間が長くなりすぎたから)今回の目的には使えないと判断すべきでしょうね。

    これに対して、ソフトで管理している送信完了したデータ数で判断する方が確実でしょう。

    >正確にはマニュアルの『て に を は』が間違っていて日本語になっていないので、正しい情報が分からないのです。

    私も、そう思うことがよくあります。RL78は慣れた分もあるでしょうが、RXを読むとバックグラウンドとなる知識がないせいか(一番の原因は、年齢かもしれませんが)、何が何をどうするかが全く理解できないことがあります。

  • チョコさんへ
     gNuco ぬこ です。

    >連続送信ができなかったら、途中でも立ち上がってしまうということです。
    >これが、ハードの限界でしょうね。
    ●TDR と TSR の間に『ダブルバッファ』があるというので、何とかなると期待していたのですが、残念。●確かに、RX シリーズは、色々と限界に達しているそうです。『動作中にレジスタ設定値が勝手に変化する』対策として、『何々レジスタ書き換え許可ビット』が用意され、更に『「何々レジスタ書き換え許可ビット」書換え許可ビット』があるのですから。●割り込み要因もテーブルに入りきれず、複数要因を一つにまとめた『グループ割込み』とか、必要な割込み要因だけベクタ番号を割り振る『選択割込み』とか。
    ●ただ、r_Config_SCI0_callback_transmitend 関数をコールする要因が何なのか分かりません。TEND ではない様ですね。今日、TEND フラグの代わりに [ ICU.GENBL0.BIT.IS0 グループBL0.割込み要求フラグ0] ( SCI 0-12 の送信完了他諸々の割込みが、グループBL0 にまとめられました)を使った改善を試していますが、うまくいきません。諦めます。

    >>正確にはマニュアルの『て に を は』が間違っていて日本語になっていないので、正しい情報が分からないのです。
    >私も、そう思うことがよくあります。
    ●仕様変更が多いからこそマニュアルはしっかりして欲しいのですが、日本語ばかりはどうにかならんもんかと。●他にもSCI関係で『フラグA が上がると割込みBが発生します。割込みBが発生するとフラグAが上がります』と因果律不明な記述もあり、お手上げです。
    ●ハードの限界、マニュアル情報の不備等、どうにもならない中で、チョコさんのアドバイスは本当に助かりました。ありがとうございます。
       

  • チョコです。

    >ただ、r_Config_SCI0_callback_transmitend 関数をコールする要因が何なのか分かりません。TEND ではない様ですね。

    単に、送信割り込み処理で送信データ数をカウントして送信が完了したかどうかを判断しているだけだと思いますが。

    >SCI関係で『フラグA が上がると割込みBが発生します。割込みBが発生するとフラグAが上がります』と因果律不明な記述もあり、

    フラグAと割り込みBは等価と考えろということでしょうか。(実際は、最初の「割り込みB」は「CPUでの割り込み処理」を表し、後ろの「割り込みB」は「ハードからの割り込み要求」を示していると考えられます。)

    ちなみに、RL78では、ハードウェアからの割り込み要求(おそらくパルス)が発生すると、割り込み要求をCPUに伝えるためのxxIFというフラグがセットされます。xxIFがセットされたら、CPUは、その割り込み要求の優先順位等を判断して、割り込み受付け可能だったら割り込みを受け付けるような動きになります。下に基本構成を示します。ここで「IF」が割り込み要求フラグで「MK」が割り込みのマスク用のフラグで、その右側がCPUでの割り込み受付けのロジックです。

    CPUが割り込み禁止状態か、より優先順位が高い割り込みを処理中などで割り込みとして受け付けられない場合にはxxIFフラグはセットされたままで、受付け可能になるまで待つことになります。このように何段階かの処理を経て、割り込み処理プログラムが起動されることになります。また、xxIFはフラグはソフトウェアでセットしても同じように割り込み要求になります。これを短縮すると、そのような表現になるのですかね。

    RL78でもこの程度なので、RXはもっと複雑化もしれません。

    おそらく、マニュアルを書いている人は、このような細かな内部の動きを完全に理解してマニュアルを書いているかは疑問です。また、正確に描写したからと言って、理解しやすいとも思えませんが。

  • チョコです。

    少し、追加してまとめなおしておきます。

    >ただ、r_Config_SCI0_callback_transmitend 関数をコールする要因が何なのか分かりません。TEND ではない様ですね。

    単に、送信割り込み処理で送信データ数をカウントして送信が完了したかどうかを判断しているだけだと思いますが。

    具体的には、gNucoさんが、最初に書かれていた下記のプログラムのelse側が送信完了したところなので、ここで、フラグを設定してください。

    そのうえで、" R_Config_SCI0_Serial_Send"を呼び出している次の行ででも、そのフラグを待つようにしておけばいいはずです。

    フラグのクリアと、" R_Config_SCI0_Serial_Send"の呼び出しとフラグのセット待ちをまとめた新しい関数を作って、" R_Config_SCI0_Serial_Send"の代わりに使うのがいいでしょうね。

  • チョコさんへ
     gNuco ぬこ です

    >単に、送信割り込み処理で送信データ数をカウントして送信が完了したかどうかを判断しているだけだと思いますが。


    ●それなら連続送信が出来なくても、文字列の最後を検知できますね。候補としては まず TXI 割込み関数 r_Config_SCI0_transmit_interrupt ( ) が挙がりますがこれは違います。●未送信データ数カウンタ g_sci0_tx_count はグローバルなので、プロジェクトツリーのどこにあっても構わないのですが、見つからないと妙に気になります。CG では xxx_yyy_interrupt.c という名のファイルがたくさんあって面倒です。

    >フラグAと割り込みBは等価と考えろということでしょうか。

    ●たとえを簡単にし過ぎて誤解を招きました。以下、マニュアルの本文を示します。
    RX72N ユーザーズマニュアル ハードウェア編 Rev.1.11 2021.02  
      P2150
     41.3.8 シリアルデータの送信( 調歩同期式モード)
      (1) SCI0 ~ SCI6、SCI12、およびFIFO 無効のSCI7 ~ SCI11 の場合

    1~5 略
    6. TDR レジスタ (注3) が更新されていなければ、SSR.TEND フラグを“1” にし、ストップビット送出後、High を出力してマーク状態になります。(文a)
    このとき、SCR.TEIE ビットが“1” であると、SSR.TEND フラグが“1” になりTEI 割り込み要求が発生します。(文b)

    ●この文章をこのまま受け入れると、時系列がおかしいです。前の投稿では適当な例え話にしたので『因果律』と呼びましたが、事実は『時系列がおかしい』でした。●この文章を擁護するなら、『1つで書ける文章を2つに分けた為に、意味不明になった』可能性もあります。

    6.SCR.TEIE ビットが“1” で(←文b)、TDR レジスタ (注3) が更新されていなければ(←文a)SSR.TEND フラグが“1”に なり(共通)TEI 割り込み要求が発生(←文b)、ストップビット送出後、High を出力してマーク状態になります(←文a)

    ●1文にまとめた動作が、ハードウェア設計者の本位なのか分かりません。本当は別のロジックで設計したけど『日本語がおかしいから誰にも通じない』だけかもしれません。●なんかヒトの揚げ足をとるのが楽しくなってきました。この十日間、連続送信の不良が解決せずかなり追い詰められ、頭おかしくなっています。