●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 CPPAPPextern "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 ) ← エンドフラグ待ちループを入れてもダメでした
}}
●以上、長くなりましたが、よろしくお願いいたします。
チョコです。
少し、追加してまとめなおしておきます。
>ただ、r_Config_SCI0_callback_transmitend 関数をコールする要因が何なのか分かりません。TEND ではない様ですね。
単に、送信割り込み処理で送信データ数をカウントして送信が完了したかどうかを判断しているだけだと思いますが。
具体的には、gNucoさんが、最初に書かれていた下記のプログラムのelse側が送信完了したところなので、ここで、フラグを設定してください。
そのうえで、" R_Config_SCI0_Serial_Send"を呼び出している次の行ででも、そのフラグを待つようにしておけばいいはずです。
フラグのクリアと、" R_Config_SCI0_Serial_Send"の呼び出しとフラグのセット待ちをまとめた新しい関数を作って、" R_Config_SCI0_Serial_Send"の代わりに使うのがいいでしょうね。