RXマイコン、ポート、システムクロック、テンプレートの考察

ちょっと横道にそれて、ソースコードをクリーンアップしている。

開発初期では、あまり深く考えないで、安全確実なシンプルなコードで運転
していたが、もうそろそろ、気になっていた、柔軟性に欠ける部分を更新す
る時期なのかもしれない。


まず、ポート関係、RXマイコンでは、非常に沢山のラインナップがあり、
パッケージによっても使えるポートが変化するので柔軟な創りが要求される。

ただ、全てのRXマイコンに対応させる品質にするのは大変だし、自分で使
うデバイスのみ定義を行い、新しいデバイスを使う必要性が生じ場合を考慮
して、「対応できるように」を目標に実装しておく。

とりあえず、カレントのデバイスは、RX64M、RX24Tなので、それ
らを中心に考える。
※最近は使わなくなった、RX621も(秋月@950)なので、CPはそ
れなりに高いから追加しておくべきかもしれない。

デバイスで異なる典型的なレジスタとして「ODR」(オープンドレイン制
御)がある。
RX64M、RX24Tで以下のようになっている

            P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 PA PB PC PD PE PF PG PJ
RX24T ODR0  o  o  o  o  x  x  x  o  o  o  o  o  x  o  o  -  -  -
      ODR1  x  x  o  x  x  x  x  o  x  o  o  o  x  o  o  -  -  -
RX64M ODR0  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o
      ODR1  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o  o

※o: 有効、x: 無効、-: ポート無し

この事実を踏まえ、ポートのテンプレートを以下のように定義して、

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  ポート定義基底クラス(PDR, PODR, PIDR, PMR, PCR, DSCR)
    @param[in]	base	ベースアドレス
    @param[in]	option	オプション
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <uint32_t base, class option>
struct port_t : public option {

...

};

ODR の定義は、option クラスとして継承させる事にすると・・

typedef port_t<0x0008C002, odr_oo_t<0x0008C084> > PORT2;
typedef port_t<0x0008C003, odr_oo_t<0x0008C086> > PORT3;
typedef port_t<0x0008C004, odr_oo_t<0x0008C088> > PORT4;
...

※RX64M

...
typedef port_t<0x0008C002, odr_oo_t<0x0008C084> > PORT2;
typedef port_t<0x0008C003, odr_ox_t<0x0008C086> > PORT3;
typedef port_t<0x0008C004, odr_xx_t<0x0008C088> > PORT4;
...

※RX24T
のように最終的な定義とした。

ここで、ODR 定義の option クラスは、

odr_oo_t    --->    ODR0、ODR1 の定義がある
odr_ox_t    --->    ODR0 のみ定義がある
odr_xx_t    --->    ODR0、ODR1 両方の定義が無い

とする。
※「odr_xx_t」は、中身の何も無いテンプレートとなっている。

あと、ポートのビット割り当ては、パッケージのピン数などでも変化があるの
で、今回は見送った(そこまでする必要があるか?)、しかしながら対応する
事は可能。

RX600/port.hpp


次にクロック関係の定義:

本来、特別な理由が無い限り、マイコンを定格より低いクロックで動作させる
事は稀(消費電力など)と思うが、一応定義はスマートに出来るようにしてお
きたい。
※初期のRXマイコンでは、USBを使う場合、12MHzのn倍にしか設定
できないので、RX621などでは、100MHzまで動作が可能でも、96
MHzでしか動かせない制限がある。
※最近のRXではPLLの設定範囲や、構成を見直し、なるべく最大のパフォ
ーマンスが出せるような工夫がされている。

(1)外部接続のクリスタルを選べる事
(2)PLL動作周波数の選択
(3)内部ペリフェラルのクロック選択

RXマイコンでは、内部のペリファラルをグループ分けしてあり、それに対応
するクロックを個別に供給している。
※専用の分周期を持っている。

以前から、Makefile 内で、コンパイルオプションを利用して、変数定義として、
各モジュールのクロック周波数を定義していた。

-DF_ICLK=80000000 -DF_PCLKA=80000000 -DF_PCLKB=40000000
-DF_PCLKD=40000000 -DF_FCLK=20000000

※しかし、実際の分周非の設定は、適切な値を直接設定していた。

