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

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

LAN8720A モジュールの試用

FreeRTOS でネットワーク関係を実験したくて、中華製のLAN8720 モジュールを試してみた。

モジュールは、アマゾンで購入した。

本当は、RX65N Envition kit で未実装のPHYチップやトランスなどを実装して、実験するつもりで部品を買っていたが、QFNパッケージのハンダ付けが難しく(1個失敗した)、また、本体を壊してしまうのではと思い、工具も無いので、ストールしていた。

LAN8720A はマイクロチップの 10/100 イーサネット PHY で、安価で入手しやすく、比較的良く使われているデバイスだ。
※GR-KAEDE にも使われている。

QFNパッケージで、裏が全面 GND、DIY ではユニバーサル基板で製作しにくい。
※QFN のユニバーサル基板が割高で入手しにくいのも要因

モジュールは安く送料も無料だが、船便なので、注文してから10日程かかる、基板が届いて早速開封、ネットで回路などを探す。
「LAN8720 ETH Board」

このモジュールは、50MHz の OSC が乗っていて、一般的な25MHz クリスタルとは異なっている。

LAN8720Aは、リセット時のピン状態を読み込んで、基本的な設定を自動で行う「Configuration Straps」と呼ばれる機能がある。

50MHz 外部クロックを使う場合、「LED2/nINTSEL(2)」をオープンかプルアップしておく必要がある。
※ボードはLEDが接続されており「オープン状態なので」50MHz外部クロックモードになっていると思われる。
同時に LED のドライブはアクティブ LOW となる。(吸い込み)

最初に試すソフトは、以前に実験した、ルネサスの T4 ライブラリなので、GR-KAEDE などと同等にしておく必要がある。

RX マイコンの仕様なのかもしれないが、PHY デバイスとの通信で使う「MDC、MDIO」は参考回路ではプルアップしてあるので、同じようにプルアップしておく。
※以前に、プルアップが無い場合にPHY通信が失敗した事があった。
※回路図を見ると、MDIOはプルアップしてあるので、MDCのみ適当な抵抗(3.9K)でプルアップしておいた。

このボードで、問題なのは、RX_ER 端子がプルアップされて、外部コネクタに出ていない。
また、この端子は、「 Configuration Straps 」における、PHYアドレスを設定するピンでもある、チップ抵抗を外して、直接ラインを接続した。
※ボードは、写真のように、ピンヘッダーを外して、直接ボードに取りつけてある。
※このような組み方を良くする、やってみると簡単で確実。

RX_ER 端子を直接接続

今回実験に使ったRXマイコンは、RX71Mで、169ピンタイプ。

イーサーネットは、チャネル0を使った。
各ピンの接続は以下のようになっている。
RX71M: P83/RMMI0_CRS_DV(74) —> CRS_DV(7)
RX71M: P82/RMMI0_TXD1(79) —> TXD1(14)
RX71M: P81/RMMI0_TXD0(80) —> TXD0(11)
RX71M: P80/RMMI0_TXD_EN(81) —> TXD_EN(12)
RX71M: P77/RMMI0_RX_ER(84) —> LAN8720 (10) 直接続
RX71M: P76/REF50CK0(85) —> RX_CLK(8)
RX71M: P75/RMMI0_RXD0(87) —> RXD0(10)
RX71M: P71/RMMI0_RXD1(88) —> RXD1(9)
RX71M: P72/ET0_MDC(101) —> MDC(5)
RX71M: P71/ET0_MDIO(102) —> MDIO(6)
RX71M: Vcc(3.3V) —> VCC(1, 2)
RX71M: Vss(GND) —> GND(3, 4)

接続の様子:

Start RX71M http sample
Link no proccess (0)
Link no proccess (1)
Link no proccess (2)
Link no proccess (3)
Link no proccess (4)
Get DHCP: 192.168.0.4

RXマイコン、FreeRTOS、FatFs でオーディオ再生

前回、マルチスレッドとは言え、シンプルな物で、動作検証を行った。

そこで、今回はもう少し複雑となる、MP3、WAV、のコーデックを動かして、実用的な実験を行った。

詳細は「RXマイコン、FreeRTOS、FatFs、で MP3、WAV の再生」に投稿した。

プログラムは、
・自作 RX64M
・GR-KAEDE
・RX65N Envition kit
などで行った。

