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

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

RX C++ フレームワーク、RX261 サポート

RX260/RX261 が発売された

ルネサス社は、RXマイコンの新シリーズ、RX260/RX261 を発売した。

https://www.nikkei.com/article/DGXZRSP680552_S4A021C2000000/

チップワンストップでの価格は、以下(現在、1品種しか確認していない)

RX261 100QFP, ROM: 512K, RAM: 128K, DataFlash: 8K

  • R5F52618BGFP#70 @852、10個時 @621

※RX260 は、RX261 から、CANFD、USB、セキリティ関係IP を省いたタイプのようだ
※セキリティ関係IPは、ルネサス社との特別な契約により、内容が公開されるようだ


主な特徴

  • RXv3 コア
  • 最大動作周波数 64MHz
  • 32 ビット単精度浮動小数点
  • 1.6V ~ 5.5V 動作
  • 高速動作モード:84 µA/MHz
  • CAN FD Module (CANFD)
  • USB2.0 Full Speed, Host, Function
  • 12ビットA/D変換器
  • 8ビットD/A変換器

このシリーズ、RX26T の系統なのかと思ったけど、RXv3 コアにして、低消費電力化を図り、RX140、RX231、のリソースを統合したような CPU で、USB が使える事は良いものの、SSIE、SDHI が省かれるなど、単純に RX231 を代替えする事が出来ないのが少し勿体ないと思う。
※RX231 の代わりが出来てしまうと、RX231 が存在する理由が無くなってしまう・・、D/A も 8 Bits だし・・・

RX231 の 54MHz に比べて、64MHz は少しだけ速くなったが、微妙な感じ。

それでも、C++ フレームワークではサポートファイルを用意して、とりあえず、使えるようにしておいた。(コミット済)

  • RX140、RX231 のペリフェラルと同等の部分が多いので、新規に作成したファイルは少ない為、労力は少なかった。
  • クロック構成が多少特殊なので、それらのファイルは新規に用意した。
  • ただ、まだ実際にデバイスを入手していないので、動作確認をしていないのだけど・・・

この CPU 割り込みが、全て標準ベクタにアサインされていて、選択型や、グループ割り込みが無い設計になっている。


CANFD のドライバーを、本格的に用意したい

このデバイス、CANFD を搭載しているので、自動用途にも向いているように思う、しかも電気を食わない。
現状 CANFD のドライバーを実装していないので、それも早々に用意したい処だ・・


まとめ

新しいシリアルコミュニケーション RSCI も搭載している、これは、他で展開する(ARM、RISC-V)新しいもので、それらと共通の仕様となっているようだ。
※CANFD もそのようだ・・
とりあえず、ドライバーは用意してある(まだ、ちゃんとした動作確認はしていない)

値段もそこそこ安いし、色々使えそうなので、早急にチップを購入して実験してみたい。

rx_prog の更新

Renesas RX Series Programmer Version 1.90
Copyright (C) 2016, 2024 Hiramatsu Kunihito (hira@rvf-rc45.net)
usage:
rx_prog [options] [mot file] ...

Options :
    -P PORT,   --port=PORT     Specify serial port
    -s SPEED,  --speed=SPEED   Specify serial speed
    -d DEVICE, --device=DEVICE Specify device name
    -e, --erase                Perform a device erase to a minimum
    --id=ID[:,]ID[:,] ...      Specify protect ID (16 bytes)
    -r, --read                 Perform data read
    -v, --verify               Perform data verify
    -w, --write                Perform data write
    --progress                 display Progress output
    --erase-page-wait=WAIT     Delay per read page  (2000) [uS]
    --write-page-wait=WAIT     Delay per write page (5000) [uS]
    --device-list              Display device list
    --verbose                  Verbose output
    -h, --help                 Display this

rx_prog の歴史的背景

RX マイコンのフラッシュ書き換えに、独自に実装したプログラムを保守、管理している。

「Renesas Flash Programmer」があるのに、何故?と思われるかもしれないが、歴史的な背景がある。

最初は、コマンドラインから動かせるとか、マルチプラットホーム(Windows,Linux,OS-X)とか、色々な理由があって、少しづつ機能追加していって、現在の姿になっている。

