「電子工作な日々」カテゴリーアーカイブ

電子工作に関連するお話など・・

RX140ボード

トラックを引いてみた

イマイチ電源品質が悪いので、もう少し色々やってみる感じだけど、このサイズで両面基板で作れそうな感じ。

KiCAD のオートルーターはかなり優秀で、この程度の規模なら、配線も速いので、何度でも試せる。
昔、プロテルで基板を作っていた時は、コストもそれなりにかかって、かなり苦労したものだが、フリーのCADでこれだけ出来れば文句は無い。
KiCAD 7 は、色々やってもクラッシュしないし、抜群の安定性で、操作性も申し分ない処まで来ている。
このプロジェクトに参加している人には本当に頭が下がる。

32ビット160円のRXマイコンRX140のテスト

160円マイコン

RX140 は、RX100 シリーズ中で唯一の RXv2 コアを採用するマイコンで、単精度浮動小数点演算命令を実行出来る。
この価格帯で、このような高性能マイコンがあるのに少々ビックリした。
詳細は、Qiitaで述べている。

8/16 ビットマイコン(RL78 など)の代替えにベストな選択だと思える。


ROM は 64K、RAM は 16K

容量的には、多少物足りないが、100円 マイコン R8C/M120AN に比べて、大きなアドバンテージがある。
データフラッシュも 4K 内臓するのはありがたい。
RX マイコンは 32ビットだが、CISC 系なので、オブジェクト効率が高く、R8C や RL78 より効率が高い場合もあり、バンクを意識しなくても良いのと、FPU を内蔵するので、ソフトの制作では、非常に助かると思える。


オーバークロック耐性は低い

この CPU は最大 48MHz 動作と、低めの CPU だが、1.8V から動作する。
その仕様のせいなのか、オーバークロックの耐性は低いようだ。
実験した範囲では、60MHz で動作しなくなり、54MHz も一応動作するが、少し怪しい・・

まぁ、48MHz でも十分な性能があると思う。


基板を作りたい

以前から、組み込みマイコンの C++ 勉強会を開きたいと思っており、その場合の教材として良いと思う。
R8C/M120AN では、多少トリッキーな部分もあり、入門用に勧められない部分もあるが、RX140 なら現行品でもあり、機能も十分なので、「お勧め」出来る。
ただ、QFP パッケージでは、扱い難いので、簡単な基板を作りたいと思っている。


USB シリアル

ただの DIP への変換基板だと、フラッシュ書き換え時、USB シリアルを用意する必要がある。
そこで、最低でも、USB シリアルは載せておこうと思い、以前に使った、CP2102N を採用しようと思ったのだが・・・
最近、このデバイスのデリバリーを調べたら、単価が爆上がりしていた。
これでは、採用が難しい・・・
仕方なく、安価な、CH340 を使ってみる事にした。


まとめ

中々気力が沸かなくて、基板の制作は停滞しているけど、今度はちゃんと作ろうと思う。
出来たら、領府しようと思っている。

RXマイコン、クロック設定関係を更新

クロックのブーストを改修

俺俺C++フレームワークでは、クロックのブーストを独自に行っている。

RX64M、RX71M、RX65x、RX671、RX66N、RX72N、RX72M、RX66T、RX72T は、ほぼ共通のレジスタ構成で、共有化していた。
ただ、共有出来ない部分もあり、「#if、#endif」を使って、デバイス毎に、別けていた。

最近、新たな方法を導入して、これを、もっとスマートな方法で分ける方法を実装した。


無効なアクセスを行う定義

RX66T/RX72T には、サブクロック発信器が無いので、それに関係するレジスタは存在しない。

以前は、以下のようにしていた。

#if defined(SIG_RX66T) || defined(SIG_RX72T)
#else
            // サブクロック発信器制御
            device::SYSTEM::SOSCWTCR = 0b0'1010;
            device::SYSTEM::SOSCCR = device::SYSTEM::SOSCCR.SOSTP.b(!clock_profile::TURN_SBC);
#endif

この、「#if ~ #endif」で分ける実装は、一か所くらいなら、まだ良いが多くなると、読み辛くなるしスマートとは言えない、どうしたものかと考えていた。

そこで、根本に返り、レジスタクラスの定義をダミーにする事で、「#if ~ #endif」を除く事が出来る。
その代わり、見た目には、普通にレジスタをアクセスしているようにしか見えないのが問題ではある。
レジスタの定義を確認して、初めて、このアクセスがダミーで無効である事に気が付く。
一応、コメントには、そのように書いてあるが・・・

        template <uint32_t base>
        struct sosccr_null_t : public rw8_null_t<base> {
            typedef rw8_null_t<base> io_;
            using io_::operator =;
            using io_::operator ();
            using io_::operator |=;
            using io_::operator &=;

            bit_rw_t<io_, bitpos::B0> SOSTP;
        };
  • rw8_null_t は、中身は空で、アクセスが発生しても何もしない
  • これは、最適化により、完全に無くなる

この手法をとりあえず、system.hpp に導入し、関係レジスタの定義を見直した

#if defined(SIG_RX64M)
    typedef system_64m_t SYSTEM;
#elif defined(SIG_RX65N) || defined(SIG_RX651)
    typedef system_65x_t SYSTEM;
#elif defined(SIG_RX66N)
    typedef system_66n_t SYSTEM;
#elif defined(SIG_RX671)
    typedef system_671_t SYSTEM;
#elif defined(SIG_RX71M)
    typedef system_71m_t SYSTEM;
#elif defined(SIG_RX72N) || defined(SIG_RX72M)
    typedef system_72n_72m_t SYSTEM;
#elif defined(SIG_RX66T) || defined(SIG_RX72T)
    typedef system_66t_72t_t SYSTEM;
