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

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

RXマイコンで、DMACを使う

RX65NのLCDが中々進まない・・・
※もう少しな感じなのだが、初期化後に、表示はしている感じだが、謎の動作をす
る・・・

-----

LCDの制御でも使う事になるので、DMAC関係のテンプレートライブラリを実装
してる。
応用範囲が広いので、継続して機能追加、拡張する事になると思う、本来色々な利用
状況を想定して、必要な機能を実装しておくのが普通だが、他のテンプレートクラス
と連携して動作させる事が必須なので、どのような設計が適しているのか良い案が思
い浮かばないので、「仮」とする。

とりあえず、メモリー転送や、メモリーFillなど、DMAの起動をソフトで行う
物で、実験して動作を確認した。

実際には、DMACは、何かのペリフェラルデータ転送を行うハードとして利用する
のが普通なので、それらから利用できるような仕組みを盛り込む必要があるのだが、
どのような構成にしたら良いか迷うとこだ・・・

DMACで、fifo のような機能がソフトの介入無しに出来れば、かなり応用範囲が
広がると思えるのだが・・

とりあえず、D/AやA/D変換でDMACを使うような想定で、全体の構成を考え
るのが良さそうだ。
まず、タイマー割り込みでD/Aの値を書き換えて、サイン波を出力してみた。
これは、問題無くできた。
※サンプリングは48KHzとした。

※流石12ビットもあると、それなりの精度で出力出来る~

-----

次にDMA版、TPUタイマー起動でDMAをスタートして、D/Aのレジスタから、
メモリに転送する、バッファは有限なので、適切なサイズで、先頭に戻るようにする。
この時、DMACはリピート転送モードを使う。
リピート転送モードでは、最大でも1024ワードの転送しかサポートされないのが、
痛いところだ・・
※D/Aチャネル0、1が連続した32ビットデータなので、32ビット転送として
いる。

今回、48KHzをサンプリングとしたオーディオのストリーム再生を想定した、
48KHzで1024サンプルだと、21ms分なので、リングバッファの書き換えを
考えた場合、半分の10msくらいでサービスする必要がある。
今回の場合なら、100Hzの割り込み(10ms)を作成して、そのタイミングでサ
ービスすれば問題は無いが、もっと大きいバッファが必要な場合はどうするのか?
普通に考えて、DMAC終了割り込みで、ターゲットのアドレスを書き換えるなどのサ
ービスが必要となるなど、この仕様は色々痛い・・・
この場合、サービスにかかるオーバーヘッドが大きいと、次のDMA起動とオーバーラ
ップしてしまう場合が考えられる・・
その場合は、DMACをもう1チャネル使って、ピンポン式にすれば何とかなりそうで
はある・・
※何で、1024ワードに制限してるんだよぅ・・・

C++ のテンプレートでファンクタ・クラスを引数としているので、割り込み内から呼ぶ
ユーザー作成のタスク呼び出しは、展開され、関数ポインターを使ったコールバックの
ようなオーバーヘッドを生まないのが救いだ。
※これは、非常に短いスパンで割り込みが発生するような場合に効果が大きい。

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

-----
設定が悪くて、思ったように動作しなかったが、ようやく思った動作になった。

呼び出しのプロトタイプはこんな感じになった~

//-----------------------------------------------------------------//
/*!
    @brief  割り込み要因による開始
    @param[in]  trg     転送開始要因
    @param[in]  tft     転送タイプ
    @param[in]  src     元アドレス
    @param[in]  dst     先アドレス
    @param[in]  lim     転送リミット(※カウント数なので注意)
    @param[in]  ilvl    転送完了割り込みレベル(0以上)@n
                        ※無指定(0)なら割り込みを起動しない。
    @return 成功なら「true」
*/
//-----------------------------------------------------------------//
bool start(ICU::VECTOR trg, trans_type tft, uint32_t src, uint32_t dst, uint32_t lim,
           uint32_t ilvl = 0) noexcept

最後に、以前に紹介した、整数計算を使った三角関数クラスを使って、リアルタイムに
計算して、周波数ジェネレーター的な実装を行い連続的な再生ができるているかを検証
してみた。


    X' = X * COS(s) - Y * SIN(s)
    Y' = X * SIN(s) + Y * COS(s)
    ※角度「s」が十分小さい場合、以下のように近似できる。
    COS(s) ≒ 1
    SIN(s) ≒ s
    X' = X   - Y・s
    Y' = X'・s + Y

CH0、CH1でsin、cosを出力している。

ターミナルから、周波数を入力すると、その周波数を出力する。
※サンプリングが48KHzなので、高い周波数だとエイリアシングが目立つ。

RX64M D/A ストリーム・サンプル

RTK5RX65N、未実装部品、SDカードの利用

