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

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

RX65Nボードの設計(その1)

RX66Tが発表になり、デバイスが入手出来るのを待っていたが、なかなかデバイス単体で購入できる状態にならないので、RX65Nのボードを先に作ろうかと思い作業を始めた。
※169ピンのRX65Nを5個購入した(@1560)
※ついでにPFCコンバーター専用ICなども購入、こちらは、CNC用インバーターなどの前段に使う予定でいる。

RX65N Envision Kit はまぁ良いのだが、惜しい部分がある。
・バッテリーバックアップがない
・RTCのクリスタルが接続されていない
・付属LCD(480x272)の視野角が狭く、表示品質がイマイチ
・無線LANがない
・SDRAMがない
・オーディオ出力がない
・バッテリー駆動系の部品などが無い
・後載せ部品など基本的な仕様
などで、本当は 最高速で動作する 240MHz の RX71M の方も捨てがたいが、DRW2Dコントローラーが魅力なので、とりあえずRX65Nで進める。
ピンアサインは RX71M、RX64M とほぼ同一なので、少し工夫すれば乗せかえる事も出来そうだが、RX71M用は、また基板を作れば良いだろう。

無線LANは、コストで有利な ESP8266 や ESP32 を繋げておけば良さそうだが、天邪鬼なので、マイクロチップ社の WiFi モジュール ATWINC1500 を乗せられるようにしておく予定でいる。
※スピードを評価したい事もあるし(ESP8266より高速に通信できると思う)、SPI 接続の代表的な物を使いたい、ただ、コストは ESP に比べると3倍くらい高い。(個数を沢山買えば、1.5倍くらいにはなりそう・・)

EDA ツールは KiCAD を使っているのだが、最新バージョン(5.02)をインストールしたら、非常に機能が追加されており、シンプルで使いやすくなっていて驚いたー(素晴らしいとしか言い様がない!)
※ただ、4.x系とファイルの互換で問題がありそうで、4.x用ファイルを読み込めない場合があるようだ・・

ボードのコストは、Wifi、SDカードインターフェース、100BaseEthernet、256Mbit SDRAM、LCD などなど乗せても、部品代だけなら Envision Kit と同等くらいで収まる。

ただ、問題もある。
実際に設計を始めて問題になったのはピン定義だ、SDRAM(16ビットバス)、SDHI(SDカード)、Ethernet、LCDなど、169ピンデバイスで、これらを全部使うピン定義を考えたが、信号が被って、同時利用は出来ないようだ・・・

LCD のバスを「8ビットシリアル」にする事で何とかアサイン出来る事が判った、ポートは余っているのに、そこにアサイン出来ない(定義が無い)のは「何で」ってなる・・
※8ビットシリアルを通常の RGB バスに変換するのに8ビットラッチを2個は用意する必要があると思う。

将来的にはマイクロコントローラのピン定義は、全てのピンで全てのペリフェラルを自由に割り当て出来るような構成になるものと思うが、LSIの設計段階で、それが大きなハードルになる場合もあるのだろう、現状では、そのような柔軟な設定が出来るマイクロコントローラは少ない。
そこまでの柔軟性は必要無くても、最低限、主要な機能を使う為の標準的定義が仕様として出来ないのは如何なものか・・・

KiCADのシンボルや footprint は、ネットを探すと自分の欲しい物はほとんど入手できる場合が多いが、部分的に気に入らない場合や、ライセンスなどの問題があったりして、一つや二つなら自分で作っても大した手間ではない。
また、5.x系の為、4.x系のライブラリが読めない事があるようだ。
※秋月電子とかで、そのような物を集めて、またはサービスとして作成して公開して欲しいと思う。
自分が使う部品は、GitHub に上げてある。
https://github.com/hirakuni45/RX/tree/master/KiCAD_lib

パルストランス内臓イーサーネットモジュラージャック RJ-45

回路設計と言っても、ルネサス社が出しているサンプルボードの回路図で必要な部分を流用すれば良い、最近は基板を作るハードルが下がっているので、失敗しても気軽に作り直しが出来る、ただ、やはり4層基板で作りたいので、それほど安くは出来ないかもしれないが、日本国内の基板屋に比べて1/4~1/10程度だろうと思う。

MicroChip ATWINC1500-MR210PB WiFiモジュール

LCD は秋月で売っているものの、タッチパネルが付いていないので、AliiExpress でタッチパネル付きの物を購入した、送料入れて22ドル程度だったが、表示品質は高そうだ、秋月で売っているものとバックライトLEDの仕様が異なるが、「CAT4238」を使えば、流れる電流値の設定変更だけで対応出来そうではある、LCDのピンアサインは共通のようだ。