#endif
  • 各クラスは、共通では無い部分のみ定義を行い、共通部分(system_base_t)は、継承している
    struct system_66t_72t_t : public system_base_t {

        static constexpr bool NCRGx_reg    = false;
        static constexpr bool NCRCx_reg    = false;

        // オプション設定メモリ
        static inline spcc_t<0x0012'0040> SPCC;
        static inline ofs0_t<0x0012'0068> OFS0;
        static inline ofs1_t<0x0012'006C> OFS1;
        static inline mde_t <0x0012'0064> MDE;

        static inline memwait8_t<0x0008'101C> MEMWAIT;

        static inline romwt_null_t<0x0000'0000> ROMWT;

        static inline sosccr_null_t<0x0000'0000> SOSCCR;

        static inline soscwtcr_null_t<0x0000'0000> SOSCWTCR;
    };
  • 一応、コメントを入れてあるが、コメントはコードとは異なるので、多少問題があるとは思う・・
            // サブクロック発信器制御
            // サブクロックが RX66T/RX72T では、ダミーアクセスとなる。
            device::SYSTEM::SOSCWTCR = 0b0'1010;
            device::SYSTEM::SOSCCR = device::SYSTEM::SOSCCR.SOSTP.b(!clock_profile::TURN_SBC);

実装ミスがあり、RX66T/RX72T が起動しなかった・・・

  • 電卓プログラムを確認している時、RX66T が起動しなかった。
  • RX66T は RAM が少ないので、それが問題と思って、色々修正したが、動作しない。
  • あれ?と思い、LED 点滅を実験したら、やっぱり起動しない。
  • 調べると、上記のダミーアクセスコードに実装ミスがあり、それが原因だった。
  • 大きな変更をしたら、ちゃんと確認しないと駄目だと痛感した。

RX24T のクロック設定にも問題が・・・

  • 以前に、ソフトディレイループを、アセンブラコードにしたので、RX24T の微調整を行った。
  • クロックを落とすとソフトディレイの誤差が大きくなる。
  • 調べると、「SCKCR」の予約ビットの設定があり、それが抜けていたので修正した。
  • それで、クロックを落とした場合でも、ソフトディレイがある程度正確になった。
  • 最大速度(80MHz)で動かす場合には、問題無かった。

RXマイコン、ソフト遅延を改修

ソフト遅延ループを再度、再考

「attribute ((optimize(1)))」で、上手くいったと思ったら、ループの回数が8回以下だと、インライン展開されるようだ・・

色々、あーでもない、こーでもないと、色々やったが、どうも駄目で、最後はインラインアセンブラで書き直す事とした。
しかし、gcc におけるインラインアセンブラの書式がイマイチ判っていないので、google 先生に尋ねながら何とか、物になる実装を見つけた。
※以前、最適化でループが無くならないように「asm("nop");」を入れていたが、アセンブラならその必要は無いので1マシンサイクル短くなる。
※ラベルの付け方がよくわからない・・、なので、他と「かぶらない」ように冗長な名称にしてある。

        //-----------------------------------------------------------------//
        /*!
            @brief  マイクロ秒単位の待ち @n
                    あまり正確では無く、速度に関連する設定に依存します。 @n
                    ※キャッシュ有効、最高速度での物理計測によるパラメータ
            @param[in]  us  待ち時間(マイクロ秒)
        */
        //-----------------------------------------------------------------//
        static __attribute__((optimize(1))) void micro_second(uint32_t us) noexcept
        {
            asm("cmp #0, %[us]" : : [us] "r" (us) );
            asm("beq.b micro_second_loop0\n\t"
                "micro_second_loop1:");
                uint32_t lpn = device::clock_profile::DELAY_MS;
                asm("micro_second_loop2:\n\t"
                    "sub #1, %[lpn]" : : [lpn] "r" (lpn));
                asm("bne.b micro_second_loop2"); 
            asm("sub #1, %[us]" : : [us] "r" (us));
            asm("bne.b micro_second_loop1\n\t"
                "micro_second_loop0:");
//          while(us > 0) {
//              for(uint32_t n = 0; n < device::clock_profile::DELAY_MS; ++n) {
//                  asm("nop");
//              }
//              if(device::clock_profile::DELAY_T1) { asm("nop"); }
//              --us;
//          }
        }

アセンブラコード(RX24T 80MHz):

fffc01a0 <__ZN5utils5delay12micro_secondEm>:
fffc01a0:   61 01                           cmp #0, r1
fffc01a2:   20 0d                           beq.b   fffc01af <__romdatastart+0xfffffefb>

fffc01a4 <micro_second_loop1>:
fffc01a4:   75 45 14                        mov.l   #20, r5

fffc01a7 <micro_second_loop2>:
fffc01a7:   60 15                           sub #1, r5
fffc01a9:   21 fe                           bne.b   fffc01a7 <__romdatastart+0xfffffef3>
fffc01ab:   60 11                           sub #1, r1
fffc01ad:   21 f7                           bne.b   fffc01a4 <__romdatastart+0xfffffef0>

fffc01af <micro_second_loop0>:
fffc01af:   02                              rts

rxprog を更新

ついでに、rxprog を更新して、RX231 をサポートした。
このプロトコルは、RX24T とほぼ同じもので、プログラム/イレースへ推移する為のコマンドが異なるだけだった。

ほぼ、同じコードの一部を修正して、コードをコピペするのは、悪手でしかないが、見直すには時間的余裕が必要なので、後回しとする。

RX24T もそうなのだが、ID コードのプロテクトが無い場合、プログラム/イレースへ推移すると、自動で、フラッシュをイレースする仕組みがあるようだ・・
なので、コードフラッシュのプログラムでは、「イレース動作」をしないで、いきなり書きに行くようにしている。


まとめ

「時間待ち」は、ソフトで行わなくても、RXマイコンなら、必ずある「TMR タイマー」とかを使って、やれば、正確で、今回のような問題は起きないとも思のだが・・・

TMR を使った時間待ちは、今後の課題としたい・・