これは、(3)に相当する部分で、シリアルのボーレートや、タイマー周期、
時間待ちループなどの基数として利用してきた。
外部クリスタルの周波数を変更した場合、それに合わせて、適切な値を設定す
る必要があるので、イマイチ柔軟性に欠けるものの、通常は、クリスタルを頻
繁に交換する事も少ないので、特に仕様を変更せずにそのままにした。
※分周比の設定は、一応計算されるが、割り切れないような設定では問題とな
ってしまう。

(2)は、内部PLLの構成がより柔軟となったもので、RX64Mなどは、
最大速度は120MHzだが、より広範囲の基底周波数を選択できるように、
内部PLLは倍の240MHzまで設定可能となっている。
そこで、クロック設定の際に、内部PLLをどの速度にするかを設定できるよ
うにした。
※PLLの倍率には、制限があるので、入れた数字がそのまま内部基数になる
訳ではないのだが・・

// 10MHz X-Tal, 80MHz
typedef device::system_io<10000000> SYSTEM_IO;
SYSTEM_IO::setup_system_clock(80000000);

※RX24Tでは、内部PLLの最大速度は80MHzなので、上記のように
使用する。

RX24T/system_io.hpp

RX24Tのマルチファンクションタイマー(MTU3)テンプレートの実装

最近RX64M関係の仕事で、忙しかったが、ようやく何とかなった感じで、
やっと、RX24T関係を再開する事ができた。

RX24T用の汎用基板を作ろうと、回路図を引いていて、そういえば、
MTU関係の実装が全く進んでいない事に気がつき、テンプレートを実装し
始めた。(なんか回路図引くのが、億劫)

MTU3は、非常に高機能なので、全てを網羅するような、汎用性の高い
テンプレートを作るのはかなり大変なので、必要な機能を少しづつ実装して
ゆき、その都度改修するしかないと思われる。

とりあえず、インプットキャプチャー機能を試してみた。

今回実装した「mtu_io.hpp」は、テンプレートパラメーターとして、
「mtu.hpp」テンプレートを内包する。

typedef device::MTU0 MTU0;
typedef device::mtu_io<MTU0> MTU0_IO;
MTU0_IO mtu0_io_;

MTUは、9チャネルあるが、全てが同じ機能ではなく、微妙に違う部分が
あり、それらを吸収する構造を考えるのはパズルのようだがそれなりに楽し
い。
※MTU5は、3相モーター用に特化しており、除外した。(指定すると
エラーになる)

「mtu.hpp」は、ルネサスのハードウェアーマニュアルに準拠したクラスな
ので、レジスターの名称は、マニュアルに準拠させている。
だが、割り込み、入出力ポートのマッピングなど、連携して動作する機構が
必要なので、それらの制御が簡潔に書けるように、ヘルパー関数を用意した。
※これは、SCIやI2C、SPIなどの知見を元に考えた構造で、さらに
MTU用に色々と拡張した。

    uint8_t intr_level = 3;		
    if(!mtu0_io_.start_capture(MTU0::channel::A, MTU0_IO::capture_type::positive, intr_level)) {
        utils::format("MTU0 input capture start fail...\n");
    }

こんな感じで書けるようにした。

※チャネルとポートのマッピングは、現在の実装では、標準的ポート固定に
なっているので、変更できる仕組みを考えないといけないが、シンプルな方
法を思いつかないので、そのうちじっくり考える事にする・・

const auto& cap = mtu0_io_.get_capture();
float a = static_cast<float>(mtu0_io_.get_base_clock()) / static_cast<float>(cap.all_count_);
utils::format("Capture: %7.2f [Hz]\n") % a;

こんな感じで、キャプチャーした周期を表示できる。

RX24Tでは、MTUモジュールの最大周波数は80MHzなので、精度
が高いと思ったのだが、かなりずれている・・、ただ、リファレンスの周波数
の精度が悪いだけかもしれないので調査が必要・・・
※R8C/M120ANで出力した信号(R8Cのクロックは内臓RCオシレーター)
※正確なオシレーターを持っていない・・

次は、単純な波形出力を実装してみようと思う。
出力も、ほぼ、キャプチャーと同等なので、実装してみた。

typedef device::MTU1 MTU1;
typedef device::mtu_io<MTU1> MTU1_IO;
MTU1_IO mtu1_io_;

※実験では、MTU1 を使った。

// MTU1 設定
{
    uint32_t frq = 1000;
    if(!mtu1_io_.start_output(MTU1::channel::A, MTU1_IO::output_type::toggle, frq)) {
        utils::format("MTU1 output start fail...\n");
    }
}