SDRAM は、秋月で128メガビット品を@300で入手出来るが、256メガビット品「IS42S16160-7TL」を購入、@423だった。(16ビットバス)
RX65Nは内臓RAMはそこそこあるものの、グラフィックスなど、容量の大きいオブジェクトを扱う場合、SDRAMは必須と言える。
※外部に接続されたSDRAMの速度は、内臓RAMに比べてかなりスローダウンすると思えるのだが、実メモリが数十メガバイトあるのは、本当に有利だ、C++ の標準ライブラリや boost も気兼ねなく使え、PC 環境と遜色無く、プログラムを実装できると思える。
また、Minix のような実行環境も揃えられるだろう。
※ gcc を動かしたいが、完全な POSIX 環境を作るのは簡単では無いだろうな・・

RX65N Envision Kit、DRW2D エンジンの仕様?不具合?

先日、RX65N に内臓の描画エンジンを使ってみたが、描画の管理を色々テスト、評価する段階で暗礁に乗り上げた。
RX65Nの場合、内臓メモリは限られているので、ダブルバッファとフリッピングによる手法を行うには無理がある。
そこで、とりあえず、シングルバッファによる方法で、描画と表示を最適化して、何とかならないかと試行錯誤してみたが、「問題」に当たった。

予定では、画面表示と描画を細かく管理する事で、高速な描画エンジンとの連携で何とかなると思っていたが、思っていたように動作せず、悩んでいる。

まず、問題をシンプルにする為、簡単な描画シーケンスを実行してみた。

    d2_startframe(d2_);
    d2_clear(d2_, 0x000000);
    d2_setcolor(d2_, 0, col);
    d2_rendercircle(d2_, 480/2*16, 272/2*16, rad*16, 0);
    d2_endframe(d2_);

上記のプログラムでは、画面全体を消去して、中心に円を描画する、描画の半径は、フレーム毎に変えるようにしている。
※実際に描画にかかる実時間は、半径が最大でも1ms程度と思われる。

普通に考えると、「描画中」は、描画アクセスが優先されるので正しい表示にならないのは判る。
しかし、実際にこのプログラムを走らせると、描画が終わってからも、正しい表示がされない。
※正しい表示がされるのは、次のフレームからになり、毎フレームこの処理を繰り返すと、ほとんど何も表示出来ない常態になってしまう。
ここからは想像なのだが、DRW2Dエンジンにディスプレイリストを渡して描画すると、DRW2Dエンジンがメモリバスを奪い取って放さず、GLCDCの読み出しが無効になってしまい、表示の読み出しが失敗しているように見える。
DRW2Dのキャッシュをフラッシュするとか、描画領域を変更するとか色々考え付く方法を試したが、一旦描画を始めてしまうと、描画の終了に関わらず、メモリバスを占有して離さないようだ、この状態は、垂直同期信号のトリガーでリセットされる。
これは、参った、この状況では、いくらパフォーマンスが高くても、リアルタイム性を要求するような描画を行えない。

何か不足している設定があるのでは?

もしかして、「バス」の優先度を設定するレジスターがあるのでは?
ハードウェアーマニュアルを良く見て、「あーーー」と唸ってしまった、「拡張バスマスタ優先度制御レジスタ (EBMAPCR)」というのがあった・・・
ヨクヨク、サンプルソースコードを見ると、GLCDC、DRW2Dの初期化時にこのレジスターにプライオリティーを設定してる・・

    {  // メインバス2優先順位設定(GLCDC、DRW2D)
        device::BUS::EBMAPCR.PR1SEL = 0;
        device::BUS::EBMAPCR.PR2SEL = 3;
        device::BUS::EBMAPCR.PR3SEL = 1;
        device::BUS::EBMAPCR.PR4SEL = 2;
        device::BUS::EBMAPCR.PR5SEL = 4;
    }

それに習って、上記のように優先順位を設定してみたら、思った通りの表示が行えた~

この問題解決に随分時間をかけてしまったようだ・・・

上の黒い「帯」でDRW2Dエンジンが描画を行っている・・

RX65N Envision Kit 、DRW2Dエンジンを使う

RX65Nには、描画をブーストするDRW2D描画エンジンがある。
ただ、ハードウェアーレジスタの詳細は公開されておらず、C言語による操作ライブラリが公開されている。
今までは、フレームバッファに対する描画は、ソフトウェアーによる描画のみを使っていたが、当然ハードウェアーの方がパフォーマンスは高く、描画中は、他の処理を実行出来る為、効率も良さそうだ。
また、DRW2Dの描画機能は、アンチエリアス付の描画が行え、「線幅」の概念があるので、かなり柔軟で品質の高い描画が簡単に行える。

そこで、DRW2Dライブラリの機能をC++から呼び出すラッパーを実装してみた。
※DRW2Dライブラリのバージョンは1.02をベースにしている。

DRW2Dの基本的な動作は、メモリー上に描画コマンド・リストを定義しておき、その先頭ポインタを描画エンジンに渡す事で描画を行う仕組みとなっている。

描画状況により、割り込みが起動でき、DRW2Dライブラリでは、標準的に割り込みサービスを呼び出すように設計されている。

「drw2d_mgr」クラスでは、初期化で、割り込みベクターを登録している。
「void drw_int_isr(void);」はDRW2Dライブラリの割り込みサービスの入り口で、それを登録しておけば良い、ただ、この割り込みは、グループベクタAL1になっていて、「icu_mgr」クラス内の AL1 dispatch クラスが、内部で振り分けを行うようになっている。
※割り込み関数アトリビュートを付けないようにしなければならない。

