前回、コンペアマッチタイマーの制御をテンプレート化してみました。
今回は、少し複雑ですが、シリアルコミュニケーションインターフェースをテンプレート化してみます。
実用的なシリアルコミュニケーションでは、通常、受信、送信は割り込みによって行い、メインとは FIFO などでやりとりします。
さらに RX マイコンでは、DMA も使う事が出来ますが、やりとりするデータ量と、出し入れに係わる細かい操作を考えると、DMA を使う事にあまりメリットが無いので、通常の割り込みで行う設計とします。
FIFO のバッファサイズは、アプリケーションの構造、送受信のボーレート、などにより最適なサイズがあると思われますので、可変に出来るようにします。
※以前のコンペアマッチタイマーより、バッファサイズをパラメーターとしている為、少し複雑です。
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// /*! @brief SCI I/O 制御クラス @param[in] SCI SCIx 定義クラス @param[in] recv_size 受信バッファサイズ @param[in] send+size 送信バッファサイズ */ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// template <class SCIx, uint32_t recv_size, uint32_t send_size> class sci_io { static utils::fifo<recv_size> recv_; static utils::fifo<send_size> send_; static INTERRUPT_FUNC void recv_task_() { bool err = false; if(SCIx::SSR.ORER()) { ///< 受信オーバランエラー状態確認 SCIx::SSR = 0x00; ///< 受信オーバランエラークリア err = true; } ///< フレーミングエラー/パリティエラー状態確認 if(SCIx::SSR() & (SCIx::SSR.FER.b() | SCIx::SSR.PER.b())) { err = true; } if(!err) recv_.put(SCIx::RDR()); } static INTERRUPT_FUNC void send_task_() { SCIx::TDR = send_.get(); if(send_.length() == 0) { SCIx::SCR.TEIE = 0; } } ...
重要な部分は、fifo の定義です、割り込み関数とクラスとで、送受信データをやりとりする必要がある為、「static」としています。
テンプレートのパラメーターから、受信サイズ、送信サイズを受け取って、静的に宣言されます。
割り込み関数も static 宣言します、この関数アドレスは、初期化時、割り込みベクターに渡されるようにしています。
sci_io<device::SCI0, 128, 128> sci0_; sci_io<device::SCI1, 64, 256> sci1_;
↑のように、SCI0、SCI1 を宣言すると、テンプレートパラメーター SCIx が異なる為、static に宣言された fifo の領域は SCI0、SCI1 で別々に確保されます。
クラス内の static 宣言では実態を別に宣言しておく必要があります。
template<class SCIx, uint32_t recv_size, uint32_t send_size> utils::fifo<recv_size> sci_io<SCIx, recv_size, send_size>::recv_; template<class SCIx, uint32_t recv_size, uint32_t send_size> utils::fifo<send_size> sci_io<SCIx, recv_size, send_size>::send_;
どうでしょうか、これで、チャネル毎バッファサイズを変更して静的に使う事が出来ます。
全ソースコードは github にあります。