又、動作クロックの違いで、プログラムの動作条件(高速動作の場合、フラッシュメモリの速度が足枷となりオペコードの読出しに遅延を設けている)が変わり、クロック数ファクターが異なるので、それに対応したい・・
constexpr を使えば、コンパイル時に計算して、定数を計算可能と思う。

RX231 動作確認と部分的最適化の抑制


RX231 の動作確認

RX231 は、RX26T と同じ時期に購入してあったけど、中々作業が出来ないでいた。
RX26T も、落ち着き、余裕が出来たので実験基板を配線した。
今回、Flash:256K、RAM:32K のデバイスで、64 ピンパッケージを購入した、RX200 系は比較的安価な製品が多い。

いつものように、変換基板を直にユニバーサル基板へハンダ付けしている。
64 ピンだと、実験基板を作成するのは楽(電源ピンが少ない)なのだが、色々な機能をアサインする場合にピンが足りなくなる・・
RX231 は動作周波数が低く、それ程興味が無かったのもあって、なるべく安いデバイスを購入。
でも、100ピン版を購入しておくべきだったかもしれない・・・
Flash も 256K は少し物足りない・・・


RX231 の特徴

  • RXv2 コア(最大 54MHz 動作)
  • USB インターフェース
  • SDHI インターフェース(SD カードアクセス)
  • SSI インターフェース(シリアルサウンドインタフェース)
  • 静電容量式タッチセンサ
  • CAN インターフェース(RSCAN なので、専用ドライバーを実装する必要があり、現在開発中)

など、意外と機能が豊富で、応用範囲が広い。

※USB のクロック用に専用 PLL 回路があり、USB を使う場合でも、CPU のクロック周波数に影響しない。
※USB を使う場合、専用 PLL の制限により、外部発振周波数は、6MHz、12MHz のいずれか。(48MHz を作る必要がある為)


gcc 関数の最適化を制御

一般に、gcc の最適化 -O3 では、インライン展開や、直接埋め込みなど、色々な手法を駆使して、最大限高速に動作するようなバイナリーを生成する。
ただ、それだと、意図と異なった動作になる場合がある。

この C++ フレームワークでは、ソフトウェアーによる時間待ちが、その影響を受ける。

以下のコードは、ソフトウェアーによる時間待ち関数になる。

        //-----------------------------------------------------------------//
        /*!
            @brief  マイクロ秒単位の待ち @n
                    あまり正確では無く、速度に関連する設定に依存します。 @n
                    ※キャッシュ有効、最高速度での物理計測によるパラメータ
            @param[in]  us  待ち時間(マイクロ秒)
        */
        //-----------------------------------------------------------------//
        static __attribute__((optimize(1))) void micro_second(uint32_t us) noexcept
        {
            while(us > 0) {
                for(uint32_t n = 0; n < device::clock_profile::DELAY_MS; ++n) {
                    asm("nop");
                }
                --us;
            }
            if(device::clock_profile::DELAY_T1) { asm("nop"); }
        }

この時間待ちは、大体1マイクロ秒になるように、ループ数を調整している。
CPU の速度が 80MHz とかだと問題無いが、54MHz だと、ループの回数が少なく、for ループが展開されて、NOP 命令のみとなり高速に動作してしまう。
for ループを最適化で展開させないようにする為「attribute((optimize(1)))」を宣言してある。
※この方法を見つける為に、色々試行錯誤した。

「((optimize(1)))」が無い場合のアセンブルリスト(for ループが展開されている):

fffc0278:   fb 5a e8 03                     mov.l   #0x3e8, r5
fffc027c:   03                              nop
fffc027d:   03                              nop
fffc027e:   03                              nop
fffc027f:   03                              nop
fffc0280:   03                              nop
fffc0281:   03                              nop
fffc0282:   03                              nop
fffc0283:   03                              nop
fffc0284:   03                              nop
fffc0285:   03                              nop
fffc0286:   03                              nop
fffc0287:   03                              nop
fffc0288:   60 15                           sub #1, r5
fffc028a:   21 f2                           bne.b   fffc027c <__romdatastart+0xffffffc4>
fffc028c:   03                              nop
fffc028d:   60 14                           sub #1, r4
fffc028f:   21 e9                           bne.b   fffc0278 <__romdatastart+0xffffffc0>

「((optimize(1)))」がある場合:

fffc01a0:   61 01                           cmp #0, r1
fffc01a2:   20 0d                           beq.b   fffc01af <__romdatastart+0xffffff07>
fffc01a4:   66 c5                           mov.l   #12, r5
fffc01a6:   03                              nop
fffc01a7:   60 15                           sub #1, r5
fffc01a9:   21 fd                           bne.b   fffc01a6 <__romdatastart+0xfffffefe>
fffc01ab:   60 11                           sub #1, r1
fffc01ad:   21 f7                           bne.b   fffc01a4 <__romdatastart+0xfffffefc>
fffc01af:   03                              nop

※「noinline」の場合、関数呼び出しを消して、インライン展開するのを除外する、関数内のループには通常の最適化が行われるので、適当ではない。


RX231 のオーバークロック耐性

とりあえず、72MHz は動作するようだ・・(この位が安全圏か!?)

2024-01-28 01:18:18 Sunday
RX231 には、「動作電力コントロールレジスタ(OPCCR)」があって、初期状態では「中速モード」になっている。
これを「高速モード」に切り替える事で、高いクロックでも安定して動作するようだ。
90MHz で駆動したが、ちゃんと動作するようだ。

PLL USB専用PLL HOCO LOCO IWDTCLK メインクロック発振器 サブクロック発振器
高速動作モード ○(注 1) ○(注 1)
中速動作モード ○(注 1) ○(注 1)
低速動作モード × × × × ×

RX231/clock_profile.hpp の定義:

#if 0
        static constexpr uint32_t   PLL_BASE    = 54'000'000;     ///< PLL ベースクロック(最大 54MHz)

        static constexpr uint32_t   ICLK        = 54'000'000;     ///< ICLK 周波数(最大 54MHz)
        static constexpr uint32_t   PCLKA       = 54'000'000;     ///< PCLKB 周波数(最大 54MHz)
        static constexpr uint32_t   PCLKB       = 27'000'000;     ///< PCLKB 周波数(最大 32MHz)
        static constexpr uint32_t   PCLKD       = 54'000'000;     ///< PCLKD 周波数(最大 54MHz)
        static constexpr uint32_t   FCLK        = 27'000'000;     ///< FCLK 周波数(最大 1 ~ 32MHz)
        static constexpr uint32_t   BCLK        = 27'000'000;     ///< BCLK 周波数(最大 32MHz)
#else
//      static constexpr uint32_t   PLL_BASE    = 72'000'000;     ///< PLL ベースクロック(最大 54MHz)

//      static constexpr uint32_t   ICLK        = 72'000'000;     ///< ICLK 周波数(最大 54MHz)
//      static constexpr uint32_t   PCLKA       = 72'000'000;     ///< PCLKB 周波数(最大 54MHz)
//      static constexpr uint32_t   PCLKB       = 36'000'000;     ///< PCLKB 周波数(最大 32MHz)
//      static constexpr uint32_t   PCLKD       = 72'000'000;     ///< PCLKD 周波数(最大 54MHz)
//      static constexpr uint32_t   FCLK        = 36'000'000;     ///< FCLK 周波数(最大 1 ~ 32MHz)
//      static constexpr uint32_t   BCLK        = 36'000'000;     ///< BCLK 周波数(最大 32MHz)

        static constexpr uint32_t   PLL_BASE    = 90'000'000;     ///< PLL ベースクロック(最大 54MHz)

        static constexpr uint32_t   ICLK        = 90'000'000;     ///< ICLK 周波数(最大 54MHz)
        static constexpr uint32_t   PCLKA       = 90'000'000;     ///< PCLKB 周波数(最大 54MHz)
        static constexpr uint32_t   PCLKB       = 45'000'000;     ///< PCLKB 周波数(最大 32MHz)
        static constexpr uint32_t   PCLKD       = 90'000'000;     ///< PCLKD 周波数(最大 54MHz)
        static constexpr uint32_t   FCLK        = 45'000'000;     ///< FCLK 周波数(最大 1 ~ 32MHz)
        static constexpr uint32_t   BCLK        = 45'000'000;     ///< BCLK 周波数(最大 32MHz)
#endif

まとめ

現状、RX231 向けに、以下のプロジェクトを動作確認して、コミットしてある。

  • FIRST_sample
  • SCI_sample
  • FLASH_sample
  • FreeRTOS
  • RAYTRACER_sample
  • PSG_sample

※RAYTRACER_sample では、RXv2 コアの優位性で、54MHz 動作の RX231 の方が、96MHz 動作の RX62N より高速だった。

マイコン core FPU fsqrt 命令 周波数 [MHz] 描画方式 時間 [ms]
RX231 RXv2 O O 54 8 bits, port-bus 1736
RX62N RXv1 O X 96 8 bits, port-bus 1860

RX26TのPLLベースクロック不具合

RX26T の PLL ベースクロック

は、ハードウェアーマニュアルでは、120 ~ 240MHz となっている。

しかし、240MHz を設定すると動作しない状況だった。

120MHz なら動作するので、まぁ問題無いかと思っていたが、やはり気になるので、ルネサス社のサポートに問い合わせていた。

色々、やりとりをした結果、スマートコンフィギュレーターでプログラムを生成して試して下さいとの事だった・・
まぁ、そうなるよなぁーと思っていたが、やはり原因は究明しておかないとと思った。

しかし、オレオレフレームワークがある程度動作する環境だと、結構億劫で、門外漢が強く後回しになっていたが、ようやく作業を始めた。
※E2Studio は起動が遅いし、プロジェクト全体の構成などが複雑で、出来れば触りたく無い。

スマートコンフィギュレーターが生成したプログラムを眺めていて、以下の部分に気がついた。

    /* b19 to b16 should be set the same value as the ICK bit. */
    tmp2_clock = tmp_clock;
    tmp2_clock &= 0x0F000000;
    tmp2_clock >>= 8;
    tmp_clock |= tmp2_clock;

あっ・・・

ハードウェアーマニュアルを確認すると、予約ビットの扱いがひっそり書かれていた・・・

これは、罠だよなぁー・・・、そういえば、RX631でも同じような事があったよなぁー・・・
まぁ、自分のミスではあるのだが・・・
何でそこに気がつかなかったのか悔やまれる。

今回は、PLL ベースクロックが、228MHz なら動作していたもので、微妙な不具合で、デバイスの不良なのかと、ハードウェアーの問題だと思ってしまい、ソフトの問題に気が回らなかった。

今後、予約ビットの扱いは、最新の注意が必要だと痛感した・・・
※予約ビットに特定の値を設定する必要があるなら、「----」にしないで、特定の名称を割り当てるべきと思う。


GNU-RX 8.3.0 202305 バージョンの不具合?

RX26T では、TFUv2 が採用されている。

このサポートには、新しいコンパイラが必要と思われ、GNU-RX ツールチェインを最新にしておいた。

しかし、以下のオプションを使って、「cmath」 をインクルードした状態でコンパイルすると、エラーが出る・・・

-mtfu-version=v2 -mtfu=intrinsic,mathlib

※「mathlib」の部分
※「-mtfu-version」が追加されている。

c:\programdata\gcc for renesas rx 8.3.0.202305-gnurx-elf\rx-elf\rx-elf\rx-elf\include\c++\8.3.0.202305-gnurx\cmath:1122:11: error: ‘::hypotf’ has not been declared

 using ::hypotf;

GNU-RX 8.3.0 202004 とか一つ前のバージョンだと発生しない。

これは、現在、問い合わせ中だ。

mathlib は、通常の数学関数が、TFU を利用した高速版に置き換えられるものと思う。


まとめ

