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

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

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 にコミットしてあり、マスターブランチにマージ済。

RXマイコンC++フレームワーク、RX220をサポート開始

RX220 マイコンをサポートする

半導体不足は未だ解消の気配は無く、RXマイコンを買うにしても、以前のような価格では流通していないし、バックオーダーで、買う事も出来ない。

RX220は、機能と価格で、CPはそんなに良くないが、秋月さんで売っているので、入手はしやすいだろうと思う。

  • DIPスイッチを逆に取り付けてしまったバージョンの基板なら比較的安価に購入できる。(1250円)
  • 以前RX72T(200MHz、RXv3コア)が10個で@600円くらいだった事を考えると、最大32MHzでRXv1コアはあまり触手が伸びない。
  • RX220はFPUも内蔵していない・・
  • 既に購入済で、積みボードになっている人もいるかもしれない。

とりあえず、RXマイコン全制覇を目論んでいるし、200番台をサポートするのは、それなりに価値がある。


秋月RX220ボードの改造

秋月さんのRX220ボードは、そのままでは多少使いづらい・・
このボードでは、内蔵フラッシュを書き換えるには、シリアル書き込みがほぼ標準的となる。
その場合、SCI1を使う事になるが、そのままだと、RSー232Cのレベル変換ICに接続されている。
今や、PCとの通信でRSー232Cを使う事は「稀」で、FT232やCP2102NなどのUSB/シリアル変換モジュールを使って、ロジックレベルで行うのが標準的となっている。
そうすると、RXマイコンのTxDは出力なので問題無いとしても、Rxdは入力となっていて、レベル変換ICの出力が接続されているので、モジュールのロジック端子を繋ぐ事ができない。
そこで、ボードのパターンをカットして、接続できるように改造した。
※何かの記事で読んだが、この「カットをする意味が判らない」と綴っている人がいた・・、これは、本当にビックリした、その程度の知識でマイコンをやってる人がいる現実に驚くばかり。
まぁ、でもマイコン掲示板で、自分で何も調べないで、いきなり質問する人や、初歩的と思えるような質問をする人、様々な人がいる現実を考えると、まぁそんなものかもしれない。


ソフトディレイの調整

RX220は最大32MHz(内蔵発振器動作)で動作する。

  • クロックジェネレーターにはPLL回路が無い為、外部にクリスタルを接続して利用する場合は、最大20MHzとなる。
  • クリスタルの発信器は、20MHzを超えると、ちょっと特殊な回路にしないと発振が安定しない(発振しない)ので、そうなっていると思う。
  • ただ、外部クロック入力でも最大20MHzなので、その他の物理的な要因が関係しているのかもしれない。
  • 内部発信器だと、正確性やジッタの問題があるとも思うが、意外と安定していると思う。
  • 内部発信器は最大50MHzで発振する事も出来るので、50MHzオーバークロックで動かしてみたが、普通に動作はするようだ。

最初、1マイクロ秒のソフト遅延を行う為、NOP命令のループ回数を調整していたが、思うように調整出来ない・・・
ある値を境に、遅くなったり、速くなったり、不思議な現象が発生した。

                for(uint32_t n = 0; n < device::clock_profile::DELAY_MS; ++n) {
                    asm("nop");
                }

・・・

少し考えたら、理由は判った、今まで、最低速度は、RX24Tの80MHzだったので、ループ回数はそれなりの値で問題無かった。
しかし、32MHzだと、ループ回数は少なく、ある値を境に、「asm("nop");」が、インライン展開されてしまう。

そこで、RX220の場合は、専用のAPIにした。

        static void delay_us() noexcept
        {
            // 定数(DELAY_MS)で指定すると、ループ数が少なくインライン展開され、予想した時間にならない為、直で’NOP’数で調整する。
            if(ICLK == 32'000'000) {  // 32MHz 用
                asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
                asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
                asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
                asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
            } else if(ICLK == 20'000'000) { // 20MHz 用
                asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
                asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
                asm("nop"); asm("nop"); asm("nop");
            } else {
                for(volatile uint8_t i = 0; i < (ICLK / 1'000'000) - 10; ++i) {
                    asm("nop");
                }
            }
        }

