「ソフトウェアー・エンジニアリング」カテゴリーアーカイブ

ソフトウェアー関係の話題など・・

最近は、github にプッシュしてます~

RXマイコンの開発環境 gcc のビルドと不具合

現在カレントとして使っている gcc は「4.9.4」最新の gcc は「7.3.0」まで
進んでいる。
gcc は超巨大なプロジェクトなので、不具合も結構あるようで、ある特定の場合に正しく
動作しないなど、依存関係など色々な問題がある。
※時間が経つと、マイナーバージョンアップで解決されたりする。
※gcc とは分離されているツール binutils など、相性も関連している場合もある為、新
しい gcc を運用する場合、組み合わせも配慮する必要がある。
また、クロスコンパイラをビルドする gcc のバージョンも以前の環境とは異なっている
と思われる。
※過去のソースをビルドする場合、最新のMSYS2環境では、同じものがビルド出来な
い状況になっている場合も考えられる。
「4.9.4」で特に不具合は無いのだが、C++ の場合、新しいコンパイラでは、最適化がより
良くなっている場合もあるので、なるべくなら新しいバージョンを使いたいと思ったりも
する。
※C++17 に移行したい、最新の C++ コンパイラを使いたい。

以前に、6.2.0を別のPCでビルドして、RXプロジェクトをコンパイルしたら、
r_net_T4(ルネサスが提供する、ネット・スタック)を使ったプロジェクトが動作しない
(原因は調べて無いので不明)という現象が発生した。
※RXのプログラムは通常通り起動するが、PC側からRXマイコンに接続が出来ない状
態(ping など不通になる)、DHCP クライアントは動作していて、DHCP アドレスを取得
している・・・

奇妙なのは、自宅のマシンでビルドした「6.2.0」では、問題なく動作するバイナリ
ーが出来る。
この違いは「何だろうか」と考えた結果、binutils、newlib のバージョンが、自宅マシン
でビルドした時と、違う(新しいバージョンを使った)点に気がついた。

そこで、要因を見極めるべく、色々な組み合わせでビルドを行い試してみた。
※非常に時間がかかり、操作を間違うと台無しになるので慎重に作業する必要がある。

※必ず MSYS2 環境で作業を行う。

binutils-2.27
gcc-4.9.4
newlib-2.2.0

割と最近の MSYS2 環境を使い、この組み合わせで、動作するバイナリーが出来た。
※2018年3月くらい

とりあえず、これを安定版としておいて問題無いだろうと思う。
※ 4.9.4 なら、C++14 がとりあえず使えるし、最適化もそこそこ良いと思う。

gcc をビルドする場合、その gcc がリリースされたタイムスタンプを考慮して、それ
より少しだけ古い判の binutils、newlib を使うようにすれば問題無いようだ、つまり、
binutils や newlib だけ、最新の物を組み合わせると問題が起きる場合が多いと思われる。

次に5系の最終版である 5.5.0 をビルドしてみる。
この時、binutils、newlib のバージョンは変更しない。

binutils-2.27
gcc-5.5.0
newlib-2.2.0

これも、問題無い、正常動作するバイナリーが出来た。

次に、newlib だけ newlib-2.4.0 に上げてみる。

binutils-2.27
gcc-5.5.0
newlib-2.4.0

これも、問題なし。

じゃぁ今度は、gcc-6.4.0 で、他は同じでビルド。

binutils-2.27
gcc-6.4.0
newlib-2.4.0

これも正常!

binutils-2.28
gcc-6.4.0
newlib-2.4.0

大丈夫だ、問題無い!

binutils-2.30
gcc-6.4.0
newlib-2.4.0

これも問題無し!、とゆー事は、newlib のバージョンで何か起こるとゆー事か・・・

今回は、とりあえず割と新しい gcc を使える事が判ったので、ここまでにしたい。
また時間に余裕が出来たら、調査を続けたい。


この組み合わせはNG・・・

binutils-2.30
gcc-6.4.0
newlib-3.0.0

RTK5RX65Nにシリアル通信など追加

仕事が重なって、凄く忙しく、なかなか趣味のマイコン関係が進まない・・・

「RTK5RX65N」のLCD関係を進めているのだが、ドライバーテンプレートを
自分で作りたいので、デバッグ環境を何とかしたい、このボードには、「PMOD」と
呼ばれる汎用インターフェースがついていて、コネクタも最初から付いている、このコ
ネクタには、SCI9がアサインされているようなので、とりあえず、これでデバッグ
用のシリアル通信を繋げてみた。
最初は、USB経由のシリアル通信で行う事を考えたが、フラッシュの書き換えなどに
USBポートを優先したいのと、切り替えが面倒なので、あえて、別のポートを使った。

