前回、コンペアマッチタイマーの制御をテンプレート化してみました。
今回は、少し複雑ですが、シリアルコミュニケーションインターフェースをテンプレート化してみます。
実用的なシリアルコミュニケーションでは、通常、受信、送信は割り込みによって行い、メインとは 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 にあります。