extern "C" {
    extern void drw_int_isr(void);
};
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  DRW2D 制御/マネージャー
        @param[in]  DRW     DRW2D クラス
        @param[in]  XSIZE   X 方向ピクセルサイズ
        @param[in]  YSIZE   Y 方向ピクセルサイズ
        @param[in]  PXT     ピクセル・タイプ
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <class DRW, int16_t XSIZE, int16_t YSIZE, glcdc_def::PIX_TYPE PXT>
class drw2d_mgr {

...

    icu_mgr::install_group_task(DRW::get_irq_vec(), drw_int_isr);

...

};

DRW2Dの初期化は、以下のように行うようで、「drw2d_mgr」クラスの初期化「start();」から呼んでいる。
この呼び出し後、DRW2Dエンジンを利用出来るようだ。

    d2_ = d2_opendevice(0);
    d2_inithw(d2_, 0);
    rb_ = d2_newrenderbuffer(d2_, dlis, stsz);

「d2_newrenderbuffer」のプロトタイプは以下のようになっている。
dlis: initialsize - number of displaylist entries in the first page (minimum is 3)
stsz: stepsize - number of displaylist entries in following pages (minimum is 3)

内部で「malloc」を使ってメモリを割り当てているので、固定長で使えるように改修する必要があるかもしれない・・

DRW2DライブラリのAPIは非常に豊富に用意されているが、とりあえず、良く使いそうな物だけラップした。
また、座標系のクラスなどを積極的に利用するようにした。
DRW2Dライブラリの構成はOpenGLのコマンドストリームの考え方に近いので(高速、柔軟性、機能性を追及すると、大体、このような構成になる)マネージャーを実装するのは比較的やりやすい。

アンチエリアスされた「線」と「サークル」の描画

とりあえず、基本が出来たので後は、スプライトなどテクスチャーの描画などだ、フォントが一通り描画できるようになったら、ソフトウェアーのエンジンと入れ替えたい・・・

drw2d_mgr.hpp

NESのパッドを付けてみたら・・

部屋をかたずけていたら、NESのコントローラーが出てきた、本体は無い、多分これは、20年くらい前のもので、その時務めていた会社(ライブプランニング)からNESのソフトと本体など借りた時(丁度「暴れん坊天狗」の NES 版「Zombie Nation」を作っていた頃だ)本体は返したがコントローラーだけ自宅に置き去りになったものと思う。

NESパッド

折角なので、RX65N Envision kit のNESエミュレーターのパッドとして使ってみた。

ネットを探して、コントローラーのピンアサインを探して、コネクタを付けた。

白:Vcc(電源、通常+5V)
茶:GND(電源、0V)
橙:P/S(パラレル、シフト切り替え)
赤:CLK(クロック)
黄:OUT(シリアル出力)

ところが・・・
ボタンを押しても反応が無い・・・
配線を確認したが、問題無さそう、ファミコン互換パッドでは問題無く動作する。

これは多分、クロックの遅延が足りないものと思い、クロックの遅延ループを6回から20回にして動作するようになった。
この純正パッドはC-MOS「4021B」を使っているが、互換パッドに使われているICは、4021Bの互換ICで、クロックの許容範囲が広いものと思う。

uint8_t update(uint32_t cnt = 20) noexcept
{
    P_S::P = 0; // seirial
    uint8_t d = 0;
    for(uint8_t i = 0; i < 8; ++i) {
        d <<= 1;
        if(!OUT::P()) ++d;
        CLK::P = 1;
        utils::delay::loop(cnt);
        CLK::P = 0;
        utils::delay::loop(cnt);
    }
    P_S::P = 1; // parallel
    data_ = d;
    return data_;
}

上記のように、ループ数を「6」から「20」に変更した。
※120MHz動作の場合なので、もっとCPUクロックが速い場合は調整する必要がある。

static void loop(uint32_t cnt)
{
    while(cnt > 0) {
        asm("nop");
        --cnt;
    }
}

loop 関数は上記のように「nop」を実行するだけのものだ。

RX65N Envision Kit には、上記のように接続してある。

FAMIPAD.hpp

今回の話とは関係無いが、写真の圧着工具、安い割りにはなかなかに良い!
この小さいコネクタの圧着では、まともにできずに、ラジオペンチで修正したり、最悪ハンダ付けしたりと苦労してきたが、この工具なら、ほぼ間違いなく綺麗に圧着できる。
専用の工具は非常に高価で、たいてい1種類のピンにしか対応しないので、DIYでは買う機会は無いのだが、この工具ならそれに匹敵する、すばらしい!

RXマイコン別性能(レイトレースによる)

RX66Tは、まだデバイスが入手できていないので評価はまだだが、RX24T、RX65N、RX71M(RX64M)の全般的な性能評価を行った。
※RX64Mは最大動作周波数がRX71Mの半分で、他はRX71Mと同等なので、スルーしている。
又、最大動作周波数でベンチマークしている。

