スマートコンフィグレータの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 ぬこ です

    ●私が作成にリプライにモタモタしている間に、新しいリプライを頂いたので、入れ違いになりましたが、アドバイスを頂いた方法を試しました。

    ●TXI 割込みハンドラ内の if-else の else でフラグ  sendEndFlag  を立てましたが、うまくいきません。

    ●やはり TEND 割込みハンドラでフラグを立てるとうまくいきます。●なんとなく、TEND 割込みハンドラの呼び出しは 『未送信文字数カウンタ:g_sci0_tx_count 』で管理しておらず、TEND フラグか、ICU.GENBL0.IS0 フラグで管理されている様な感じがします。グループ割込み:BL0:GENBL0.IS0 は src > smc_gen_r_bsp > mcu > all > r_bsp_interrupts.c に記述が見つかりましたが、マクロの塊なので、サッパリ理解できません。●ベクタテーブルもマクロで書かれていて、私の手に余ります。すみません、私にはこれ以上深く追及する力量がありません。●結果報告だけになってしまいます。

    ●TXI, TEND ハンドラ以外のコードは下の方に添付しています。

    main 関数内の『Send 関数のコール』の次に『フラグ立ち待ちループ』を置きました。フラグのクリアは Send 関数に移しました。

    フラグのクリアは、Send 関数の頭で実行しています。

  • チョコです。

    >TXI 割込みハンドラ内の if-else の else でフラグ  sendEndFlag  を立てましたが、うまくいきません。

    >やはり TEND 割込みハンドラでフラグを立てるとうまくいきます。

    RXでは割り込み処理の構成が異なっているようですね。gNuco 山河、添付された以下の部分の一番下で

    "r_Config_SCI0_callback_transmitend"関数を呼び出しています。これが、最初にコメントした送信完了時のコールバック関数のようです。この関数の中でフラグをセットしてください。それ以外のところにプログラムを書くと、コード生成をやると消されてしまうはずです。

    >なんとなく、TEND 割込みハンドラの呼び出しは 『未送信文字数カウンタ:g_sci0_tx_count 』で管理しておらず、

    それは、間違いです。。TXI割り込み関数のelse側にSCI0.SCR.BIT.TEIE= 1U;の記述がありますが、ここでTEND割り込みを許可しているようです。ここは、最後のデータがシフトレジスタに転送されたタイミングで、最後のデータの送信は完了していないようです。ここで、割り込みのタイミングを送信完了タイミング(ストップビットを送信タイミング)に変更しています。

    つまり、送信データ数を確認して残りデータが0なら、TEND割り込みを許可していますから、TEND割り込み自体はデータ数を管理した結果になっています。TEND割り込では、送信処理の後処理を行っているようです。その最後で、"r_Config_SCI0_callback_transmitend"関数を呼び出すことで、全ての処理を完了しているようです。

    スマート・コンフィグレータのロジックは、単に、"r_Config_SCI0_callback_transmitend"関数の中でフラグをセットするだけです。これは、RL78と同じロジックです。

    また、フラグクリアをSend関数の中に追加していますが、これでは、コード生成をやり直すたびに消されてしまう可能性があります。ここは、やはり、フラグクリア~Send関数呼び出し~フラグ待ちの形にすべきでしょう。面倒なら、フラグの初期値を0にしておき、フラグ待ちでフラグが接地されていたら、フラグをクリアして終了するようにするのもありかと思います。

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

    >それ以外のところにプログラムを書くと、コード生成をやると消されてしまうはずです。
    >また、フラグクリアをSend関数の中に追加していますが、これでは、コード生成をやり直すたびに消されてしまう可能性があります。

    ●ありがとうございます。●先に生成ファイルを修正したプロジェクトで、コード生成だけをやり直すと、生成関数は初期化され、コールバック関数は修正箇所が残っていました。●初心者なので、『コード生成関数から呼び出すコールバック関数を呼び出す』のが無意味と思っていました。チョコさんのおかげでコールバック関数使う意義がようやく理解できました。●活用させていただきます。

    >それは、間違いです。
    >送信データ数を確認して残りデータが0なら、TEND割り込みを許可していますから、TEND割り込み自体はデータ数を管理した結果になっています。

    ●その通りですね。私は全く気付いていませんでした。これならデータ数管理プログラムが TEND 割込みの許可を制御しています。こんな事にも気づかずにこれまでのリプライをしていたとは、恥じ入るばかりです。

    ●いまさらですが、前のリプライで大事なことを間違っていました。
      間違い r_Config_SCI0_callback_transmitend 関数をコールする要因が何なのか分かりません。
      訂正   r_Config_SCI0_transmitend_interrupt 関数をコールする要因が何なのか分かりません。
    ●チョコさんには私の疑問の真意を汲んでいただき、適切な回答を頂いたので助かりました。今後はミスを無くすようにします。


    ●これで気がかりも無くなり安心してマイコン道を進めます。初心者の初歩的な間違いにも丁寧に指導して頂いて本当に感謝しております。ありがとうございました。