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

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

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

KIT-RX65Nでnesemu(≒ファミコンエミュレーター)の動作に成功

最近はESP32のM5Stackが流行っているようですがー、日本人なら、
ルネサスの「ENVISION KIT-RX65N」 ですよ!

Space Invaders は、元々、モノクロで、8080の2MHzくらいのシンプルなハード
なので、まぁ動くと思っていたが、nesemu は、カラーで、スプライトや、BGなど、
CPU(6502、1.7MHz)以外にも、かなり多くのハードウェアーをエミュレ
ーションする必要があるので、正直、普通に動作するとは思っていなかったが、駄目元
で、一応動作テストをしてみた。

-----

以前に、ESP32をやろうと思い、ソースコードのアーカイブを観ていたら、nesemu
のコードがあり、興味を持った。
とりあえず、nesemu 部分のソースを取ってきて、実験的に、Windows 上の OpenGL 環境
で動作試験を行った。
※その過程で、nesemu 関係のコードで、ポーティングに不都合な部分を色々修正した。
当然ながら、Windows 環境では問題無く動作するようになり、OS-Xでも試したが、
どうにも、サウンドストリームを適切に流す事ができず(ノイズが入る)に、中途な状
態で放置してあった。

nesemu のソースはCなので、丸ごと持ってきて、追加してコンパイルが通るまでは直ぐ
出来た、また、カラーテーブル付インデックスカラーを、RX65Nのフレームバッファ
にレンダリングする部分も一瞬で出来たが、動作するにはそこそこの時間が必要だった。
その過程で、POSIXのファイル操作関数にバグがある事が判り、修正したら、直ぐ
に走る事が判った。
※ファイルのシーク関数のステート判定に誤りがあった。

前から判っていた事ではあるが、STLを使うと、非常に多くのメモリーを消費する。
「vector だけならまぁいいか」と思っていたが、実際には、vector を使うには、他の
クラスも必要で、何だかんだ100K近くのRAMを消費して、ROMも250K程余
分に消費する・・・
※I/Oストリームなどを入れると500K近く消費する・・・
なので、vector を諦め、malloc で実装して、余分なメモリーをダイエットした。

RX65Nは二つのメモリーブロックがある。
一つは256K(0x00000000から始まる)、もう一つは384K
(0x800000から始まる)、以前は、RX64Mなどと同等に最初のブロックを
メインメモリにしていた。
LCDのフレームバッファとして16BPPなら255K(480×272×2)のメモ
リーはどうしても必要なので、これを、先頭の256Kに割り当て、メインRAMは後
半の384Kを使うようにリンクローダのスクリプトを修正した。
※この過程で、「start.s」のRAMクリアルーチンにバグがある事が判り修正した。
※RAMは0番地から始まる前提だった・・・

次に、サウンドのバインドを行った。
ファミコンのサウンドをソフトでエミュレーションするのは、そこそこ大変で、処理負
荷も高くなる。
サウンドのエミュレーションを有効にしたら、処理落ちする・・
また、1MビットROMのカートリッジはメモリー不足で動作しなくなった・・
※これは、サウンド関係でメモリを多く消費する為のようだ・・

            if(nesrom_) {
                apu_process(audio_buf_, audio_len_);
                nes_emulate(1);
            }
// nesemu.hpp の apu_process をコメントアウトすると、1Mカットリッジのゲームが走る(音無)

現状のコードでは、D/A出力用のコードが追加された為1Mビットのカートリッジは、
音無でも動作しない。

「処理落ち」を解消する為、一番処理負荷が高そうな部分に見当を付け、最適化してみ
た・・
本来、ファミコンエミュレーターは8ビットのインデックスカラーなので、LCDコン
トローラーの設定をそうすれば良さそうだが、ドライバーを手直しする必要があり、時
間がかかりそうなので、とりあえず、ビデオのコピー処理を最適化した。
それだけで、サウンドも大体スローダウンする事なく鳴るようになった。

Dragon Quest
GRADIUS

まだ、ソフトの完成度はあまり高く無いが、とりあえず、動作する・・

-----
ファミコンのパッドは、C-MOS4021B、シフトレジスターを使ったもので、
簡単に繋げる。
自分は互換ファミコンのパッドを流用した、5本のコードで接続する。
赤:VCC(本来は5Vだが、3.3Vでも動作する)
黄:GND
青:P/S(P60に接続)
茶:CLK(P61に接続)
白:OUT(P62に接続)

