DTCを用いたRSPI通信時の割り込みについて

皆様

毎度お世話になっております。

 

RX71Mマイコンを使用して、DTCによりRSPIから32bitのデータを連続送受信することを試みています。

現時点でDTCが正常に起動して、実際に通信も起きていることが確認できたのですが、

CPUへの割り込みが2回発生してしまう問題があります。

DTCはFITモジュールを使用しており、CPU割り込みはDTCの全転送終了後に1度発生する設定にしてあります。

 

DTCの転送回数を2回や4回などに変更しても、同じようにCPU割り込みは2回発生しています。

 

通信の流れは以下のようにしています。

 

①RSPI0の割り込みを無効化

②DTC起動要因の設定(FITモジュールのR_DTC_Create, R_DTC_Control関数)

③RSPI0の割り込みを有効化

④RSPI.SPDR.LONGレジスタに最初の32bitデータを書き込み

 

④に関しては、現時点では送信バッファエンプティ割り込みを発生させるために、最初のデータはプログラムから手動で書き込んでいます。

 

割り込みのタイミングに関しては、

最初の一回は④で書き込んだデータの転送終了時、2回目はDTCの全転送終了時に発生しているようです。

 

自分の希望としては、最初の一回目の割り込みは発生しないようにして、2回目の割り込みだけを発生させるようにしたいのですが、

そのような方法はあるのでしょうか?

 

よろしくお願いいたします。

 

開発環境:CS+ for CC V7.00.00