今回の評価では、「レイトレース・プログラム」を使った。
現実的には、このベンチマークでは不十分とも思えるが、浮動小数点演算が混在したプログラムを走らせるようなアプリの評価では、整数演算とのバランス(浮動小数点の比率が高めだけど・・)で、十分参考になると思える。
※整数演算のみの評価では、他のマイコンと比べるとRXマイコンは、CISC系で、ルネサスが独自に工夫しており、実行効率が優れている為、評価するまでもなく速い。
※現状では、消費電力辺りの能力、強力な各種ペリフェラルなど、色々な面で、敵ナシだと思う。(gcc を使わない場合の開発環境が有料、又、やはりコストは多少高い、その点で、他より劣る)

RX200シリーズなどのFPUを持たないマイコン(RXv1コア)は、手持ちが無いので評価していないが、コストの問題から下位のシリーズを使う場合でも、CPの高いRX24Tの存在があり(RX220とあまりコストが変わらないと言うのは言い過ぎだと思うが・・)低価格路線では、それを目安にする事ができる。
※自分としては、RX200シリーズはFPUを持たないし、動作周波数も低く、あまりメリットを感じない。
これは多分、RL78などの8/16ビットマイコンとの差別化で、同じような価格帯で、性能差が大きすぎると差別化が難しい為と思われる、それでも、32ビットコアのメリットは大きい。
※RXマイコンが、ARM、PIC32、ESP32に比べて割高感があるので、「敬遠」している人がいるかもしれないが、たとえば、RX65Nと同等の機能を持った、ARMと比べた場合、同等の性能を出す事が出来るシリーズは無かったり、価格もそれほど変わらない場合も多い。
今回評価していないものの、RX630(100MHz)などもあり、RXマイコンは色々な場面で有用だと思える。

RX24T、8ビットバス、I/Oポート制御
RX65N、フレームバッファ制御
RX71M、フレームバッファ制御
型番 動作周波数 [MHz] FPU ROM RAM 実時間 [ミリ秒] 価格 [円]
R5F524TAADFP RX24T 80 256K 16K 1670 974 (572/10)
R5F565NEDDFB RX65N 120 2M 640K 812 1910 (1320/10)
R5F571MFDDFC RX71M 240 2M 512K 410 2600 (1940/10)
ESP32(参考) 160 4M 520K 13000 550
STM32F4(参考) 72 × 1M 192K 52000 320
STM32F756BGT6(参考) 216 1M 320K 620 1820 (1250/10)

備考:
・コンパイラは「rx-elf-gcc 6.4.0」で、最適化「-O3」でバイナリーを作成。
・ESP32 の結果が悪すぎるのは、LCD とのインターフェースに問題があるように思う。(描画のオーバーヘッドが大きいものと思う)
・内臓メモリのサイズと値段は相関があるので、単純にCPを比べる事は出来ない。
・ESP32、STM32F4、STM32F7 の結果は、ネット情報による。
・RX65NのCPが意外に高い、LCD接続が容易で、トータルで考えた場合、バランスが良い。
・RX71M、RX65Nは、フレームバッファを使い、描画コストが低い、STM32F7も同様の方式と思われる。
・RX24Tは、RAMが少ないので都度描画を行っている、描画コストがそれなりにある。
・ベンチマークに使ったソースは、Arduino 向けの物なので、細かい部分で、動作が微妙に異なり、条件も違う。
・RX マイコンでは、float の平方根を求める専用命令(FSQRT)を使っている。(STM32F7もそれは同様なようだ)

RX71MにLCDを接続してみる。

かなり昔に、Aitendo でセールしてたTFT-LCDをRX71Mに接続してみた。

2.2インチ、320x240、64Kカラー、コントローラーは、R61505

LCDコントローラーのバスをデータラインに直接接続するのがゴールだったが、動作しない・・

RXマイコンのバス設定は面倒なので、最初、I/Oポート制御でコントローラーの初期化を実験してみた。
しかし、何をやっても、思ったように動作しない・・
※初期化コードは Arduino 用をネットで拾ってきて、適当に改造して実験していた。

相当、色々やったが、不安定で動作しない・・・
※数回に1回、初期化だけ動作する事はあるが、ピクセルの描画では、おかしな動作をしてまともに動作しない。

それで、しばらく放置してた、2019年になって、そーいえば8ビットバスで試して無かったなぁーってふと思い、「IM」ピンをGNDからVCCに変更(8ビットバス)して、16ビットバス用から8ビットバス用に修正して試してみたら、普通に動作する。

何で?
8ビットバス接続では、DB8~DB15 を使う、16ビットバスでは、DB0~DB15 を使う。
以前に、DB0~DB15 の結線に誤りがあるのかと思い、調べたが問題無い・・

再度、DB0~DB7 の結線を調べたら、DB6 の結線が間違っていた・・
※PD6(145) に繋ぐべきところが、PG0(146) に接続していた・・・
最近、視力が落ちて、細かい配線が見難い(車の運転には支障無い視力)事が大きな要因と思うが、「メガネ」を作りにいくのが億劫で、先延ばしにしていた。