俺俺テンプレートドライバーでは、非常に簡潔にインターフェースを定義できるように
工夫してある。
ポートのマッピング、消費電力制御、割り込みなど、雑多な制御は、全てコンパイル時
に行う事が出来るようにしてあり、ポートのマッピングを別の経路に変更したい場合で
も可能なような仕組みを用意してある。
テンプレートの良い所は、内部で、プログラムによって、切り替えをしていないので、
その切り替え等によって生じるオーバーヘッドや余分なメモリを消費せず、最適化され
た状態になる点で、基本的に「#define」を使っていない(プロセッサシリーズの切り替
えでは使っている)ので、プログラムも読みやすくシンプルになっている。

    typedef utils::fixed_fifo<char, 512>  RECV_BUFF;
    typedef utils::fixed_fifo<char, 1024> SEND_BUFF;
    typedef device::sci_io<device::SCI9, RECV_BUFF, SEND_BUFF> SCI;
    SCI     sci_;

SCIの起動は、割り込みレベルと、ボーレートだけでOK!
※現在は、8ビット、1ストップビット固定になっているが、変える必要性を感じない。

    {  // SCI 設定
        static const uint8_t sci_level = 2;
        sci_.start(115200, sci_level);
    }

また、C言語の関数、「printf」が使えるように(C++では使わないが・・)stdio
経由の出力が可能な仕組みを用意してある。
printf では、POSIX の「write」関数に対して、文字列を出力する、この際のディスク
リプタ「stdout」は、通常固定になっているので、「syscalls.c」で実装してある、
「write」関数で、SCI の文字出力に繋げておけばOKとなる。
※「C」の関数から呼ぶ為、「extern "C"」にしてある。

extern "C" {

    void sci_putch(char ch)
    {
        sci_.putch(ch);
    }

    void sci_puts(const char* str)
    {
        sci_.puts(str);
    }

    char sci_getch(void)
    {
        return sci_.getch();
    }

    uint16_t sci_length()
    {
        return sci_.recv_length();
    }
}

※C++の「iostream」も使えるけど、このライブラリをインクルードすると、とてつも
なく多くのメモリを食うので、「common/format.hpp」を用意してあり、このテンプレート
クラスで、「boost::format.hpp」と同等な操作が出来る、このテンプレートは、他に依存
しないように利便性を追求してあり、IEEE754 浮動小数点フォーマットのバイナリーを
デコードできるよう独自の実装を行っている。
※安易に「sprintf」を呼ぶような事をしていない。

gcc 「__attribute__((weak));」は、外部で定義されていれば、その関数を呼ぶが、定義
が無い場合、そのソースに置かれた関数を呼ぶ仕組みで、POSIX 関係の関数を外部で定義
してオーバーライトする事が出来るようになっている、「syscalls.c」にも同様な仕組み
を用意してあり、シリアルの入出力と標準入出力を繋げる仕組みに使っている。

void sci_putch(char ch) __attribute__((weak));
void sci_putch(char ch) { }
char sci_getch(void) __attribute__((weak));
char sci_getch(void) { return 0; }

今回はここまでー、次は頑張ってLCDを動かす・・・

RTK5RX65Nの最初の一歩

溜まった仕事が、ひと段落したので、少しだけ、RX65N搭載のキットを触ってみた。

このボードの良いところは、前回説明したので、とりあえず、俺俺 C++ フレームワーク
を使って、簡単な動作検証と、開発環境を試してみた。

まず、ボード上には、「E2 Lite」が内蔵されている為、プログラムを転送するのに不便
は無い、ボード上のDIP-SWを切り替える事で、「E2 Lite」を有効にして、ルネサ
スのフラッシュプログラマーで書き込み等が出来る。

とりあえず、上記写真のように「SW1-1」を「ON」にして、USBを接続すると、
「Renesas Flash Programmer」から認識でき、接続する事が出来る。
・「新しいプロジェクトの作成」を選ぶ
・「プロジェクト名、作成場所」などを設定する
・「ツール」で「E2 Lite」を選ぶ
・「接続」ボタンを押すと、「RTK5RX65N」に接続する事が出来る。

一応、出荷時に書き込まれているデモプログラムを読み出して、保存しておく。

次に、LED点滅プログラムを実装してみる。

#include "common/renesas.hpp"

namespace {
    typedef device::system_io<12000000> SYSTEM_IO;
    typedef device::PORT<device::port7, device::bitpos::b0> LED;
}

int main(int argc, char** argv);

int main(int argc, char** argv)
{
    SYSTEM_IO::setup_system_clock();

    LED::DIR = 1;
    while(1) {
        utils::delay::milli_second(250);
        LED::P = 0;
        utils::delay::milli_second(250);
        LED::P = 1;
    }
}

※上記プログラムは「hirakuni45」の RX マイコン用 C++ フレームワーク上で、gcc 環境で
コンパイル出来る。
※開発環境の構築や、その他の情報は、GitHub RX に詳細な説明があるので参考にしていただきたい。
※RTK5_first_sample