R8C/M120AN マイコン用のフラッシュプログラマーを実装したのもあって、「RX マイコン用も欲しいなぁー」と単純に思ったのも要因としてある。
なので、同じように使えるような仕様にしてある。

自分は、どうも GUI の操作が面倒だと感じる、複数のマイコンを試す場合など、R.F.P.では、プロジェクトを開き直す必要がある。

又、マルチプラットホームで動作するようにしてあるので、個々に専用の設定キーがあったり、色々な環境で使い回すのに都合が良いように工夫してある。

ただ、現状、機能的には完全では無い。


RX26T のサポート

RX26T は、今までの RX マイコンと異なり、書き込むページサイズが 128 バイトとなっている。
※以前は 256 バイト

その仕様に伴い、細かく色々変更したものの、何故か、書き込みに失敗する不具合があり、長い間、ほったらかしていた・・

丁度良い機会だったので、不具合の原因を調べてみたー
ところが、中々原因が掴めない。

結局、「erase_page」にバグがあり、それが引き金となり、ちゃんと消去されていない為、書き込みに失敗する事が判った。
この原因を見つけるのに、かなり時間を使ってしまったが、ちゃんと動作するのは嬉しいのものだー

これで、手持ちの RX マイコンは全て、サポートして、動作実績がある事になる!
※RX65x は、ボードを作って無いので、試せていないが・・・


RX220 の erase_page で不具合

RX220 は、ID コードプロテクトをしていない状態だと、ブートモードでデバイスと接続して、P/E モードに入ると、自動でフラッシュを消去してくれる機能がある。
※P/E モード: プログラム、イレース モード
※このような仕様は、RX220 に限らず、RX24T、RX63T など、少し古いデバイスでは、そのようになっている場合がある。
※その為、「erase_page」の機能をちゃんと実装していなかった。

又、消去されている、されていないに限らず、必ず「消去」コマンドを発行する事で、プログラムの書き込みに関する手順を一般化出来るので、消去の機能を省くのは良くない。

今回、そのケアも行った。
ただ、古い、RX マイコンでは、フラッシュのプログラミングプロトコルが、あまり洗練されていない事がある。

RX220 のハードウェアーマニュアルを読み、「erase_page」の実装を行い、実験すると、エラーで消去出来ない。

エラーのステータスを調べると、「ブロック番号エラー」となっている。

「ブロック番号」とは、RX220 の解説によると、2K バイト単位で、128 ブロックあると書かれている。(256K品)
※「36.4 ブロック構成」

ところが、この仕様に沿って、適切なブロック番号を渡しても、エラーとなる・・

そもそも、ブロック単位が 2K バイトって「変」だよな・・と思って、デバイスの接続時に、取得するエリア情報を観てみたー

#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

やっぱりね・・・
このリストによると、FFFC0000~FFFF7FFF は 16K 単位で、
FFFF8000~FFFFFFFF は 4K 単位であるようだ・・・

この事実に沿って、ブロック番号を指定したら、ちゃんと消去出来たー
マニュアルの嘘は勘弁して欲しい~、これは、あまりに酷いので、報告しておこうかな・・・


RX231/RX24T の書き込み速度

最近、RX231、RX24T の書き込みで、途中ストールする場合が多くなった・・・
この症状は、ページライト時に、十分な遅延が不適切で、書き込みデータを転送出来ない場合に起こると思われる。

そこで、通常の倍、遅延を取るように common/makefile に指示した。
※「--write-page-wait=15000, --erase-page-wait=4000」


ブランク・チェック

主に、RX200 系や、古い RX62x 系、RX63x 系では、ブランクチェックの仕様が古く、全体が消去されているか、いないかしか判らない。
rx_prog は、書き込む際、書き込むデータのマップを 256 バイト単位で作成して、必要な領域のみ、消去するようにしている。

又、ID コードが無指定の場合、デバイス接続で、自動で消去される仕様なので、ブランクチェックを行い、全体が消去されていたら、余分な消去操作を行わないようにした。

