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 ストリーム・サンプル