FreeRTOS は使える~

元は、シングルタスク用に作ったもので、それを別タスクで動かし、コーデックのデコードをやっている。

タスク間は、ファイル名の受け渡しを行っている。

音楽再生中に、SDカードのディレクトリーを取るなど、平行動作させても、音楽の再生は途切れずに鳴り続ける。

FreeRTOS で FatFs を使う

FatFs 0.13c には、スレッドセーフで動かす為の機能が用意されている。

そこで、FreeRTOS で異なるタスクから、ファイル操作を行う実験を行い、その設定などをまとめ Qiita に投稿した。

RXマイコンを使って、FatFs を FreeRTOS で運用する

GR-KAEDE(RX64M)、自作のRX64Mボード、RX65N Envition Kit などで動作を確認した。
※RX66T、RX71M でも動作するだろうが、SDカードのインターフェースを付けていないので確認できない・・

RX24Tではメモリが少なく、動作を確認出来なかった・・

RX24Tは、RAMが16Kしか無いので、タスク別にスタックを確保する必要があるので、どうしても無理があるのかもしれない。
多分、32Kあれば、動くと思える。

FreeRTOS で FatFs を使う場合、現在のバージョンでは、多少、FatFs のソースコードを修正する必要がある。

FatFs をバージョンアップ

FreeRTOS を本格的に運用する目処がたったので、まず、FatFs を最新版にした。

以前は、「ff12b」を使っていた。

今回「ff13c」に移行した。

意外と大きく変更になっている。

・ファイル名やパスが整理された。
・ヘッダー定義名やマクロ名などが、吟味され、より良くなった。
※マクロ名など、他のシステムと「当たらない」ように修正されたようだ。
・ファイルパスの文字コードがより洗練されて扱いやすくなった。
※ファイルのパスコードで、以前は、CP932 か、UTF-16 しか選べなかったが、UTF-8 も使えるようになった。
・排他制御用をやりやすいように変更があったようだ。
※lock、unlock などの関数コールが追加され、FreeRTOSと親和性が高い。
・一部、API が廃止になり、新しい API になった。
※日本だけなら、コードページ932だけで良いが、世界中で使っているので、その辺りを柔軟に改良したようだ。

などなど、細かく色々修正されている。

えるむ/ChaN さんのこのプロジェクトは世界中の人が使っている。
本当に素晴らしく、高機能なもので、今でも、少しづつ改良されているのには驚くばかりで、本当に頭が下がる。

FreeRTOS のような RTOS では、複数のタスクから、ファイル操作が出来ないとならないので、ドライバーの出来は、性能に直接影響するので、現在のソフト転送は改良する必要性がある。

ただ、難しい部分でもあり、性能を上げるのは簡単ではなさそうだ・・・

—–

とりあえず、github の FatFs を使っているアプリを全て修正し、master ブランチにマージしてある。

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のソースをコピーして、それを自分の要求する見た目に合わせて改造すれば良いだろうと思う。

  • フレーム
  • グループ
  • ボタン
  • チェックボックス
  • ラジオボタン
  • スライダー

全ての部品は、親子関係を持つ事が出来る。(構造的には、親の部品を知っている)
※親が全ての子供を知っている方が良い場合が多いのだが、構造が複雑になってしまう。
もし、全ての子供を知りたい場合、管理リストをスキャンして子供のリストを作るしか無い。

また、親子関係を利用する事で、相対的な部品位置で管理できたり、部品をグループ化して、全体を制御したり出来る。

「ラジオボタン」は、自分の変化により他の部品の状態を変える必要があるので、グループ化しておき、親を指定しておく。
その中のボタンで変化が起きた場合、親が同一のリストを作成して、他のボタンの状態を自動で変更する。

「スライダー」は、縦、横のサイズにより、水平か垂直か判断して対応する。
通常、部品からフォーカスが外れると、部品のハンドリングが終了してしまう、しかしその仕様だと、スライダーのような部品では、操作性が悪い(スライダーの領域は通常狭いのと、フォーカスしたままスライドするのが困難)なので、小細工として、スライダーの場合は、初期に領域内でタッチされた時にフォーカスを有効にして、タッチが外れるまでホールドする事で、操作性を改善している。

RX65N envision kit
// 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」にある。