さらに、消去領域は、広いので、一旦消去されたブロックに対して、何度も消去操作が発生しないようにした。


まとめ

マイコンの違いで、手順を完全に分けているが、マイコンが異なっても、同じ手順で重複している物がかなりある。
現状では、これらは、コピー、ペーストになっていて、保守性が最悪な状態だ・・・
次は、これらの仕組みを整理してまとめようと思う。

又、まだサポートしていない機能が色々あるのでそれも何とかしたい・・

  • Config memory への書き込み
  • プロテクト ID の書き込みと管理
  • 読出し機能と管理など
  • 詳細なエラーレポート

RXマイコン関数電卓、他


※ 120km を mi に変換 (74.56 mi)

関数電卓を考える

関数電卓は、丁度良いボリュームで、難易度も適当な事から、昔から興味の尽きないアプリケーションとなっている。

マイコンで作る電卓なら、大容量メモリや周辺機能を活かして、通常流通している物には無い機能を盛り込める。
前回、倍精度浮動小数点よりも高精度に計算が行える、gmp、mpfr ライブラリを使って、計算の核を実装している。

RX マイコン EnvisionKit の機能を活かして実現が出来るのもガジェットとして都合が良い。

最終的には、簡単に持ち運びが出来る形態で、実用的なハンドヘルド関数電卓を作りたいと考えている。

構成的には、タッチキーでは無く、物理ボタンが欲しい処ではあるけど、複雑な操作は GUI じゃないと作りずらい場合もある。
物理ボタンなら、フルキーボードが欲しい処ではあるけど、気軽に使えるような、小型のフルキーも少ない・・
市販されているボタンを組み合わせてキーアレイを構築するにしても、コストの割に良い物を作る事が難しい・・

それでも、手頃な RX マイコン、液晶、物理キーを組み合わせた、スクラッチの関数電卓も作ってみたい。

色々考えても、一長一短で最適解があるのか無いのか・・、とりあえず、ソフトで出来る事を地道に積み上げて、完成度を高めるのが良さそうだと感じている。

GUI が無くても、シリアル接続で、対話式に計算を行えるようにしてあり、殆どのRXマイコンで動作する。
※容量が 256K 品では不足するのが、多少問題で、最低でも 512K 品が必要・・


単位の換算機能

2進、16進の変換機能などを実装して、及第点にはなった感があるのだけど、自分としては前から欲しいと思った機能もある。
Qiita の記事:RXマイコンで動作する関数電卓
※上記記事は、2進、10進、16進の機能を追加したバージョンの記事で、内部の構成などを解説している。

新たに追加した機能は「単位の変換」機能だ。

単位変換は、長さ、速度、重量など相互に変換したい場合があり、電卓の専用機能として実装すれば、利便性が格段に上がると思われる。

電卓では、単純に小数点の位置をオフセットして、10 の乗数で表す機能(ENG)があり、単位の変換は、これに近い機能。
そうすれば、元の値を保持したまま、自由に単位を変更出来るので、非常に便利。
※元の値を保持したまま変換出来る点が利便性が高い。

追加で、貨幣の変換も追加した、貨幣の場合、レートが日々変化するので、変換レートを更新する必要がある。
なので、貨幣レートのみ、変換レートを再設定出来るようにしてある。
※GUI版は、貨幣レートを入力するダイアログ関係を実装中で、現在、コマンド入力では再設定出来る。


GUI spinboxt

スピンボックスtは、登録された単語集を、左右の小さいボタンにより変更して、目的の機能を選択する。
※通常のスピンボックスは、数値を変化させて、定量的な値を得るもので、それとは少し異なるものだ。

  • ボタンを三等分して、左、右、中心で機能を別けているので、ある程度の幅が必要となる
  • 左右の小さい三角は、選択肢の有無を表している
  • メニューの方が良いかもしれないが、画面タッチでは、シンプルな操作性の方が使い易いと思う

レートの再設定

貨幣レート変換の場合、時間と共にレートが変わるので、レートを変更出来るようにする必要がある。
コマンドラインのインターフェースでは、その機能を入れてあるが、GUI は、現在実装中となっている。