rx_prog でも、RX220をサポート

最初、とりあえずルネサスフラッシュプログラマーで書き込みを行ったが、非常に不安定で、書き込みに失敗、そもそも接続も出来ないなどのトラブルが多発した。
この原因は追究していないが、USBシリアルデバイスがCP2102Nなのが問題なのかと思った。

  • CP2102Nは、FTDIより高速で、同じボーレートでも、転送にかかる遅延が非常に少ない為と思った。
  • RX200系は、RXマイコン初期の物なので、あまり枯れていないのかもと思った。
  • ルネサスフラッシュプログラマーの無料版は、ノークレームなので、改修を要求する事さえ出来ない。

そこで、まず、rx_prog にRX220のプロトコルを追加する事にした。
ブートモードの説明を斜め読みした感じでは、RX63Tとほぼ同じ感じで、そのまま行けると感じた。

「rx_prog.conf」に、RX220 デバイスのプロファイルを追加して、「rx220_protocol.hpp」を追加、説明と照らし合わせた。

R5F52206 {
    group = "RX220"
    clock = 3200
    divide_sys = 1
    divide_ext = 1
    rom = 256K
    ram = 16K
    data = 8K
    comment = "; RX220 Flash:256K DataFlash:8K RAM:16K"
    rom-area  = FFFC0000,FFFFFFFF
    data-area = 00100000,00101FFF
    ram-area  = 00000000,00003FFF
}

「rx63t_protocol.hpp」ほぼ同じでOKだったが、ファイルは別けておいた。

まず、コネクションを試してみた。

 % rx_prog -d RX220 --verbose
# Platform: 'Cygwin(MSYS2)'
# Configuration file path: '/usr/local/bin/rx_prog.conf'
# Group: 'RX220'
# Serial port path: 'COM7'
# Serial port speed: 230400
# Erase Page Wait: 2000 [uS]
# Write Page Wait: 5000 [uS]
# Serial port alias: COM7 ---> /dev/ttyS6
# Serial port path: '/dev/ttyS6'
# Device: R5F52206 (first find)
#   Master clock: 32.00 MHz
#   ICLK multiplier: 1 (32.00 MHz)
#   PCLK multiplier: 1 (32.00 MHz)
Connection OK. (RX62x)
#01/01: Device: RX200 Series (LittleEndian)
#01/01: Device ID: 0x33306A37
#01/01: Clock Mode: 0x00
#01/02: Multiplier: 1
#02/02: Multiplier: 1
#01/02: Frequency Min: 32 MHz, Max: 32 MHz
#02/02: Frequency Min: 32 MHz, Max: 32 MHz
#01/01: Change baud rate: 115200
#01/01: Boot Area: FF7FC000, FF7FFFFF
#01/01: Area: FFFC0000, FFFFFFFF
#01/26: Area: FFFFF000, FFFFFFFF
#02/26: Area: FFFFE000, FFFFEFFF
#03/26: Area: FFFFD000, FFFFDFFF
#04/26: Area: FFFFC000, FFFFCFFF
#05/26: Area: FFFFB000, FFFFBFFF
#06/26: Area: FFFFA000, FFFFAFFF
#07/26: Area: FFFF9000, FFFF9FFF
#08/26: Area: FFFF8000, FFFF8FFF
#09/26: Area: FFFF4000, FFFF7FFF
#10/26: Area: FFFF0000, FFFF3FFF
#11/26: Area: FFFEC000, FFFEFFFF
#12/26: Area: FFFE8000, FFFEBFFF
#13/26: Area: FFFE4000, FFFE7FFF
#14/26: Area: FFFE0000, FFFE3FFF
#15/26: Area: FFFDC000, FFFDFFFF
#16/26: Area: FFFD8000, FFFDBFFF
#17/26: Area: FFFD4000, FFFD7FFF
#18/26: Area: FFFD0000, FFFD3FFF
#19/26: Area: FFFCC000, FFFCFFFF
#20/26: Area: FFFC8000, FFFCBFFF
#21/26: Area: FFFC4000, FFFC7FFF
#22/26: Area: FFFC0000, FFFC3FFF
#23/26: Area: 00101800, 00101FFF
#24/26: Area: 00101000, 001017FF
#25/26: Area: 00100800, 00100FFF
#26/26: Area: 00100000, 001007FF
#01/01: Program size: 256 Bytes
#01/01: ID Protect: false