Start TFT sample
ID: C505
Probe TFT OK to start...
Render time: 630ms (1)

ところで、RX71M の 240MHz 動作では、320x240のレイトレースベンチマークは上記のように0.63秒だった。
ただ、ピクセルの描画コマンドをコントローラーに送る際のオーバーヘッドが大きいので、実際には、もっと速いと思うが、素晴らしいパフォーマンスだ!
RXマイコンは、本当に優秀なマイコンだと思う、使わない理由が無い、逆に何故ARMやPICを使うのか問いたいくらいだ。

https://github.com/hirakuni45/RX/tree/master/rx71m_LCD
※一応、テストで使っているプロジェクト

RXマイコン関係ソースコードを整理する

RX66T関係を追加する過程で、RX関連ソースコードを整理した。

今まで、RX24Tに始まり、RX64M、RX71M、RX65Nとサポートデバイスを広げてきたが、RX66Tを加えるにあたり、重複しているファイルや、醜い部分を整理した。
基本はRX64Mとなっている。
・RX64M、RX71Mはほぼ同じ
・RX651/RX65Nは、微妙に異なる
・RX24Tは別品種(割り込み関係が異なる)
・RX66Tは、RX24TとRX64M系の中間的
こんな感じだが、デバイスのレジスター関係は、全てにおいて共通部分が多く、共有出来る。
異なるのは、デバイス(自分のフレームワークでは、ペリフェラルと呼んでいる)の有無。
RX64M、RX71Mは非常に沢山のペリフェラルを持っているが、RX24Tなどは、それに比べて少ないが、中でも「割り込み」ベクターが大きく異なる。
これをどのように表現するかが大きな課題となっていたが、とりあえず、テンプレートにしておけば何とでもなる事が判った。
また、今までは、似ているけど少し異なるような場合は、「#if」などで、分けて凌いでいたが、基本的に各デバイスで、ファイルを分けて対応する事にした。
懸念事項としては、同じコードを全てのデバイス専用ファイルにコピーする必要があり、この場合、一つの修正が、他のデバイスのソースも同じように修正する必要が出てくる・・
一つのファイルで共有して「#if」で細かく分ける書き方だと、かなりトリッキーで読みにくくなる、どちらが良いかは、ケースバイケースで何とも言えないが、保守より読みやすさを優先した。

ペリフェラル:
各デバイスには、「peripheral.hpp」があり、このファイル内で、「enum class」により、「peripheral」型で、利用できるペリフェラルが列挙してある。
この「列挙型」の違いにより、ポートの設定、消費電力設定、割り込み制御など、大まかな動作を分けている、ペリフェラルを直接叩くドライバーは、たとえば割り込みベクター型の違いを考慮する必要が無いように実装してある。

RX24Tのペリフェラルでは、割り込みベクターは、通常ベクターに全て割り当てられているが、RX64Mなどペリフェラルが多いデバイスでは、通常ベクターの数が足りずに、グループベクター、選択型ベクターを新規に設け、それらに割り当てるように工夫されている為、そのままでは同じように扱う事が出来ない。
この違いを吸収して、デバイスドライバーを共通化する為、考えた結果、以下のような実装を行う事でかなりスマートに解決出来た。

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
        @brief  CMT I/O クラス
        @param[in]  CMT チャネルクラス
        @param[in]  TASK    タイマー動作クラス
*/    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <class CMT, class TASK = utils::null_task>
class cmt_io {

...

};

上記はCMTの制御クラスの型だが、「CMT」は、CMTペリフェラルクラスで、CMTの制御レジスターを定義したものになっている、通常CMTは0~3まで4チャネルある。
RX64M、RX71M、RX65Nでは、CMT0、CMT1の割り込みは「通常」ベクターだが、CMT2、CMT3は「選択型」ベクターとなっていて、割り込みの設定手順が異なる。

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  CMT 定義基底クラス
    @param[in]  base    ベース・アドレス
    @param[in]  per     ペリフェラル
    @param[in]  INT     割り込みベクター型
    @param[in]  ivec    割り込みベクター
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <uint32_t base, peripheral per, typename INT, INT ivec>
struct cmt_t {

...

};
#if defined(SIG_RX24T) || defined(SIG_RX66T)
    typedef cmt_t<0x00088002, peripheral::CMT0, ICU::VECTOR, ICU::VECTOR::CMI0> CMT0;
    typedef cmt_t<0x00088008, peripheral::CMT1, ICU::VECTOR, ICU::VECTOR::CMI1> CMT1;
    typedef cmt_t<0x00088012, peripheral::CMT2, ICU::VECTOR, ICU::VECTOR::CMI2> CMT2;
    typedef cmt_t<0x00088018, peripheral::CMT3, ICU::VECTOR, ICU::VECTOR::CMI3> CMT3;
