6.DMAでPWMデータを更新する設定方法
CPU処理を軽減するためにDMAを使う。組み込みでは当たり前の話。
でもマイコンによって仕様が微妙に違うのがめんどくさい。
ハードウェアマニュアルとSDKマニュアル読んでサンプルコード読んでいくと、便利な機能が見つかった。
今時のマイコンって便利だね。
そして決めた仕様は以下の通り。
DMAを2チャンネル使う。
DMA1はPWMのデューティ比を設定するために使う。
DMA2はDMA1のデータ転送後、DMA1の転送元アドレスをリセットするために使う。
DMAタイマーをPWMの更新タイミング設定に使う。
DMA1
・PWMのデューティ比設定レジスタは32bitなので転送単位は4バイト。自動アドレス更新なし。
・転送元アドレスは自動更新あり。転送回数はバッファサイズに合わせる。
・バッファサイズはとりあえず20ms分確保
・転送タイミング(DREQ)としてDMAタイマーを指定する。
・DMAタイマーはMP3のサンプリングレートに合わせる。
なおCPUクロック * 定数1 / 定数2 の設定なので、誤差 1% ぐらいは我慢する
(別のPWMチャネルを使ってDREQを出せば正確なレートにすることもできるが、そこまでは頑張らない)
・DMAチェーン機能で、一連の転送完了後にDMA2を起動する。
DMA2
・転送先アドレスは、DMA1の転送元アドレスレジスタを指定。自動アドレス更新なし。
・転送元アドレスは、DMA1の転送元アドレスの初期値を格納したメモリのアドレスを指定。自動アドレス更新なし。
・転送回数は1を設定。(チェーン機能で起動されるたびに1回書き込む)
この設定で DMA2 起動ごとにDMA1の転送元アドレスが初期化される
転送回数は、自動で前回値に戻るので再設定不要。
全体の動作は以下の通り。
1.DMA1の転送元アドレス(PCMデータ領域)のバッファにPCMデータを書き込む。
2.DMA1に起動要求を出すと44.1kHzでPCMデータがPWMのレジスタに転送される。
(CPU処理: 随時転送回数レジスタをチェックし、転送済みバッファに追加のPCMデータを書き込む。)
3.DMA1が転送完了すると自動的に転送回数が再設定される。
4.DMAチェーンがDMA2を起動。
5。DMA2は、PCMデータ領域のアドレスを格納したメモリから、DMA1の転送元アドレスレジスタにデータ転送。
ここで、このマイコンの面白い機能を使う。
DMACのレジスタは4つあるが、これの並び方を変えたエイリアスレジスタがある。
エイリアスレジスタの最後のレジスタに値を書き込むと自動的にDMA転送を開始できる。
エイリアスは複数あって、転送先を書き込んだらスタート とか 転送回数を書き込んだらスタートとかを選べる。
今回は、DMA2がDMA1の転送元アドレスレジスタをセットするので、転送元を書き込んだらDMAを開始するエイリアスレジスタを使う。
この設定で、一旦起動したらノンストップでPWMを更新し続けることができる。実に便利だ。
CPUプログラムでは、転送回数レジスタをチェックしつつバッファを更新すれば良いので、CPU負荷を低減しつつ、動画再生も並列処理できるはず。
なお、動作中に更新が止まると、レコードの針が飛んだように繰り返すのはご愛敬。