問題無い。

次に、書き込み、ベリファイも試して、問題無かった。
rx_prog は、多少書き込み速度が遅いものの、安定して書き込めるし、OS-X、Linux でも同じように動作する実績がある。
※RX220 は、OS-X、Linux では試していないけど・・

rx_prog -d RX220 --progress  --write --verify sci_sample.mot
Write:  #################################################
Verify: #################################################

これで、RX220を正式サポートした事になると思う。

Makefile は、以下の部分のみ異なるだけで良く、RX220 に移る事は簡単だ。

DEVICE      =   R5F52206

RX_DEF      =   SIG_RX220

まとめ

現状、サンプルプログラムは、「FIRST_sample」、「SCI_sample」のみだが、今後拡充してゆく予定。
※基本、各プロジェクトで、Makefileを用意すればOKだが、まだ、RSPIや、RIIC(I2C)ペリフェラルの追加などをしていない。

RX220 は浮動小数点を扱うとエミュレーションになってしまうが、「utils::format」の表示関係は、内部はほぼ整数を使っているし、速度以外はそれなりに使えると思う。
もう少し安価に入手できれば・・・
それでも、32ビットなので、RL78などの8ビット系に比べて大きなアドバンテージがあるのは言うまでも無い。

Start SCI (UART) sample for 'AE-RX220' 32[MHz]
SCI PCLK: 32000000 [Hz]
SCI Baud rate (set): 115200 [BPS]
  Baud rate (real): 117647 (2.08 [%])
  SEMR_BRME: false
  SEMR_BGDM: false
CMT Timer (set):  100 [Hz]
  Timer (real): 100 [Hz] (0.00 [%])
#

現在、RX631/RX63N もサポート中で、秋月ユーザーでも、C++ フレームワークを使ってみる機会がそれなりに増えると思う。

C++ に対する嫌悪感

主にC言語しか使わない人は、C++ に対する嫌悪感が半端ない事が多い。
また、C++ は判らないし、難しそうだから近寄らない人も多い。

しかしながら、マイコン初心者(プログラムの経験が全く無い人)に教える場合、C++ から始めても、そんなに敬遠したりしない事が判っている。
※もちろん、最初はあまり多くを示さないで、簡単な事、理解しやすい事、シンプルな事から始める。
むしろ、半端にプログラム出来る人より、飲み込みが速く、応用が利く人が多いように思う、これは、教え方次第のように思う。
年齢は関係無い、若い人は頭が柔らかく、吸収する力が大きいように感じる。

C++だと、コンパイラが教えてくれる事が多く、小さなミスは、ほぼ起きなくなるし、柔軟で応用範囲が広いライブラリなど、利便性が高い。

今回 RX220 をサポートしたが、アプリケーションレベルでは変更が全くなく、同じように動作する。

今後、勉強会や、講習会、YouTubeビデオなど、学べる機会や媒体を増やしていく予定でいる。

R8C、RX開発環境のアップデート

R8C の開発環境が作れないとのツイートをもらう・・

先日、Twitter で 過誤出来ないツイートをもらった。

ツイートは短く、詳細は不明なので、実際にどんな事が起きているのか判らなかった。

何度かやりとりをする中で、どうやら、これは Linux 環境で発生している事が判った。

その要因は、最新の gcc 環境(Version 11)などで、gcc-4.9.4 の C++ ビルドで失敗する事が判った。

そういえば、Windows の MSYS2 環境もしばらくアップデートしていない、そこで、まずは、MSYS2 をアップデートする事から始めた。
※Linux 環境は、ノートPC にあり、古いので、新しい環境に入れ直す必要があり、確認するのも時間がかかる。

pacman -Sy pacman
pacman -Syu

この段階で、データベースの更新に失敗して、先に進まない・・

MSYS2 は、かなり更新しているようで、根本的にシステムが大幅に変わったようだ、そこで、インストールからやり直す事にした。

念の為、MSYS2 のコア部分、「C:\msys64」をリネームして、残しておいた。