#elif defined(SIG_RX64M) || defined(SIG_RX71M) || defined(SIG_RX65N)
    typedef cmt_t<0x00088002, peripheral::CMT0, ICU::VECTOR, ICU::VECTOR::CMI0> CMT0;
    typedef cmt_t<0x00088008, peripheral::CMT1, ICU::VECTOR, ICU::VECTOR::CMI1> CMT1;
    typedef cmt_t<0x00088012, peripheral::CMT2, ICU::VECTOR_SELB, ICU::VECTOR_SELB::CMI2> CMT2;
    typedef cmt_t<0x00088018, peripheral::CMT3, ICU::VECTOR_SELB, ICU::VECTOR_SELB::CMI3> CMT3;
#endif

上記のように、テンプレートパラメータで「INT」(割り込みベクター型)を設ける事で、cmt_t クラスは、どの型のベクターなのかを意識しなくて済むようになっていて、「typedef」だけで対応できる。

cmt_io クラスでは、ベクターの型を元に、割り込み設定の方法を分ける事ができ、面倒な「#if文」から開放される。
また、C++ では、ベクター型の違いによる分岐は、コンパイル時に決定できるので、最適化により、余分の分岐一切が無くなるので、速度の面もリソースの面も好都合となる。
このような仕組みは、C言語だと、スマートに実現する事は難しい、C++ が組み込みマイコンのプログラムに向いた言語である事の一例であると思う。
※C言語プログラマは、#define で実現可能と思うかもしれないが、#define では、正確で厳密な「型」チェックは行われないし、構造的や論理的に誤ったコードをエラー無くコンパイルしてしまう可能性があり、テンプレートとは雲泥の差がある。

C++ のテンプレートでは、構造的や論理的に誤った構造は、「ほぼ」エラーになるので、最初の設計が必要十分な要素を詰め込んであれば、自ずと正しい方向に誘導してくれる感じがある。
大雑把に言うと、コンパイルエラーが無くなったら、プログラムも正しく動く事が多いとも言える。

自分が実装したソースでは、「#define」でマクロ的な定義を行う事は一切していない。

RXv3コア使用、RX66Tが発表された

RXv3 コアを内臓した初めての製品が発表された。
予想ではRX71Mの上位製品が最初だと思っていたが、モーター制御系の低価格版が最初のようだー。
RX66Tは、RXv3以外にも面白い特徴がある。
その一つは、高分解能PWMだろう、マスタークロックも160MHz動作が可能な上に、位相制御で、「最小195ps(ピコセカンド)でタイミング調整が可能」となっている点が新しい、位相制御は以前には、RX62Gで採用されたが、インバーターでは、必要な機能だろう、デジタルSWレギュレーターなどを実現するのに欲しい機能だ。

デバイスは、主に、RAMが128KBと64KBの製品があり(コードフラッシュは256K~1M)、多分、最初に出てくるのはRAMが64KBの製品と思う、また、USBも無しタイプが最初だろうと思う。
※コードフラッシュは256Kで十分だが、512K版との価格差は少ないものと思う。

現段階では、デバイスの販売はされていないものの、ハードウェアーマニュアルはダウンロード可能になっているので、早速、ダウンロードして、フレームワークに必要な実装を始めた。

構成は、RX63Tの後継らしいが、レジスターの構成は、RX64MやRX65Nに近いと思う。
RXマイコンのソフトウェアー資産は、今となっては沢山あるので、自分にとっては非常にメリットがある。
また、シリアルポートからのコードフラッシュプログラムも、プロトコルはRX24Tとほとんど同じ仕様と思うので、少しの追加でサポートできるだろう。

RX66TにはUSB内臓タイプがあるが、クロックレジスタの構成を考えると、USBを使う前提だと、最大周波数の160MHzでは動かせないと思う。
※USBで基準になる、24MHzの倍数で動かす必要があると思うので、156MHz動作になると思う(24MHz×6.5倍)。
RXv3コアは、RXv2コアに比べて、命令の効率が高いので、周波数が同じでもRXv2コアに比べてパフォーマンスが高いと思われる、どのくらい高いのか、早くデバイスを入手して試してみたい!
※多分、レイトレーサーを動かす事になると思う。

デバイスは、果たして、幾らで買えるのか?
RX24Tと同じく、10個購入程度で、それなりに安く買えるとありがたい・・
※上記ボードは、ルネサス純正ボードで、13200円(自分は高いのでスルー)

CPが最高に高いRX24T

100円マイコンのR8Cは別格としても、安くても十分機能があり、それでいてパフォーマンス(馬力)があるマイコンが必要な場合がある。
ルネサス社が発表しているマイコンで、どれが、コスト、パフォーマンス、機能が優れているか、検討してみた。
※実際は、かなり前に検討したものだが、未だにCPの高さトップに君臨している。

ちょっとした物を作る場合でも、昔には戻れない・・
※ファミコンやゲームボーイの時代はROMが高かったので、より多くのリソースを積み込む為、データ圧縮や、手動による最適化を行ったものだ、ハードウェアーがアップグレードして、記憶媒体がROMから、RAMになってCD-ROMなどの光学媒体になってから、もう容量の事で悩むような事は少なくなり、開発環境もアセンブラから高級言語に移っていった。
※PS2、EEのようにアセンブラでチューニングしなければ性能が出なかった例外的なハードもあるのだけど・・

