JiGoRo です。 かふぇルネの皆様へ、教えてください。
RZ/A2Mでソフトウェアをコーディングしてます。
Software Package v4 を FreeRTOS上にて使わせていただいておりますが、SCIFAn のUARTを用いて、半二重通信を実装しようとして困ってます。
困っている点は、次のステップの実装です:
1)データを送信する (ここはOK)
2)データ送信完了後、特定のGPIOポートの状態を1から0に反転させる (*)
3)2に続いてデータを受信する
ここで、3については、1と同時に受信開始しても良いので、動作上は実装できるのですが、2のデータ送信後にポート状態を変更したいという動作が実装できていません。
具体的な目的は、RS485の半二重通信制御となります。 外付けICのRS485 I/Fチップの送受信モードを切り替えたいのです。
現時点は DMAは併用しておりません。 併用したほうが簡単に実装できるのであれば、DMAを使うことは何ら問題ございません。
Smart Configuratorにて、r_scifa/ にコード生成されたものがありますが、送信完了のAPI(もしくはコールバック関数)が見当たらず、上記2の実装が難航しています。
どなたか、ご存じの方、ご教授いただけると助かります。
JiGoRoさん、こんにちは。NoMaYです。これは拙いかな、と気になるところがありました。送信リングバッファに充填する時にずっと割り込み禁止にしてしまっているようですね。最大8Kバイトを処理する時間が割り込み禁止になりそうなのですが、送信割り込み動作も禁止されるので、この期間中([追記] 正しくは、この期間が終了して、割り込み禁止が解除された時)に、自チャンネルや他チャンネルで望まれない送信終了割り込みが発生する危険性があるような気がしてきました。そして、送信終了割り込みで、送信を止める動作をすると思われるR_SCIFA_StopTransmit()を呼び出していますので、以後、送信動作が破綻してしまうかも知れない気がしてきました。(自分の印象ですが、もともとの処理が果たして正しいのか常に気にしながら作業した方が良いかも知れない、という気がします。)generate/sc_drivers/r_scifa/src/hld/r_scifa_hld_prv.c
/** * @brief start_tx starts data transmission * * @param[in] channel Channel to send data. * * @param[in] p_buffer Location of data to send. * * @param[in] ui_count Length of data to send. * * @retval 0 Success * @retval -1 Fail */static void start_tx(int_t channel, const uint8_t *p_buffer, uint32_t ui_count){ size_t free_space; uint32_t i; /* we mustn't be interrupted while manipulating the buffer */ R_COMPILER_DisableInterrupts(); /* find out how much free space there is in the buffer */ free_space = cbFree(gs_ch_ctrl[channel].p_tx_cbuff); /* copy as much of the data as possible into the transmit buffer */ for (i = 0; (i < ui_count) && (i < free_space); i++) { cbPut(gs_ch_ctrl[channel].p_tx_cbuff, p_buffer[i]); } /* we're done with the buffer */ R_COMPILER_EnableInterrupts(); /* set SCR.TIE bit to start transmission */ R_SCIFA_StartTXI(channel); /* put the remaining data into the buffer as space becomes available */ while (i < ui_count) { /* we mustn't be interrupted while manipulating the buffer */ R_COMPILER_DisableInterrupts(); free_space = cbFree(gs_ch_ctrl[channel].p_tx_cbuff); if (free_space > 0) { /* fill up the free space */ while ((i < ui_count) && (free_space > 0)) { cbPut(gs_ch_ctrl[channel].p_tx_cbuff, p_buffer[i]); i++; free_space--; } /* we're done with the buffer */ R_COMPILER_EnableInterrupts(); /* just in case the buffer emptied completely */ R_SCIFA_StartTXI(channel); } else { /* we're done with the buffer */ R_COMPILER_EnableInterrupts(); /* hand over CPU cycles to other tasks while we wait */ R_OS_TaskSleep(5); } }}/****************************************************************************** * End of Function start_tx ******************************************************************************/
上と関連して、これは拙いかな、という、もうひとつの例ですが、TIとTEIを同時にイネーブルするのはそもそもアカンのではないかな、という気がします。(RXスマートコンフィグレータが生成したコードでは、送信バッファエンプティ割り込み(TI)で最終データ送信処理をした後に送信終了割り込み(TEI)をイネーブルするようになっていた筈です。)generate/sc_drivers/r_scifa/src/lld/r_rza2_scifa_lld.c
/** * @brief R_SCIFA_StartTX enable transmit and transmit interrupts * * @param[in] channel to start transmit * * @retval 0 DRV_SUCCESS * @retval -1 DRV_ERROR */int_t R_SCIFA_StartTX (int_t channel){ if ((channel > R_PRV_SCIF_LAST_CHANNEL) || (channel < 0)) { return (DRV_ERROR); } RZA_IO_RegWrite_16((volatile uint16_t *) &gsp_scifa[channel]->SCR.WORD, 1, SCIFA_SCR_TE_SHIFT, SCIFA_SCR_TE); /* enable interrupts to trigger DMA */ RZA_IO_RegWrite_16((volatile uint16_t *) &gsp_scifa[channel]->SCR.WORD, 1, SCIFA_SCR_TIE_SHIFT, SCIFA_SCR_TIE); /* enable transmit end interrupt */ RZA_IO_RegWrite_16((volatile uint16_t *) &gsp_scifa[channel]->SCR.WORD, 1, SCIFA_SCR_TEIE_SHIFT, SCIFA_SCR_TEIE); return (DRV_SUCCESS);}/****************************************************************************** * End of Function R_SCIFA_StartTX ******************************************************************************/