最新版をインストールして、必要なツールをインストール。
※複数パッケージのインストールが、マルチスレッドで同時進行するようになっているw

MSYS2 はアイコンが少し新しくなり、大きな変更があったようだ。

また、新たな環境が二つ追加された:

  • MSYS
  • mingw32
  • mingw64
  • ucrt64(追加)
  • clang64(追加)

※追加された環境が、どのような特徴があるのか調べていない。(clang64 は何となく判る)

MSYS のカレント gcc は11系になっている。

gcc (GCC) 11.3.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

次に、R8C 用 gcc のビルドにとりかかる。
gcc のビルドは、MSYS で行う。(この環境がもっとも Linux などに近い)

手順を進めていって、やはり、gcc C++ の構築でエラーが発生して止まる・・・

うーーん、これは、どうしたものか・・・

そもそも、gcc-4.9.4 は古すぎると以前から思っていた。
しかし、開発環境を変更する事で、発生する別の問題を恐れて「まぁ動いているから枯れた方がいいかな」とも思っていた。

この機会に、手始めに R8C の開発環境をアップデートして、gcc-11 でエラー無くコンパイル出来るようにした方が建設的ではと思った。
この段階で、エラーを報告してくれた人は、ネットの情報を精査して、configure で生成された Makefile に、C++11 のオプションを付ける事で回避したようだ。
※なるほど、その回避もあるよなぁーと思ったが、やはり、gcc のビルドで特別な事を行うのは少し抵抗がある。


RX マイコンの開発環境では、最近は GNU-RX(魔改造されている)を使っている為、素の gcc を使う事が無くなっている。

RX のツールチェインは、以下の組み合わせとなっている。

binutils-2.34
gcc-7.5.0
newlib-2.4.0

組み合わせは重要で、リリースが同じくらいのパッケージを組み合わせないと、ビルドが通っても、コンパイル中にインターナルエラーで止まったり、
出来たコンパイラで作ったバイナリーをマイコンに焼いても動作しないなど、色々なトラブルが起こったりする。

そこで、R8C(m32c-elf)のビルドを上記組み合わせで作ってみた。

ビルド途中で、エラーで、失敗する・・・

うーーーん・・・

この組み合わせは、m32c-elf では相性が悪い・・・

そこで、少し古いバージョンの組み合わせで、色々試してみた。
m32c-elf は多分、メンテナンスされていないので、欲張らずにそこそこ新しい物で我慢する方が安全と考えた。
SSD(1TB) と、大きな主記憶(32GB)で武装された、最新の PC(Rizen7) でも、gcc のビルドは、そこそこの時間を要する。

色々、試して:

  • binutils-2.28.1.tar.gz
  • gcc-6.4.0.tar.gz
  • newlib-2.4.0.tar.gz

この組み合わせで、ビルドが通った。


boost 問題・・・

r8cprog など、一部のコードは、boost を使っている。

本来なら、MSYS 環境に boost を入れるのが良いと思うが、mingw64 などには対応しているが、MSYS 環境には無い。
そこで、mingw64 環境に入れた boost を間借りする形で使っていた。
しかし、新しい MSYS2 ではそのやり方では問題が発生する事が判った。

そこで、boost_1_74_0 のアーカイブを取ってきて、C ドライブのルートに展開し、そのパスを食わせる事で解決した。

この変則的なやり方は、あまりスマートとは言えないが、手順は難しく無いので、まぁ及第点だろうか・・


R8C のプロジェクトを全ビルド

新しく出来たツールチェインを使って、R8C のプロジェクトを全てビルドしてみた。

エラー無くビルドが通った。

とりあえず、「UART_sample」を動かしてみて、ちゃんと動作するバイナリーが出来る事も確認した。


RX 関係も確認

RX 関係も、一応確認した。

RX の gcc ビルドは問題無く通ったので、「良し」としたが、boost のパスは、R8C と同じく変更した。


RL78 環境

RL78 も、R8C と同じ環境にして、gcc をビルドしてみた。
これも、順調に通り、構築出来た。

しかし、プロジェクトをビルドすると、gcc がインターナルエラーで停止する・・・