RX231 のフラッシュ書き込みの不具合

RX231 を、rx_prog でフラッシュ書き込みを行った処、途中でストールして書き込めなくなった・・・
色々調べたが原因が良く判らない・・
とりあえず、「--write-page-wait=10000 --erase-page-wait=5000」書き込み時の遅延を大きくしたら、ストールしなくなったので、RX231 だけ遅延を再設定するように、common/makefile を修正した。


sci_io、rsci_io、scif_io クラスのエラーハンドリング

以前の実装では、オーバーランエラー、フレーミングエラー、パリティエラーが発生した場合、受信を受け付けなくなる不具合があった。

長い間、放置され修正を忘れていたものだった・・・
それを思い出し、ちゃんと実装した。

  • エラー割り込みを有効にして、エラーフラグを消去する
  • エラーの回数を記録する

まだ、緻密なテストを行っていないが、多分問題無いと思う。
エラーが発生した場合、受信データを捨てる事になるが、エラーをクリアして、正常に受信を行えば自動で復帰する。


RXマイコン GUI ダイアログ

ダイアログボックスは、優先度の高い GUI で、フォーカスを占有する。
現状、gui/widget_director は、これらの管理を全くしておらず、新規に実装する必要がある・・

しかし、ここにきて、行き当たりばったりで実装してきた事がかなり痛いー、ちゃんと良く考えないと管理が難しく複雑になる。
少し時間を取って、ゆっくり考えたい。
glfw3_app では、実装済みなのだが、昔実装した時には、かなり面倒だったと記憶している。
本来、こんなに高機能にするつもりが無かった、シンプルな構造で十分と思っていたのだが、関数電卓の GUI を実装する過程で、やっぱり、シンプルな機能だけでは、不可能な事案が出てきてしまった。

RX140ボード、RXマイコンC++フレームワークの整備など

最近ブログ書いて無かったので・・

RX140ボードは出来て、組み立て途中、クリスタルのフットプリントを間違えていた・・
新たに、USBシリアルとして安価なCH340、を採用した、それは動いている事は確認した。
@70円は、確かに安いが、どうだろうか・・・

クリスタルの表面実装品は取り付けが困難な事が判ったー、ハンダペーストは出来れば使いたく無い・・

1603サイズのLEDが見つからないので、動作検査はまだ出来ていないが、まぁ問題無いと思う。

今回、JLPCBを使った。

準備が出来たら、領府を行う予定、多分1000円位。


RX マイコンC++フレームワークの構成など、細かく見直した

まず、サポートしているRXマイコンの種別を増やした、ただ、実際にデバイスに書き込んで動作検査をしていない品種もある。
ChipOne ストップでの入手性、値段などから品種の追加等を行っている。
現行デバイスでは無いものでも、まだ流通している品種はそのまま残しているが、古いデバイスを新たに追加するかは未定。

又、各ディレクトリに「README.md」を置いて、特徴、リンカーファイルの構成、専用ファイル、基本ピンアサイン、フラッシュプログラマ関係の情報などを記述してコミットした。
これを観れば、デバイスを選択する際の要点などが判ると思う。


最近、秋月で、RX231 の販売を開始したようだが、値段が高く、フラッシュ容量も少ない品種で、中途半端な感じだ・・
※フラッシュ容量128Kは、USBが使えても、少ないと思う、それで580円、まぁCANが使える品種のようだが・・
それでも、一応、リンカーファイルは追加しておいた。
ChipOne ストップで、もっとフラッシュ容量が大きく、ピン数が多い品種を買った方が良いと思える。

CAN は自動車やバイクで使えるので、そのような用途に使えるかもしれない。
C++フレームワークでは、現在「RSCAN」は未サポートなので、早急に何とかしたい~


format_class を少しだけ更新

GitHub の format_class 関係、少しだけ修正した。

「make run」で、セルフテストを行うと、文字出力で、「ゼロサプレス」を使った場合にリファレンスと異なった動作をしていた。
それを修正した。
この評価は、clangコンパイラで行っており、「標準」的な動作なのだと思われる。

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 を利用した高速版に置き換えられるものと思う。


まとめ

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