SSブログ

Leonardo で SDカードの WAVファイルを再生する [Arduino]

Leonardo で SDカードの読み取りができるのなら、そこから WAVファイルの再生にもいけるだろう、、ということでやってみました。
Leonardo で使われている ATmega32u4 には、ATmega328P にあった 8bit Timer/Counter2 がないので以前のスケッチを少し書き換えました。
少し書き換えただけですが、また新たな勉強でした。
16bit の Timer/Counter1 を 8ビットで使うことにしました。
以前のスケッチは、タイマーがオーバーフローするのを割り込みにしていましたが、16ビットになりオーバーフローでの割り込みではだめなので、input capture register1 (ICR1) で Timer/Counter1 のTOP値を8ビットの0xFF (255) として、タイマ/カウンタ1 捕獲割り込みというもので割り込むようにしてみました。
OC1Aを使用しましたが、このピンは Uno (PB1) でも Leonardo (PB5) でも共に Arduino上はデジタル9番なので両機種に対応できているはずです。

// 「SDカードのWAVファイルを再生」
// 16MHzのArduino で 256 clock毎に割り込むので 62.5kHz(8bit Monoral)が理想だが
// ボクの持っているソフトが対応していないので、32kHz(8bit Stereo)で代用
// Leonardo対応バージョン
#include <SD.h>

#define BUF_SIZE 384          // バッファ・サイズ

volatile uint8_t              // グローバル変数
    buf[2][BUF_SIZE],           // バッファ
    buf_page,                   // バッファ・ページ
    buf_flg;                    // バッファ読み込みフラグ
volatile uint16_t buf_index;    // バッファ位置
volatile uint16_t read_size[2]; // バッファ読み込みサイズ

void setup() {
  pinMode( 4, OUTPUT);                             // SDライブラリ使用時のお約束 (CSピンの指定)
  while( !SD.begin(4) );                           // ライブラリとSDカードを初期化
  // PWM初期化
  pinMode( 9, OUTPUT);                             // OC1A使用 - Uno(PB1), Leonardo(PB5)ともにD9
  TCCR1A = _BV(COM1A1) | _BV(WGM11);               // 高速PWM (OC1A 非反転)(TOP値:ICR1), 分周なし
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);    //    (COM1A1-0=10, WGM13-0=1110, CS12-0=001)
  ICR1   = 0xFF;                                   // input capture register:TOP値を255(8bit)とする
}

void loop() {
  File dataFile;
  if ( !(dataFile = SD.open( "hoge.wav" )) ) return;   // error opening wavefile
  
  buf_index = 44;  buf_page = 0;  buf_flg = 1;     // パラメータ設定 (44byteはヘッダ)  
  read_size[buf_page] = dataFile.read( (uint8_t*)buf[buf_page], BUF_SIZE );
  TIMSK1 |= _BV(ICIE1);                            // Input Capture Interrupt Enable (ICIE)で割り込み
  while(TIMSK1 & _BV(ICIE1)) {
    if(buf_flg) {     // データ読み込み指令のフラグが立ったら読み込む
      read_size[buf_page ^ 1] = dataFile.read( (uint8_t*)buf[buf_page ^ 1], BUF_SIZE );
      buf_flg = 0;    // 読み込んだらフラグを下ろす
    }
  }
  OCR1AL = 0;
  dataFile.close();
  delay(5000);
}

ISR(TIMER1_CAPT_vect) {                            // タイマ/カウンタ1 捕獲割り込み
  OCR1AL = buf[buf_page][buf_index++];                 // データをPWMとして出力
  if(buf_index == read_size[buf_page]) {               // 現在のバッファの最後まで来たら...
    if(buf_index != BUF_SIZE)  TIMSK1 &= ~_BV(ICIE1);    // ファイルの最後なら,ICIE1をクリア
    buf_index = 0;  buf_page ^= 1;  buf_flg = 1;         // バッファを切り替え
  }
}


せっかくなので、ダ・ヴィンチ32U を使ってみました。
davinci-sd-audio.jpg
写真の圧電サウンダでは音量が足りませんでしたが、100円ショップスピーカを直結(たぶん良くない)したところそこそこの音量が得られました。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。