クロック設定を見直す
C++ でRXマイコンフレームワークを作り始めた頃、あまり考えずに、適当に作った部分が、未だに「悪い」見本として残っている。
RXマイコンのクロックジェネレータは、意外と複雑で、面倒な設定を要するデバイスとなっており、柔軟性も必要なのに、かなり適当な創りとなっている。
そこで、これを見直して、もう少し「サッパリ」としたより良い物に変更する。
意外と広範囲な修正になる事から、今まで、見なかった事にしてきたものの、「痛い」部分は速いうちに処置した方が良いので、修正を行った。
以前の設定
以前は、「Makefile」と「main.cpp」の両方で微妙な設定を行っていた・・・
Makefile の設定:
USER_DEFS = SIG_RX71M \
F_ICLK=240000000 \
F_PCLKA=120000000 F_PCLKB=60000000 F_PCLKC=60000000 F_PCLKD=60000000 \
F_FCLK=60000000 F_BCLK=120000000
main.cpp:
#if defined(SIG_RX71M)
typedef device::system_io<12'000'000, 240'000'000> SYSTEM_IO;
...
int main(int argc, char** argv)
{
SYSTEM_IO::setup_system_clock();
ベースクリスタルの周波数は、ソースコードに埋め込んであるのに、クロックジェネレータの分周器による周期は「Makefile」で環境変数で設定してある・・・
これは、初期の実験コードで色々やっていた時、テスト的に行ったものが、「標準」となってしまい、見直す事が先延ばしになり現在に至ったもの。
第三者を交えて、コードレビューを行えば、かなり早い段階で「ツッコミ」を入れられたと思うが、の機会が無く、そのままになっていた・・
改修後
改修後、クロック設定プロファイルクラスを新規に作り、そこに定数として設定してある。
#pragma once
//=====================================================================//
/*! @file
@brief RX71M グループ・クロック。プロファイル @n
クロックジェネレータで発生させる周波数の定義
@author 平松邦仁 (hira@rvf-rc45.net)
@copyright Copyright (C) 2021 Kunihito Hiramatsu @n
Released under the MIT license @n
https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
namespace device {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief クロック・プロファイル・クラス
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
class clock_profile {
public:
static const uint32_t BASE = 12'000'000; ///< 外部接続クリスタル
static const uint32_t PLL_BASE = 240'000'000; ///< PLL ベースクロック
static const uint32_t ICLK = 240'000'000; ///< ICLK 周波数
static const uint32_t PCLKA = 120'000'000; ///< PCLKA 周波数
static const uint32_t PCLKB = 60'000'000; ///< PCLKB 周波数
static const uint32_t PCLKC = 60'000'000; ///< PCLKC 周波数
static const uint32_t PCLKD = 60'000'000; ///< PCLKD 周波数
static const uint32_t FCLK = 60'000'000; ///< FCLK 周波数
static const uint32_t BCLK = 120'000'000; ///< BCLK 周波数
};
}
このソースは、各プラットホーム毎に切り替えて、他ソースから参照するようにしてある。
クリスタルが特殊な場合は、このファイルに追加して、環境変数で切り替えれば良いだろうと思う。
PLL_BASE の周波数は、BASE 周波数の倍率(0.5単位)で割り切れる必要がある。
当然、他の周期も、PLL_BASE からの分周比で割り切れる周波数を設定する必要がある。
また、mainの最初で、クロック周波数を切り替える関数名は、
typedef device::system_io<> SYSTEM_IO;
int main(int argc, char** argv)
{
SYSTEM_IO::boost_master_clock();
とした。
※RX71M は、クロック設定の特定レジスタが、スーパーバイザモードでアクセスする必要があり、その部分を「start.s」で行っている為、「Makefile」にアセンブラに渡す変数がある。
AS_OPT = --defsym MEMWAIT=1
クロックジェネレーターの周波数を参照する場合、以下のように行える。
auto iclk = device::clock_profile::ICLK / 1'000'000;
utils::format("Start test for '%s' %d[MHz]\n") % system_str_ % iclk;
内臓高速発信器を利用する場合
typedef device::system_io<device::system_base::OSC_TYPE::HOCO> SYSTEM_IO;
内蔵高速発信器は、通常、16MHz、18MHz、20MHzがあり、「BASE」にどの周波数を使うか指示する。
まとめ
かなり広範囲な修正だったが、それだけの価値はあると思う。