使用デバイス: RX71M_RSK

  • anonyさん、こんにちは。NoMaYです。

    RX65N TBボードとRXスマートコンフィグレータでコード生成させ(更にあれこれ修正して)試してみたところ、この場合でも同様に送信バッファエンプティ割り込みが2回発生していました、、、

    プロジェクトのファイル一式 (RX65NのTBボード、CS+プロジェクト(rcpeファイル同梱))
    issue_20190304.zip

    割り込み回数は素朴に以下のようにしてカウントしました。

    src\smc_gen\Config_RSPI0\Config_RSPI0_user.c

    #if FAST_INTERRUPT_VECTOR == VECT_RSPI0_SPTI0
    #pragma interrupt r_Config_RSPI0_transmit_interrupt(vect=VECT(RSPI0,SPTI0),fint)
    #else
    #pragma interrupt r_Config_RSPI0_transmit_interrupt(vect=VECT(RSPI0,SPTI0))
    #endif
    static void r_Config_RSPI0_transmit_interrupt(void)
    {
        ////////r_Config_RSPI0_callback_transmitend();
        RSPI0_txint_count++;
    }

    結果をTeraTermに送信して割り込み回数を確認したら2回発生していました。

  • NoMaYさん
    ご親切にありがとうございます。お作りいただいたプロジェクトの方を頂戴しました。
    RX65Nでも同様の問題が発生するのですね

    一応自分の方で、ダミー割り込みを発生させるためにSPEを1にした直後(いただいたプロジェクトだとR_Config_RSPI0_Send_Receive内)でIR(RSPI0, SPTI0) = 0;の処理を入れることで、割り込みが1回に出来ているらしいということが分かりました(ただしDTCが1度しか起動していないのですが・・・)

    コード生成で出力されたDTCを用いて再度試してみたいと思います。
  • 2回クリアしてみてはどうかと書きましたが、少し曖昧でしたので、
    送信データセット部のコードを見てみました。
    下記の順になっていました。他にネタが無かったら試して頂ければと思います。
    繰り返しますが、RX63TとRX71Mで違ってたらごめんなさい、です。

    xxx.SPE = 0;
    ...
    xxx.SPTIE = 0;
    IR(RSPI0, SPTI0) = 0; //既にセットされている場合の分を消す(DTC起動にするためにも必要)
    xxx.SPE = 1;
    IR(RSPI0, SPTI0) = 0; //SPE=1でフラグ発生するが、自分で送信データをセットする分として消す
    xxx.SPDR.LONG = data;
    xxx.SPTIE = 1;

    こちらの案件では、RSPIにはDTCを使っていないのですが、DTCのセットアップの配置は、SPE=0からSPE=1の間だと思います(まずはDTCを分離して挙動を把握できると良いと思います)。

    NoMayさんの 3/4 17:04 の投稿ですが、そのように感じます
    (ハード設計の意図は最初のデータも割込ルーチンでセットするようにしたいと感じる)
    最初のデータをセットだけのために、割込を起動するのは、個人的には時間的に無駄と感じます。
    結局、最初の送信データは自分でセットして、割込フラグは自分で消すようにしてしまいます。
    割込を利用すると、送信データをセットするところは1箇所にまとまるので、ソースコードは、綺麗に見えるかもしれません。どなたでも、他に意図を理解できている方がいれば、教えて頂きたいです。
  • 皆様
    お世話になっております。anonyです

    送信バッファエンプティ割り込みだけでなく、受信バッファフル割り込みもDTCで処理するようにしてみたところ、受信バッファフル割り込みに関してはCPU割り込みは1度しか発生しないことが分かりました。

    送信バッファエンプティ割り込みは相変わらず2回発生してしまいますが、初回の割り込み時にIRn.IRの値を読むと1、2回目に読むと0になっていて、受信バッファフル割り込み時には0となっていることから、この値が1の時にはDTC終了時の割り込み要求ではないという風に判断してしまおうと考えています。

    あまり根拠が明確でないので不安なところではありますが、一先ずその形で進めて、今後も原因を探っていきたいと思います。

    ありがとうございました。
  • anonyさん、こんにちは。NoMaYです。

    こちらのRX65Nで新たに分かったことがあります。そして、(少なくとも)こちらでのカラクリは分かったような気がしてきました。

    今回、送信バッファエンプティ割り込み処理内で、DTCE bitと残り転送カウント数(RAM上の構造体のCRAフィールド)の内容を記録するようにしてみたところ、1回目の割り込みの時点でDTC転送が完了していたことに気付きました。(お昼のanonyさんの投稿を読んだ後、DTC終了を判定するならDTCE bitで判定した方が良いのではと思いプログラムを修正して確認してみた時に、このことに気付きました。)

    それで、私が今予想しているカラクリは、以下の通りです。(転送データ数は3個です。)

    (1) RXスマートコンフィグレータのコードにてダミーの送信バッファエンプティ割り込みを発生させた → DTC転送開始
    (2) DTCは1個目のデータを転送元のRAMからリードしてSPDRへ転送 → 次の送信バッファエンプティ割り込み発生
    (3) DTCは2個目のデータを転送元のRAMからリードしてSPDRへ転送 → 次の送信バッファエンプティ割り込み発生
    (4) DTCは3個目のデータを転送元のRAMからリードしてSPDRへ転送 → DTC転送終了 しかし 次の送信バッファエンプティ割り込みは発生する!
    (5) DTC転送終了割り込み発生 (DTCの仕様としてDTC転送終了割り込みは送信バッファエンプティ割り込みとして発生)
    (6) そして(4)による次の送信バッファエンプティ割り込み発生 ただし DTC転送は終了しているので単なるCPU割り込みとして受け付けられる

    結果を確認していたTeraTermの画面コピー


    プロジェクトのファイル一式 (RX65N TBボード、CS+プロジェクト(rcpeファイル同梱))
    issue_20190305.zip

    割り込み処理内でDTCE bitと残り転送カウント数(RAM上の構造体のCRAフィールド)の内容を変数に記録する箇所

    src\smc_gen\Config_RSPI0\Config_RSPI0_user.c

    #if FAST_INTERRUPT_VECTOR == VECT_RSPI0_SPTI0
    #pragma interrupt r_Config_RSPI0_transmit_interrupt(vect=VECT(RSPI0,SPTI0),fint)
    #else
    #pragma interrupt r_Config_RSPI0_transmit_interrupt(vect=VECT(RSPI0,SPTI0))
    #endif
    static void r_Config_RSPI0_transmit_interrupt(void)
    {
        ////////r_Config_RSPI0_callback_transmitend();
        RSPI0_dtce_chk[RSPI0_txint_count] = ICU.DTCER[39].BIT.DTCE;
        RSPI0_dtc_cra_chk[RSPI0_txint_count] = (dtc_transferdata_vector39.cra_crb >> 16);
        RSPI0_txint_count++;
    }

    転送開始前にDTCE bitと残り転送カウント数(RAM上の構造体のCRAフィールド)の内容を変数に記録する箇所

    src\tb_rx65n_main.c

    int main(void)
    {
    ...
        RSPI0_txint_count = 0;
        RSPI0_dtce_chk_0 = ICU.DTCER[39].BIT.DTCE;
        RSPI0_dtc_cra_chk_0 = (dtc_transferdata_vector39.cra_crb >> 16);

        R_Config_RSPI0_Send_Receive( RSPI0_send_buff, RSPI0_DATA_LEN, RSPI0_recv_buff );
    ...
    }

     

  • わわいです。
    なんやら難しく考えてるようですが、、、
    DTCの起動時というのは、DTCの動作パラメータを、メモリ上より読み出す必要があります。
    で、DTCの起動は、送信割り込みにより起動されます
    1.RSPIに初回データ設定
    2.データ送信開始で送信割り込み発生
    3.送信割り込みによりDTCが起動(送信割り込みはDTCの起動トリガになってるので実際の割り込みは起こらない)
    4.DTCの起動の際に、DTC動作パラメータをメモリ上より読み出し
    5.DTCによるデータ転送

    というシーケンスを経ます
    RSPIのクロックが早い場合、4.の動作パラメータのメモリ上よりの読み出し+DTCのメモリ転送開始までの間に、RSPIの初回転送が済んでしまった場合には、当然のことながら送信エンプティ割り込みが発生します

    この初回の割り込みを発生しないようにするには、RSPIのクロックを遅くする、あるいは、初回でデータ設定を複数ワード設定する、という対処が必要となります

    まあ、現実的には、(前にも書きましたが)割り込みルーチン内でDTCが動作中か否かで、処理をわけることでしょう。
  • anonyさん、こんにちは。NoMaYです。

    こちらのRX65Nでは、私の先日の予想に基づいて割り込みを1回にする方法を考えて試したら出来ました。

    予想したカラクリは、以下の通りです。(転送データ数は3個です。)

    (1) RXスマートコンフィグレータのコードにてダミーの送信バッファエンプティ割り込みを発生させた → DTC転送開始
    (2) DTCは1個目のデータを転送元のRAMからリードしてSPDRへ転送 → 次の送信バッファエンプティ割り込み発生
    (3) DTCは2個目のデータを転送元のRAMからリードしてSPDRへ転送 → 次の送信バッファエンプティ割り込み発生
    (4) DTCは3個目のデータを転送元のRAMからリードしてSPDRへ転送 → DTC転送終了 しかし 次の送信バッファエンプティ割り込みは発生する!
    (5) DTC転送終了割り込み発生 (DTCの仕様としてDTC転送終了割り込みは送信バッファエンプティ割り込みとして発生)
    (6) そして(4)による次の送信バッファエンプティ割り込み発生 ただし DTC転送は終了しているので単なるCPU割り込みとして受け付けられる

    そこで、(5)に対して以下のようにしたら(6)の割り込みは発生しませんでした。

    (5-1) DTC転送終了割り込み処理内で、RSPIからの送信バッファエンプティ割り込みの送出を不許可にして、かつ、ICUに取り込まれて保留中の送信バッファエンプティ割り込みを取り消す(もしあれば)
    (5-2) ogawaさんに教えて頂いたハードウェアマニュアルの記載では最大2個の割り込みが保留される可能性があるが、送信バッファエンプティ割り込みに関しては、DTC転送終了割り込みとしての送信バッファエンプティ割り込みと本物の送信バッファエンプティ割り込みの計2個までとなる(と思う)ので、DTC転送終了割り込み処理内ではDTC転送終了割り込みとしての送信バッファエンプティ割り込みはCPU受付済みですので、保留されている可能性があるのは本物の送信バッファエンプティ割り込みの1個のみである(と思う)
    (5-3) 割り込みの取り消し操作に関しては別スレッド「RX65NのSCIgのTENDフラグの挙動を調べてみた(RX631のSCIcのTENDフラグの挙動も調べてみた)」にあるような点にも注意した

    具体的には、以下の赤文字箇所の処理を行いました。(なお、正直に言うと、投稿文を書き始めてみて、この内蔵周辺回路へのライトの並び(RSPI0.SPCR.BIT.SPTIE、IR(RSPI0,SPTI0)、RSPI0.SPCR2.BIT.SPIIE)ならば、Waitは2つとも無くても大丈夫なような気がして来ています、、、実際に無しにしても大丈夫でした、、、)

    src\smc_gen\Config_RSPI0\Config_RSPI0_user.c

    /******************************************************************************
    * Function Name: r_Config_RSPI0_callback_transmitend
    * Description  : This function is a callback function when RSPI0 finishes transmission
    * Arguments    : None
    * Return Value : None
    ******************************************************************************/

    static void r_Config_RSPI0_callback_transmitend(void)
    {
        /* Start user code for r_Config_RSPI0_callback_transmitend. Do not edit comment generated here */
        RSPI0_dtce_chk[RSPI0_txint_count] = ICU.DTCER[39].BIT.DTCE;
        RSPI0_dtc_cra_chk[RSPI0_txint_count] = (dtc_transferdata_vector39.cra_crb >> 16);
        RSPI0_txint_count++;

        /* Disable transmit interrupt */
        RSPI0.SPCR.BIT.SPTIE = 0U;

        /* Wait for a completion of write access to RSPI and (if exists) an arrival of last interrupt request to ICU */
        if ( RSPI0.SPCR.BIT.SPTIE != 0 ) /* Always false */
        {
            nop(); /* Never come here */
        }

        /* Clear transmit interrupt request (if exists) */
        IR(RSPI0,SPTI0) = 0U;

        /* Wait for a completion of write access to ICU and (if exists) a cancel of last interrupt request to CPU */
        if ( IR(RSPI0,SPTI0) != 0 ) /* Always false */
        {
            nop(); /* Never come here */
        }

        /* Enable idle interrupt */
        RSPI0.SPCR2.BIT.SPIIE = 1U;
        /* End user code. Do not edit comment generated here */
    }

    以下、参考までにプロジェクトのファイル一式を添付します。(なお、今回、送信をDTC転送するものの他に、比較用に、受信をDTC転送するもの、送受信共にDTC転送ではなく素朴に割り込みで行うもの、も一緒に含めました。ただ、今回、コード生成したソースの変更をStart user code ~ End user codeに全て押し込んだこともあって、少し分かり難くなってしまっていますが、、、)

    プロジェクトのファイル一式 (RX65N TBボード、CS+プロジェクト(rcpeファイル同梱))
    issue_20190307.zip
    RX65N_SCFG_RSPI_DTC_SEND_3 → 送信をDTC転送するものの
    RX65N_SCFG_RSPI_DTC_RECV_3 → 受信をDTC転送するものの
    RX65N_SCFG_RSPI_INT → 送受信共に割り込みで行うもの

    以下、結果を確認したTeraTermの画面コピーです。

    割り込みは1回のみ


    [追記]

    RXスマートコンフィグレータでコード生成したソースの話になってしまいますが、送受信共にDTC転送ではなく素朴に割り込みで行うもので、ループバック動作時の送信バッファエンプティ割り込みと受信バッファフル割り込みの回数をカウントしてみました。(添付したzipファイルのRX65N_SCFG_RSPI_INTプロジェクトではカウントしていませんでしたので、少しコードを追加してカウントしてみました。) 結果、送信と受信で割り込み回数は一致していませんでした。送信の方が1回多いのは最後のデータを送信した後の次の送信バッファエンプティ割り込みの分です。

    送受信共にDTC転送ではなく素朴に割り込みで行った時(RXスマートコンフィグレータでコード生成したソース)


    [追記その2]

    上の方で「この内蔵周辺回路へのライトの並び(RSPI0.SPCR.BIT.SPTIE、IR(RSPI0,SPTI0)、RSPI0.SPCR2.BIT.SPIIE)ならば、Waitは2つとも無くても大丈夫なような気がして来ています、、、実際に無しにしても大丈夫でした、、、」と書きましたが、自分自身でソースのコメントに「if exists」と書き込んでいるような箇所に対して、ちょっと試して大丈夫だった、というのは良くなかったですね。ちゃんと確認する手が無いかどうか、これから考えてみます。すみません。

  • NoMaYさん
    お世話になっております。 anonyです。

    返事が遅くなり大変申し訳ございません。

    教えていただいた方法を試してみたところ、無事にこちらでも割り込みを1回にすることができました!
    1回目の割り込み時点で既に転送終了しているという発想がありませんでした。

    大変丁寧に調査していただき恐縮です。
    また何かありましたらよろしくお願いいたします。