次はLCDと宣言してたが、その前に未実装部品についてまとめておきたい。
また、SDカードを使う為にカードソケットを追加で取り付けた。

このボード、未実装の部品がある。
(1)SDカードソケット「SD/MMCカードソケット:101-00565-64(AMPHENOL COMMERCIAL PRODUCTS製)」
(2)SDカード電源用ゲートIC「ISL61861BIBZ」
(3)JOYスティック「SW3(JOYSTICK):SKQUDBE010(ALPS製)」
(4)イーサーネットコネクタ「RJ45_J3011G21DNL」
(5)イーサーネットPHY「LAN8720A」
※主に、上記部品で、SDカードソケット、JOYスティックは、部品が判らなかったので、
ルネサスに問い合わせをした。

もちろん、自分で部品を実装したら、保障は受けられなくなるのだが、機能があるのに使わな
いのは勿体無い。
一番困難なのは、表面実装部品で、DNFパッケージだが、これは、後々、手順などを整理し
たいと思う。(基板の実装屋さんなら簡単だと思う)

多少問題なのは、上記部品で、SDカードソケット、JOYスティックは、製造が終了してお
り、現在部品の入手が難しい。(入手できても割高になってしまう)
※代替部品を探したが、適当な物を探せなかった、また、日本では、やはり入手が困難だと思
われる。

特に、SDカードは、このような機器では必須のI/Oなので、マイクロSDカードを使って
代用させる方法を考えた。
ソケットは、秋月電子製、マイクロSDカードスロットDIP化キットを使う。
多少細かい、配線は比較的簡単ではあるが、強引な方法なのでお勧めできないのだが、他に良
い方法を思いつかない。
また、RTK5RX65Nでは、SDカードの電源をマイコンによって制御しているのだが、
電源制御につかっているIC(インターシル製)は、入手できるが割高なので、とりあえず
直接接続しておく事にする。

※自分は、「セメダイン SuperX」で、基板を接着した。
※強力両面テープでも良いかもしれない。

※マイクロSDには、ライトプロテクトが無いのでオープンにしてある。
※ほぼ、ストレートな結線なので配線は簡単だが、電源系は、熱が拡散するので、容量の大
きいハンダコテが必要と思う。

SDカード関係のソフトSPIでの定義

    // カード電源制御は使わない場合、「device::NULL_PORT」を指定する。
//  typedef device::PORT<device::PORT6, device::bitpos::B4> SDC_POWER;
    typedef device::NULL_PORT SDC_POWER;

    // Soft SDC 用 SPI 定義(SPI)
    typedef device::PORT<device::PORT2, device::bitpos::B2> MISO;  // DAT0
    typedef device::PORT<device::PORT2, device::bitpos::B0> MOSI;  // CMD
    typedef device::PORT<device::PORT2, device::bitpos::B1> SPCK;  // CLK

    typedef device::spi_io2<MISO, MOSI, SPCK> SPI;  // Soft SPI 定義

    typedef device::PORT<device::PORT1, device::bitpos::B7> SDC_SELECT;  // DAT3 カード選択信号
    typedef device::PORT<device::PORT2, device::bitpos::B5> SDC_DETECT;  // CD   カード検出

    typedef fatfs::mmc_io<SPI, SDC_SELECT, SDC_POWER, SDC_DETECT> MMC;   // ハードウェアー定義

    MMC     sdh_(spi_, 20000000);

-----
以前に自作のRX64Mボードで、SDHIのドライバーを実装しようと、色々やったが、
どうやっても動作せず、また、ルネサスのサンプルも無いようだったので、あきらめていた。
だが、よくよく調べると、RX64Mマイコンには、SDHIインターフェース内臓版と、そう
では無いバージョンがある事がわかった。
実験で使ったデバイス「R5F64MFCFDC」は、SDHIは「無し」なので動くハズは
無い。
※SDHIインターフェースのバージョンを取得するレジスターは読めて、それらしい値だった
ので、てっきりSDHIがあるものと思っていた。

RTK5R65NボードのRXマイコン「R5F565NEDDFB」は、SDHI「あり」の
デバイスなので、SDHIインターフェースを使ってSDカードのアクセスを行う事が出来る。
4ビットモードを製品として使う場合は、SDアソシエーションとのライセンス締結が必要なよ
うだが、自分がリリースしているテンプレートドライバー、フレームワークは無保証なので、こ
れらには関知しない。
※SDHIには、ライセンスが必要無い1ビットモードもある。

現在、SDHIドライバーは開発中であり、とりあえず、動作確認の為、SPIのソフトウェア
SPIドライバーを使って、動作を確認してある。
RTK5 SD カードアクセス、サンプル

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          ---> ヘルプ

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の三菱系が一番スマートだと思う。