今は、時代が違う、それでも、組み込みマイコンの場合、容量は有限だし、価格の安いデバイスはRAMも少ない、それゆえ、小さな工夫はしないとならない。
「数」を沢山作るような製品とは異なり、DIYでは機能を実現できれば、コストは度外視しても良いが、開発がやりやすいとか、リソースの再利用とか、便利で短時間で完成させる事が出来る方が良い。
C++ のテンプレートライブラリを多様したペリフェラルフレームワークは、Arduino のスケッチを書くより簡潔で判りやすく、最適化されたコードを作る事が出来る。

8/16ビットマイコンは、CPが高いと思うかもしれないが、実際はそうでは無い(ルネサス社のラインナップでは・・)、また、個人で数個単位で扱う場合と、大手が数百個、数千個、数万などスケールが異なる場合は、全く異なる価格帯になると思われるが、実際、数個のオーダーで個人が買う場合には、状況が異なる。
また、8/16ビットマイコンは、通常ポインターが16ビットで、大きな容量にアクセスする場合は、その都度、「方法」を選択してトリッキーなコードを実装しなければならない。
意外な盲点として、RXのような32ビットマイコンに比べて、同じプログラムでも、コードサイズが大きくなってしまうケースは良くある、又、内部レジスターは16ビットなので32ビットの演算では、さらに遅くなるので、場合により汎用のクラスは改修する必要もある。
32ビットマイコンは、プログラミングにおける基本的な制限はほぼ無いので、開発のしやすさや、リソースの再利用性から、少々コストが高くなっても選択したい理由となる、それでも@1000くらいだと、少し考えてしまう・・

マイコンの選択は、単純に、フラッシュの容量と内臓RAMサイズ、動作周波数などだが、マイコンの販売価格を見るに、非常にCPの高い製品がある事に気がつく。
※ARMやPIC32の価格には到底太刀打ち出来ないのだが、自分は、RXマイコンのソフトウェアー資産が豊富にあるので、ARMやPIC32よりも、RXマイコンを選択する事は十分メリットがある。
※まぁ、AVR、ARM、など各社マイコンは使った事もあるにはあるが、ルネサス社のマイコンだけにフォーカスしている人は少ないかもしれない。

RX24Tは、ブラシレスモーターのベクトル制御に特化した製品のようで、多分、エアコンや冷蔵庫などに使う目的でデザインされラインナップされた物と思う、イーサーネットやUSBは内臓していないが、他のペリフェラルが豊富で高機能なマイコンだ、そしてそれなりに安い。
※コード256K、RAM16K、データフラッシュ8K、LQFP100(10個購入時@594)
chip1stop「R5F524TAADFP#30」
※10個購入時だけど、DIY用でも10個くらいは使うだろって事で勘弁してほしい~
※RL78の256K版(@400)と比較しても、馬力を考えるとお得感がある。
※32MHzでFPU無しのRX220より安い。
※RXマイコンは、意外と命令効率が高いので、128KBの製品でも十分かもしれないが、価格差が僅かなので、256Kの製品リンクを張った。
※最近、Bバージョンが発売され、CANが使えて、RAM容量が2倍の32Kになった製品もある。(自動車向けか?)
#コード256K、RAM32K、データフラッシュ8K、LQFP100(10個購入時@657)
chip1stop「R5F524TBADFP#31」

  • RXv2コア
  • 80MHz動作(80MHz動作では、プログラムフラッシュにはウェイトが入る)
  • DSP命令(有効に使うには、アセンブラで実装する必要がある・・)
  • FPU(各種32ビットの浮動小数点命令)
  • ベクトルの正規化に威力を発揮するFSQRT(平方根)命令
  • 2.7V ~ 5.5V の単一電源動作
  • 普通に低消費電力
  • 12ビットA/D(最大1uS、3ユニット)
  • RSPI(1チャネル)※SDカードもかなり高速にアクセス可能
  • SCI(3チャネル、簡易SPI、I2Cが使える)
  • I2C(1チャネル)
  • DTC(データトランスファーコントローラー)
  • 高速で、豊富なタイマー郡(最大80MHz動作)
  • コンパレーター(4チャネル)
  • 必要十分なI/Oポート数
  • BバージョンのみCANインターフェースを備える
  • コードフラッシュの書き換え回数(1000回と少し少ない・・)

これだけの特異な特徴があり、他のRXマイコンと基本的にペリフェラルは共通。
ちょっとした用途ならこれで十分と思う、また、フラッシュROMの書き込みはシリアルで行うが(J-TAGはサポートしないが、エミュレーター専用端子FINEを持っているので、対応したE1でも当然書き込めるしデバッグもできる)、何故か、RX64Mなどと異なり、かなり高速に書き込めるので、シリアル書き込みでも開発ではあまり不自由しない。
※自分の開発スタイルでは、コードのブレークは必要としない。
※Apple、Linux、Windowsで開発出来る。
この価格帯にしては、浮動小数点がかなり強力なので、ジャイロや加速度センサーを使った姿勢制御(ロボットなど)にも、かなりマッチすると思う。
タイマーも非常に多く使えるので、RCサーボを沢山動かすのにも向いている。
多少残念なのは、コードフラッシュの書き換え回数が1000回と少し少ない。
それでも、ちょっとしたDIYボードに最適と思う。

