スクラッチ・メモリとDMA

注意:以下は「DMAレジスタに直接書き込んでDMAをおこなうことはできない」という誤った理解に基づいて書かれています。それ以外の部分は特に間違っていません。

先日書いたことですが、DMAコントローラはスクラッチ・メモリにアクセスできないため、スクラッチにはデスクリプタを置けません。通常のアプリケーションならばいくらでも逃げ道はありますが、_mi_initializeの場合は事情が特殊です。TOPPERS/JSP for BFはデフォルトのLDFでは_mi_initializeを呼び出すときにスタックをスクラッチ・メモリにおいて呼び出します。これは標準の_mi_initializeならば問題ありませんが、先日紹介したdmacopy()を使う改良版_mi_initializeはスタック上にデスクリプタをおくため使用できません。この問題は状況によって対策が極端にかわるので、TOPPERS/JSP for BFに限って話を進めます。
まず最初に思いつくのは「デスクリプタを大域変数にすればいいではないか」ということです。確かにそれはひとつの手です。しかし次のような点が引っかかります。

  • 初期化時しか使わない変数にメモリを割り付けなければならない
  • 大域変数を必ず未初期化変数として処理しなければならない

もっぱら2番目が間違いやすくていやらしいのでできれば大域変数にはしたくないところです。
さて外部RAMがあるなら解決は非常に簡単です。DMA化した_mi_initializeを呼ぶ直前に外部メモリの仮領域をスタックポインタにセットすればそれで終わりです。速度は遅いですが問題にはなりません。ただし、仮領域を変数として宣言したりすると初期化されたりして面倒ですので、LDFで非割り当て領域をつくり、決めうちでそこを使用するのが一番です。
外部RAMがない場合は内部データSRAMの中で初期化されない領域を探すしかありません。使いやすい順に以下の三つが考えられます。

  1. 未使用領域
  2. ヒープ
  3. 非初期化変数

内部データSRAMに未使用領域があれば、それを使って問題解決です。ない場合、ヒープ領域を仮スタックにできます。ヒープはmalloc()関数用のメモリープールです。ここは初期化されませんので間借りするには絶好の場所です。
未使用領域がなく、ヒープもないとなると、非初期化変数領域を使うことになります。非初期化変数はリンカを使って指定する領域です。デフォルトではVisualDSP++は初期値を持たない変数を全部0フィルします。しかし、ある種の変数は初期化しないままにすることができます。

  • 以下次回。