※良く考えたら、ファミコンパッドで使っているICはCMOSで電流をほとんど消費し
ないと思うので、配線を簡略化する為、ポートから供給する事にしたので、ピンアサイン
を変更。
赤:VCC(P60に接続)
黄:GND(P61に接続)
青:P/S(P62に接続)
茶:CLK(P65に接続)
白:OUT(P73に接続)

※このポートは、CN2を使う。

-----
将来的には、「.NES」ファイルを選択したり、ステートのセーブなど、必要な GUI を揃
えたりする予定だが、まだ色々パーツ(ソフト)が揃っていない為、少し時間がかかると
思う。
なので、現状、どのように動作させるか、簡単に記しておく。
・SDカードのインターフェースが必要。(NESファイルを読み込む為)
・D/Aコンバーター出力をアンプに繋ぐ必要がある。(音が欲しいなら)
※ファミコンはモノラルだが、ステレオ出力にしてある。
・ファミコン互換のジョイパッドを接続する必要がある。
・「.NES」ファイルを用意する必要がある。(ぐぐって欲しい)
現在、どのNESファイルを起動するか、「nesemu.hpp」に直接記述してあるので、それ
を修正する。

void service(void* org, uint32_t xs, uint32_t ys)
{
    if(delay_ > 0) {
        --delay_;
        if(delay_ == 0) {
            open("GALAXIAN.NES");
//          open("GRADIUS.nes");
//          open("DragonQuest_J_fix.nes");
//          open("Dragon_Quest2_fix.nes");
//          open("Solstice_J.nes");
//          open("Zombie.nes");
         }
     }
.
.
.

ソースコード

KIT-RX65N、LCDの初期化まで出来た。

ずいぶん長い間放置されていたが、最近、ようやくLCDの初期化が出来た。

画像は出ているようだが、「赤」、「青」、「緑」、「白」、「チェッカー」、
「ストライプ」などと、数秒おきに画面が自動で切り替わるナゾ動作が続く。
RX65NのGLCDC関係の部分を読んでも、この「現象」に対するヒント
は見つけられなかった。
この動作は、GLCDCの何かの機能なのだと思って、それを「OFF」にす
る方法をひたすら探したが、それらしい記述はどこにも載っていない。

結局、BGENレジスタを設定したら、このテストモードのような状態を抜け
て、想定した表示が得られた・・・
※BGENレジスタの設定が抜けていただけだった・・・

とりあえず、フレームバッファに適当に書いて、表示してみた。

ちゃんと表示するようだが、ガンマ補正がちゃんとしていない為か発色が少し変
な感じがする。(これは、これから解析するとして・・)
また、LCDは、そこそこコントラストがあるが、視野角が狭いようだ・・

もっとダイナミックな表示が欲しくなり、スペースインベーダーのエミュレータ
ーを動かしてみた。(あまりにあっさり動作したので拍子抜けだ・・)
このエミュレーターは「side」と言うオープンソースで、8080CPUと、
スペースインベーダーのアーケード基板をエミュレーションするもので、メモリ
ーも、内蔵メモリで足りるので動作の確認に便利だと思う。
※動作には、スペースインベーダーのROMデータが必要。
・invaders.h, invaders.g, invaders.f, invaders.e (invaders.zip)
今回は、それを、SDカードに書き込んで、SDカードから読み出している。
・inv_roms/
※コンパイルは「-O3」で最適化してある。
・エミュレーションにかかる処理負荷を計測したら、およそ60%程度を消費し
ているようだ、8080、2MHz程度でこの負荷は思ったより大きいが、その
気になって最適化すれば、20%くらいは下げられる感じはある。


現状では、音も無いし、操作も出来ないが、今後、それらを実装したい。
少し苦労したけど、音は鳴るようにした。

YouTube

ソースコードは、GitHubへコミット済み。

-----
このボードは5000円くらいで買えて、非常に使い勝手が良い、これから、
グラフィックス関係を強化して、色々なガジェットを作ってみたい!

追記:
・GLCDCのVPOS割り込みを設定して、画面更新の同期を行った。
・LCDの表示タイミングを調整して、画面の更新レートを60Hz近くにした。

追記:
・ファミコンパッド接続で、操作できるようにした。
※「SELECT」でコイン、「START」1Pスタート、左右キー、Aボタン

KIT-RX65NでもMP3再生の確認

動作は確実だろうけど、一応、確認だけしてみた。
※LCDの動作はまだもう少し・・
SDカードを使えるようにする必要がある。

「ENVISION KIT-RX65N」では、D/A出力は、それぞれ、
JoyStick、SW2に接続されているので、仮に配線して音出しの確認
をしてみた。
全く問題なくMP3の再生が出来た。
※将来的には、SPI通信とかで16ビットのD/Aをに出力する予定。

ソースコードは GitHub にプッシュ済み。

このボードは「E2-Lite」オンボードなので、プログラムの書き込みは
多少大きいサイズでも、短い時間で書けるのが良い。(Windows 環境のみだけ
ど・・)

D/A出力には、オペアンプによるボルテージフォロワを入れてある、3.3V
の中間の電圧が0Vとなっている。
参考回路
写真の物はPWM出力のRCフィルターが付いているが、まぁ問題無い。

-----
libmad のライセンスは、GPL なので、多少注意が必要と思う。
まぁ、自分のコードはそれより緩いMITライセンスなので、問題は無いと思
うが・・

RX64MでMP3ファイルのデコードとリアルタイム再生

WAVファイルの再生は出来た、しかしこれは当たり前すぎて、面白みが無い。

既に、RXマイコンでMP3ファイルの再生は実装した人がいたと思うのだが、
自分も確認の意味も含めて、実験してみた。

MP3のデコードには、libmad ライブラリを使う(これも先人と同じ)。
このライブラリ、かなり低負荷でMP3のデコードが出来るので、色々なプラ
ットホームで使われている。
※凄く昔に、i486DX100とかで、MP3をデコードするのがカツカツだ
ったように思う、それから考えると、ワンチップマイコンでデコードできるのは
かなり画期的な事だと思う。

DMACの制限により、1024ワード以上のバッファを転送するには別の工夫
が必要な事から、MP3デコーダーとD/Aのバッファの間にもう一つバッファ
を設ける事にした。
※そうしないと、MP3デコード処理の遅延により、バッファオーバーランが発
生して、再生が途切れてしまう。
それ以前に、120MHzのRXマイコンで、MP3をデコードした場合の処理
負荷を検証してみる。
MP3デコーダーにMP3ファイルを食わせて、回してみた、約4分くらいのフ
ァイルを1/2くらいの時間でデコードした、これなら、十分実用になる。
ただ、ビットレートやMP3をエンコードした条件により、処理負荷はかなり変
動するので、その変動時間を吸収できる量のバッファが必要と思われる。
簡単な実験では4096ワードでオーバーランが微妙に発生する感じなので、倍
の8192ワード設けるようにした。
※色々な曲を再生して聴いていたら、それでも怪しいファイルがあったので、さ
らに倍にした。

MP3の別の問題として、タグの問題がある。
MP3のタグは、ID3V1、ID3V2など複数のフォーマットがあり、ファ
イルの先頭にある場合(V2、可変長)、ファイルの終端にある場合(V1、固
定長)、バージョンの違い、文字コードの種類など、かなり面倒な仕様となって
いる、オープンソースのタグのパーサーはいくつかあるのだが、組み込みマイコ
ンのような少メモリの設計では無いのが痛い、結局は、「車輪の再発明」となる。

libmad はタグには感知しないので、もしID3V2タグが先頭にある場合、デコ
ーダーに食わせる前に、タグを見つけ出して、その部分を飛ばす必要がある。
以前にOpenGLのアプリで音楽プレイヤーを作った経験があり、その時に、
MP3のID3タグを色々とサポートした、その時は、libtag を利用したが、
やはり、組み込みマイコンにポートするには大掛かり過ぎる。
※とりあえず、ID3V2を見つけて、スキップするだけの実装を行った。
内部のフレームをパースするのは、暇なときにでも進める事とする・・

残念と思うのは、RAMの使用量が意外と大きい(現在81Kくらい)ので、
RX621、RX62NなどのRAMが少ない(確か64K)マイコンでは使え
ないと思う。(外部メモリーを実装すれば問題無いだろうか)
※プログラムサイズは、280K程度。
※gcc-6.4.0

-----
☆ 自作RX64Mボード

☆ GR-KAEDE

自作のRX64Mボードは、プログラムの書き込みをシリアル経由で行う為、
360Kのプログラムを書くのがかなり遅い、E1を持っている(借り物だけど)
のだから、J-TAGインターフェースを配線した方が良さそうだ・・・

必要なソースコードは、GitHub にプッシュしてある。
※libmad は、gcc-6.4.0 でコンパイル、ライブラリとヘッダーを上げてある。

RX64MでWAVファイルの再生

DMACを使い、D/A出力に気を良くして、WAVファイルの再生も行って
みた。

以前にRL78/G13を使い、8ビットPWM変調を使った、WAVファイ
ルの再生を行った事があり、その時のリソースを使ったので、とても簡単だっ
た。
RX64MはRL78/G13より桁違いに強力なので、処理負荷的には全く
問題無い。

SDカードの読み込みは、SDHIのポートに接続しているけれども、SDH
Iの無いRXマイコンなので、ソフトSPIで読み込みをしている、イマイチ
パフォーマンスが悪い(読み込み速度が遅い)が、それでも、120MHz動
作は伊達ではない。

各種サンプルレートに対しては、単純にサンプリングレートを変化させて行っ
た。
RX64Mにはサンプリングレート変換のハードウェアーがあるのだが、RX
65Nには無いので、それも踏まえている。
※RTK5_RX65Nでオーディオプレイヤーを作るのが本命。

DMACのトリガーとなる、TPUタイマーのクロック(60MHz)では、
44.1KHzは割り切れないので正確ではない。(44.118KHz)
※48KHzは割り切れるので、正確なタイムベースとなっていると思う。
※22.05KHzや38KHzもやはり割り切れないので正確では無い。
まぁ、12ビットのD/Aを使った簡易再生なので、多少の事は妥協する。
それでも、聴いた感じは、そんなに悪くは無い。(8ビットのPWMでもかな
り良い音がする事に驚く)
44.1KHzを48KHzにアップコンバートするのは、簡易的な方法なら
そんなに難しく無いので、44.1から48へソフトでアップコンバートする
のでも良いかもしれない。

コンソールのコマンドは
・dir
・cd [directory]
・pwd
・play file-name
・help

「play *」で、ディレクトリーの WAV ファイルを順番に再生する。
※WAV形式では無いファイルは無視する。

再生が始まる時、コンソールにヘッダー情報を表示し、時間経過をコンソール
に出力する。

ISFT: Lavf57.3.100
File:  '03 愛Dee.wav'
Size:   50807808
Rate:   44100
Chanel: 2
Bits:   16
Time:   00:04:48
00:04:47

IART: minato (流星P) Feat. 初音ミク
ICRD: 2010
IGNR: Pop
INAM: FAIRYLAND -mintia mix-
IPRD: magnet -favorites plus-
IPRT: 4/15
ISFT: Lavf57.3.100
ITCH: iTunes 9.0.2.25
File:  '04 FAIRYLAND -mintia mix-.wav'
Size:   39518208
Rate:   44100
Chanel: 2
Bits:   16
Time:   00:03:44
00:01:27

再生中は、
・「Space」:一時停止
・「>」:次の曲
・「<」:曲の先頭
で、プレイヤーを制御できる。

WAVファイルは、48KHz、44.1KHz、38KHz、22.05KHz、
8、16ビット、モノラル、ステレオのPCM形式ファイルに対応する。
※8ビットやモノラルはあまり実験していないので不具合があるかもしれない。
※GR-KAEDEでも簡単な修正で動かす事ができる、方法を知りたい場合
は、コメント欄にどうぞ。
※GR-KAEDEは、SDカードのハードウェアーに致命的な問題がある、
回避方法はあるのだが・・

「main.cpp」で、「GR_KAEDE」を有効にしてコンパイルすれば、GR-KAEDE でも
動作すると思うが、いくつか問題がある。
・SDカードのハードウェアー「DO」端子のプルダウン問題を回避する必要がある。
※色々な解決策があると思うが、「main.cpp」に具体的な回避策を載せてあるので参考
にして下さい。
・D/A出力0がLED4に接続されているので、ジャンパーを飛ばす必要がある。

GitHub AUDIO Player

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の設定や描画を実験してみたい。