FreeRTOS を本格的に運用する目処がたったので、まず、FatFs を最新版にした。
以前は、「ff12b」を使っていた。
今回「ff13c」に移行した。
意外と大きく変更になっている。
・ファイル名やパスが整理された。
・ヘッダー定義名やマクロ名などが、吟味され、より良くなった。
※マクロ名など、他のシステムと「当たらない」ように修正されたようだ。
・ファイルパスの文字コードがより洗練されて扱いやすくなった。
※ファイルのパスコードで、以前は、CP932 か、UTF-16 しか選べなかったが、UTF-8 も使えるようになった。
・排他制御用をやりやすいように変更があったようだ。
※lock、unlock などの関数コールが追加され、FreeRTOSと親和性が高い。
・一部、API が廃止になり、新しい API になった。
※日本だけなら、コードページ932だけで良いが、世界中で使っているので、その辺りを柔軟に改良したようだ。
などなど、細かく色々修正されている。
えるむ/ChaN さんのこのプロジェクトは世界中の人が使っている。
本当に素晴らしく、高機能なもので、今でも、少しづつ改良されているのには驚くばかりで、本当に頭が下がる。
FreeRTOS のような RTOS では、複数のタスクから、ファイル操作が出来ないとならないので、ドライバーの出来は、性能に直接影響するので、現在のソフト転送は改良する必要性がある。
ただ、難しい部分でもあり、性能を上げるのは簡単ではなさそうだ・・・
-----
とりあえず、github の FatFs を使っているアプリを全て修正し、master ブランチにマージしてある。
hira のすべての投稿
FreeRTOS、Rxv2 と、他デバイス対応
現在自分が扱う RX マイコンはどれも、RXv2 コアなので、GCC/RX600v2 のコードを使いたい。
しかしながら、gcc-6.4.0 は「RXv2」に対応していない。
rx-elf-as は、RXv2 に対応している。
% rx-elf-as -v --help
GNU assembler version 2.28 (rx-elf) using BFD version (GNU Binutils) 2.28
Usage: ./rx-elf-as [option...] [asmfile...]
Options:
.....
.....
.....
--mcpu=<rx100|rx200|rx600|rx610|rxv2>
--mno-allow-string-insns
Report bugs to <http://www.sourceware.org/bugzilla/>
そこで、RXv2 依存のアセンブリコードを使った関数を、アセンブラソースに分離して、対応する事にした。
多少の問題としては、「FreeRTOSConfig.h」の設定を使っている部分で(割り込みの優先順位)なのだが、まぁこれはあまり変更する事が無いと思うので、とりあえず、直接値を代入しておいた。
これで、リンクして、無事実行ファイルが出来、動作を確認したのだけど、そーいえば、コンパイラからアセンブラにオプションを渡せないのかな?
調べたら、あったー・・・
-Wa,option
option をアセンブラに対するオプションとして渡します。
なんだー、これだー、とゆー事で、Makefile を少し修正して、ソースコードはそのままで、「RXv2」に対応する事が出来たー
非常にスマートに対応出来た。
下記のようにコンパイラオプションを追加する事で、内部動作は、コンパイル後にアセンブラを起動する場合に、以下のオプションが追加される。
-Wa,-mcpu=rxv2
続いて、他のCPUについても、ICU 関係のクラスに「SWINT」関係を追加して、Makefile を作成して、実行ファイルを各マイコンに書き込んで試してみた。
とりあえず、問題なく動作するようだ。
これで、
RX24T
RX64M
RX71M
RX65N
RX66T
に対応する事が出来た、次は、よく使うドライバークラスをマルチタスク対応にして、ネットスタックの実験に進みたい。
ソースコードは、github の master ブランチにマージ済みとなっている。
FreeRTOS を使い始めました~
少し時間が出来たので、FreeRTOS をポートして、自分の環境で動かし始めた。
詳細は、
「RXマイコンで、FreeRTOS を使う場合の要点
に投稿している。
自分のブログでは、今回「はまった」点にフォーカスしてみたい。
そもそも、FreeRTOS は RX マイコンをサポートしており、RX マイコン用コードもアーカイブに含まれる。
しかし、それは、ルネサスさんの環境用で、自分のように、gcc を自前でコンパイルして使っている場合、そのままでは使えない。
それと、ルネサスさんの環境用なので「iodefine.h」定義が必要なのも、敬遠する理由となっている。
※ハードウェアー定義は C++ クラスで独自に実装してある。
なので C++ ベースの制御クラスを定義して、そのコンテキストを FreeRTOS に使ってもらうようにしたい。
最初は、「簡単」だと思ってやっていたが、勘違いから、かなり時間を使ってしまった・・・
FreeRTOS では、ソフトウェアー割り込みも使う。
今まで、ソフトウェアー割り込みは使った事がなく、割り込み関係クラスもサポートしていなかったので、それらを追加した。
※これが、間違いの始まり・・・
「SWINT」はベクター番号27で、この割り込み許可と、割り込みレベル設定は、ICU 関連レジスターにある。
割り込み許可は、問題無かったが、割り込みレベル設定は、IPRのベースアドレス+27と思い込み、そのような設定にして、何の疑いもしなかった。
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
@brief IPR レジスタ @n
全て、下位4ビットが有効
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <uint32_t base>
struct ipr_t {
rw8_t<base + 27> SWINT;
};
static ipr_t<0x00087300> IPR;
そして、ようやく、主要な部分が出来て、簡単なサンプルを用意して、マイコンに書き込み起動するが動作しない・・・
その過程で、色々「マズイ」部分も見つかり、直すが、全く動かない。
デバッグ用コードを入れて、どこまで動いているか確認すると、定義したタスクが起動していない・・・
そして、なぜ起動しないのか、ソースを追うと、どうやら、ソフトウェアー割り込みが怪しい事に気がつき、単独で、ソフトウェアー割り込みの動作を確認してみた。
当然のように「動かない」・・・
そこで、ハードウェアーマニュアルを見直したら、ベクター27のソフトウェアー割り込みレベル設定は、+3である事が判った・・・
それを修正したら、動作するようになった。
rw8_t<base + 3> SWINT;
そこで、不思議に思った事がある・・
ソフトウェアー割り込み(SWINT)を使う場合、「asm("int #27");」を実行するハズだけど、どこを探しても、それらしい実装が見つからない。
よくよく調べると、ICU レジスターには、ハードウェアーから、SWINT を発生させる機能があり、それをハードコードしていた。
※「portmacro.h」
#define portYIELD() \
__asm volatile \
( \
"PUSH.L R10 \n" \
"MOV.L #0x872E0, R10 \n" \
"MOV.B #0x1, [R10] \n" \
"MOV.L [R10], R10 \n" \
"POP R10 \n" \
)
「0x872E0」 に「1」をライトするのがそれだー、これは痛い・・・
何で、iodefine.h をインクルードしているのに、こんな事してるのか?
それに、こんな面倒な事しなくても、「asm(int #27);」で良くない??
疑問は残るけど、FreeRTOS に戻って、実験したらようやく動作したーー(ヤレヤレ~)
そもそも、ハードウェアー依存部分は、完全に外部に出せるから、「port.c、portmacro.h」に含める必要性は無いのに・・・
そんなこんなで、動くようになったので、github に上げた。
これから、色々マルチタスク対応にしていこうと思う。
追記:
「ソフトウェアー割り込み命令(int #27)」と「SWINT ハードウェアー割り込み」は動作が異なるとの知見(RXマイコン内の動作がどのように異なるのか不明なので、完全に理解している訳ではないが・・)を受けて、とりあえず以下のように変更した。
※気になっていたのは、32ビットリードなので・・
#define portYIELD() \
__asm volatile \
( \
"PUSH.L R10 \n" \
"MOV.L #0x872E0, R10 \n" \
"MOV.B #0x1, [R10] \n" \
"CMP [R10].UB, R10 \n" \
"POP R10 \n" \
)
RX72Mが発表になってた・・
ルネサスRXv3コアを持つRXマイコンのフラッグシップRX72Mが発表されていた・・
最近、久しぶりに Unity 関係の仕事を請けた為忙しくなり、趣味のマイコンには、なかなか触れない。
RX66T が入手出来るようになり、RX72Tも発表になり、RX71Mの後継が待たれていたが、遂に発表された。
多少、期待していた仕様とは異なるが(最大クロック速度が上がるものと思っていた)それでも、色々新しい機能を追加しているようだ。
デバイスは、今年の9月末量産受付となっているようだ。
RX71Mとどこが異なっているのか、簡単にトピックを記しておく。
- EtherCAT 対応
- GLCDC、DRW2D 対応
- 1Mバイトの内臓RAM
- 224LFBGA パッケージの追加
- 倍精度浮動小数点コプロセッサ
- RXv3 コア
- ΔΣインターフェース
- 単精度三角関数演算器
- PHY マネジメントインターフェース
逆に、無くなった機能として・・
- サンプリングレートコンバータ
- USB 2.0 ハイスピードモジュール(480Mbps)
- FIFO内臓シリアルコミュニケーションインターフェース
他にも細かい違いはあるが、色々改善もされているようだ。
224LFBGA は、ピン数が増えて、良さそうだ、176ピンパッケージでも、主要な機能をアサインしようとすると、使えない事が多い。
ただ、自作基板とかで、デバイスを載せるのは難しいかもしれず、また、多層基板とピン間3本くらいのルールが必要かもしれず、製作コストが上がる・・
GLCDC、DRW2D、1Mバイト内臓RAMのおかげで、LCD を接続した機器を作りやすくなった。
480×272 の LCD で、ダブルバッファが行なえそうだ。
内臓 RAM は、前半512Kがノーウェイト、後半512Kが1ウェイトとなっているので、後半をフレームバッファにする事になるだろうか・・
USBのハイスピード(480MBps)が無くなったのは残念だ・・
シリアルサウンドインターフェース(SSIE)が機能強化されており、外部にオーディオ用DACをより繋ぎやすくなった。
倍精度浮動小数点演算がサポートされたが、gcc などで使えるようになるには、RXマイコン用ライブラリが、gcc のソースツリーに集約される必要があり、それには時間がかかりそうで、多少不安だ、現在のように、かなり古い gcc (gcc-4.8)ベースがこのまま続くとなると、自分で何とかしないといけなくなる・・・
※もうそろそろ、自前のCコンパイラは諦めて、gcc や LLVM ベースに統合するべきだと思うが、専用コンパイラを数十万円で販売していて、フリー版に制限を設けているようでは難しいと思われる。
とりあえず、RX72M に対応したライブラリを追加している。
速くデバイスを入手して動かしてみたい~
組み込み(RXマイコン)向けGUI管理クラスの実装
主に、RX65N Envision kit 用にまともなGUI管理を用意しておこうと作業を進めている。
既に、Windows、OS-X、用マルチプラットホームのGUI管理があるのだが、こちらは、リッチな環境向けであり、かなり高機能となっている。
描画はOpenGLで行っている為、そのようなインフラが無いシステムでは、ルックアンドフィールなど多くの面で適合しない。
組み込みマイコン用では、グラフィックスの能力も低いし、解像度も低いので、高機能過ぎるのは逆に使いにくいし、リソースも食ってしまい実用的ではない。
既に、RX65N用には、emWin GUI ライブラリがあり、利用できるようだが、C言語ベースなのでとても使う気にならない。
※GUIのような複雑な機構をC言語ベースで実装する合理的な理由が見当たらない。
そこで、glfw_app/widgets で養ったエンジニアリングを土台に、機能を絞って、設計をやり直してみた。
既に、1度実装した経験があるので、アプリを作る場合の利便性や、どのような構成、構造にすれば良いかは十分理解しているつもりなので、組み込み環境を考えながら実装する。
C++ ベースの GUI では、各GUIに応答する機能の実装は、ラムダ式を使う事で、非常にシンプルに書けるのが判っているが、それ以外の方法でも GUI の応答をサービスする方法を提供する必要性がある。
組み込み系なので、new、delete などの記憶管理を使わない方針で進めた。
※経験的に、テンプレートデザインパターンを使うと何とでもなると判っている。
また、オペレーターやテンプレートなど C++ の機能を盛り込む事で、アプリケーション実装時の「判り易さ」を追及できる。
RX65N 専用では無いので、DRW2D のようなハードウェアーを使った描画機能が無い場合も考えて、ソフトウェアだけで描画する事も視野に入れて、そこそこ見栄え良く、軽く、簡単に扱えるように、実験などしながら進めている。
RX65Nで基本的な部分が動作したら、glfw_app で動作するエミュレーションを実装して、機能をチェック等を実機で行わなくても良いようにする予定でいる。
※実機確認では、作業効率が悪すぎると思われる。
GUI の部品としては、非常に多くあるが、簡単に実装できるものと、最低限必要な物を最初に実装して、後は、必要に応じて追加していこうと思う。
GUI の見た目は、経験的に、ビットマップで細かく作るより、円、直線などを組み合わせた幾何学的な図形をベースにする方が良いと思う。
これは、プログラムで細かく描画する事になるが、その方がリソースの節約にもなり、制御がしやすく、応用が利く。
※様々なサイズに対応出来る。
※たとえば、少なくとも3つの状態が必要となる場合。
・通常の状態
・活性した状態(ボタンが押された等)
・ストールした状態(表示されているが、無効になっている状態)
もしビットマップで作る場合、これらの状態を用意しておく必要があり、それだけでも実用的とは思えないし、ビットマップリソースをリンクするツールが必要となる。
自分が作りたい「ルック」が欲しいのなら、近いGUIのソースをコピーして、それを自分の要求する見た目に合わせて改造すれば良いだろうと思う。
- フレーム
- グループ
- ボタン
- チェックボックス
- ラジオボタン
- スライダー
全ての部品は、親子関係を持つ事が出来る。(構造的には、親の部品を知っている)
※親が全ての子供を知っている方が良い場合が多いのだが、構造が複雑になってしまう。
もし、全ての子供を知りたい場合、管理リストをスキャンして子供のリストを作るしか無い。
また、親子関係を利用する事で、相対的な部品位置で管理できたり、部品をグループ化して、全体を制御したり出来る。
「ラジオボタン」は、自分の変化により他の部品の状態を変える必要があるので、グループ化しておき、親を指定しておく。
その中のボタンで変化が起きた場合、親が同一のリストを作成して、他のボタンの状態を自動で変更する。
「スライダー」は、縦、横のサイズにより、水平か垂直か判断して対応する。
通常、部品からフォーカスが外れると、部品のハンドリングが終了してしまう、しかしその仕様だと、スライダーのような部品では、操作性が悪い(スライダーの領域は通常狭いのと、フォーカスしたままスライドするのが困難)なので、小細工として、スライダーの場合は、初期に領域内でタッチされた時にフォーカスを有効にして、タッチが外れるまでホールドする事で、操作性を改善している。
// widget の定義
gui::button button_;
gui::check check_;
gui::group group_;
gui::radio radio1_;
gui::radio radio2_;
gui::radio radio3_;
gui::slider slider_;
// widget のコンストラクタ
setup() noexcept :
button_(vtx::srect( 30, 20, 80, 30), "OK"),
check_(vtx::srect( 30, 70 + 40*0, 0, 0), "Check"),
group_(vtx::srect( 30, 70 + 40*1, 0, 0)),
radio1_(vtx::srect( 30, 70 + 40*1, 0, 0), "Red"),
radio2_(vtx::srect( 30, 70 + 40*2, 0, 0), "Green"),
radio3_(vtx::srect( 30, 70 + 40*3, 0, 0), "Blue"),
slider_(vtx::srect(150,20, 120, 0))
{
// ラジオボタンのグループ化
group_ + radio1_ + radio2_ + radio3_;
}
// 初期化
void init() noexcept override
{
button_.enable();
// ボタンが押された時の応答ラムダ式
button_.at_select_func() = [this](uint32_t id) {
change_scene(scene_id::root_menu);
};
check_.enable();
// チェックボックスの応答ラムダ式
check_.at_select_func() = [this](bool ena) {
utils::format("Check: %d\n") % static_cast<int>(ena);
};
radio1_.enable();
radio2_.enable();
radio3_.enable();
slider_.enable();
}
// シーン終了処理
void exit() noexcept override
{
button_.enable(false);
check_.enable(false);
radio1_.enable(false);
radio2_.enable(false);
radio3_.enable(false);
slider_.enable(false);
}
※GUI の構築と、それに対応する「応答」などを含めたアプリケーションプログラム。
GUI関連のソースコードは:
graphics/widget.hpp
graphics/widget_director.hpp
graphics/group.hpp
graphics/frame.hpp
graphics/button.hpp
graphics/check.hpp
graphics/radio.hpp
graphics/slider.hpp
graphics/color.hpp
graphics/graphics.hpp
となっており、他のヘッダーにも依存しているが、内部は、なるべく依存が低くなるようにしているつもり。(実際はレビューしないといけない)
また、widget の追加と削除を行う関数をスタティック扱いとして参照している。(この仕組みは、推奨されるべきものでは無いが、現状の設計ではそのようにしている、今後より良い方法に変更していくかもしれない・・
USBシリアル、どれがいい?
RXマイコンのフラッシュ書き込みでは、自分は、シリアルインターフェースによる書き込みが基本だ。
E1も持ってはいるが、OS-XやLinuxでは使えないし、14ピンのコネクタを繋ぐのも億劫だ。
それに、エミュレーターをほとんど使わないので、フラッシュの書き込みにしか用途が無い。
そうなるとUSBシリアルを使って、シリアル通信で書き込む方が簡単だと思う。
※書き込みツールも独自に対応している。
最近まで、アマゾンで買える格安の中華USBシリアルとしてCP2102を押していたが、状況が変わってきている。
問題として、以下の事項がある。
- 使っているデバイスは古いCP2102(現在はCP2102Nが主流、古いデバイスを使っているのが安い理由なのかもしれない)
- 複数のCP2102を一旦接続するとCOMポートの移り変わり現象が発生してまともに使えなくなる。
- 複数接続するには、専用ツールで、内部シリアルIDを変更して、固体識別をさせる必要があるようだ。
- CP2102では、専用ツールが正常に機能しないし、ツールのインストールからしてハードルが高い。
- 色々やったが、CP2102では内部シリアルIDを変更する事が出来なかった。(理由が不明)
そこでやっぱり正統派FTDIだと思い、FTDIでも格安なFT231XSを使おうと思ったが、これには別の問題がある事が判った。(以前に自作したもの)
通信速度が明らかに遅い!
RX66T にレイトレーシングのプログラム(バイナリーで47K程度)を書き込んだ場合の時間:
※230400ボー、8ビット、1ストップビット
FT231XS: 16.6 秒
CP2102: 6.6 秒
上記のように、同じボーレートで条件は同じなのに、3倍近く通信速度が違う。
FT231XSは安い廉価バージョンなので、高級バージョンのFT232RLの場合も確かめてみた。
FT232RL: 18.1 秒
驚きだ、FTDIのデバイスは値段に関係無く、シリコンラボ製に比べてかなりパフォーマンスが劣るようだ・・・
※以前にシリアル通信を使った機器を作った時に感じたが、詳しく評価しなかった。(そんな事が起こるとは思ってない)
J-TAGなどの代用によく使われる、FT232HLも手元にあったので、試してみた。
FT232HL: 17.5 秒
※全然ハイスピードじゃねぇ・・・
上記書き込み時間は、イレース時間、書き込み時間、比較時間などが組み合わさったもので、送信、受信をかなり頻繁に行い、目安なのだが、単純な送受信ではないアプリケーションレベルでの利用なので、逆に、ベンチマークには適しているとも思う。
そこで、今度は、CP2102Nを評価してみたい(主にシリアルIDの変更)と思ったが、調べてみると、CP2102Nを使ったモジュールは少ないようで、入手出来ていない。
※CP2102Nを使った、メーカーの標準キットが1000円くらいなのだが、送料がかかるのが痛いとこだ(同時購入品が何かないと・・・)
現状は、そんな状態だ、進展があったらまた報告するが、どちらにしてもFTDIを使う理由は無いだろうな・・・
RXマイコンでシーン管理(タスク管理)テンプレート
多少複雑なアプリなどを実装する場合、動作の推移を行う管理機構が必要になる事が多い。
やり方は色々だが、組み込みシステム向けに、シンプルな機構を実装したので紹介する。
平行処理にする程でも無い場合など、少し大きい単位で処理を分けて、影響範囲を限定的にする事が出来る。
※この方法は既に色々なシステムで利用しているが、多少アレンジした点として、以下のトピックがある。
- シーンオブジェクトによる推移管理。
- 可変引数テンプレートの利用。
- std::tuple テンプレートを使い、シーンオブジェクトを管理。
- 記憶割り当てを使わない。
まず、一つの推移単位をシーンクラスとして、インターフェースクラスを継承させている。
インターフェースクラスは以下のようなものとなっている。
※C++ では「= 0; 」とする事で「純粋仮想関数」とする事が出来る。(薄い皮のような物)
※デストラクタを「仮想」として実装しておく必要がある。
struct scene {
virtual ~scene() { } ///< デストラクタ
virtual void init() = 0; ///< シーン開始前処理
virtual void service() = 0; ///< シーン・サービス
virtual void exit() = 0; ///< シーン終了処理
};
- シーンを開始する前に必ず「init()」を呼び出す。
- シーン中は「service()」が呼ばれ続ける。
- シーンが切り替わる時、シーンを終了するタイミングで「exit()」が呼び出される。
シーン作成時、上記「scene クラス」を継承させて実体を実装する。
以下は「title」クラス。
class title : public scene {
public:
void init() override
{
}
void service() override
{
}
void exit() override
{
}
};
通常シーンは複数あり、シーン管理機構で管理される、アプリケーション側は、各シーンの中身を実装する。
シーン管理クラス(scene_director)では、個々のシーンの実体をstd::tuple で保持しており、切り替えの操作や手順を提供する。
scene_director は、可変引数テンプレートを使って、ユーザー定義のシーンクラスを複数受け取る。
template<class... Args>
class scene_director {
typedef std::tuple<Args...> SCENES;
SCENES scenes_;
scene* cur_scene_;
scene* new_scene_;
public:
scene_director() noexcept : scenes_(), cur_scene_(nullptr), new_scene_(nullptr)
{ }
template <class T>
void change() noexcept
{
auto& news = std::get<T>(scenes_);
new_scene_ = &news;
}
void service() noexcept
{
if(new_scene_ != nullptr) {
if(cur_scene_ != nullptr) cur_scene_->exit();
new_scene_->init();
cur_scene_ = new_scene_;
new_scene_ = nullptr;
}
if(cur_scene_ != nullptr) {
cur_scene_->service();
}
}
};
このテンプレートを使い、以下のように全体を定義する。
#include "scene_director.hpp"
#include "title.hpp"
#include "menu.hpp"
#include "setup.hpp"
typedef scene_director<title, menu, setup> SCENES;
SCENES scenes_;
これで大体全てなのだが、大きな問題がある、通常シーンの切り替えは、scene_director の change メソッドを使うのだが、各シーンから、scene_director にアクセスするには、scene_director のインスタンスと定義、各シーンの型などが必要で、それにアクセスする手段を設けるのは難しい。
そこで、かなり冗長でシンプルでは無いが、各シーンに通し番号を振っておき、この番号で切り替える機構を設けて、この関数呼び出しを extern しておく事にした。
各シーンの切り替えは「整数」なので、定義がシンプルでどこからでも呼び出せる。
※ただ、シーンとIDを二重に管理しなければならず、かなり痛い・・・
void change(scene_id id)
{
switch(id) {
case scene_id::title:
scenes_.change<title>();
break;
case scene_id::menu:
scenes_.change<menu>();
break;
case scene_id::setup:
scenes_.change<setup>();
break;
}
}
※他の注意点として、インスタンス化の順番を理解しておく必要がある。
scene_director がインスタンス化されるタイミングで、各シーンのコンストラクターが呼び出されるので、各シーン中で何かをインスタンス化している場合、それが関わるクラスは、事前にインスタンス化されておかなければならない。
システムが複雑になると、忘れがちなので注意する必要がある。
※ソースコードは、「RX/common/scene.hpp」にある。
RXマイコン別性能(レイトレースによる)その2
RX66Tを入手したので、レイトレースを実行してみた。
その中で、RX65N Envision kit のコードを標準的にして、他のデバイスも評価していたが、LCDへの転送は、ポートバスによるソフトウェアー書き込みになっている。
水平ライン毎に、レンダリング時間を描画しているが、ポート経由だと、フォント描画がボトルネックになっている事実などがあり、コーディングを整理した。
まず、各マイコン別のタイムを表にしたので参考にしてもらいたい。
※今回、RX64M も加えた。
型番 | 動作周波数 [MHz] | ROM | RAM | 実時間 [ミリ秒] | 価格 [円] |
---|---|---|---|---|---|
R5F524TAADFP RX24T | 80 | 256K | 16K | 1224 | 974 (572/10) |
R5F565NEDDFB RX65N | 120 | 2M | 640K | 784 | 1910 (1320/10) |
R5F564MFCDFC RX64M | 120 | 2M | 512K | 751 | 2120 (1570/10) |
R5F566TEBDFP RX66T | 160 | 512K | 64K | 602 | 900(参考) |
R5F571MFDDFC RX71M | 240 | 2M | 512K | 439 | 2600 (1940/10) |
RX66Tの価格は、RSコンポーネンツで1個購入時のもので、チップワンストップで扱うようになれば、多少異なると思う。
描画ハードに関して、RX64M、RX66Tは、実際にはLCDを接続していないが、RX64MはRX71M、RX66TはRX24Tと同一のインターフェースがあるものとしているので正確だと思う。
※ポート経由の描画オーバーヘッドは、RX66Tで118ミリ秒もある。(ただRAMに書くだけだと484ミリ秒)
通常、描画時間は、ライン毎に%表示されるが、ソフトによるポートバスでは、オーバーヘッドがかなり大きいので、その部分をコメントアウトして、描画後に1回だけ表示するようにしている。
RX66TのRXv3コアの評価は、この結果からはイマイチ判らないが、RX71MやRX64Mの値からすると、やはり少し効率が高いようだ、ただ、浮動小数点演算が多いので、イマイチ参考にならない。
現段階でも、CPはRX66Tがもっとも優れていると言える。
ソースコードなどは、Github のRX/RAYTRACER_sample に全てある。
EMLE 端子のプルダウンを入れてから、フラッシュの書き込みは一度も失敗しないようになった。
ルネサスRX66T(その1)
ルネサスRXマイコンを購入する場合、自分の場合「チップワンストップ」がほとんどで、他ではほぼ買わない(値段が一番安く、種類が豊富、個数割引もあるので)。
RX66Tは、発表されてからかなりたつものの、未だにチップ単体での販売はされていない。
ところが、ツイッターで「RX66TでLチカした」とゆーツイートを見つけた・・
※変換基板だったので、デバイス単体で入手したようだった。
ツイートした人はマイクロマウスをやってる人のようで、「どうやって入手したの?」と聞いたが連絡は取れず、色々調べたら「RSコンポーネンツ」で販売している事を見つけた。
1個900円と少し高いと思ったが、早く試してみたかったので、早速1個購入した。
※それにRXマイコンも10周年らしぃのでw
※現在(4月9日)、ルネサスのHPでも、RX66Tの販売先としてはどこも登録されていない。
※次の日には届いて、変換基板にハンダ付け。
※購入した型番は「R5F566TEBDFP」で、PGA 差動入力なし、USB なし、100 ピン、プログラムフラッシュ 512K、RAM 64K、データフラッシュ 32K
写真のハンダ付けはちょっと汚いが、一応ブリッジや接触不良は無いものと思う。(よく確認した)
いつものように「直付」する為、裏側をカプトンテープで保護する。
ユニバーサル基板に直接乗せ、ガイドとして、適当なヘッダーピンを刺しておき、対角のピンにハンダを流して、変換基板と、下のユニバーサル基板を固定する。
後は、電源ライン、MD端子、クリスタル関係、リセットSW、シリアルラインなど、最低限必要な線だけ配線する。
- (20) PD5/RXD1 <--- TXD (USB Serial)
- (22) PD3/TXD1 ---> RXD (USB Serial)
- (6) MD L:Boot、H:Run
- (1) /RES
- (5) VCL GND 間に 0.47uF
- (11) XTAL 10MHz、GND間に 8pF
- (13) EXTAL 10MHz、GND間に 8pF
- (2) EMLE 4.7K で プルダウン(エミュレーターイネーブル)
- (15) PE2/NMI 10K でプルアップ
rxprog も、RX66T 用にプロトコルを追加して、LED 点滅は直ぐに動作した。
RX66T関係のデバイス定義は、発表と同時くらいに、ハードウェアーマニュアルをダウンロードして、実装していたので、ソフトの準備はそれなりに出来ていた。
RX66T の内部構成は、RX24T よりRX64M 系に近い。
今回入手したデバイスは、USB は内臓していないバージョンだが、ラインナップには USB 付きもある、その場合、内臓クロックは12の倍数にする必要があり、144MHz 動作になってしまうと思う(最高速は160MHzなので少しもったいない)。
static void micro_second(uint32_t us)
{
while(us > 0) {
#if defined(SIG_RX64M) || defined(SIG_RX63T) || defined(SIG_RX71M)
for(uint32_t n = 0; n < (F_ICLK / 4285714); ++n) {
asm("nop");
}
#elif defined(SIG_RX65N)
for(uint32_t n = 0; n < (F_ICLK / 4444444); ++n) {
asm("nop");
}
#elif defined(SIG_RX24T)
for(uint32_t n = 0; n < (F_ICLK / 4444444); ++n) {
asm("nop");
}
#elif defined(SIG_RX66T)
for(uint32_t n = 0; n < (F_ICLK / 3346666); ++n) {
asm("nop");
}
#else
# error "delay.hpp requires tune dummy operations"
#endif
--us;
}
}
RX66T は、RXv3 コアとなっており、実測による簡単なソフトループだが、今までのRXコアより15~20%くらい速いようだ。
※同じバイナリーでこれだけ高速なのは、驚くべき性能だと思う。
※ちゃんとしたベンチマークは後ほど行う予定
現在の問題として、フラッシュプログラム中に停止する症状がある。
これは、原因を特定出来ていない・・・
とりあえず、rx_prog.conf のシリアル速度を、230400から115200に落としたら、多少安定して書き込めるようなので、当面そうしておく。
※RX64M、RX71M、RX24T では、問題無いのだが・・・
とりあえず
FIRST_sample/RX66T(LED 点滅)
SCI_sample/RX66T(シリアル通信)
は、動作する事を確認した。
※RX66T では、SCI のベースクロックは、PCLKBを利用するが、このクロックの最大は60MHzで、内臓クロックを160MHzで動かす場合、最大では40MHzとなる。
フラッシュ書き込み時にハングアップする原因が判ったと思う。
RX66Tでは、EMLE端子が増設された、「1」でエミュレーターイネーブルなので、とりあえずGNDに落としておいたが、これが原因のようだ、4.7Kでプルダウンしたら、安定して書き込めるようになった。
多分、フラッシュ書き込み時などに一瞬出力になる場合があるのだろう・・
※ボーレートは関係無かった。
Makefile 、環境毎の違いを補正
既に、「glfw_app」などで行っていたのだが、RXマイコンの開発環境でも、boost を使うようになった為、Makefile の修正を行った。
※プロジェクトの数が多いので、主要な部分のみ行った。
boost は、パッケージマネージャーでインストールするのが標準的となったので、環境毎にパスを追加で指定しなければならない。
そこで、以下のようなスクリプトで、環境を識別して、内部変数を設定している。
# Include path for each environment
ifeq ($(OS),Windows_NT)
SYSTEM := WIN
LOCAL_PATH = /mingw64
else
UNAME := $(shell uname -s)
ifeq ($(UNAME),Linux)
SYSTEM := LINUX
LOCAL_PATH = /usr/local
endif
ifeq ($(UNAME),Darwin)
SYSTEM := OSX
OSX_VER := $(shell sw_vers -productVersion | sed 's/^\([0-9]*.[0-9]*\).[0-9]*/\1/')
LOCAL_PATH = /opt/local
endif
endif
INC_SYS = $(LOCAL_PATH)/include
これで、Windows(MSYS2)、Linux、OS-Xの違いを識別して、適切な「パス」を設定できる。
OS-X では、OS のバージョンも抜き出している。
他、emacs を起動した場合の TAB を強制的に指示する為、以下の「おまじない」をファイルの先頭に追加した。
# -*- tab-width : 4 -*-
さらに、既に2019年だが、今まで「C++14」を指定していたコンパイルオプションを「C++17」に変更しておいた。
PFLAGS = -std=c++17 $(CP_OPT) $(OPTIMIZE) $(MCU_TARGET) $(DEFS)