今回の騒動、素直に「スマートコンフィギュレーターを使ったらどうですか?」と言われそうだが、本当にそれが素晴らしいものなら初めから使っている。
色々と、ハードルがあっても、自分の信念は貫きたい、より一層の注意力が必要と思う一件だった。

RX26Tの動作確認

RX26T が発表されている

RX26Tが発表されて、購入が可能な事が判り、いつもの chip1stop で購入した。
品番は、R5F526TFDGFPで、フラッシュ512K、RAM64K、データフラッシュ16K、100ピンのバージョンだ。

構成としては、かなり目新しい部分もあるが、基本的にはRX200シリーズなので、RX24Tの後継品だろうか・・

基本、家電製品や自動車などに使う事がメインと思うので、値段もまぁまぁ安い部類。


特徴

  • RXv3 コア(最大120MHz動作)
  • TFU2 内蔵(バージョンアップ版 TFU)
  • RSCI モジュール(新しいシリアル通信モジュール)
  • I3C バスインターフェース
  • RSPIA(シリアルペリフェラルインターフェース)
  • CANFD(FD 仕様の CAN モジュール)

こんな感じだろうか・・
他にも細かい部分で色々な機能がある。
残念なのは、USB インターフェースが無い点。
※CANFD のクロック分周器が新設されたが、これは以前は、USB クロックの分周器として利用していたものなので、そのせいで、USB を切ったのかもしれない。

TFU2 は、レジスタ退避機能があり、割り込み内で利用可能になったようだ。

RSCI、I3C、RSPIA,CANFD は、新たにドライバーを作り直す必要がある。
これらモジュールは、ARM 系モジュールでも使われて、今後、RX マイコンでも主流になるものと思う。
※ソフト資産を共有可能なのだろう~

内蔵メモリの容量違いで、機能が削られたりする仕様があり、デバイス選択に複雑な要因が入り込む。
このようなセールスはやめて欲しいと思う、何かメリットがあるのだろうか?
内蔵RAMが64K版と48K版がある・・、この仕様も、何かメリットがあるのだろうか?


難産・・・

早速、ユニバーサル基板に組み、初期実験を行った。
フレームワークは、RX24T、RX66T、などと共通点が多く、必要な部分を実装しておいた。
どちらかと言うと RX66T に近い構成。

しかし、ちゃんと動作しない・・・
簡単なLED点滅ですら、動かない・・・

調査調査調査・・・

少し調査した限りでは、クロックのブーストは動作しているようだが、その先でつまずくようだ・・・
こんな症状は初めてで、基板の配線、電源、色々と検査した。
VSS が1本接続忘れがあったり、細かい部分でミスを発見したが、直しても、駄目・・・

簡単なプログラムでも、リセットを繰り返すと、頻度は少ないが動作しない場合がある。
これは、クロックのブーストが失敗するのかも・・

基板の配線、主に電源ラインを確認したり、何か間違いが無いか確認したりと色々と行ったが成果無し。

色々な事をトライして、判ったのは、内部 PLL の最大周波数を 240MHz にすると、動作が不安定になる。
120MHz だと、安定して動作するようだ。
ハードウェアーマニュアルでは、120MHz~240MHz となっている。

VCL に接続したコンデンサは、 0.47uF が無かったので 1uF を付けた、それが原因なのかもしれない。
しかし、内部電源の平滑用なので、容量は PLL の動作に関係無いと思うのだが・・

昔に、チップワンストップで、チップコンデンサがファイルされた「コンデンサセレクション」を買った(高かった)、それを探したら、0.47uF があったので付け替えた。
※ここぞと言う場合に使うので、あまり使いたく無いのと、サイズが1608なのが・・
しかし、やはり 240MHz の動作は不安定でほぼ動作しない。

とりあえず、内部 PLL は 120MHz で動作させる事とした。


ソフト・ディレイループ定数

RX24T より、優秀で、単純なループでも、40%くらい速い感じがある、同じ RXv3 コアの RX66T、RX72T とほぼ同等の性能のようだ。

        static constexpr uint32_t   DELAY_MS    = ICLK / 3'065'133;   ///< ソフトウェアー遅延における定数(1マイクロ秒)

オーバークロック耐性

        static constexpr uint32_t   PLL_BASE    =  180'000'000;       ///< PLL ベースクロック(最大 120 to 240MHz)

        static constexpr uint32_t   ICLK        =  180'000'000;       ///< ICLK 周波数(最大 120MHz)
        static constexpr uint32_t   PCLKA       =   90'000'000;       ///< PCLKA 周波数(最大 120MHz)
        static constexpr uint32_t   PCLKB       =   45'000'000;       ///< PCLKB 周波数(最大 60MHz)
        static constexpr uint32_t   PCLKC       =   90'000'000;       ///< PCLKB 周波数(最大 120MHz)
        static constexpr uint32_t   PCLKD       =   45'000'000;       ///< PCLKD 周波数(最大 60MHz)
        static constexpr uint32_t   FCLK        =   45'000'000;       ///< FCLK 周波数(最大 60MHz)

オーバークロックによるSCIサンプルの動作:

Start SCI (UART) sample for 'RX26T DIY' 180[MHz]
SCI PCLK: 45000000 [Hz]
SCI Baud rate (set): 115200 [BPS]
  Baud rate (real): 115355 (0.13 [%])
  SEMR_BRME: true
  SEMR_BGDM: true
CMT Timer (set):  100 [Hz]
  Timer (real): 100 [Hz] (0.00 [%])
#

とりあえず、180MHz(1.5倍)の動作は確認した、PLL が 240MHz で不安定なので、240MHz(2倍)は動作しないだろうと思う。
それでも、十分な耐性だと思える。


サンプルアプリの動作

当然なのだが、C++ フレームワークの柔軟性により、FIRST_sample が動作したら、SCI 関係も、何の苦労無く普通に動作する。

  • FIRST_sample
  • SCI_sample
  • RAYTRACER_sample

