新版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 割り込みコールバック関数の中で行なっていますが、それについては次回に説明します。