rl78-elf-g++ -c  -std=c++17 -Wall -Werror -Wno-unused-variable -Wno-exceptions -Wno-unused-function -Os -mmul=g13 -DSIG_G13 -DF_CLK=32000000  -I. -I../ -I../G13  -o release/main.o main.cpp
In file included from main.cpp:15:0:
../common/format.hpp: In member function 'void utils::basic_format<CHAOUT>::out_fixed_point_(VAL, uint8_t, bool) [with VAL = long long unsigned int; CHAOUT = utils::stdout_chaout]':
../common/format.hpp:589:3: internal compiler error: in push_reload, at reload.c:1348
   }
   ^
unrecognized DWARF version in .debug_info at 6
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
make: *** [Makefile:112: release/main.o] Error 1

うーーーん、これは痛い・・・

そーいえば、ルネサスさん、RL78 用に LLVM ベースのコンパイラをリリースしているんだよなぁー、アレ試してみたいんだよなぁー

今ここ。


まとめ

とりあえず、R8C、RX 関係は、何とかなったので、RL78 も何とかしたいけど、時間切れ。
Linux 環境も試しておく必要があるし、まだ、時間がかかる。

R8C の教材も中途だし、中々先に進まない。

しかし、Windows の最新環境にマッチするように改修したのは、大きな進歩と思える。

RXマイコン、RX621/RX62N のサポート

※昔に購入した RX62N が載った格安ボード、確か2000円くらいで買った覚えがあるが、現在は5000円くらいする。


古い、RX621/RX62N のサポート

RX621/RX62N は、そこそこ古いRXマイコンのグループで、C++ フレームワークの出発点となった記念すべきCPUでもある。

しかし、新しいグループがリリースされ、使わなくなり、機能的に見劣りするのと、新規に購入するのもコスト的に見合わないので、ある時期から「レガシー」として、サポートをやめてしまった。

ところが、現在、政治的な動きに係る半導体不足から、最近リリースされた新しいデバイスの購入が殆ど出来なくなっており、いつ解消するかも不透明となっている。
RX621/RX62N は、かなり昔のデバイスで、そこそこ流通しており、かなり昔に、本の付録として流通した事もあるし、秋月では、未だに販売もされている。
なので、持っている人で肥やしになってる人も少なからずいるのではないか?

最終的には、RXマイコン全制覇を目論んでいるので、そろそろ、仕組みを考えておくのも必要だと考えていたので今回のサポートは丁度良いタイミングとなっている。

速度的には、100MHz 動作で、浮動小数点演算器も持っているデバイスなので、パフォーマンス的には、現在でもそんなに悪くなく、機能もそこそこあるので、何か作る場合でも、そんなに困らないのではと思う。

それでも、新規に購入しようとするとそこそこの価格だが、秋月で購入も可能なので、入手性など考えると、サポートしない理由はない。


構成を部分的に考え直して修正

この頃のRXマイコンは、現在の豊富な機能と比べると、かなり見劣りする。

C++ フレームワークでは、機能的に異なる部分を隠蔽するような仕組みを多数使っているので、「#if」などコンパイルの制御文を駆使しなくても、かなり綺麗に実装が可能となっている。
それでいて、最適化後のコードには、余分な部分が殆ど残らないので、速度低下もなく、上位の層(アプリケーション部分)は、ほぼそのまま再利用が可能となっている。

「#if」を多用して、細かい動作を切り替えているソースを読んだ事がある人は、判ると思うが、非常に読みにくく、デバッグも困難になる。
C++ では、そんな実装方法をとらなくても、最小限の分岐だけで、かなり複雑で柔軟な構成にできる。


FIRST_sample

まずは、LED 点滅から・・・

RX62x は、クロック生成部分が、非常にシンプルで、構成が大きく異なるので、専用のクラスとし、新規に書き直した。

ポートの構成も、大きく異なるので、専用のクラスとした。

各ファイルのインクルード制御は、common/device.hpp、common/renesas.hpp で行っている。

  • なので、アプリケーション側は、「common/renesas.hpp」をインクルードするだけで良い。

また、オシロスコープを使って波形を計測、ソフト遅延のパラメーターを適正な値に調整した。

