JPY | USD

STM32によるオーディオ処理

STMicroelectronics(ST)は、高性能ARM Cortex-M7ラインの新しい仲間STM32H735をリリースしました。これは、リリース後30日間は、Digi-Keyでのみ入手できます。リリースされたばかりの新しい製品が私の机に回ってくると、それを使って複数の機能を組み込んだ小さなプロジェクトを作りたくなります。このブログでは、さまざまなオーディオペリフェラルを調べ、STM32H735G-DK Discoveryキットを使用して結果を表示することにしました。キットの概要とお手軽デモについては、1人の同僚が提供してくれた下のビデオをご覧ください。

サウンドキャプチャ

STM32H735Gは、2つの専用シリアルオーディオインターフェース(SAI)を搭載しており、柔軟性に富んでいます。各SAIには2つのサブブロックがあり、マスターまたはスレーブとして、およびI2S通信用の送信機または受信機として個別に構成することができます。または、PDMマイク用のクロックを提供し、出力をPCMに変換することもできます。

デバイスの他のペリフェラルもオーディオ用に再利用できます。デバイスの4つのSPIインターフェースは、I2S用に構成できます。SAIの代わりにPDMマイク用の変換も、内蔵のシグマデルタフィルタ(DFSDM)で対応できます。

Discoveryキットでは、上述したSAIの両構成を実際に確認できます。SAIインターフェースの1つは、I2Sを介してCirrus LogicWM8994コーデックに接続されています。コーデックを使用すると、オーディオはラインインポートで受信され、ヘッドフォンジャックまたは増幅されたスピーカ出力で再生されます。2つ目のSAIはPDMモードで動作し、オンボードマイクに直接接続されます。

STは、STM32CubeMXフレームワークのBSPサンプルプロジェクトを提供しており、これらのオーディオペリフェラルの開発をすぐに始めることができます。このプロジェクトには、ペリフェラル用の低レベルドライバと、オーディオコーデックなどのDiscoveryキット機能用の高レベルドライバが含まれています。たとえば、BSPドライバを使用してライン入力コネクタからのオーディオ入力を設定するのは非常に簡単です。

コピーする
#define BUFFER_SIZE    2048

int16_t audio_buffer[BUFFER_SIZE]
BSP_AUDIO_Init_t  AudioInInit;

/* Initialize audio interface to use line in port for input */
AudioInInit.Device = AUDIO_IN_DEVICE_ANALOG_LINE1;
AudioInInit.ChannelsNbr = 2;
AudioInInit.SampleRate = 44100;
AudioInInit.BitsPerSample = AUDIO_RESOLUTION_16B;
AudioInInit.Volume = 80;

/* Initialize audio in on Instance 0 (SAI I2S) */
BSP_AUDIO_IN_Init(0, &AudioInInit);

/* Start DMA recording into buffer */
BSP_AUDIO_IN_Record(0, (uint8_t *) audio_buffer, 2* BUFFER_SIZE);

ARMCMSIS-DSPを利用する

ARMで開発したことがある人なら、CMSIS(Cortex Microcontroller Software Interface Standard)を知っている可能性が高いでしょう。そうでなければ、異なるARM Cortex実装間で一貫したコードを持つハードウェア抽象化レイヤです。ここでは、ARMアーキテクチャに最適化された共通の信号処理機能を搭載したCMSIS-DSPライブラリが関心の対象です。

私にとって、CMSISライブラリを組み込む最もシンプルな方法は、ソースから直接取り込むことでした。CMSISレポ全体はARMのGitHubから複製することができますが、CMSIS/DSP/IncludeCMSIS/DSP/IncludeディレクトリのみをSTプロジェクトに追加して開始する必要があります。通常、これらはデフォルトのプロジェクト構造のDrivers/CMSISディレクトリにコピーする必要があります。

コンパイルする前に、プロジェクトで2つの簡単な調整を行う必要があります。まず、プロジェクトのインクルードパスに新しいCMSIS/DSP/Includeディレクトリを追加します。ここにあるarm_math.hヘッダは、DSP関数にアクセスするためにアプリケーションに含めます。

次に、DSPライブラリがハードウェアアーキテクチャに関する情報のために使用する、__FPU_PRESENT と ARM_MATH_CM7 の2つの #define があります。一番簡単な方法は、以下のようにグローバルプロジェクトのシンボルに追加することだとわかりました。

図1:プロジェクトシンボルの定義。

その後のFFTの計算は数行で済みます。

コピーする
#include “arm_math.h”

#define FFT_SIZE    256

arm_rfft_fast_instance_f32 fft_inst;
float32_t fft_in[FFT_SIZE], fft_out[FFT_SIZE];
float32_t fft_mag[FFT_SIZE>>1];

/* Initialize ARM FFT instance with num points */
arm_rfft_fast_init_f32(&fft_inst, FFT_SIZE);

/* Fill the fft_in buffer from Line In or Microphone input */

/* Perform forward direction 32-bit FFT */
arm_rfft_fast_f32(&fft_inst, fft_in, fft_out, 0);

/* Calculate magnitude (buffer size is half because real + imag parts are merged) */
arm_cmplx_mag_f32(fft_out, fft_mag, FFT_SIZE >> 1);

すべてを一緒にする

FFTが計算された状態で、結果をグラフィカル表示できるのは便利です。以下の関数は、ST BSPドライバとCMSIS-DSPライブラリの関数を組み合わせて、Discoveryキットのディスプレイにミニマリストのビジュアライザスタイルのグラフを描画します。

図2:Discoveryキットに表示されるビジュアライザ。

コピーする
static void Display_FFT(float32_t *fft_mag)
{
	uint8_t i;
	float32_t max_val;
	uint32_t max_idx;
	uint32_t box_height;
	uint8_t box_width = 2;

	/* Draw horizontal axis */
	UTIL_LCD_FillRect(10, 135, 460, 2, UTIL_LCD_COLOR_WHITE);

	/* Use max value in the results for scale */
	arm_max_f32(fft_mag, FFT_SIZE >> 1, &max_val, &max_idx);

	/* Draw frequency bins */
	for(i = 0; i < 230; i++)
	{
		box_height = 100 * (fft_mag[i] / max_val);
		UTIL_LCD_FillRect(10 + box_width*i, 135, box_width, box_height, UTIL_LCD_COLOR_WHITE);
	}
}

まとめ

STM32H735は、特にマルチメディアや信号処理アプリケーション向けに多くの機能を搭載した強力なマイクロコントローラです。Digi-Keyは月末までこの製品の独占販売ディストリビュータですので、次のプロジェクトに適していると思われる場合は、当社のウェブサイトをチェックしてみてください。

著者について

Image of Taylor Roorda Digi-Key ElectronicsのアソシエートアプリケーションエンジニアであるTaylor Roorda氏は、2015年に組込みシステム、プログラム可能ロジック、および信号処理に主に関心を持つ分野に参加しました。ノースダコタ州立大学で電気工学の学士号を取得し、余暇にはギターを演奏したり、作曲したりしています。
More posts by Taylor Roorda