Аудио плеер на Cortex M0+ через I²S

Платформы Arduino с ядром Cortex-M0+ имеют в своём арсенале интерфейс I²S для передачи и приёма цифровых аудио файлов с другими внешними устройствами. При этом контроллер может спокойно заниматься своими делами и мигать светодиодами.

В качестве примера соберём простой плеер. Для этого подключим к платформе Arduino внешний I²S цифро-аналоговый преобразователь и модули управления.

Что понадобится?

Аудиофайл

Подготовьте файл для воспроизведения:

  1. Скачайте и установите программу для конвертации аудио-форматов «Audacity»
  2. Сконвертируйте требуемый музыкальный файл в формат WAV с характеристиками:
    1. Режим: стерео
    2. Частоте дискретизации: 22050 Гц
    3. Количестве бит в сэмпле: 16 бит
  3. Скопируйте полученный файл на SD-карту.

Как собрать?

Схема для Arduino MKR Zero

Пример кода

Для работы примера — установите библиотеку Arduino Sound из менеджера библиотек.

play-music-i2s.ino
// коммуникация между платформой Arduino MKR Zero и I²S-DAC
// LRC подключите к цифровому пину 3 платы MKR Zero
// BCLK — к пину 2
// DIN — к пину A6 
 
// библиотека для работы с картой памяти
#include <SD.h>
// библиотека для воспроизведение и анализа цифрового звука по I²S
#include <ArduinoSound.h>
// библиотека для работы с кнопками
#include "TroykaButton.h"
 
// имя воспроизводимого файла
const char filename[] = "i2s-m0.wav";
 
// создаём объект для работы с аудио-файлом
SDWaveFile waveFile;
 
// текущее состояние громкости
int volumeMusic = 50;
 
// создаём объект для работы с кнопкой с параметром номер пина
TroykaButton buttonOne(9);
TroykaButton buttonTwo(8);
TroykaButton buttonThree(7);
TroykaButton buttonFour(6);
 
// на плате Arduino MKR Zero флешка подключена к SPI1
// выбираем в качестве пина CS определение SDCARD_SS_PIN
#define SS_PIN SDCARD_SS_PIN
 
void setup() {
  // открываем монитор Serial порта
  Serial.begin(9600);
  // ждём открытия Serial-порта
  while(!Serial);
  // начало работы с кнопками
  buttonOne.begin();
  buttonTwo.begin();
  buttonThree.begin();
  buttonFour.begin();  
  // выводим сообщение в Serial-порт о поиске карты памяти
  Serial.println("Initializing SD card...");
  // если microSD-карта не была обнаружена
  if (!SD.begin(SS_PIN)) {
    // если microSD карта не была обнаружена
    Serial.println("Initialization failed!");
    return;
  }
  // выводим сообщение об успешной поиске карты памяти
  Serial.println("Card initialization is OK");
 
  // создаём SDWaveFile и передаём ему имя воспроизводимого файла
  waveFile = SDWaveFile(filename);
 
  // проверяем допустимость файла
  if (!waveFile) {
    Serial.println("Wave file is invalid!");
    while (1);
  }
 
  // печатаем данные о файле
  Serial.print("Bits per sample = ");
  Serial.println(waveFile.bitsPerSample());
 
  long channels = waveFile.channels();
  Serial.print("Channels = ");
  Serial.println(channels);
 
  long sampleRate = waveFile.sampleRate();
  Serial.print("Sample rate = ");
  Serial.print(sampleRate);
  Serial.println(" Hz");
 
  long duration = waveFile.duration();
  Serial.print("Duration = ");
  Serial.print(duration);
  Serial.println(" seconds");
 
  // выставляем громкость в диапазоне от 0 до 100
  AudioOutI2S.volume(volumeMusic);
 
  // проверяем воспроизводимость файла
  if (!AudioOutI2S.canPlay(waveFile)) {
    Serial.println("Unable to play wave file using I2S!");
    while (1);
  }
 
  // воспроизводим файл
  Serial.println("Playing music from I²S");
  AudioOutI2S.play(waveFile);
}
 
void loop() {
  // считываем данные с кнопок
  buttonOne.read();
  buttonTwo.read();
  buttonThree.read();
  buttonFour.read();
 
  // если есть клик по кнопке S1
  if (buttonOne.justPressed()) {
    // делаем паузу
    Serial.println("Pause music from I²S");
    AudioOutI2S.pause();
  }
 
  // если есть клик по кнопке S2
  if (buttonTwo.justPressed()) {
    if (volumeMusic == 0) {
      Serial.println("Volume is min");
    } else {
      volumeMusic = volumeMusic - 5;
      AudioOutI2S.volume(volumeMusic);
      Serial.print("Volume ");
      Serial.println(volumeMusic);
    }
  }
 
  // если есть клик по кнопке S3
  if (buttonThree.justPressed()) {
    if (volumeMusic == 100) {
      Serial.println("Volume is max");
    } else {
      volumeMusic = volumeMusic + 5;
      AudioOutI2S.volume(volumeMusic);
      Serial.print("Volume ");
      Serial.println(volumeMusic);
    }
  }
 
  // если есть клик по кнопке S4
  if (buttonFour.justPressed()) {
    // воспроизводим файл
    Serial.println("Resume music from I²S");
    AudioOutI2S.resume();
  }
}