この部分、「#if」で別けているので、定数を clock_profile に定義して参照するようにしないと駄目だな・・・
※今後改修する予定。


SCI_sample

  • SCI を動かすには、割り込みが必要なので、まずは、割り込み関係をサポート
  • 構成は、RX24T に近く、部分的に流用した
  • ついでに、他マイコンで、割り込み関係に係る部分を修正した

SCI 関係のペリフェラルは、現行のRXマイコンと、初期のRXマイコンでは、かなり異なる。

大きく異なるのは、ボーレートクロック生成の仕組みとなっている:

  • 倍速モードの追加
  • ボーレート変調レジスタの追加(比較的高いボーレートの場合に、クロックを間引いて、なるべく正確なレートになるように調整)
        //-----------------------------------------------------------------//
        /*!
            @brief  シリアル拡張レジスタ (SEMR)
            @param[in]  ofs     レジスタ・オフセット
        */
        //-----------------------------------------------------------------//
        template <uint32_t ofs>
        struct semr_t : public rw8_t<ofs> {
            typedef rw8_t<ofs> io_;
            using io_::operator =;
            using io_::operator ();
            using io_::operator |=;
            using io_::operator &=;

            bit_rw_t<io_, bitpos::B0> ACS0;
            bit_rw_t<io_, bitpos::B2> BRME;       // sci[g]

            bit_rw_t<io_, bitpos::B4> ABCS;
            bit_rw_t<io_, bitpos::B5> NFEN;       // sci[g]
            bit_rw_t<io_, bitpos::B6> BGDM;       // sci[g]
            bit_rw_t<io_, bitpos::B7> RXDESEL;    // sci[g]
        };

上記は、SEMR レジスタの定義だが、「sci[g]」は、新しいRXマイコンにはあるが、RX62x には存在しない。
現行の SCI 制御クラス(sci_io.hpp)では、全てを使ってボーレートを生成しているので、そのままでは、機能の無いマイコンには使えない。

RX62x に無いフラグやレジスタを定義から外す事も可能だが、それを行うと、sci_io.hpp のコンパイルが出来なくなってしまう。

  • なので、利用しているフラグビットは、常に存在するようにしないとならない(使う、使わないだけで別ける)
  • より厳密に行うには、そのビットにアクセスしても、無意味になるように出来るけど、それはやり過ぎと思ったので・・

