最近、仕事が忙しく、更新が無かった・・・
RXマイコンでタイマー割り込みに使うのに適したペリフェラルはCMTだろ
う、単機能、シンプルで扱いやすく、理解しやすい。
しかし、CMTのカウンターは16ビットだが、プリスケーラーの仕様により
最大で、PCLKBの1/8の周期になってしまう為、間隔の短いタイマー割
り込みを組みたい場合に、誤差が大きくなる場合がある。
※メインクロックとの相性もあるが・・
そこで、他の選択肢としてTPUを使ったタイマーを実装する事にした。
※TPUは、PCLKBの1/1を選択可能なので、より正確なタイミングを
生成でき、ポートの出力も制御できる。
TPUユニットは、RX24Tには無いが、RX64Mには、1ユニット、6
チャネルある。
※RX631、RX63Nなどにもあるようだ。
ただ、面倒なのが、割り込み設定で、RX64Mではモジュールが大量に増え
た為、TPUの割り込みは固定ベクターではなく、選択的なベクターになって
いる。
TPUの操作をテンプレートで実装する場合に、割り込みベクターの管理を自
動で行いたいので、工夫してみた。
※RX631のTPUは、固定ベクターなので、その辺りも上手く吸収できる
ようにしなければならない。
また、TPUの機能は、タイマー割り込みの他、色々な機能があるので、それ
も簡単に扱えるような工夫が必要となるが、全ての機能を盛り込むと、設定が
複雑になるので、ある程度は妥協も必要で、その辺りのバランスが難しい。
※現在は、拡張中・・
TPUを考える前に、省電力機能の管理を少し拡張した。
「省電力機能」は、内部ペリフェラルの電源を「On/Off」して、使わない電力
を削減できるもので、起動時、最低限必要なものしか有効になっていない。
※ドライバー実装時、この省電力を「無効」にするのを忘れて、ペリフェラル
が動作せずに、時間を浪費した事があるのでは無いだろうか?
※注意事項には書いてあるのと、「お約束」ではあるのだが・・
ペリフェラルのテンプレートでは、個別IDを設定しておいて、それを定義に
忍ばせておく事で、他の連携クラスが、固有の動作を切り替えて実現でき、ま
た、連携クラスの実装分担を、ペリフェラルの定義から分離できる。
この簡単な仕組みにより、ペリフェラルの実装時、ペリフェラルやチャネルに
より異なる実装を隠蔽できる。
自分は、「手」を動かす事が好きなので、あーでもない、こーでもないを繰り
返して今の実装になっている。
ペリフェラルの定義:
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// /*! @brief ペリフェラル種別 */ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// enum class peripheral : uint16_t { TPU0, ///< 16 ビットタイマパルスユニット0 TPU1, ///< 16 ビットタイマパルスユニット1 TPU2, ///< 16 ビットタイマパルスユニット2 TPU3, ///< 16 ビットタイマパルスユニット3 TPU4, ///< 16 ビットタイマパルスユニット4 TPU5, ///< 16 ビットタイマパルスユニット5 ... };
TPUの定義:
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// /*! @brief 16 ビットタイマパルスユニット(TPUa) @param[in] base ベースアドレス @param[in] per ペリフェラル型 @param[in] intra 割り込み要因A @param[in] intrb 割り込み要因B @param[in] intrc 割り込み要因C @param[in] intrd 割り込み要因D @param[in] intru 割り込み要因U @param[in] intrv 割り込み要因V */ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// template <uint32_t base, peripheral per, uint8_t intra, uint8_t intrb, uint8_t intrc, uint8_t intrd, uint8_t intru, uint8_t intrv> struct tpux_t { ... //-----------------------------------------------------------------// /*! @brief ペリフェラル型を返す @return ペリフェラル型 */ //-----------------------------------------------------------------// static peripheral get_peripheral() { return per; } };
TPUチャンネル毎の定義:
typedef tpux_t<0x00088110, peripheral::TPU0, 15, 16, 17, 18, 0, 19> TPU0; typedef tpux_t<0x00088120, peripheral::TPU1, 20, 21, 0, 0, 22, 23> TPU1; typedef tpux_t<0x00088130, peripheral::TPU2, 24, 25, 0, 0, 26, 27> TPU2; typedef tpux_t<0x00088140, peripheral::TPU3, 28, 29, 30, 31, 0, 32> TPU3; typedef tpux_t<0x00088150, peripheral::TPU4, 33, 34, 0, 0, 35, 36> TPU4; typedef tpux_t<0x00088160, peripheral::TPU5, 37, 38, 0, 0, 39, 40> TPU5;
※「割り込み要因」は、選択型割り込みを設定する際に必要なIDで、チャネル
毎に機能が微妙に異なるが、シンプルな定義になっている。(0は、割り込み要
因が存在しない場合)
省電力管理で、必要な要素として、チャンネルの起動と廃棄時、まだ、使ってい
るチャネルがある場合に、省電力機能を無効にしないようにする事で、リファレ
ンスカウンタのような仕組みが必要な点だ。
実装は、簡単なのだが、スタティック変数の定義問題がある。
現在、ほぼ全ての実装は、ヘッダーのみで行っているので、それを壊したくは無
いが、単純にスタティック変数を記述すると、その実態として、ソースコードに
も書く必要があり、そうすると、そのソースコードのオブジェクトをリンクしな
ければならなくなる。
そこで、簡単なテンプレート関数を書いて、その中で定義できるようにした。
テンプレートにすると、「実態」をヘッダーに書けるので、ソースとヘッダーに
分ける必要が無くなる。
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// /*! @brief スタティック・ホルダー・テンプレート・クラス @param[in] ST 構造体 */ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// template <class ST> class static_holder { public: static ST st; }; template <class ST> ST static_holder<ST>::st;
実際の定義では以下のようになっている。
struct pad_t { uint8_t tpu_; pad_t() : tpu_(0) { } }; typedef utils::static_holder<pad_t> STH;
この構造体の具体的な操作は、「RX64M/power_cfg.hpp」で行っている。
これら関連したコードはGitHubにプッシュ済み。
今回はここまで。