新版FM音源プログラム (8)
BSP_AUDIO_OUT_Init() で初期化したあとは、
BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)
で実際に DMA 転送によるオーディオ・データ出力を開始します。
第一引数 pBuffer は、配列要素がハーフワード (16 ビット) の DMA バッファ配列の先頭へのポインタで、この配列に出力データを格納しておきます。
DMA 転送は 1 ステレオ・サンプルの 1 ch ごとに行なわれ、ステレオ・データとしては、先頭から LRLR ... の順に並べます。
バイト単位でのデータの並び順を見ると
[L ch 下位バイト]、[L ch 上位バイト]、[R ch 下位バイト]、[R ch 上位バイト]、...
となります。
第二引数 Size は、バイト単位で表現した pBuffer 配列のサイズです。
1 ch 分のオーディオ・データ (16 ビット) でカウントした数 (pBuffer 配列の要素数) の 2 倍、ステレオ・サンプル (2 × 16 ビット) 数の 4 倍になります。
これは、Standard Peripheral Library 時代のライブラリではバージョンにより混乱があったのですが、BSP に改編される際にバイト単位に統一されました。
BSP_AUDIO_OUT での設定では、指定された回数の DMA 転送が終了すると DMA 転送自体は終了する「標準モード」になっていますが、次に示すように、手間を省くために自動的に DMA 転送を繰り返す「circular mode」に再設定するようにしています。
"main.c" ファイルのユーザ・コード記述部に書くべき内容について下に示します。
. . . . . <中略> . . . . . /* USER CODE BEGIN Includes */ #include "stm32f4_discovery_audio.h" #include <string.h> extern I2S_HandleTypeDef hAudioOutI2s; /* USER CODE END Includes */ . . . . . <中略> . . . . . /* USER CODE BEGIN PV */ #define DAC_DMA_BUF_SIZE (16) // 8 stereo samples per single buffer #define DAC_DMA_BUF_BYTES (2*DAC_DMA_BUF_SIZE) // byte count typedef int16_t dac_dma_buf_t[DMA_BUF_SIZE]; dac_dma_buf_t dac_dma_buf[2]; // double buffer /* USER CODE END PV */ . . . . . <中略> . . . . . /* USER CODE BEGIN 2 */ BSP_AUDIO_OUT_Init(0, // output = AUTO 85, // volume 48000); // f_sample // Re-configure the DMA Stream to circular mode hAudioOutI2s.hdmatx->Init.Mode = DMA_CIRCULAR ; HAL_DMA_Init(hAudioOutI2s.hdmatx); // Start DMA transfer BSP_AUDIO_OUT_Play((uint16_t *)dac_dma_buf, 2*DMA_BUF_BYTES); /* USER CODE END 2 */ . . . . . <中略> . . . . .
DMAC の初期化データは hAudioOutI2s.hdmatx->Init 構造体の中に残されており、その転送モードの設定 ("Mode" メンバ) だけを DMA_CIRCULAR に書き換えて HAL_DMA_Init() 関数により再設定しています。
DMA バッファを「2 面」持つ「ダブル・バッファ」構成としており、BSP_AUDIO_OUT_Play() 関数で指定する転送バイト数は、シングル・バッファでのバイト数の 2 倍になっています。
DMA バッファへの出力オーディオ・データの書き込みは DMA 割り込みコールバック関数の中で行なっていますが、それについては次回に説明します。