MTU1 の出力「PA5/MTIOC1A (36)」を「PB3/MTIOC0A (32)」に繋いで1000Hz
出力。
そしてキャプチャーしてみた。

概ね正確なようだ、昨日の「ズレ」は、R8C/M120ANの周期が不正確
なのが原因だったようだ・・
それでも、真っ当な信号発生器は買うか、作る必要があるようだ・・・

ソースコードは GitHub にプッシュした
インプット・キャプチャー、サンプル
※RX64MのMTUもほぼ同等な機能なので、そのまま使えそうだが、割り
込み関係のハンドリングがかなり異なるので、それを吸収する仕組みを考えな
いとならない。

R8Cを使ったタッチスイッチ(センサー)

以前に、RL78で実験したものをR8Cで焼きなおしたものです。

通常、マイコンの入力ポートは、非常にインピーダンスが高い入力元である事
を利用しています。


ガラスエポキシのユニバーサル基板上に、10mm角の銅版を載せ、表面をポ
リイミドテープなどで絶縁します。
この銅版を入力ポートに接続しておきます。
この銅版は、1Mオームの抵抗でプルアップしておきます。

・この銅版は、等価的には微小なコンデンサと考える事ができます。
・まずポートを出力として、GNDに落とし、コンデンサの電荷をリセットします。
・次に、ポートを入力にすると、1Mオームの抵抗を通じて、コンデンサがチ
ャージされ、微小な時間差で「H」になります。
・この実験では、この時間は、数マイクロ秒~数十マイクロ秒だと考えられます。
※銅版の大きさ、ベースとなるユニバーサル基板の誘電率などの条件で変化する。
※ある程度再現性はあると思うが、環境によって調整が必要。
・上記で計測した時間の違いで、「タッチ」されているか、「開放」なのかを
判断する。
※サンプルでは、通常は常に出力、Lにしておき、コンデンサをショート状態
にしてあり、計測の時だけ、入力にしている。

プログラムを単純にする為、CPUループ数で計測している。

uint16_t count_input_()
{
    uint16_t n = 0;
    INPUT::DIR = 0;  // 検出する場合だけ、「入力」にする。
    do {
        ++n;
    } while(INPUT::P() == 0) ;
    INPUT::DIR = 1;  // 出力
    INPUT::P = 0;    // 仮想コンデンサをショートしてリセット
    return n;
}

実験では、「開放時14」、「タッチ時18以上」となった。

Github

※計測値を単純に表示する場合、「DISP_REF」を有効にする。

RL78の開発は中断しています

RL78/G13系は、低価格で、高性能なマイコンで、R8CとRXの
中間を埋めるものとして期待して、始めたものの、以下の理由で、中断し
ている。

(1) 内臓データフラッシュのハードウェアー仕様などが公開されない。
(2) 内臓データフラッシュ操作ライブラリーは、gcc 環境では提供されな
い。

以上が、「中止」の主要因で、他にもある。
(3) 16ビットマイコン特有の、特殊な制限
(4) RX24Tの存在

(3) については、色々あるが、16ビットマイコンとは言っても、内部の
構成は8ビットマイコンと変わらず、リニアにアクセスできる領域は64
Kバイトとなっており、特別な命令により、広範囲にアクセスできる。
また、領域には特別な意味を持たせ、小さい空間を効率よくアクセスでき
るようにしているが、デバイス特有なもので、専用のコードになってしま
う。

(4) は、コストに関するものだ、RX24Tは、10個購入で@550円
なので、それでもRL78/G13に比べるとコスト高だが、32ビット
マイコンで、80MHz動作、256Kのフラッシュ、16KのRAMと、
かなりCPが高いマイコンではある。
また、あまり多くのデバイスに手を広げるのはリソースの集中の観点から
も良くないと感じる。
当面、R8C、RXマイコンに集中する。

それでも、RL78のリソースは、一通りあり、基本的にハードウェアー
特有の部分は隠蔽してあるので、特別な事をしない限り困らないと思う。
また、R8CやRXのテンプレートライブラリーと共通性がある為、コー
ドの再利用は可能と思う。

GitHub のリポジトリーはそのまま残す。

-----
RX24TはCPが高いが、RTCが無い、CAN、イーサーネットが無
いなど、ハードウェアーを制限している(元々インバーター向けの製品な
ので・・)為、後付すると、RX62系や、RX63系など、より上位の
マイコンとコストは変わらなくなるので、使い方は多少微妙だが・・・