おなじみ、レイトレーサーを走らせてみたが、約1.2秒くらいでレンダリングする。
これは、160MHz動作のESP32の10倍以上高速となっている、FPU内臓は伊達では無い。
※ピクセルの描画コストを5マイクロ秒としている。
※ESP32でのレイトレーサー速度は、ネットでの記事を参考にしており、RXマイコンに比べてあまりに遅い、ESP32はFPUを内臓しているので、ベンチマークの方法に問題があるかもしれず、単純に比較するのはフェアではないかもしれない事を付け加えておく。
200MHz動作のARMでは0.6秒との事なので、妥当なスピードと思う。

デバイスは以前に10個ほど買った(Aバージョン)ので、自分用にでも汎用ボードを作ろうと思っている。
又、折角のDSP命令も使わないのは勿体無いので、gcc 向けアセンブラ・ライブラリを実装しようと思っている、これはRXマイコン全般で使えると思う。

RX65N Envision Kit オーディオプレイヤー(その2)

picojpeg デコーダーのポーティングが出来たので、ID3 タグ内のジャケット画像などを格納するタグ「APIC、PIC」内データ(JPEG)をデコードして画像表示は出来たのだが、画面サイズにフィットさせるのは後回しになっていた。

まず、仕組みを考える・・

画面デザインから、画面の右端に272×272ピクセル(液晶の縦ピクセル)で表示させるのが良さそうだ。
ただ、タグ内の画像サイズは様々なので、適切にスケーリングする必要がある。
スケーリングの方法も重要だ、RX65Nの内蔵メモリはあまり大きく無いので、画像のような大きなデータを扱う場合、出来れば、一時メモリを使用しない(利用できない)方が良い。

それらを踏まえて、画像のデコーダーテンプレートは、直接画像の操作を扱うAPIを叩かないで、中間に「スケーリング」を行うオブジェクト(クラス)を入れる事にした、こうしておけば、レンダリングを行う対象がどんな場合にも対応可能となる。

    typedef graphics::render<uint16_t, LCD_X, LCD_Y, AFONT, KFONT> RENDER;
    RENDER      render_(reinterpret_cast<uint16_t*>(0x00000000), kfont_);
    typedef img::scaling<RENDER> PLOT;
    PLOT        plot_(render_);
    typedef img::picojpeg_in<PLOT> JPEG_IN;
    JPEG_IN     jpeg_(plot_);

C++ では、「ファンクタ」と呼ばれる方法(通常「()」オペレーターを使う)で、クラスに対しての操作を一般化できる。

//-----------------------------------------------------------------//
/*!
    @brief  描画ファンクタ
    @param[in]  x   X 座標
    @param[in]  y   Y 座標
    @param[in]  r   R カラー
    @param[in]  g   G カラー
    @param[in]  b   B カラー
 */
//-----------------------------------------------------------------//
void operator() (int16_t x, int16_t y, uint8_t r, uint8_t g, uint8_t b) noexcept
{
・・・
}
まず、plot_ クラスに対して、スケールを設定する。
※スケールは、「整数比」で設定する。
※画像全体を収める為、縦か横で長い方を基準にする。

    auto n = std::max(ifo.width, ifo.height);
    plot_.set_scale(272, n);

jpeg_ クラス内から、plot_ クラスに対して、以下のように普通に描画すれば、設定された拡大、縮小比で描画される。
※ワークメモリを使わないのと引き換えに、描画する領域は、あらかじめ「0」クリアしておく必要がある。

    plot_(x, y, r, g, b);

また、描画時にオフセットを与えられるようにしてある。

    plot_.set_offset(vtx::spos(480 - 272, 0));

最初、縮小をさせる場合に、エイリアシングを考慮しない簡易的な実装を行ってみたのだが、当然のように描画品質はあまり良くない。
※ジャギジャギしてる・・

そこで、ピクセルの加重割合を考えずに平均化してみる事にした。
・フレームバッファはRGB565となっている。
・フレームバッファを読み出して、「0x0000」なら、初期に書き込むピクセルとして、そのまま書き込む。
・もし、新規に書き込むピクセルが「0x0000」なら、「0x0001」に直して書き込む。
・フレームバッファを読み出して、「0x0000」以外なら、既に書き込まれている値なので、新規に書き込む値との平均(1/2)を求めて書き込む。

この実装は、厳密な意味では正確ではないものの、「ジャギー」感が減り、かなりマシに見える。
とりあえず、これで良しとした、ピクセルサイズによる厳密な加重平均や、フィルタ的要素は、次の課題とする。

※現状では、「拡大」する場合は、簡易的なものになっていて「ジャギー」が目立つ。