RAYTRACER_sample:

マイコン core FPU fsqrt 命令 周波数 [MHz] 描画方式 時間 [ms]
RX62N RXv1 O X 96 8 bits, port-bus 1860
RX631 RXv1 O X 96 8 bits, port-bus 1868
RX24T RXv2 O O 80 8 bits, port-bus 1224
RX26T RXv3 O O 120 8 bits, port-bus 692
RX65N RXv2 O O 120 Frame Memory 784
RX64M RXv2 O O 120 16 bits, port-bus 751
RX66T RXv3 O O 160 8 bits, port-bus 602
RX72T RXv3 O O 192 8 bits, port-bus 464
RX71M RXv2 O O 240 16 bits, port-bus 439
RX72N RXv3 O O 240 Frame Memory 361
  • CALC_sample
Start CALC sample for 'RX26T DIY' 120[MHz]
# Rad
# tan(355/226)
 -7497258.185325587112905071831891248663417267943785263161571
# Deg
# sin(45)
 0.7071067811865475244008443621048490392848359376884740365883
# cos(60)
 0.5
# cos(45)
 0.7071067811865475244008443621048490392848359376884740365883
# sin(60)
 0.8660254037844386467637231707529361834714026269051903140279
#

まとめ

久しぶりにブログを書いた。
RXマイコン関係もかなり久しぶり。

RX26T は、CP が高めなのと、新しいペリフェラルの投入もあり、中々面白いCPUとなっている。
RX26T に新設されたペリフェラルの実装もまだなので、今後それらを中心にサポート、実験をしていきたい。

RXマイコン CAN_sample

記事を Qiita に投稿

CAN_sample は、RXマイコン C++ フレームワークを使った、対話形式の CAN 通信サンプルです。

その解説を Qiita に投稿しました。

RXマイコン C++ フレームワークによる CAN 通信


今回のキモはやはり C++

boost::unordered_map、boost::unordered_set を利用しています。

std ライブラリにも同等のクラスはあるけど、boost の方がサイズが若干小さくなるので、CAN_sample では、boost 版で説明しています。

CAN 通信を行う場合、C++ を利用するとメリットが多いです。


GR-CITRUS を使ってみた

GR-CITRUS は、プロダクトとしては及第点に達していないけれでも、入手性と、コストで選びました。

  • GR-CITRUS は秋月電子で、処分価格(1500円)で販売されています。
  • GR-CITRUS に載っているRXマイコンは、Flash:2M、RAM:256K と豊富なので、大きなプログラムも動かせます。
  • GR-CITRUS で数少ないピンでも CAN0 を利用可能。

RXマイコンの品不足はいつまで続くのだろうか・・・


通信実験の相方は RX72T

以前、RX72M を購入する際、同時に購入して実験した RX72T/144 ピンボードを利用しました。


今後

RX72N Envision Kit の PMOD 端子に出ているポートにも、CAN バスをアサイン可能なので、RX72N でも試してみたい・・
それと、LCD もあるので、OBD2 を使って、車の ECU 情報を表示をしてみたい・・

CAN は意外と簡単に扱え、ノイズに強い高品質な通信が出来るので、複数のマイコンを使った装置など作る際に、相互の通信インターフェースとして重宝すると思われます。

RX631/RX63N 割り込みレベル設定の不具合など・・

CAN の実験で気がついた

GR-CITRUS はピンの制限が非道なのだが、CAN0 で利用するピン CRX0(P33), CTX0(P32) はとりあえず使える。
そこで、CAN_sample を動かしてみようと思い、プロジェクトに RX631 を追加してコンパイル。
とりあえず、ターミナル表示を確認した。

Start CAN sample for 'RX631 GR-CITRUS' 96[MHz]
CAN command version: 0.89
CAN0: SPEED: 1000000 [bps], BRP: 2, TSEG1: 15, TSEG2: 8, SJW: 4
    RX Interrupt level: 1, TX Interrupt level: 0
#

何故か、TX の割り込みレベルが0と表示されている・・
can_io クラスは、ポーリングでの動作は出来ない、必ず、1以上の割り込みレベルが必須となっていて、何も指定しないと、レベル1割り込みを設定する。
おかしいな・・、色々調べて、icu.hpp の CAN 関係の割り込みベクターに間違いがあった・・・
それを直して、もう一度。

Start CAN sample for 'RX631 GR-CITRUS' 96[MHz]
CAN command version: 0.89
CAN0: SPEED: 1000000 [bps], BRP: 2, TSEG1: 15, TSEG2: 8, SJW: 4
    RX Interrupt level: 0, TX Interrupt level: 0
#

