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

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

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)

Visual Studio Code を使う為の設定

自分は、マルチプラットホームにこだわりがあり、色々な異なった環境でも同じような操作性を提供できる事に注目している。

Visual Studio Code は、マイクロソフトのオープンソースによるもので、アプリケーションとしてはテキストエディターだが、単なる文書を書くだけではない、色々な拡張機能を追加でき、カスタマイズ出来る点で大きな広がりがある。
拡張機能は、emacs が先人でもあるが、emacs がスタートした時代は古く、VSC は最近の「流行」を取り入れて斬新な物になっている、emacs を現代風に作り直したアプリケーションとも言えると思う。
※emacs は Lisp だが、VSCは Json なので、より多くの人に受け入れやすい。

「創作活動のほとんどは、文書を作る動作が起点になっている。」と言う事実に改めて気がつく。

既に多くの人が、VSC を利用した拡張機能をリリースしており、自分で新規に作らなくても、インストールして利用する事が出来る。
また、VSC の設定方法や Tips など豊富にある、ただ、目的の機能を実現する方法は複数(無限)あり、VSC のバージョンとも関連するので、シンプルな方法を選んで取り込む必要がある。

自分が VSC で感激した点:
・拡張機能が豊富で、検索してインストールする事がコンビニエンス。
・Git と連携していて、git で行う操作を標準で色々行える、git 用フロントエンドアプリを使うより強力で判りやすく便利かもしれない。
・Markdown 形式を標準でサポートしており、プレビューしながら記述出来る。
※拡張機能を入れると PDF 化する事も出来る。
・Terminal 機能があり、MSYS2 の bash などを呼び出して使う事が出来る。
・C++ では非常に有能なインテリセンスが使える。
※インクルードパスの設定が重要
・プラットホーム毎の「固有」設定が出来る。
・比較的軽い。

それでも、小躍りする前に事前の調査が重要、「道具」類は、良さそうと思って使ってみても、細かいとこで気に入らない事も多い。
少し使ってみて、「何だコレ!」って思った事もあったけど、やはり「短所」より「長所」が勝っており、将来性を考えたら、コレを使わない理由が無い事に気がつく。

今まで emacs を中心に使ってきた、ただ、積極的に Lisp を使う気になれなくて、ほぼコードを書くだけで使っていた。
※知り合いは、自分で Lisp を書いて、自分の欲しい環境を色々実装している。
それを横目で観ていて、自分もやってみたいと思っていたが、もう少しハードルを下げた方法は無いのかとも思っていた。

最近の VSC では、「ワークスペース」と言う概念を使う事ができる点で、異なった環境を柔軟に切り替える事が出来る。
※以前は、フォルダーのルートを指定するシンプルな物だったが、それを少し拡張して、複数フォルダーに関連するファイル郡を一括して扱う事が出来るようになった。
「ワークスペース」では、設定が書かれた専用ファイルを開く事から始めるので、固有の設定を取り込む事が出来る。

まずインストール。
MSYS2 は現状でも、ツールの中心なので、インストールする、詳しい方法は、https://github.com/hirakuni45/RX を参照の事。
※MSYS2 は MinGW とは異なったアプリケーションなので、必ずMSYS2 を使うように。

・Terminal で MSYS2 の bash が起動出来るようにする設定、「settings.json」を編集して、以下のように追加しておく。
※「settings.json」の直接編集の正しい方法は「ぐぐって」もらうとして、自分の場合は、
「設定」などで、「settings.json で編集」などのリンクがあるので、それをクリックして編集している。
※キーワードを入れると候補が表示されるので判りやすい。

{
    "git.ignoreLegacyWarning": true,
    "git.autoRepositoryDetection": "subFolders",
    "C_Cpp.default.cppStandard": "c++14",
    "C_Cpp.default.cStandard": "c99",
    "files.autoSave": "afterDelay",
    "C_Cpp.default.intelliSenseMode": "gcc-x64",
    "C_Cpp.intelliSenseEngineFallback": "Disabled",
    // MSYS2 bash のパスと、起動設定
    "terminal.integrated.shell.windows": "C:\\msys64\\usr\\bin\\bash.exe",
    "terminal.integrated.env.windows": {
        "MSYSTEM": "MINGW64",
        "CHERE_INVOKING": "1"
    },
    "terminal.integrated.shellArgs.windows": [
        "--login"
    ],
    "terminal.integrated.cursorStyle": "line",
    "editor.renderWhitespace": "all"
}

※必要な部分のみコピーする場合は、「,」に注意

・拡張機能を入れよう~
※「拡張機能」ボタンを押して、検索ボックスでキーワードを入れれば、候補がリストされ、簡単にインストール出来る。

(1) C/C++ (Microsoft)
※自分は、マイクロソフトの物を入れているが、検索すると複数の物が見つかるので、自分の嗜好に合った物を使えば良いだろう。
※現段階で、gcc などでインテリセンスを機能させる設定が判っていない。

(2) Emacs Friendly Keymap
※とりあえず、キーバインドを Emacs 風にしている、vi や他のエディター用もあるし、自分でキーバインドを設定する事も出来る。
※VSCでは、「ESC」キーは別の意味で使われており、一般的な Emacs のメタキーとして利用するには反故が多いようだ。
なので、「M-v」は「ALT+v」として機能する、今まで「ESC」を使ってきたが、矯正する必要がありそうだ・・・
まぁ確かに、ESC を押してから v を押すより、ALT+v の方が利便性が高い。

(3) Japanese Language Pack for VS Code (Microsoft)
英語のメニューでも、そんなに困らないが、日本語の対応は流石に本家だけあって良く出来ている


最後はインテリセンスの設定だが、MSYS2 上の gcc g++、clang などで運用するには、もう少し調査が必要だと思う。

思いつくインクルードパスを設定しても、思ったように、インテリセンスが機能しない・・・

色々調べたが、何故思ったように機能しないかも不明で、WEBにある「こうすればおけー」と言った情報を見て、そのように設定してみたが、やはり駄目・・

何か特殊な設定をするのか、別の拡張機能を入れるのか、謎である・・・

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

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

RX65N Envision Kit はまぁ良いのだが、惜しい部分がある。
・バッテリーバックアップがない
・RTCのクリスタルが接続されていない
・付属LCD(480×272)の視野角が狭く、表示品質がイマイチ
・無線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では買う機会は無いのだが、この工具ならそれに匹敵する、すばらしい!