RX65Nは、120MHz動作可能ではあるが、RX64Mなどのように、120MHzで
はフルスピードで動作しないようで、メモリーウェイトを入れる必要があるようだ。
ただ、ウェイトを入れた状態でも、おおよそ、10%減の速度では動作しているようなので、
実用上は問題無いと思える。
※「system_io」クラスは、工事中ではあるが、12MHzのクリスタル、120MHzの速度
で使う場合は問題無い。
※RX65N用にコンパイルすると、自動でメモリーウェイトを入れるようになっている。
※LEDは、ポート7のビット0にある。

RX関係のコードを github からチェックアウトしたら、「RTK5_firest_sample」へ移動して、

make

とすれば、実行ファイル(.mot)が出来るので、「Renesas Flash Programmer」を使って、転送
すれば、動作する。
※転送後、リセットを自動で解除するには、「接続設定」、「ツール詳細」、「モード端子設定」
で、「切断時のモード端子」で、「リセット端子をHighレベル」を選択しておく必要がある。

今回はここまで、次回はいよいよLCDの設定や描画を実験してみたい。

RL78、gccリンカースクリプトの改造

今年の初めから、大幅に遅延していたプロジェクトに係りきりになり、凄く忙しく、
立川から、兵庫の三田(さんだ)に毎週のように通い、最近ようやく、見通しがつき、
他の作業もようやく進みだした。

その中で、RL78を使った機器のプログラムを実装していたのだけど、その過程で
リンカースクリプトを改造していたので、覚書程度に紹介しておく。

RL78は、非常に沢山の種類があるのだけど、1つのグループでも、リソースが異
なるデバイスが沢山ある。
プログラム・フラッシュ・メモリーの容量が、異なるのは良くあるのだが、データ・
フラッシュの容量も色々ある。
以前は、Makefile から、容量を与えていたが、デバイス固有のリンカースクリプトに
記述した方がシンプルでスッキリするなぁーと思っていた。
ただ、リンカースクリプトは、イマイチ、記述方法が判らない部分もあり、敬遠してい
たのだが、色々実験して、ようやく方法を理解した。

多分、他に、より良い方法があるのかもしれないが、とりあえず、以下の方法で解決し
た。
まず、「メモリー」で、データフラッシュの領域を記述する。

MEMORY {
    VEC (r)   : ORIGIN = 0x00000, LENGTH = 0x00002
    IVEC (r)  : ORIGIN = 0x00004, LENGTH = 0x0007C
    OPT (r)   : ORIGIN = 0x000C0, LENGTH = 0x00004
    SEC_ID (r): ORIGIN = 0x000C4, LENGTH = 0x0000A
    ROM (r)   : ORIGIN = 0x000D8, LENGTH = 0x0FF28
    RAM (w)   : ORIGIN = 0xFDF00, LENGTH = 0x01F20
    DATAF (W) : ORIGIN = 0xF1000, LENGTH = 0x02000
    STACK (w) : ORIGIN = 0xFFE20, LENGTH = 0x00002
}

※「DATAF」が、データフラッシュの、アドレスと領域の設定。

続いて、rdata セクション内に、データフラッシュのサイズを置いて、アクセスできるよ
うに、シンボルを宣言しておく。

    PROVIDE (__dataflashsize = .);
    SHORT(LENGTH(DATAF));

これだけだ・・
新しいのは、「LENGTH()」で、「DATAF」の「LENGTH」を参照している。
領域は、「uint16_t」サイズで置いてある。
※「uint32_t」サイズで欲しい場合は、「LONG()」を使う。

「C、C++」からは、

extern const uint16_t _dataflashsize;


で参照できる。
ただ、リンクしないと参照出来ないので、コンパイル時には参照はできない変数となって
いるので、プログラム起動後に参照するような構成にしなければならない。

「RX65N Envision Kit」の紹介

Arduino や ARM には、よそ見をしないで、ルネサス製マイコンのみを扱ってきたが、
最近、ようやく、面白そうなガジェットが出てきたー

ARM界隈では、コスト度外視、メーカーでなければ出来ないような評価ボードを色々
出していて、そんなのが出る度に、ARMerたちがそこに注力するとゆー構図があった。

自分は日本人なので、「日本製マイコン使え!」と言ってはいたが、中々胸を張って、
「これはイイですよと言えない」状況が続いていた。

そんな折、マルツさんのメールニュースで、「Renesas Synergy Target Board Kit」
のアナウンスがあり、ARMベースのルネサスマイコンで、興味は無いのだけど、
リンクを観に行った。
そこで、見つけてしまい、思わず購入してした。
※自分の好きなRXマイコン、120MHz動作、液晶付、など目一杯盛り込んでいて
5000円!、しかも、何かガジェットを作った場合に、コンパクトにまとめられる
ように配慮された基板サイズ。

このボード2017年11月頃に発表されていたボードのようだが、丁度仕事が忙しく
情報を漏らしていた。