今度は、両方「0」に・・・
調べると、RX631/RX63N の割り込みレベル設定(IPR レジスタ)は、かなりの部分が共有されており、この部分のケアが抜けていた。
RX621、RX62N や、RX63T、RX24T などでも同じだが、そちらはケアされていた。
RX621/RX62N に比べると、規則性があるが、全般に渡ってかなりの分量だったが、何とか修正した。

        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
        /*!
            @brief  IPR レジスタ・クラス @n
                    全て、下位4ビットが有効
            @param[in]  base    ベースアドレス
        */
        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
        template <uint32_t base>
        struct ipr_t {

            //-------------------------------------------------------------//
            /*!
                @brief  []オペレータ
                @param[in]  vec     標準割り込みベクター型
                @return IPR レジスターの参照
            */
            //-------------------------------------------------------------//
            volatile uint8_t& operator [] (VECTOR vec) {
                uint32_t idx = 0;
                switch(vec) {
                case VECTOR::BUSERR: idx = 0; break;
                case VECTOR::FIFERR: idx = 1; break;
                case VECTOR::FRDYI:  idx = 2; break;
                case VECTOR::SWINT:  idx = 3; break;
                case VECTOR::CMI0:   idx = 4; break;
                case VECTOR::CMI1:   idx = 5; break;
                case VECTOR::CMI2:   idx = 6; break;
                case VECTOR::CMI3:   idx = 7; break;
                case VECTOR::SPRI0:
                case VECTOR::SPTI0:
                case VECTOR::SPII0:
                    idx = static_cast<uint32_t>(VECTOR::SPRI0);
                    break;
                case VECTOR::SPRI1:
                case VECTOR::SPTI1:
                case VECTOR::SPII1:
                    idx = static_cast<uint32_t>(VECTOR::SPRI1);
                    break;
                case VECTOR::SPRI2:
                case VECTOR::SPTI2:
                case VECTOR::SPII2:
                    idx = static_cast<uint32_t>(VECTOR::SPRI2);
                    break;
                case VECTOR::RXF0:
                case VECTOR::TXF0:
                case VECTOR::RXM0:
                case VECTOR::TXM0:
                    idx = static_cast<uint32_t>(VECTOR::RXF0);
                    break;
                case VECTOR::RXF1:
                case VECTOR::TXF1:
                case VECTOR::RXM1:
                case VECTOR::TXM1:
                    idx = static_cast<uint32_t>(VECTOR::RXF1);
                    break;

...

                default: idx = static_cast<uint32_t>(vec); break;
                }
                return *reinterpret_cast<volatile uint8_t*>(base + idx);
            }
        };
        typedef ipr_t<0x0008'7300> IPR_;
        static IPR_ IPR;

※最近の RX マイコンは、ほぼ、割り込み要因毎に割り込みレベルが設定出来る仕様になっているのでスルーしていた。
※古い、RxV1 コアなどのマイコンは注意しなければならない・・


未定義ビットの扱い

システムクロックコントロールレジスタ(SCKCR)の予約ビットの扱いを見直した。

このレジスタ、B0~B7 には書き込む場合に特定のビットを立てなくてはならない。
素のままだと、特定のビットだけを変更する場合に問題が発生する。

    device::system::SCKCR.ICK = 10;

このような実装では、最終的に SCKCR レジスタ、B0~B7 には、読み出した値(全て0)が上書きされる。

そこで、以下のように、書き込み時に、特定のビットフィールドを追加するように改修した。

        //-----------------------------------------------------------------//
        /*!
            @brief  システムクロックコントロールレジスタ(SCKCR)
            @param[in]  base    ベースアドレス
        */
        //-----------------------------------------------------------------//
        template <uint32_t base>
        struct sckcr_t : public rw32_t<base, 0b0001'0001> {
            typedef rw32_t<base, 0b0001'0001> io_;
            using io_::operator =;
            using io_::operator ();
            using io_::operator |=;
            using io_::operator &=;

            bits_rw_t<io_, bitpos::B8,  4> PCKB;
            bits_rw_t<io_, bitpos::B12, 4> PCKA;
            bits_rw_t<io_, bitpos::B16, 4> BCK;

            bit_rw_t <io_, bitpos::B22>    PSTOP0;
            bit_rw_t <io_, bitpos::B23>    PSTOP1;
            bits_rw_t<io_, bitpos::B24, 4> ICK;
            bits_rw_t<io_, bitpos::B28, 4> FCK;
        };
        typedef sckcr_t<0x0008'0020> SCKCR_;
        static SCKCR_ SCKCR;

rw32_t クラスは、以下のように変更。

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  Read/Write 32 bits アクセス・テンプレート
        @param[in]  adr アドレス
        @param[in]  wov 書き込み OR 値(通常0)
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    template <address_type adr, uint32_t wov = 0>
    struct rw32_t {

        typedef uint32_t value_type;

        static constexpr auto address = adr;    ///< アドレス定義
        static constexpr auto write_or_value = wov; ///< 書き込み OR 値
        static constexpr uint8_t BUS = 32;      ///< バス幅
        static constexpr bool RD = true;        ///< 読出し
        static constexpr bool WR = true;        ///< 書き込み

        //-----------------------------------------------------------------//
        /*!
            @brief  書き込み
            @param[in]  data    書き込み値
        */
        //-----------------------------------------------------------------//
        static void write(value_type data) noexcept { wr32_(adr, data | wov); }

...

    };

テンプレートパラメーター、wov は、何も指定しない場合、「0」なので、影響を与えない。
書き込み時に「0」を OR するのが余計だと思うかもしれないが、最適化されると、その操作は削除されてて無くなるので通常動作で余分なマシンサイクルを消費しない。
最適化しない場合、余分なコードが大量に生成されてしまうので、専用関数とするべきかもしれない・・


まとめ

実装時、かなり注意しているが、間違いを避ける事は難しい、集中している時は、それも少ないとは言え、何かの別作業が間に入ったりすると、凡ミスも多くなる。
少し前から、ペリフェラルの定義を検証する為の仕組みを入れ始めている。
重要な部分はユニットテストなどを行うしかないが、テストコードを生成する、良い方法を考えないと現実的では無いとも思う。
これは、すこし考えたい・・
ハードウェアーマニュアルから必要な部分を抽出して、テストコードを自動生成するような事が必要かもしれない・・

RXマイコン、RX631/RX63N をサポート開始

最終的にはRXマイコン全サポートしたい!

かなり昔、RX63N が出た時期、176ピン版を購入した。(今は販売していない)

その時、変換基板も同時に購入して、実験基板を作ろうとしていたが、ピンの配置間隔がハーフピッチずれたバグ基板を掴まされ、作る気力が萎えてしまった・・
※ハーフピッチずれている為、ユニバーサル基板に乗せる事が出来ない。

そうこうしているうちに RX64M が出て、それを購入、品質の高い変換基板も購入、実験基板を制作して動かすまでになった。
そんなこんなで、RX631/RX63N はサポートをしていなかった。

デバイスは持っているので、実験しないと肥やしになるだけだし、ペリフェラル定義も、共通部分が多い事から RX220 サポートの勢いで進めていた。
必要最低限のピンを接続して、とりあえず動作する状態にしたい。

