RXマイコン、TPUテンプレートクラス、その1

最近、仕事が忙しく、更新が無かった・・・

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にプッシュ済み。

今回はここまで。