このボード、海外のソフトウェアーベンダーが音頭を取り、製作したようだが、この価格
でこの内容は、コストパフォーマンスが良すぎる。
しかも、インサーネットやSDカードを後から付けられるようにもなっているし、かなり
練られた設計となっていて好感が持てる。

ボードの特徴など気がついた部分を列挙する。
・RX65Nマイコン120MHz動作
・2MBの内臓フラッシュ
・256KB+320KBのRAM
※このメモリー空間は別なので、液晶のフレームバッファで、320KBは利用不可と思う。
・インサーネット対応「N」バージョン
※物理層PHYは乗っていないが、後から乗せられるようにパターンがある!
※25MHzのクリスタルは乗っているので、PHY(LAN8720A)、パルストランス
付コネクタ(表面実装タイプ)を取り付けるだけと思う。
・エミュレーター(簡易バージョン)内蔵なので、フラッシュの書き換えや開発が容易。
・480×272ピクセル、タッチ機能付液晶付
・RX65N内に、液晶の制御と、描画エンジンなど内臓(パフォーマンスは現在不明)
・拡張コネクターや、未使用端子の取り出しランドなど多数。
・SDカード接続用パターン有り
・マイコン用3.3V電源用に、同期整流式のDC/DCコンバーター
※5Vから降圧で動作し、効率が高い(安易なシリーズレギュレーターでは無いのが凄い!)
※液晶用バックライトもDC/DCコンバーターを内臓
・USBコネクター装備(RXマイコン用と、エミュレーター用)
・モード切替用、DIPスイッチ4ビット分(1ビットはユーザー利用可能)

今は、仕事が忙しいのだが、これをベースに色々な物を作りたいと思う。

AD9833(周波数シンセサイザ)のテスト

マイコンでA/Dコンバーターを使った、ストレージオシロぽぃ物を作る過程で、
機能検査を行う必要があり、手頃な信号発生器を探していた。

最近は良いデバイスがあるもので、ワンチップで、最大12.5MHzまで出力
可能なDDSモジュールが安く売られていたので、早速注文した。

※基準発信器付きで小さいモジュールとなっている。
※中華、船便なので、それなりの時間がかかるが格安。

早速、AD9833のライブラリをネットから取得して、自前のシステムに合うよ
うに、テンプレートクラスとして整形し直した。

このデバイスは、SPI通信で内部設定を行うので、マイコンで制御する必要があ
る。
そこで、とりあえずR8C/M120ANを使ってテストしてみた。
※このIC、3.3Vでも5VでもOKのようだが、とりあえず3.3Vで動作確
認。(モジュールに付いてるOSCはArduino系が主なので5Vと思えるが、
ちょっと調べた限りでは、どの電圧で動作するのか記述が見つからない・・)

サンプルは1KHzのサイン波を出力している。(起動するとデフォで1KHzの
をサイン波を出力する)

実用的に使うには、出力にアンプを追加したり、レンジ切り替え、周波数切り替え、
高性能なエイリアシング除去フィルターなど工夫が必要だと思うが、とりあえず、
機能を実験するだけのシンプルな構造になっている。

ソースコードは AD9833 Sample に上げてある。
※AD9833.hpp テンプレートは chip ディレクトリーにある。
※このデバイステンプレートは、他のマイコンでも修正無しで使えるはずだ。

-----
シリアルポートと57600(8ビット、1ストップ)で接続する事で、対話形式
で、周波数、波形の変更ができるようにした。

freq 2000     ---> 2000Hz
form tri      ---> 三角波
help          ---> ヘルプ

MSYS2/mingw64 で boost/asio を使う場合の要点

MSYS2 では、BSD ソケットの API を使う場合は、msys2 環境で行う必要があり、
mingw32/64 環境では、windows 依存の WinSock2 などを使う必要がある。
※WinSock は、BSD ソケットに似ているが、完全に同じではなく、BSD ソケット
用に書かれたソースコードをそのままコンパイルする事は出来ない。

そこで、今後の互換性(マルチプラットホーム)や、発展性を考えて、boost/asio
を使う事にした。
mingw32/64 では、boost の環境依存ライブラリーをパッケージマネージャーで簡
単に導入できるので、コンパイルする必要も無い。
多くのサンプルが、VC環境の場合が多く、MSYS2 環境で、gcc や clang での利
用方法が少ないので、覚書程度に要点をまとめてみた。

まず、boost をインストールする。
現在は、

 % pacman -Ss boost
mingw32/mingw-w64-i686-boost 1.63.0-1
    Free peer-reviewed portable C++ source libraries (mingw-w64)
mingw64/mingw-w64-x86_64-boost 1.63.0-1 [インストール済み]
    Free peer-reviewed portable C++ source libraries (mingw-w64)

「1.63.0-1」がカレントのようだ。

※インストールする場合

 pacman -S mingw-w64-x86_64-boost