RXマイコンも、未だ購入が出来ない状態が続いているので、シリーズを増やすにしても、何とも歯がゆい状態が続いている。


GR-CITRUS を買う

基板を作る準備をしていたが、面倒になり、停滞していた。

そんな時、秋月のRXマイコン関係で、GR-CITRUS が1500円(通常2200円)の処分価格で売られている事を発見し、他の部品と共に注文した。
※使っていないピンを出していないとか、かなり不満の残るボードだが、1500円ならまーいいかと思って購入。

GR-CITRUS は、標準では USB 接続でフラッシュを書き換えるようになっている。
※MD端子は出ているが、2.54mm ピッチでは無い、狭いフットプリントになっているのが駄目・・(何で?)

RX631/RX63N は、フラッシュプログラム「rxprog」もサポートしたいので、外部にSCI1、MD 端子などを出してシリアルブート出来るように改造した。

RX631/RX63N は RX63T に近いプログラミングフォーマットとなっており、簡単に実装出来た。
マイクロマウスでRX631を使っている人が、rxprog を改造して使っているようだが、最新バージョンではコンパイルするだけで利用出来ると思う。

プログラムの書き込みは何の問題もなく出来た。

GR-CITRUS でシリアル書き込みを行う場合、P30(RXD1)、P26(TXD1) を配線する必要がある。
又、PC7 を抵抗でプルダウンする必要がある。
P26 は J5 によって、P05/DA1 ピンと共有するのだが、そうすると P05 を使えなくなる。
なので、J5 の P26 側にだけ配線を行い、外部に出す。
折角 100 ピンの RX631 を実装しているのに、多くのピンが未接続だし、ピンを共有していたり(何かの互換の為?)、ハッキリ言って糞ボードだと思う。
以上の点を許容できる人のみ購入を検討してみるのが賢明と思う。


クロックのブーストでハマる

RX631/RX63N は RX63T に近いクロック機能なので、RX63T のコードをコピーして少し手直しした。

とりあえず、LED 点滅「FIRST_sample」を書き込んだが、点滅しない・・・

調べると、クロック速度が遅い状態で、先に進まないようだ。
RX63T では動いていたから、何か違いがあるのか、色々調べたり、クロック関係のレジスタに直で値を入れたり、色々やったが全く駄目・・・
高速内部発振器「HOCO」では、ちゃんと動作しているようで、何で???と、数時間悩んだ・・・

そして、ようやく謎が解けたー

システムクロックコントロールレジスタ(SCKCR)の予約ビットに「0b0001」を書き込む必要があり、それが「0b0000」だと、ICLK が正しい周波数にならない・・

読み出すと「0b0000」なので、何も対策しないとハマる・・・

            device::SYSTEM::SCKCR = device::SYSTEM::SCKCR.FCK.b(clock_div_(clock_profile::FCLK))
                                  | device::SYSTEM::SCKCR.ICK.b(clock_div_(clock_profile::ICLK))
                                  | device::SYSTEM::SCKCR.BCK.b(clock_div_(clock_profile::BCLK))
                                  | device::SYSTEM::SCKCR.PCKA.b(clock_div_(clock_profile::PCLKA))
                                  | device::SYSTEM::SCKCR.PCKB.b(clock_div_(clock_profile::PCLKB))
                                  | 0b0001'0001;

この修正を加えたら、システムクロックがブーストするようになった。

RX631 のソフトディレイを調整した。


現在のフレームワーク状態

現在、ペリフェラルの実装、動作確認、は以下のようになっている。

シリーズ コア FPU DFPU 動作確認 ペリフェラルクラス rx_prog サポート リンカーファイル
RX220 RXv1 No - R5F52206
RX631/RX63N RXv1 Yes - R5F5631F/NE
RX63T RXv1 Yes - R5F563T6
RX621/RX62N RXv1 Yes - R5F562N7/8
RX24T RXv2 Yes - R5F524T8/A
RX64M RXv2 Yes - R5F564MF/G/J/L
RX71M RXv2 Yes - R5F571MF/G/J/L
RX651/RX65N RXv2 Yes - R5F565NE
RX66T RXv3 Yes - R5F566TA/E/F/K
RX72T RXv3 Yes - R5F572TF/K
RX72N RXv3 Yes Yes R5F572ND/N
RX72M RXv3 Yes Yes R5F572MD/N

RX631/RX63N は、RX63T にフラッシュプログラムは近いので、rx_prog もサポートした。


まとめ

とりあえず、FIRST_sample、SCI_sample、RAYTRACER_sample などで動作確認を行った。

SCI_sample:

Start SCI (UART) sample for 'RX631 GR-CITRUS' 96[MHz]
SCI PCLK: 48000000 [Hz]
SCI Baud rate (set): 115200 [BPS]
  Baud rate (real): 115384 (0.16 [%])
  SEMR_BRME: false
  SEMR_BGDM: false
CMT Timer (set):  100 [Hz]
  Timer (real): 100 [Hz] (0.00 [%])
#

RAYTRACER_sample:

RX631 GR-CITRUS Start for Ray Trace: 320, 240
# Render time: 1886ms (1)

CALC_sample:(関数電卓サンプル)

# Rad
# tan(355/226)
 -7497258.185325587112905071831891248663417267943785263161571

CAN_sample:

  • コンパイルのみ、動作確認はしていない。

I2C_sample:

  • コンパイルのみ、動作確認はしていない。

PSG_sample:

  • DA1 出力をアンプに接続して、動作確認。

「rxprog」は、RX631/RX63N を追加して、プログレス表示で、%の表示を追加した。

GR-CITRUS は、メモリもそれなりに多く、今後、他プロジェクトでも、RX631 を追加して、動作確認をおこなっていく。
惜しいのは、使っていないピンをランドに出していない点、そして、一部のポート同士を接続してある点、これが無ければ、色々応用が出来るのだが・・

現状のコードは、Github にコミットしてあり、マスターブランチにマージ済。