スマートコンフィグレータの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 ) ← エンドフラグ待ちループを入れてもダメでした

    }
}

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

Parents
  • チョコです。

    >ただ、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はもっと複雑化もしれません。

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

Reply
  • チョコです。

    >ただ、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はもっと複雑化もしれません。

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

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