-----
サーバー、クライアントのサンプルは、TCP - boostjpが判りやすい。

コンパイルの際に注意する点として:

-DWIN32 -DBOOST_USE_WINDOWS_H -DWIN32_LEAN_AND_MEAN

を定義しておく必要があるようだ。

また、リンク時のライブラリーは、

boost_system-mt ws2_32 wsock32

をリンクする必要がある。
※OS-X や Linux 環境では、「boost_system-mt」だけリンクすれば大丈夫だ。

あと、boost が出力するエラーメッセージは、日本語化されているのは良いのだが
CP932(ShiftJIS)な為、UTF-8 などに変換する必要がある。
※もしかしたら、UTF-8 を標準にする切り替えが出来るのかもしれないが調べてい
ない、ただ、コンパイルし直す必要があるかもしれない・・

-----
コネクション(同期関数利用)の際に、エラーが発生した場合に、エラーステート
か、例外の補足を選択できるようだが、私の環境依存なのか、コアダンプが出て正
常に動作しなかった、async_connect にしたら、問題は解決した。
※mingw64 の boost 絡みのバグなのかもしれない・・・
※OS-X で同じプログラムを動作させると、問題無く動作した。

あと、asio を使ったサンプルは、動作しないものもあるようなので、注意が必要と
思う。
サーバーとクライアントが不明確だったり、関係性を説明していないものも多く、
単純には動作しないものもある。

基本的に、TCPでは、サーバーを動作させて待機しておき、クライアントが接続に
行くスタイルなので、単純に繋げて、データをやりとりする事は出来ない。
少なくとも、サーバーとクライアントのプログラムを実装する必要がある。

boost::asio は使ってみると、良く出来ていると感じる、それでも、タイムアウトし
た場合のケアなど、かなり前もって緻密に設計しておかないと、後で苦労しそうでは
ある。
また、例外でエラーを受け取るのは、ソケットの場合、以外と相性が悪いかもしれな
い。
※非同期で行う場合は特にそう感じる。

RXマイコン、TPUテンプレートクラス、その1

最近、仕事が忙しく、更新が無かった・・・

RXマイコンでタイマー割り込みに使うのに適したペリフェラルはCMTだろ
う、単機能、シンプルで扱いやすく、理解しやすい。

しかし、CMTのカウンターは16ビットだが、プリスケーラーの仕様により
最大で、PCLKBの1/8の周期になってしまう為、間隔の短いタイマー割
り込みを組みたい場合に、誤差が大きくなる場合がある。
※メインクロックとの相性もあるが・・

そこで、他の選択肢としてTPUを使ったタイマーを実装する事にした。
※TPUは、PCLKBの1/1を選択可能なので、より正確なタイミングを
生成でき、ポートの出力も制御できる。

TPUユニットは、RX24Tには無いが、RX64Mには、1ユニット、6
チャネルある。
※RX631、RX63Nなどにもあるようだ。

ただ、面倒なのが、割り込み設定で、RX64Mではモジュールが大量に増え
た為、TPUの割り込みは固定ベクターではなく、選択的なベクターになって
いる。
TPUの操作をテンプレートで実装する場合に、割り込みベクターの管理を自
動で行いたいので、工夫してみた。
※RX631のTPUは、固定ベクターなので、その辺りも上手く吸収できる
ようにしなければならない。

また、TPUの機能は、タイマー割り込みの他、色々な機能があるので、それ
も簡単に扱えるような工夫が必要となるが、全ての機能を盛り込むと、設定が
複雑になるので、ある程度は妥協も必要で、その辺りのバランスが難しい。
※現在は、拡張中・・


TPUを考える前に、省電力機能の管理を少し拡張した。
「省電力機能」は、内部ペリフェラルの電源を「On/Off」して、使わない電力
を削減できるもので、起動時、最低限必要なものしか有効になっていない。
※ドライバー実装時、この省電力を「無効」にするのを忘れて、ペリフェラル
が動作せずに、時間を浪費した事があるのでは無いだろうか?
※注意事項には書いてあるのと、「お約束」ではあるのだが・・

ペリフェラルのテンプレートでは、個別IDを設定しておいて、それを定義に
忍ばせておく事で、他の連携クラスが、固有の動作を切り替えて実現でき、ま
た、連携クラスの実装分担を、ペリフェラルの定義から分離できる。

この簡単な仕組みにより、ペリフェラルの実装時、ペリフェラルやチャネルに
より異なる実装を隠蔽できる。

自分は、「手」を動かす事が好きなので、あーでもない、こーでもないを繰り
返して今の実装になっている。

ペリフェラルの定義:

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  ペリフェラル種別
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
enum class peripheral : uint16_t {
    TPU0,   ///< 16 ビットタイマパルスユニット0
    TPU1,   ///< 16 ビットタイマパルスユニット1
    TPU2,   ///< 16 ビットタイマパルスユニット2
    TPU3,   ///< 16 ビットタイマパルスユニット3
    TPU4,   ///< 16 ビットタイマパルスユニット4
    TPU5,   ///< 16 ビットタイマパルスユニット5

...

};