そこで、SCI の定義クラスに、どのビットが有効なのかを宣言しておく。

  • sci_io クラスは、それを参照して利用するか、しないかを決定する。
  • 無効なビットに書き込む場合は、「0」を必ず書くようにする。
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  SCIa 定義クラス
        @param[in]  base    ベース・アドレス
        @param[in]  per     ペリフェラル型
        @param[in]  txv     送信ベクター
        @param[in]  rxv     受信ベクター
        @param[in]  tev     送信終了ベクター
        @param[in]  pclk    PCLK 周波数
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    template <uint32_t base, peripheral per, ICU::VECTOR txv, ICU::VECTOR rxv,
        typename INT, INT tev, uint32_t pclk>
    struct scia_t : public sci_core_t<base> {

        static constexpr auto PERIPHERAL = per; ///< ペリフェラル型
        static constexpr auto TX_VEC = txv;     ///< 受信割り込みベクター
        static constexpr auto RX_VEC = rxv;     ///< 送信割り込みベクター
        static constexpr auto TE_VEC = tev;     ///< 送信終了割り込みベクター
        static constexpr auto PCLK = pclk;  ///< PCLK 周波数

        static constexpr bool SEMR_BRME = false;    ///< BRME(ボーレート微調整)
        static constexpr bool SEMR_BGDM = false;    ///< BGDM(ボーレート倍速)

最近のRXマイコンでは:

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  SCIg クラス
        @param[in]  base    ベース・アドレス
        @param[in]  per     ペリフェラル型
        @param[in]  txv     送信ベクター
        @param[in]  rxv     受信ベクター
        @param[in]  tev     送信終了ベクター
        @param[in]  pclk    PCLK 周波数
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    template <uint32_t base, peripheral per, ICU::VECTOR txv, ICU::VECTOR rxv,
        typename INT, INT tev, uint32_t pclk>
    struct scig_t : public sci_core_t<base>, sci_core2_t<base> {

        static constexpr auto PERIPHERAL = per; ///< ペリフェラル型
        static constexpr auto TX_VEC = txv;     ///< 受信割り込みベクター
        static constexpr auto RX_VEC = rxv;     ///< 送信割り込みベクター
        static constexpr auto TE_VEC = tev;     ///< 送信終了割り込みベクター
        static constexpr uint32_t PCLK = pclk;  ///< PCLK 周波数

        static constexpr bool SEMR_BRME = true; ///< BRME(ボーレート微調整)
        static constexpr bool SEMR_BGDM = true; ///< BGDM(ボーレート倍速)
    };

RXマイコングループの違いは、以下のようになっている(#if が必要な部分)

  • SCI の基準クロックは、clock_profile に定義してあり、それを参照している。
  • RX62x の場合は「clock_profile::PCLK」、RX24T の場合は「colock_profile::PCLKB」となる。
  • SCI ハードウェアーの開始アドレスも大きく異なる。
  • RX72N などでは、割り込みの「型」も異なる。
#if defined(SIG_RX621) || defined(SIG_RX62N)
    typedef scia_t<0x00088240, peripheral::SCI0, ICU::VECTOR::TXI0, ICU::VECTOR::RXI0,
        ICU::VECTOR, ICU::VECTOR::TEI0, clock_profile::PCLK> SCI0;
    typedef scia_t<0x00088248, peripheral::SCI1, ICU::VECTOR::TXI1, ICU::VECTOR::RXI1,
        ICU::VECTOR, ICU::VECTOR::TEI1, clock_profile::PCLK> SCI1;
    typedef scia_t<0x00088250, peripheral::SCI2, ICU::VECTOR::TXI2, ICU::VECTOR::RXI2,
        ICU::VECTOR, ICU::VECTOR::TEI2, clock_profile::PCLK> SCI2;
    typedef scia_t<0x00088258, peripheral::SCI3, ICU::VECTOR::TXI3, ICU::VECTOR::RXI3,
        ICU::VECTOR, ICU::VECTOR::TEI3, clock_profile::PCLK> SCI3;
    typedef scia_t<0x00088268, peripheral::SCI5, ICU::VECTOR::TXI5, ICU::VECTOR::RXI5,
        ICU::VECTOR, ICU::VECTOR::TEI5, clock_profile::PCLK> SCI5;
    typedef scia_t<0x00088270, peripheral::SCI6, ICU::VECTOR::TXI6, ICU::VECTOR::RXI6,
        ICU::VECTOR, ICU::VECTOR::TEI6, clock_profile::PCLK> SCI6;
#elif defined(SIG_RX24T)
    typedef scig_t<0x0008A020, peripheral::SCI1, ICU::VECTOR::TXI1, ICU::VECTOR::RXI1,
        ICU::VECTOR, ICU::VECTOR::TEI1, clock_profile::PCLKB> SCI1;
    typedef scig_t<0x0008A020, peripheral::SCI1C, ICU::VECTOR::TXI1, ICU::VECTOR::RXI1,
        ICU::VECTOR, ICU::VECTOR::TEI1, clock_profile::PCLKB> SCI1C;
    typedef scig_t<0x0008A0A0, peripheral::SCI5, ICU::VECTOR::TXI5, ICU::VECTOR::RXI5,
        ICU::VECTOR, ICU::VECTOR::TEI5, clock_profile::PCLKB> SCI5;
    typedef scig_t<0x0008A0A0, peripheral::SCI5C, ICU::VECTOR::TXI5, ICU::VECTOR::RXI5,
        ICU::VECTOR, ICU::VECTOR::TEI5, clock_profile::PCLKB> SCI5C;
    typedef scig_t<0x0008A0C0, peripheral::SCI6, ICU::VECTOR::TXI6, ICU::VECTOR::RXI6,
        ICU::VECTOR, ICU::VECTOR::TEI6, clock_profile::PCLKB> SCI6;
    typedef scig_t<0x0008A0C0, peripheral::SCI6C, ICU::VECTOR::TXI6, ICU::VECTOR::RXI6,
        ICU::VECTOR, ICU::VECTOR::TEI6, clock_profile::PCLKB> SCI6C;

sci_io クラスでは、SCI に定義してある、値を参照して処理を切り替えている。

            // BGDM が使える場合、1/8 スタート
            uint32_t mtx = 8;
            uint32_t limit = 1024;
            if(!SCI::SEMR_BGDM) {  // BGDM が使えない場合 1/16 スタート
                mtx = 16;
                limit = 512;
            }
            uint32_t brr = SCI::PCLK / mtx / baud;
            uint8_t cks = 0;
            while(brr > limit) {
                brr >>= 2;
                ++cks;
                if(cks >= 4) {  // 範囲外の速度
                    port_map::turn(SCI::PERIPHERAL, false, PSEL);
                    power_mgr::turn(SCI::PERIPHERAL, false);
                    return false;
                }
            }

            // BGDM フラグの設定
            bool bgdm = true;
            if(SCI::SEMR_BGDM) {
                if(brr > 512) { brr >>= 1; bgdm = false; mtx <<= 1; }
            } else {
                bgdm = false;
            }
            bool abcs = true;
            if(brr > 256) { brr >>= 1; abcs = false; mtx <<= 1; }

C++ を知らない人は、最適化されても、余分なコードが含まれると思うかもしれないが、C++ の最適化では、参照先の状態に応じて、必要無い部分は、全て消してくれる。
テンプレートクラスでは、それが、究極的に行われる。
そして、必要な部分だけが、残る、コンパイル時に計算出来る部分は、計算され、定数が直接使われる。
※なので、constexpr などが重要な要素となる。


GNU-RX 8.3.0 の対応

今まで、RXv2 コアは、コンパイルオプション、「-misa=v2」を使っていたのだが、RXv2 コアは、昔と今では、多少異なるようだ・・・

RX62x で、「-misa=v2」でコンパイルすると、浮動小数点の計算で例外が出るようだ。
RX62x は、RXv1 コア。
※RX24T、RX65x などでは問題無い。
結局、RX62x では、「-mcpu=RX600」とする事で、適合するコードが生成される事が判った。

以下、makefile の共通部分:

ifeq ($(RX_DEF),SIG_RX62N)
  RX_CPU = RX62N
  RX_CHOOSE = -mcpu=RX600
  LDSCRIPT  =   ../../RX62x/$(DEVICE).ld
endif

ifeq ($(RX_DEF),SIG_RX24T)
  RX_CPU = RX24T
  RX_CHOOSE = -misa=v2
  LDSCRIPT  =   ../../RX24T/$(DEVICE).ld
  PROG_VERIFY =
endif

RAYTRACER_sample

少し大きいアプリを試しておく必要があるので、浮動小数点演算などが多く含まれたプログラムを走らせてみた。

RX62x は、RXv2 コアだが、fsqrt などの命令をサポートしないようだ・・
RX62x は、RXv1 コア
これが利いて、96MHz ではあるが、一番遅い・・

マイコン core fsqrt 命令 周波数 [MHz] 描画方式 時間 [ms]
RX62N RX600 X 96 8 bits, port-bus 1860
RX24T RXv2 O 80 8 bits, port-bus 1224
RX65N RXv2 O 120 Frame Memory 784
RX64M RXv2 O 120 16 bits, port-bus 751
RX66T RXv3 O 160 8 bits, port-bus 602
RX72T RXv3 O 192 8 bits, port-bus 464
RX71M RXv2 O 240 16 bits, port-bus 439
RX72N RXv3 O 240 Frame Memory 361
  • 単に動かしただけで、生成した画像を観ていないが、ストールせずに走るので、ちゃんと計算しているものと思う。
  • 余裕が出来たら LCD を接続して確認したい。

まとめ

RX62x のサポートがスムーズに出来たので、頃合いをみて、次は手持ちの RX63T をサポートしようと思う。
その前に、各サンプルで、RX62x のプロジェクトを追加する必要があるけど・・

それと、rx_prog で RX62x のフラッシュを書けるようにしたいが、これは、かなり昔のプロトコルなので時間がかかりそうだ・・・


雑誌付録の RX62N 基板を持っていて、譲っても良い人は連絡をくれると助かります。