こんにちは。NoMaYです。先日、「SCIのTENDフラグの注釈」というスレッドでRX210やRX63Nに搭載されているSCIcのTENDフラグ(送信終了フラグ)というのは、ハードウェアマニュアル上は、TDRレジスタ(送信データレジスタ)に書き込みした直後からフラグの値が変化する(前の状態が送信終了であれば直ちに1(送信終了)→0(送信中)になる)のでは無くて暫くしてから値が変化する、という挙動を示す(と受け取れる)ように書かれていることを知りました。更に、その後、「RZ/A2MのDMACについて教えてください」というスレッドでRZ/A2MやRX65Nに搭載されているSCIgのTENDフラグの挙動が気になって説明を読む機会があったのですが、その時、ハードウェアマニュアル上は、書かれている内容が変わっていることに気付きました。(ちなみに、同様にSCIgを搭載したRX64Mでも変わっていました。) そこには、以下の画面コピーのように、TENDフラグの変化タイミングに関することは書かれていなくてレベル検出割り込みの一般的な話(のページを参照して下さいとの話)が書かれていました。もともと、先ほど挙げたスレッドの1つ目ではRX210の実際の挙動はハードウェアマニュアルの記載と違っているということ?(と受け取れる)ような話も出ていて、ちょっと腑に落ちないところもあったので、この際なので、RX65NのTBボードでRX65NのSCIgのTENDフラグの挙動を調べてみました。(なお、後ほどGR-CITRUSでRX631も調べてみようと思っています。)調べてみたところ、RX65NのSCIgのTENDフラグでは、TDRレジスタに書き込みした直後からTENDフラグの値が変わるようになっていました。(マイコン内部の信号を観測することが出来ませんので、正確には、直後にTENDフラグを読み出すと値が変わるようになっていた、ということではありますが。)プロジェクトファイル一式 (RX65NのTBボードのサンプルプログラムをCS+プロジェクトへ変換して流用)issue_20190212.zip結果:TDRレジスタ書き込み前が送信終了状態だった場合の画面コピー(TeraTermへ結果を送信した時の画面コピー)TENDフラグ読み出し箇所のCソース(なおSSRレジスタのbit2がTENDフラグ)
TEND_sampling[0] = SCI6.SSR.BYTE; ← 上の画面コピーの左側の赤枠 SCI6.TDR = data; TEND_sampling[1] = SCI6.SSR.BYTE; ← 上の画面コピーの右側の赤枠 TEND_sampling[2] = SCI6.SSR.BYTE; TEND_sampling[3] = SCI6.SSR.BYTE; TEND_sampling[4] = SCI6.SSR.BYTE;
TENDフラグ読み出し箇所のアセンブラコード(なおSSRレジスタのbit2がTENDフラグ)
MOV.B 02H[R2], [R5] ; TEND_sampling[0] = SCI6.SSR.BYTE; ← 上の画面コピーの左側の赤枠 MOV.B R15, 01H[R2] ; SCI6.TDR = data; MOV.B 02H[R2], 01H[R5] ; TEND_sampling[1] = SCI6.SSR.BYTE; ← 上の画面コピーの右側の赤枠 MOV.B 02H[R2], 02H[R5] ; TEND_sampling[2] = SCI6.SSR.BYTE; MOV.B 02H[R2], 03H[R5] ; TEND_sampling[3] = SCI6.SSR.BYTE; MOV.B 02H[R2], 04H[R5] ; TEND_sampling[4] = SCI6.SSR.BYTE;
参考:TDRレジスタ書き込み前が送信中状態だった場合の画面コピー(つまり連続送信時の2バイト目の場合)以下、ハードウェアマニュアルの画面コピーです。(赤枠は私によるものです。)RX210のSCIcのTENDフラグの説明www.renesas.com/jp/ja/doc/products/mpumcu/doc/rx_family/r01uh0037jj0150-rx210.pdfRX63NのSCIcのTENDフラグの説明www.renesas.com/jp/ja/doc/products/mpumcu/doc/rx_family/r01uh0041jj0180_rx63n631.pdfRX65NのSCIgのTENDフラグの説明www.renesas.com/jp/ja/doc/products/mpumcu/doc/rx_family/r01uh0590jj0210-rx651.pdfRX65Nのレベル検出割り込みの説明 (上の説明内で参照するよう指示されている)RX65NのI/Oレジスタ書き込み時の注意事項の説明 (上の説明内で参照するよう指示されている)RX65NのSCIgの割り込みの説明 (ここにもTENDフラグと割り込みの話が書かれていることに気付いたので)[余談]RX65NのTBボードで調べるのに使用した端子(というかボードのスルーホール)の場所の写真
こんにちは。NoMaYです。先日、RX65NのTBボードでRX65NのSCIgのTENDフラグの挙動を調べてみましたが、今回、GR-CITRUSでRX631のSCIcのTENDフラグの挙動を調べてみました。結果はRX65Nと同じで、TDRレジスタに書き込みした直後からTENDフラグの値が変わるようになっていました。(マイコン内部の信号を観測することが出来ませんので、正確には、直後にTENDフラグを読み出すと値が変わるようになっていた、ということではありますが。)ところで、RX65Nのハードウェアマニュアルを見た時に思ったのですが、RX210のハードウェアマニュアルもRX63Nのハードウェアマニュアルも、注意を喚起したかったのは、実は、RX65Nのハードウェアマニュアルが喚起しているレベル検出割り込みの注意事項だったのではなかろうか、という気がしています。ですので、次は、そのレベル検出割り込みの注意事項の現象が実際にSCIgやSCIcで起きるかどうか、調べてみようかと思います。プロジェクトファイル一式 (先日のプロジェクトファイル一式をRX65N→RX631へ改造)(CS+プロジェクト)issue_20190215.zip結果:TDRレジスタ書き込み前が送信終了状態だった場合の画面コピー(TeraTermへ結果を送信した時の画面コピー)TENDフラグ読み出し箇所のCソース(なおSSRレジスタのbit2がTENDフラグ)
TEND_sampling[0] = SCI0.SSR.BYTE; ← 上の画面コピーの左側の赤枠 SCI0.TDR = data; TEND_sampling[1] = SCI0.SSR.BYTE; ← 上の画面コピーの右側の赤枠 TEND_sampling[2] = SCI0.SSR.BYTE; TEND_sampling[3] = SCI0.SSR.BYTE; TEND_sampling[4] = SCI0.SSR.BYTE;
MOV.B 02H[R2], [R5] ; TEND_sampling[0] = SCI0.SSR.BYTE; ← 上の画面コピーの左側の赤枠 MOV.B R15, 01H[R2] ; SCI0.TDR = data; MOV.B 02H[R2], 01H[R5] ; TEND_sampling[1] = SCI0.SSR.BYTE; ← 上の画面コピーの右側の赤枠 MOV.B 02H[R2], 02H[R5] ; TEND_sampling[2] = SCI0.SSR.BYTE; MOV.B 02H[R2], 03H[R5] ; TEND_sampling[3] = SCI0.SSR.BYTE; MOV.B 02H[R2], 04H[R5] ; TEND_sampling[4] = SCI0.SSR.BYTE;
参考:TDRレジスタ書き込み前が送信中状態だった場合の画面コピー(つまり連続送信時の2バイト目の場合)[余談]GR-CITRUSで調べるのに使用した端子(というか自分で立てたピンソケット)の場所の写真
こんにちは。NoMaYです。RX210のハードウェアマニュアルもRX63Nのハードウェアマニュアルも、注意を喚起したかったのは、実は、RX65Nのハードウェアマニュアルが喚起しているレベル検出割り込みの注意事項だったのではなかろうか、という気がし始めていますので、そのレベル検出割り込みの注意事項の現象が実際にSCIgやSCIcで起きるかどうか、調べてみました。結果、RX65NのTBボードでは何事も無かったプログラムがRX631のGR-CITRUSでは確かに偽の送信終了割り込みを発生させる現象を起こしてしまうことが分かりました。(次はハードウェアマニュアル記載の回避手段を確認してみようかと思っています。)プロジェクトのファイル一式 (先日のプログラムを改造、RX631のGR-CITRUSとRX65NのTBボード、CS+プロジェクト)issue_20190217.zip 入れるlstファイルを間違えたので以下へ差し替えました 2019/02/18 1:00issue_20190217.zipRX65Nでは何事も無く動作したプログラム
PORT3.PMR.BYTE |= 0x04U; /* 端子設定 @ PORT */ SCI6.SCR.BIT.TE = 1U; /* 送信許可 @ SCI */ clrpsw_i(); /* 割り込み禁止 @ CPU */ SCI6.SCR.BIT.TEIE = 1U; /* 送信終了割り込み許可(送信終了割り込み信号出力許可) @ SCI */ nop100(); /* 送信終了割り込み信号伝達待ち(取り敢えず NOP 100個) @ SCI → INTC */ /* 動作OK */ SCI6.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ setpsw_i(); /* 割り込み許可 @ CPU */
同等のプログラムでもRX631では偽の送信終了割り込みが発生してしまって動作しない
PORT2.PMR.BYTE |= 0x01U; /* 端子設定 @ PORT */ SCI0.SCR.BIT.TE = 1U; /* 送信許可 @ SCI */ clrpsw_i(); /* 割り込み禁止 @ CPU */ SCI0.SCR.BIT.TEIE = 1U; /* 送信終了割り込み許可(送信終了割り込み信号出力許可) @ SCI */ nop100(); /* 送信終了割り込み信号伝達待ち(取り敢えず NOP 100個) @ SCI → INTC */ /* 動作NG */ SCI0.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ setpsw_i(); /* 割り込み許可 @ CPU */
幾つかNOPを入れて確かめてみると、NOP 6個ではNGでしたがNOP 7個ではOKになりました。NOP 6個 ⇒ 動作NG (まだsetpsw_i()のタイミングが早いため偽の送信終了割り込みが発生する)
/* 動作NG */ SCI0.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ nop6(); /* NOP 6個 ⇒ 送信前に偽の送信終了割り込み発生 ⇒ 動作NG */ setpsw_i(); /* 割り込み許可 @ CPU */
NOP 7個 ⇒ 動作OK (充分setpsw_i()のタイミングが遅いため偽の送信終了割り込みが発生しない)
/* 動作OK */ SCI0.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ nop7(); /* NOP 7個 ⇒ 送信前に偽の送信終了割り込み無し ⇒ 動作OK */ setpsw_i(); /* 割り込み許可 @ CPU */
なお、添付したプロジェクトですが、動作OKの場合と動作NGの場合で、それぞれTeraTermの表示内容が以下の画面コピーのようになります。動作OKの場合動作NGの場合(何も表示されない)[追記]朝になって気付いたのですが、RX65NのTBボードでプログラムが何事も無く動作したのは、もしかすると、RX65Nでは送信終了割り込みがグループ割り込みになっているからかも知れません。つまり、setpsw_i()の後に実際は偽の送信終了割り込み要因でグループ割り込みが発生してしまっているけれども、グループ割り込み処理ルーチン内で要因判定しようとしている箇所が実行されるタイミングでは、その偽の送信終了割り込み要因は既に降りていて、送信終了割り込み処理ルーチンが実行されずに済んでいたのかも知れません。後で、調べてみます。
eLeMさん、こんにちは。NoMaYです。この7クロックというのは、内蔵周辺回路のレベル割り込み信号出力が、CPUが内蔵周辺回路にライトしたことで出力が変化して、それが割り込みコントローラを経由し、CPUに認識されるまでの(RX631に於いてのSCIのTENDでの)遅延です。ある端子へのポート出力を別の端子からのポート入力で読む場合は、また違う遅延のカラクリになってしまう筈です(あるいは遅延が無い可能性もあります)。きっと、事例ごとに確認するしかないのだろうな、という気がします。ですが、今回、ハードウェアマニュアルを読んでいて、RXマイコンにはバスアクセスの高速化手法として色々な事例に共通的に影響する以下のような手法が採用されているらしい、ということを認識するようになりました。(1) CPUが(少なくとも?)内蔵周辺回路バスでライトアクセスする際には1エントリのライトバッファが使われるらしい(1-A) CPUはライトバッファにアドレスとデータをラッチさせるところまでしかケアしない(1-B) CPUは、ラッチさせたら、さっさと次の命令実行に移ってしまう(1-C) ラッチされたアドレスとデータに従って、内蔵周辺回路バスが自立的にライトアクセスを開始→完了させる(2) CPUは内蔵周辺回路バス(に限らず?)でリードアクセスする際にはリードアクセスの完了を待たないらしい(2-A) CPUはリードすべきアドレスを内蔵周辺回路バスに引き渡すと、とりあえず次の命令実行に移ってしまう(2-B) 内蔵周辺回路バスは自立的にリードアクセスを開始→完了させるべく動作する(2-C) CPUは、演算等で本当にリードデータが必要になった時にリードアクセスが未完了だった時、ようやく命令実行に「待ち」が生じる(3) 上記の(1-C)も(2-B)も開始されないまま命令実行が先へ先へと進んでいくことがあるらしい(3-A) 上記の(1-C)と(2-B)の順序は維持される筈(?)(3-B) (1-C)が完結してから(2-B)が開始される筈(?)そして、これらに加えて、SCIのTENDの割り込みでは、信号が割り込みコントローラを通り抜ける時間も関係してくるだろうと思われます。他方、IOポートの場合は、上記の(3-B)により遅延は生じないかも知れません。
リカルドさん、こんにちは。NoMaYです。> ボーレイトにも関係するかも知れませんよ。ボーレイトを遅くしてテストしてみたらどうでしょう。あと、PCLKも関係するかも知れないような気がします。追々調べてみようかと思います。それと、ハードウェアマニュアル上は、命令実行と割り込み発生/割り込み要求取り消しのタイミングのズレの回避手段(命令実行が先に進まないように待たせる手段)は、前の投稿に書いた(2-C)ということになっていますので、それも調べてみようかと思います。(でも、あれっ、信号が割り込みコントローラを通り抜ける時間に関しては?という気がしなくもないですが、、、)
eLeMさん、こんにちは。NoMaYです。>最後に、話がずれてしまいますが、RX63Nのマニュアルの抜粋されている部分ですが、>私には、TDRに書き込んだら、常にTENDをチェックしなければいけないような記述に読めるんですけど、>(他にもこんな記述のところ、ありますよね!)>日本語がおかしい? だけで、皆さん読みに行いきませんよね???その件が、このスレッドの初めに書いた私がゴソゴソやり始めたきっかけの「SCIのTENDフラグの注釈」というスレッドの件ですね。そのスレッドに書いたように、私は私で、また別の意味に受け取ってしまいましたが、、、でも今は、ひょっとしたら、命令実行(内蔵周辺レジスタへの書き込み命令/本当の書き込みタイミング/後続の命令)(前の投稿に書いた以下の(3)のこと)と割り込み発生/割り込み要求取り消しのタイミングに関しての話をしたかったのでは?という気がしています。>(3) 上記の(1-C)も(2-B)も開始されないまま命令実行が先へ先へと進んでいくことがあるらしい
こんにちは。NoMaYです。以前の投稿で、RX631では動作しなかったプログラムと同等の以下のプログラムがRX65NのTBボードで何事も無く動作したのは、もしかすると、RX65Nでは送信終了割り込みがグループ割り込みになっているからかも知れない、と書いたのですが、それを確かめてみました。結果、やはりそういうことでした。プロジェクトのファイル一式 (先日のプログラムを改造、RX65NのTBボード、CS+プロジェクト)issue_20190220.zip以前の投稿でRX65Nでは何事も無く動作してしまったプログラム???
PORT3.PMR.BYTE |= 0x04U; /* 端子設定 @ PORT */ SCI6.SCR.BIT.TE = 1U; /* 送信許可 @ SCI */ clrpsw_i(); /* 割り込み禁止 @ CPU */ SCI6.SCR.BIT.TEIE = 1U; /* 送信終了割り込み許可(送信終了割り込み信号出力許可) @ SCI */ nop100(); /* 送信終了割り込み信号伝達待ち(取り敢えず NOP 100個) @ SCI → INTC */ /* 動作OK??? */ SCI6.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ setpsw_i(); /* 割り込み許可 @ CPU */
今回、グループ割り込みと送信終了割り込みを実験用に以下のように変更src/smc_gen/r_bsp/mcu/rx65n/mcu_interrupts.c (元々のグループ割り込みハンドラを削除)
#if 0 /* toriaezu */#pragma interrupt group_bl0_handler_isr(vect=VECT(ICU,GROUPBL0))void group_bl0_handler_isr (void){ if (1 == ICU.GRPBL0.BIT.IS1) { R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI0_ERI0, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR); } if (1 == ICU.GRPBL0.BIT.IS0) { R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI0_TEI0, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR); }途中省略 if (1 == ICU.GRPBL0.BIT.IS13) { R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI6_ERI6, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR); } if (1 == ICU.GRPBL0.BIT.IS12) { R_BSP_InterruptControl(BSP_INT_SRC_BL0_SCI6_TEI6, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR); }途中省略 if (1 == ICU.GRPBL0.BIT.IS29) { R_BSP_InterruptControl(BSP_INT_SRC_BL0_DOC_DOPCI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR); } if (1 == ICU.GRPBL0.BIT.IS31) { R_BSP_InterruptControl(BSP_INT_SRC_BL0_PDC_PCERI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR); } if (1 == ICU.GRPBL0.BIT.IS30) { R_BSP_InterruptControl(BSP_INT_SRC_BL0_PDC_PCFEI, BSP_INT_CMD_CALL_CALLBACK, FIT_NO_PTR); }}#endif
src/smc_gen/Config_SCI6/Config_SCI6_user.c (グループ割り込みハンドラを送信終了割り込み処理で代用)
#if 1 /* toriaezu */#pragma interrupt r_Config_SCI6_transmitend_interrupt(vect=VECT(ICU,GROUPBL0))#endifvoid r_Config_SCI6_transmitend_interrupt(void){ PORT3.PMR.BYTE &= 0xFBU; SCI6.SCR.BIT.TIE = 0U; SCI6.SCR.BIT.TE = 0U; SCI6.SCR.BIT.TEIE = 0U; r_Config_SCI6_callback_transmitend();}
結果、RX65NでもRX631と同じ以下のようになったNOP 0個 ⇒ 動作NG
/* 動作NG */ SCI6.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ /**/ /* NOP 0個 ⇒ 送信前に偽の送信終了割り込み発生 ⇒ 動作NG */ setpsw_i(); /* 割り込み許可 @ CPU */
NOP 6個 ⇒ 動作NG
/* 動作NG */ SCI6.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ nop6(); /* NOP 6個 ⇒ 送信前に偽の送信終了割り込み発生 ⇒ 動作NG */ setpsw_i(); /* 割り込み許可 @ CPU */
NOP 7個 ⇒ 動作OK
/* 動作OK */ SCI6.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ nop7(); /* NOP 7個 ⇒ 送信前に偽の送信終了割り込み無し ⇒ 動作OK */ setpsw_i(); /* 割り込み許可 @ CPU */
こんにちは。NoMaYです。RX210のハードウェアマニュアルでは、以下の画面コピーの通り、TDRレジスタにライトした後に、SSRレジスタをリードして、更にリード値で何らかの演算をせよ、との指示があります。今回、この演算の有無と送信終了割り込み要求取り消しタイミングとの関係を、今までと同じ手法で調べてみました。(この演算の役割は先日の投稿に書いた通りです。) 次は、ボーレートを変えたり、ICLKとPCLKの比を変えたり、等してみようと思っています。(その後、無茶なDMAの使い方をして、内蔵周辺回路バスを渋滞させて、挙動を調べてみることにトライしてみようかとも思っています。)プロジェクトのファイル一式 (先日のプログラムを改造、RX631のGR-CITRUSとRX65NのTBボード、CS+プロジェクト(rcpe同梱))issue_20190221.zipRX210のSCIcのTENDフラグの説明 (赤枠は私によるものです。)www.renesas.com/jp/ja/doc/products/mpumcu/doc/rx_family/r01uh0037jj0150-rx210.pdf今回は以下の少し変なインラインアセンブラ関数を使用(使い捨てるつもりで'_'という名前にしてあります)
#pragma inline_asm _void _(uint32_t data){}
リードと演算有りの場合
/* 動作OK */ SCI0.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ _(SCI0.SSR.BYTE & 0x04); setpsw_i(); /* 割り込み許可 @ CPU */
MOV.B R1, 01H[R2] MOVU.B 02H[R2], R1 AND #04H, R1 SETPSW I
リードのみ(演算無し)の場合
/* 動作NG */ SCI0.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ _(SCI0.SSR.BYTE); setpsw_i(); /* 割り込み許可 @ CPU */
MOV.B R1, 01H[R2] MOVU.B 02H[R2], R1 SETPSW I
リードのみ(演算無し)でNOP 5個の場合
/* 動作NG */ SCI0.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ _(SCI0.SSR.BYTE); nop5(); // 参考情報:以前のSSRリード無しの場合ではNOP 6個だった setpsw_i(); /* 割り込み許可 @ CPU */
MOV.B R1, 01H[R2] MOVU.B 02H[R2], R1 NOP NOP NOP NOP NOP SETPSW I
リードのみ(演算無し)でNOP 6個の場合
/* 動作OK */ SCI0.TDR = data; /* 送信&送信終了フラグクリア @ SCI */ _(SCI0.SSR.BYTE); nop6(); // 参考情報:以前のSSRリード無しの場合ではNOP 7個だった setpsw_i(); /* 割り込み許可 @ CPU */
MOV.B R1, 01H[R2] MOVU.B 02H[R2], R1 NOP NOP NOP NOP NOP NOP SETPSW I