TPUの定義:

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  16 ビットタイマパルスユニット(TPUa)
    @param[in]  base    ベースアドレス
    @param[in]  per     ペリフェラル型
    @param[in]  intra   割り込み要因A
    @param[in]  intrb   割り込み要因B
    @param[in]  intrc   割り込み要因C
    @param[in]  intrd   割り込み要因D
    @param[in]  intru   割り込み要因U
    @param[in]  intrv   割り込み要因V
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <uint32_t base, peripheral per,
    uint8_t intra, uint8_t intrb, uint8_t intrc, uint8_t intrd, uint8_t intru, uint8_t intrv>
struct tpux_t {

...

    //-----------------------------------------------------------------//
    /*!
        @brief  ペリフェラル型を返す
        @return ペリフェラル型
    */
    //-----------------------------------------------------------------//
    static peripheral get_peripheral() { return per; }
};

TPUチャンネル毎の定義:

typedef tpux_t<0x00088110, peripheral::TPU0, 15, 16, 17, 18,  0, 19> TPU0;
typedef tpux_t<0x00088120, peripheral::TPU1, 20, 21,  0,  0, 22, 23> TPU1;
typedef tpux_t<0x00088130, peripheral::TPU2, 24, 25,  0,  0, 26, 27> TPU2;
typedef tpux_t<0x00088140, peripheral::TPU3, 28, 29, 30, 31,  0, 32> TPU3;
typedef tpux_t<0x00088150, peripheral::TPU4, 33, 34,  0,  0, 35, 36> TPU4;
typedef tpux_t<0x00088160, peripheral::TPU5, 37, 38,  0,  0, 39, 40> TPU5;

※「割り込み要因」は、選択型割り込みを設定する際に必要なIDで、チャネル
毎に機能が微妙に異なるが、シンプルな定義になっている。(0は、割り込み要
因が存在しない場合)

省電力管理で、必要な要素として、チャンネルの起動と廃棄時、まだ、使ってい
るチャネルがある場合に、省電力機能を無効にしないようにする事で、リファレ
ンスカウンタのような仕組みが必要な点だ。

実装は、簡単なのだが、スタティック変数の定義問題がある。
現在、ほぼ全ての実装は、ヘッダーのみで行っているので、それを壊したくは無
いが、単純にスタティック変数を記述すると、その実態として、ソースコードに
も書く必要があり、そうすると、そのソースコードのオブジェクトをリンクしな
ければならなくなる。

そこで、簡単なテンプレート関数を書いて、その中で定義できるようにした。
テンプレートにすると、「実態」をヘッダーに書けるので、ソースとヘッダーに
分ける必要が無くなる。

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  スタティック・ホルダー・テンプレート・クラス
    @param[in]	ST	構造体
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <class ST>
class static_holder {
public:
    static ST    st;
};
template <class ST> ST static_holder<ST>::st;

実際の定義では以下のようになっている。

struct pad_t {

    uint8_t    tpu_;

    pad_t() : tpu_(0) { }
};
typedef utils::static_holder<pad_t> STH;

この構造体の具体的な操作は、「RX64M/power_cfg.hpp」で行っている。

これら関連したコードはGitHubにプッシュ済み。

今回はここまで。

RL78関係をマルチデバイスに対応する

RL78を再開したのは、RL78関係の仕事を受注したのが大きい。

本来R8CやRXもまだまだなので、RL78をやるのは、現状では良く
ないが、仕事を請けたので、仕方がないが、丁度良かったかもしれない。

RL78は、他のマイコンに比べて、かなり魅力的なところがある。
・以外と高速で動作する。
※WAVファイル(16ビット、48KHz)をSDカードからSPIで
読み、再生する能力がある。
・とにかく電気を食わない。
・周辺機器(UART、I2C、SPI、ADCなど)が充実している。
・C++ で開発が可能。
・デバイスの値段が安く、バリエーションも多い。

マイナス要因:
・グループ(シリーズ)が多すぎる。
・内部は基本8ビットなので、32ビットなどの値を扱うと、肥大化して
遅くなる。
・アクセスできる範囲は16ビットが基本なので、64Kの空間を、特別
なポリシーを使って、RAM領域と、ROM領域に分けている為、設計の
段階で気を使う必要があり、リソースの再利用でも、注意を要する。
※これが結構、判りずらい場合がある。

仕事では、G13とL1Cグループに対応して欲しいとのオーダーを受け、
G13専用の構造を修正して、L1Cも含めるように改修した。

RXマイコンで複数グループ対応を行い、どのような構造にするとシンプル
(アプリケーション側でグループの違いを意識しなくて済む)になるのか、
実績があるので、それらの構造を継承している。

