最近、仕事が忙しく、更新が無かった・・・
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にプッシュ済み。
今回はここまで。