Lynx-EyEDの電音鍵盤 新館

広帯域制御屋の駄文とか

LPC1114で音声再生

◆eXodusino量産向け試作品とピン配置
前回のエントリの続きです
f:id:Lynx-EyED:20120225144503j:image

ピン配置は以下の通りです。
f:id:Lynx-EyED:20120311230948p:image
◆ピン名称と入出力設定の関係
eXodusinoはArduino標準API互換*1なので、上記のD2ピンを出力ピンかつ、HIGHにしたい場合、

pinMode(2,OUTPUT);
digitalWrite(2,HIGH);

あるいは、LPC1114のオリジナルのピン名称を使って

pinMode(P0_3,OUTPUT);
digitalWrite(P0_3,HIGH);

とすることも可能です。

◆書き込み方法
eXodusinoにプログラムを書き込む方法はこちらをご覧ください。

◆アプリケーション例:非圧縮wav音声データの再生
ローム製音声用DAC BU9480Fか浜松ホトニクス製カラーセンサS9706どちらか1つを実装できるパターンに設計してある訳ですが、
今回はBU9480F版で音を出してみようと思います。音源は16bit、ステレオ、22.050kHzサンプリング非圧縮wavファイルとしました。
48pinのLPC1114はSPIが2chあるのでSDカードをSPIモードで読み込みつつ、同時にもう一方のSPIでBU9480FなどのSPI DACを駆動することができます。

↓BU9480F版eXodusino
f:id:Lynx-EyED:20120225143203j:image

BU9480FはDFも出力段用アンプも内蔵していないため、外部にフィルタ付きアンプを設計して接続してやる必要がありますが、
取り急ぎの音声の確認くらいならイヤホンジャック直結みたいな横着してもOK(一応ボード上の1uFでバイアスカットしてるので)
でも、インピーダンスくらいは計算しとかないとぶっ壊れるかも。。。オススメはしません。

f:id:Lynx-EyED:20120225143518j:image

コードはこちら。eXodusinoプロジェクトのuser_application.cppにコピペで動くはず。

#include <libmary.h>
#include <SD.h>
#include <SPI1.h>		// BU9480FのSPI

#define LRCLK		6					// LRCLK(BU9480F) -> D6(eXodusino)
#define AudioBufRow	256					// length of proc_r
volatile uint16_t	empty_c	= 0;		// Column
volatile uint16_t	proc_r	= 0;		// Row
uint16_t	AudioBuf[2][AudioBufRow];	//AudioBuf[empty_c][proc_r]
bool dac_semp;							// オーディオバッファ書き込み完了フラグ true:完了, false:まだ


uint16_t br;
FRESULT rc;

void readSound(void)
{
	volatile int16_t i=0,j=0;
	while(1){
		if(i != empty_c)
		{
			if(j >= AudioBufRow - 1)
			{
				i = empty_c;			// DACが使用してない(使い終わった)バッファを選択
				j = 0;
			}
		}

		if (j < AudioBufRow - 1)
		{
			rc = pf_read(AudioBuf[i], sizeof(uint16_t)*256, &br);	// Read a chunk of file
			if (rc || !br)break;

			j = j + 256;

		}
		if(j >= AudioBufRow - 1)
		{				// 音声バッファは満タン?(DACがリードしてもOK?)
			dac_semp = true;
		}
	}
}


void playSound(void)
{
	static uint16_t i,j;					// AudioBuf[j][i]
	uint16_t k;
	if(i >= AudioBufRow - 1)
	{
		if(dac_semp)						// empty_cカラムは書き込み完了?(=true?)
		{
			i = 0;
			empty_c =(empty_c == 1)?0:1;	// DACが使い終えたバッファをempty_cとする
			j = (empty_c == 1)?0:1;			// decode()関数がデータを貯めているバッファに切り替え
			dac_semp = false;				// empty_cは空なのでfalse

		}else
		{									// 書き込み完了してない?
			return;
		}
	}
	//DACへデータ送信
	k =(AudioBuf[j][i++]);
	digitalWrite(LRCLK,HIGH);
	SPI1.transfer(k);

	k =(AudioBuf[j][i++]);
	digitalWrite(LRCLK,LOW);
	SPI1.transfer(k);

	return;
}

void setup()
{
	// XBeeの初期化
	Serial.begin(9600);

	//BU9480Fの初期化
	pinMode(LRCLK,OUTPUT);
	SPI1.setBitLength(16);
	SPI1.setClockDivider(SPI_CLOCK_DIV2);
	SPI1.begin();

	// SDCard初期化のtry&catch
	if (!SDFile.begin())
	{
		Serial.println("Cannot detect SDCard") ;
		return ;
	}

	Serial.println("card initialized.") ;
	rc = SDFile.open("hoge.wav") ;

	if (rc)
	{
		// ファイルオープン失敗
		Serial.println("Failed to open...") ;
		SDFile.close() ;
		while(1);		//ここに動作停止処理を記述
	}

}

void loop(void)
{
	Serial.println("play start");

	// 45マイクロ秒ごと=22.05kHzごとにplaySound()をコールする
	attachMicroseconds(playSound,45);
	readSound();

	SDFile.close() ;		// ファイルをクローズ
	detachMicroseconds();	// 割り込みを停止

	Serial.println(""); 			//改行
	Serial.println("play end.");
	while(1);				//ここに動作停止処理を記述


}


microSDカードに16bit、ステレオ、22.050kHzサンプリング非圧縮wavをhoge.wavというファイル名で保存します。
eXodusinoのmicroSDソケットにセットします。
eXodusinoに上記のプロジェクトのバイナリを書き込み。(自動で再起動します。)

クリスタルイヤホンや、アンプを接続したスピーカから音声が確認できたら成功です。
f:id:Lynx-EyED:20120225140132j:image

*1:ただしソフトの開発はLPCXpresso IDE4となります