・デバイスのクラスでは、「ペリフェラル」型を設定して、それを取得でき
るようにした。

たとえば、SAU(シリアル・アレイ・ユニット)では、以下のテンプレート
として実装されている。

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  シリアル・アレイ・ユニット・テンプレート
    @param[in]  PER     ペリフェラル型
    @param[in]  UOFS    ユニット・オフセット(0x00、0x40)
    @param[in]  CHOFS   チャネル・オフセット(0x00, 0x02, 0x04, 0x06)
    @param[in]  SDR_O   SDR レジスターオフセット
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <peripheral PER, uint32_t UOFS, uint32_t CHOFS, uint32_t SDR_O>
struct sau_t {

...

    //-------------------------------------------------------------//
    /*!
        @brief  ペリフェラル種別を取得
        @return ペリフェラル種別
    */
    //-------------------------------------------------------------//
    static peripheral get_peripheral() { return PER; }
};
typedef sau_t<peripheral::SAU00, 0x00, 0x00, 0x00> SAU00;
typedef sau_t<peripheral::SAU01, 0x00, 0x02, 0x02> SAU01;
typedef sau_t<peripheral::SAU02, 0x00, 0x04, 0x34> SAU02;
typedef sau_t<peripheral::SAU03, 0x00, 0x06, 0x36> SAU03;

「peripheral」は、enum class で定義されている、RL78のデバイス機能
分類。

uart_io.hpp クラスのプロトタイプは、以下のようになっている。

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/*!
    @brief  UART 制御クラス・テンプレート
    @param[in]  SAUtx   シリアル・アレイ・ユニット送信・クラス(偶数チャネル)
    @param[in]  SAUrx   シリアル・アレイ・ユニット受信・クラス(奇数チャネル)
    @param[in]  BUFtx   送信バッファサイズ(8バイト以上のサイズである事)
    @param[in]  BUFrx   受信バッファサイズ(8バイト以上のサイズである事)
*/
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
template <class SAUtx, class SAUrx, class BUFtx, class BUFrx>
class uart_io {

割り込み関係を設定する場合、以下のようにシンプル
に書ける。

