RXマイコン、クロックプロファイルクラスの導入

クロック設定を見直す

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」にどの周波数を使うか指示する。

まとめ

かなり広範囲な修正だったが、それだけの価値はあると思う。