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と申します。

    内蔵周辺機能には詳しく無くて、どこまでリプライ出来るか分からない(RSPIはループバックモードを動かした程度、DTCは未経験、RX71Mも未経験)ですけれども、気になったのは、以下の「最初の一回は④で書き込んだデータの転送終了時」に発生する割り込みなのですが、具体的には、何の割り込みなのでしょうか?(送信バッファエンプティ割り込み、アイドル割り込み、エラー割り込み、受信バッファフル割り込み、それ以外?、のどれでしょうか?)

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

  • わわいです
    送信バッファエンプティ割り込みであるなら、

    > ③RSPI0の割り込みを有効化
    > ④RSPI.SPDR.LONGレジスタに最初の32bitデータを書き込み

    この③の時点で割り込みがかかってしまうのは当然じゃないでしょうか。
    ④を先にしたらどうなるでしょう
  • NoMaYさん、わわいさん
    ありがとうございます。

    >NoMaYさん
    >「最初の一回は④で書き込んだデータの転送終了時」に発生する割り込みなのですが、具体的には、何の割り込みなのでしょうか?

    この割り込みの種類は、送信バッファエンプティ割り込みになります。
    また現在はRSPI送信処理だけを確認するために、RSPI機能の割り込みは送信バッファエンプティ割り込みのみを有効化している形にしてあります。

    >わわいさん
    >この③の時点で割り込みがかかってしまうのは当然じゃないでしょうか。
    >④を先にしたらどうなるでしょう

    現在は③の時点では送信バッファエンプティ割り込みが入らず、④で格納したデータの送信終了時に割り込みが入るようになっております。
    仰るように④と③を逆にして実行してみたのですが、その場合には割り込みが一度も発生しませんでした。

    まず送信バッファエンプティの割り込み要因として、「SPCR.SPTIEビットが“1”の状態で送信バッファエンプティ(SPTEFフラグが“1”)になったとき」という風にRX71Mのマニュアルには記載されていて、
    SPTEFフラグが1になる条件としては、
    「• SPCR.SPE ビットが“0” (RSPI 初期化) のとき
    • 送信バッファからシフトレジスタに送信データが転送されたとき」
    という記載があります。

    このことから、割り込みを有効化しただけでは割り込みは発生せず、送信バッファ(RSPI.SPDR.LONG)にデータを書き込み、それがシフトレジスタに転送されて初めて割り込みが発生しているのだと思われます。(送信バッファエンプティ割り込みの検出方法はエッジ検出なので、割り込み有効化中に送信バッファに書き込む必要がありそうです)

    割り込み発生のタイミングに関しては意図通りなのですが、最初の一度目の割り込みで割り込みハンドラが起動してしまうのを回避したいです。
    もしくは、割り込みハンドラが起動してしまうにしても、それが最初の一度目のものなのか、それともDTCの全転送終了時のものなのかを区別できれば、と考えております。

    長文失礼いたしました。
    よろしくお願いいたします。
  • わわいです
    なるほど、エッジ検出なんですね
    RSPIのクロックをかなり早くしていると見受けられますが、もしかしるとDTCの最初のデータ転送が間に合ってないという話なのかもしれません
    そういうことで、2回の割り込みが発生するというのはしようがない、ということで、割り込みの中でDTCの動作状況をチェックし、DTCの動作中であればその割り込みの処理をスキップする、というのではどうでしょうか
  • anonyさん、こんにちは。NoMaYです。

    RX71Mのハードウェアマニュアル(画面コピー)のDTCの割り込みの説明とINTCのブロック図を見る限り、どうして「最初の一回は④で書き込んだデータの転送終了時」に送信バッファエンプティ割り込みが発生するのか、不思議ですね、、、もう少しハードウェアマニュアルを見てみます、、、

    www.renesas.com/jp/ja/doc/products/mpumcu/doc/rx_family/r01uh0493jj0110-rx71m.pdf
    今回は前者の設定ですね

    割り込み要因の伝播経路(推測)からは最初の一回目の挙動は不思議ですね(ただ、ブロック図はブロック図、ですが、、、)

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

    RXマイコンでは、送信割り込みを使った連続送信処理をシンプルに記述する手法として、ダミーの送信バッファエンプティ割り込みを強制的に発生させる手法がありますが、その手法と今回の謎の1回目の割り込みとは話が整合しているような予感がしなくもないような気がしてきました。もし、この手法がDTCでも使えるのであれば、そもそも最初の1バイト目の送信を特別扱いすることなく、最初の1バイト目からを全てDTC転送することが出来るようになるのですが、そのことを見越して、そのような挙動になっている可能性もあります。ですが、まだ、ハードウェアマニュアルに記載を見付けることは出来ていません。(なお、ハードウェアマニュアルの他に、RXスマートコンフィグレータでRSPI+DTCで送信するコードを生成させ、そのコードを参考に見てみようかとも思い始めました。)

    なお、以下のRX71Mのハードウェアマニュアルの画面コピーは、DTC(やDMA)が絡んで来ない状況でRSPI単独またはSCI単独(参考)でダミーの送信バッファエンプティ割り込みを強制的に発生させるやり方について書かれた箇所ですが、参考までに抜き出してみました。

    RSPIの場合


    SCIの場合

  • こんにちは、当方、RX62T, RX63T でRSPIの使用経験あり、DTCの使用経験あり、FITの使用経験無しです。

    まず、④の前で、送信バッファエンプティのIRn.IR がセットされていないでしょうか。
    RX71Mハードマニュアル 1.10のp.472、表15.9の注2に、
    「IRn.IRフラグが“1”のとき、再度発生した割り込み要求(DTC/DMA転送要求)は無視されます。」
    とあります。フラグがセットされていて、④の後にDTC起動でなくCPU割込となっていないでしょうか。

    フラグクリアでもNGなら、騙されたと思って、2回クリアしてみて試してもらえると嬉しいです。
    RX71Mのマニュアルに同様の記載は見当たりませんでしたが、RX63Tのマニュアルのp.320の注1に、
    「ただし、SCI、RSPI、RIIC の各送信割り込み/ 受信割り込みの場合、IRn.IR フラグが“1” の状態で発生した
    割り込み要求は保持され、IRn.IR フラグが“0” になった後、保持された要求によって再度IRn.IR フラグが“1”
    になります。」
    と書かれています。RX62TからRX63Tへ移行するときに、ハマりました。RX71Mでは外れかもしれません。なお、RSPIだけでなく、UARTでも問題になりました。
  • 後半の、RX63Tのマニュアルの記載内容については、なぜそのような仕様になっているのか(なぜRX62Tから変更したのか)、目的がよく分かりませんので、理解できる方、教えて頂けると助かります。2回クリアしないと、履歴を完全に消すことはできないと捉えています。
  • 皆様
    anonyです。
    様々な情報をご提供くださりありがとうございます。

    皆様から頂いた情報をもとにいろいろと変更をかけていたのですが、結局未だに解決に至っておりません。
    現在は以下のような処理にしています

    ①RSPI機能を有効化(SPEビットを1)
    RSPI0.SPCR.BIT.SPE = 1;

    ②送信バッファエンプティ割り込みの無効化
    SYSTEM.PRCR.WORD = 0xA50BU;
    IEN(RSPI0,SPTI0) = 0U;
    RSPI0.SPCR.BIT.SPTIE = 0U;

    ③DTC起動要因の設定
    dtc_cfg.transfer_mode = DTC_TRANSFER_MODE_NORMAL;
    dtc_cfg.data_size = DTC_DATA_SIZE_LWORD; //32bit data
    dtc_cfg.src_addr_mode = DTC_SRC_ADDR_INCR;
    dtc_cfg.chain_transfer_enable = DTC_CHAIN_TRANSFER_DISABLE;
    dtc_cfg.response_interrupt = DTC_INTERRUPT_PER_SINGLE_TRANSFER;
    //dtc_cfg.response_interrupt = DTC_INTERRUPT_AFTER_ALL_COMPLETE;

    dtc_cfg.dest_addr_mode = DTC_DES_ADDR_FIXED;
    dtc_cfg.source_addr = (uint32_t)dtc_src;
    dtc_cfg.dest_addr = (uint32_t)&RSPI0.SPDR.LONG;
    dtc_cfg.transfer_count = 3;
    dtc_cfg.block_size = 1;
      dtc_err = R_DTC_Create(DTCE_RSPI0_SPTI0, &dtc_data, &dtc_cfg, 0);
    dtc_err = R_DTC_Control(DTC_CMD_DTC_START, NULL, NULL);
    dtc_cmd_arg.act_src = DTCE_RSPI0_SPTI0;
    dtc_err = R_DTC_Control(DTC_CMD_ACT_SRC_ENABLE, NULL, &dtc_cmd_arg);

    ④RSPI機能を無効化(SPEビットを0)
    RSPI0.SPCR.BIT.SPE = 0;

    ⑤送信バッファエンプティ割り込みの有効化、SPIの通信設定
    IEN(RSPI0,SPTI0) = 1U; //ここで1にしとかないとDTC起動しない
    RSPI0.SPCR.BIT.SPTIE = 1U;
    RSPI0.SPCMD0.BIT.SPB = 3; //32bit data
    RSPI0.SPCMD0.BIT.SSLKP = 1; //Keep SSL assert when finish

    ⑥IRフラグをクリア
    IR(RSPI0, SPTI0) = 0;
    IR(RSPI0, SPTI0) = 0;

    ⑦RSPI機能を有効化
    RSPI0.SPCR.BIT.SPE = 1;

    この処理を実行した結果、CPU割り込みが2回発生し、通信はなぜか発生しないようになってしまいました。
    しかし、通常実行ではなくエミュレーターでステップ実行をしたときには、⑦でSPEビットを1にした瞬間に、1回の32ビット通信が発生していることが確認できました。

    また、DTCからCPUに割り込みを発生させるタイミングも、全転送終了時でなく一回の転送終了毎に変更しました。(なぜかこちらにしないと通信が発生しなくなってしまいました。)

    正直色々いじっているうちにどこか元々の設定がおかしくなってしまった感がありますので、もう一度新規プロジェクトを作って試してみたいと思います。

    また何か進展しましたら報告いたします。
  • anonyさん、こんにちは。NoMaYです。

    RXスマートコンフィグレータでコード生成させたコードを見たところ、以下のようになっていて、最初の1バイトの送信を特別扱いしていないようでした。今回の件は、だんだんと、ダミーの送信バッファエンプティ割り込みを使う前提に立った上での、そういう割り込みを発生させるようになっているという、DTC(およびDMAも)の仕様なのではないだろうか?という気がしてきました。[追記] 17:55 下の方に追記しました。

    src\smc_gen\Config_RSPI0\Config_RSPI0.c

    /******************************************************************************
    * Function Name: R_Config_RSPI0_Send_Receive
    * Description  : This function sends and receives RSPI0 data
    * Arguments    : tx_buf -
    *                    transfer buffer pointer (not used when data is handled by DMAC/DTC)
    *                tx_num -
    *                    buffer size
    *                rx_buf -
    *                    receive buffer pointer (not used when data is handled by DMAC/DTC)
    * Return Value : status -
    *                    MD_OK or MD_ARGERROR
    ******************************************************************************/

    MD_STATUS R_Config_RSPI0_Send_Receive(uint32_t * const tx_buf, uint16_t tx_num, uint32_t * const rx_buf)
    {
        /* Enable transmit interrupt */
        RSPI0.SPCR.BIT.SPTIE = 1U;

        /* Enable receive interrupt */
        RSPI0.SPCR.BIT.SPRIE = 1U;

        /* Enable error interrupt */
        RSPI0.SPCR.BIT.SPEIE = 1U;

        /* Enable RSPI function */
        RSPI0.SPCR.BIT.SPE = 1U;

        return MD_OK;
    }

    [追記] 17:55

    更にコードを見ていたら、以下のようにもなっていて、r_Config_RSPI0_transmit_interrupt()で素朴にr_Config_RSPI0_callback_transmitend()が呼ばれているので、これは送信バッファエンプティ割り込みは1回しか発生していないことを示唆しているようにも、思え始めました、、、(RX71Mは手元に無いので、自分でRX65Nで確かめてみた方が良さそうな気がしてきました、、、)

    src\smc_gen\Config_RSPI0\Config_RSPI0_user.c

    /******************************************************************************
    * Function Name: r_Config_RSPI0_transmit_interrupt
    * Description  : This function is SPTI0 interrupt service routine
    * Arguments    : None
    * Return Value : None
    ******************************************************************************/
    #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();
    }

    途中省略

    /******************************************************************************
    * 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 */
        /* End user code. Do not edit comment generated here */
    }