    intr::set_level(SAUtx::get_peripheral(), level);
    intr::set_level(SAUrx::get_peripheral(), level);
    intr::enable(SAUrx::get_peripheral());

また、ポートの設定などは、デバイス毎にイレギュラー的に異なるが、これも
シンプルに書ける。

manage::set_uart_port(SAUtx::get_peripheral());
manage::set_uart_port(SAUrx::get_peripheral());

「L1C」は扱ってみると、「G13」と大きく違う事が判った。
・割り込みテーブルのエントリーがかなり異なり、完全に分ける必要がある。
・当然割り込み関係のハンドリングも異なるので、これらの違いを隠蔽して
ドライバーからは同じように扱えるように改修作業を行っている。
・L1CはUSB対応デバイスの為、最大動作周波数は24MHzとなって
いる。
※ソフトディレイをかなり強引な方法で実装している。
・A/Dコンバーターは、12ビットになっている。(G13は10ビット)
・DMAコントローラーが廃止され、DTC(データトランスファコントローラ)
と、ELC(イベントリンクコントローラ)が追加されている。
・USB2.0コントローラーがある(L1C特有)
※USBは、PC側のドライバーが関係するので、簡単では無いが、USB
接続機器を接続する事が出来るのは大きいかもしれない。
※2.0と言っても、フルスピード(12Mbps)、ロースピード
(1.5Mbps)しかサポートされない。
・LCDコントローラーを内臓している。(今回は使用しない)

今回使っているデバイスは、FlashROM:64K、RAM:8K、デー
タフラッシュ:8Kの仕様で、gcc リンクファイルの領域記述を誤り、謎の
挙動を示した、しばらく原因不明で苦労したが、ようやく原因を特定して、
思ったように走るようになった。

※個人的にはG14グループを使いたいなぁーと思うのだが・・・

-----
ハードウェアーマニュアルの書き方が、日立や三菱系では無く(多分NEC系)
慣れが必要で、レジスターの令名規則も、構造的になっていない為、テンプレート
クラスを実装する際、整理しないと駄目なところが痛い。
※アセンブラで、直接ビット操作をするような場合には都合が良いのかもしれ
ない・・
※RXの三菱系が一番スマートだと思う。

RL78を再開

以前に、gcc では、内部データフラッシュメモリーへのアクセスがサポートされない
事で、開発をストールさせていたが、GR-Cotton でRL78/G13が使われており
WEBコンパイラは gcc となっている、また、データEEPROMのアクセスライブ
ラリーもあるようなので、これらを利用する事にした。
※以前に、ルネサスのIDEでは、RL78はC++をサポートしないので、gcc 用
ライブラリの提供をお願いした際「できません」と断られた事があった。

GR-Cotton では WEB コンパイラで gcc を使っていて、gcc 用ライブラリーを同梱し
ている。
それなら、それを教えてくれてもいいと思うのだが・・・

今回、仕事でRL78のオファーを受けた事で、データ・フラッシュは必須なので、
検討を始めた。
以前に、データフラッシュライブラリのオブジェクト(CS+IDE)をダンプした
ら、リバースエンジニアできそうな感じだったのだが、gcc 判があれば話が早い。

早速、GR-Cotton のプロジェクトを作成して、ソースコード一式を入手した。

その中にデータEEPROM操作関係のAPIがあるので、関係する部分を取得して、
自分のシステムに組み込んでみた。
※肝心な部分は、やはり、ライブラリーになっており隠蔽されている。(pfdl.a)

「pfdl.a」は、2つのオブジェクトをアーカイブしたものであるようだ。

% rl78-elf-nm pfdl.a

pfdl.o:
0000009d R _PFDL_Close
00000025 R _PFDL_Execute
00000091 R _PFDL_Handler
00000000 R _PFDL_Open
0000009d R PFDL_Close
00000025 R PFDL_Execute
0000006b r PFDL_Execute_erase
0000008a r PFDL_Execute_exit
00000061 r PFDL_Execute_firmware
0000007c r PFDL_Execute_read
0000007f r PFDL_Execute_read_next
00000091 R PFDL_Handler
00000000 R PFDL_Open

pfdl_version.o:
00000000 R _PFDL_GetVersionString
00000009 R _PFDL_VERSION_STRING
00000000 R PFDL_GetVersionString

ライブラリから、オブジェクトを分解して、肝心なオブジェクトを逆アセンブルして
みた。

rl78-elf-ar x pfdl.a
rl78-elf-objdump -D pfdl.o > pfdl.lst
00000000 :
   0:   c1                              push    ax
   1:   c3                              push    bc
   2:   a8 08                           movw    ax, [sp+8]
   4:   71 00 90 00                     set1    !f0090 .0
   8:   c7                              push    hl
   9:   16                              movw    hl, ax
   a:   bf 04 08                        movw    !f0804 , ax
   d:   8c 01                           mov a, [hl+1]
   f:   9f 01 08                        mov !f0801 , a
  12:   e5 03 08                        oneb    !f0803 
  15:   f2                              clrb    c
  16:   fc f8 ff 0e                     call    !!efff8 
  1a:   c6                              pop hl
  1b:   cf 80 08 04                     mov !f0880 , #4
  1f:   62                              mov a, c
  20:   9d f0                           mov 0xffef0, a
  22:   c2                              pop bc
  23:   c0                              pop ax
  24:   d7                              ret

上記は、PFDL_Open API の逆アセンブルソースだが、妙なアドレスをアクセスしている。
「F0804、F0801、F0803、F0880」これは、データフラッシュ関係の
制御レジスターと思われる。(ハードウェアーマニュアルには記載は無い)
また、「EFFF8」をコールしている、この部分に、データEEPROMのファーム
があるものと思われる。(このファームの存在も、一切記述が無い)

※改めて思うが、何故、隠蔽して、情報をオープンにしないのか、全く理解に苦しむ。
※本当に知りたいのなら、リバースエンジニアリングできるし、制限を設ける理由も思
いつかない。(ユーザーは不便になり、メーカーはサポートする仕事が増えるだけ)

早速テスト・・・
PFDL_Open関数を呼び出すと、戻ってこない・・・
PFDLライブラリのドキュメントを調べると、暗黙的に利用するワークRAMがあるよ
うだ。(セルフRAM領域)
※不思議な事に、デバイスにより、必要な場合と不必要な場合がある。
しかし、自分が使っているRL78/G13(R5F100LG)では、セルフRAMは
必要無い。
また、これとは別に、デバイス共通で、RAMの最終アドレス付近は、(0xFFE20
~後ろ)はライブラリの利用領域として予約されている。
※スタックやデータバッファと記述がある。

自分は、スタックを共有する為、RAMの最終アドレスを設定している。

色々、悩んだ末、解決した。
どうやら、ライブラリ内では、スタックを再設定して、内部処理を行い、ライブラリを出
る時に元に戻しているようだ。
この動作の為、共有していると正常に動作しないようだ、アプリ側のスタックを完全に分
離して、オーバーラップしないようにしたら、あっけなく動作した・・・
※これだからブラックボックスは嫌いだ・・・(まぁ自分の思い込みが原因ではあるけど)

以前にRXマイコンで作成した、対話形式で、データフラッシュの操作を行うプログラム
を組み込んで、実際に操作してみた。

問題なく書き込める!

とりあえず、操作できるようだ、これで、RL78も他のマイコンと遜色無く使える事が
判ったので、色々利用してみたい。
RL78はコストが安いので、R8C/M120とRXの中間を埋める「駒」として重宝
しそうだー

RL78データフラッシュサンプル