Showing posts with label AAAudio. Show all posts
Showing posts with label AAAudio. Show all posts

Monday

AutoAnalogAudio Library - nRF52 Now supports Successive Approximation Analog-to-Digital Converter for Audio Input

 AutoAnalogAudio Library - nRF52 Now supports SAADC

Support for Successive Approximation Analog-to-Digital Converter for Audio Input

I've been doing a lot of work on my AAAudio library lately in regards to nRF52 devices like the XIAO BLE SENSE 52840 or the Feather Express 52840, and just added support for the onboard SAADC. This allows users to capture input audio from a regular analog microphone instead of requiring I2S or PDM. 

After having developed support for PDM, PWM and I2S, this wasn't too complicated. I've grown to understand the nRF52 interface, which is really nice and user friendly, and the documentation is great.



To use the SAADC interface start up analog audio by calling the following:

aaAudio.dinPin = 1; //Where 1 represents the AIN0, 2 represents AIN1, etc...
aaAudio.begin(3, 1); // Where 3 represents enabling of SAADC, 1 is for PWM output



All in all the SAADC seems to work very well! I am still doing initial testing & code review, but the changes have been pushed to GitHub as usual. Users can install from ZIP to test out the new code, or wait until the next release.

Tuesday

AutoAnalogAudio Library: New examples for nRF52x including a BLE controlled Audio Player

 AutoAnalogAudio Library Updates for nRF52x:

 New examples for nRF52x & a BLE controlled Audio Player

With recent updates to the AutoAnalogAudio library, I've been able to put together a bunch of examples specific to the nRF52x platforms. The examples range from examples that use the onboard PDM microphone capabilities and either an I2S or Analog (PWM output) amplifier to a BLE controlled Audio Player.




The examples also demonstrate usage of the radio capabilities as well, using the radio either at a low level (nrf_to_nrf library), capable of streaming very high-quality audio or using BLE control to playback audio from SD card. 

When recording via PDM and either re-playing to an amplifier or broadcasting via radio, fairly high sample-rates can be used along with 16-bit modes, making for very decent quality wireless audio. There are some limitations when reading from SD card, as it seems the max SPI speed on these devices isn't that fast, so users need to play around with sample rates, stereo/mono modes and 8 or 16-bit samples.

Once the AutoAnalogAudio library is installed, the nRF52x examples can be found in Arduino examples under AutoAnalogAudio/Platforms/NRF52

XIAO BLE Sense 52840 used for testing


The BLE controlled audio player uses a bunch of different peripherals and pushes the capabilities of the device a bit, but it seems to work great. I've created another example using the Adafruit Bluefruit library as well, which supports faster SD reading & higher quality playback, which I will also include in the library soon. 

Here is the current code using the standard Arduino BLE library:

/* Arduino BLE control
led Audio Player for nRF52

 *
 * This is an example of me playing around with BLE control and different
 * services/characteristics to test the AutoAnalogAudio library.
 *
 * Requirements:
 * 1. nRF52 Device (Tested on nRF52840)
*  2. SD Card with WAV files: 8-bit, 16-24kHz, Mono
 * 3. I2S or Analog Amplifier + Speaker connected
 * 4. Mobile device or 'other' with nRF Connect installed
 *
 * Connect via nRF Connect App:
 * 1. Device should come up as BLE Audio Player
 * 2. You should see:
 *   a: Common Audio
*    b: Audio Input Type:
      Send a UTF-8 String to play a file: myfileDirectory/myfilename.wav
 *   c: Audio Input Control Point:
      Send an Unsigned value between 0-10 to set the volume low-high
 */


#include <SPI.h>
#include <SD.h>
#include <ArduinoBLE.h>
#include <AutoAnalogAudio.h>

AutoAnalog aaAudio;

/************** USER CONFIG ***********/
// File to play on startup
const char* audioFilename = "far8b16k.wav";  // 8-bit @ 24kHz audio is the max over SD card while BLE is running
uint8_t SD_CS_PIN = 2;                       // Set this to your CS pin for the SD card/module
#define USE_I2S 1                            // Set this to 0 for analog (PWM) audio output instead of I2S

/*********************************************************/
/* Tested with MAX98357A I2S breakout
/* BCLK connected to Arduino D1 (p0.03)
/* LRCK connected to Arduino D3 (p0.29)
/* DIN  connected to Arduino D5 (p0.05)
/* SD   connected to Arduino D6 (p1.11)
/*********************************************************/

#define FILENAME_BUFFER_LENGTH 64
char songName[FILENAME_BUFFER_LENGTH];
float volumeControl = 0.2;
#define AUDIO_BUFFER_SIZE 1600

BLEService audioService("1853");

// BLE Audio Charactaristic
BLECharacteristic audioDataCharacteristic("2b79", BLERead | BLEWrite | BLENotify, FILENAME_BUFFER_LENGTH);
BLEByteCharacteristic audioVolumeCharactaristic("2b7b", BLERead | BLEWrite);

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);

  aaAudio.begin(0, 1, USE_I2S);  //Setup aaAudio using DAC and I2S or PWM

  // BLE initialization
  if (!BLE.begin()) {
    Serial.println("Starting BLE failed!");
    while (1) {};
  }

  BLE.setLocalName("BLE Audio Player");
  BLE.setAdvertisedService(audioService);

  audioService.addCharacteristic(audioDataCharacteristic);
  audioService.addCharacteristic(audioVolumeCharactaristic);
  BLE.addService(audioService);

  BLE.advertise();
  Serial.println("BLE Peripheral is now advertising");

  Serial.print("Init SD card...");
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("init failed!");
    return;
  }
  Serial.println("SD init ok");
  pinMode(6, OUTPUT);  //Connected to SD pin of MAX98357A
  digitalWrite(6, HIGH);

  playAudio(audioFilename);
}

void loop() {

  BLEDevice central = BLE.central();

  if (central) {

    if (central.connected()) {
      if (audioDataCharacteristic.written()) {
        memset(songName, 0, sizeof(songName));
        audioDataCharacteristic.readValue((uint8_t*)songName, FILENAME_BUFFER_LENGTH);
        playAudio(songName);
        Serial.println(songName);
      }
      if (audioVolumeCharactaristic.written()) {
        uint8_t vol;
        audioVolumeCharactaristic.readValue(vol);
        volumeControl = vol / 10.0;
        Serial.print("BLE Set Volume: ");
        Serial.println(volumeControl);
      }
    }
  }

  loadBuffer();

  // Control via Serial for testing
  if (Serial.available()) {
    char c = Serial.read();
    if (c == '=') {
      volumeControl += 0.1;
    } else if (c == '-') {
      volumeControl -= 0.1;
      volumeControl = max(0.0, volumeControl);
    } else if (c == 'p') {
      playAudio("brick/brick24.wav");
    }
    Serial.println(volumeControl);
  }
}

/*********************************************************/
/* A simple function to handle playing audio files
/*********************************************************/

File myFile;

void playAudio(const char* audioFile) {

  if (myFile) {
    myFile.close();
  }
  //Open the designated file
  myFile = SD.open(audioFile);

  myFile.seek(22);
  uint16_t var;
  uint32_t var2;
  myFile.read(&var, 2);   // Get channels (Stereo or Mono)
  myFile.read(&var2, 4);  // Get Sample Rate
  aaAudio.setSampleRate(var2, var - 1);

  myFile.seek(34);
  myFile.read(&var, 2);  // Get Bits Per Sample
  aaAudio.dacBitsPerSample = var;

  myFile.seek(44);  //Skip past the WAV header
}

void loadBuffer() {

  if (myFile.available()) {

    if (aaAudio.dacBitsPerSample == 8) {
      myFile.read(aaAudio.dacBuffer, AUDIO_BUFFER_SIZE);
      for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE; i++) {
        aaAudio.dacBuffer[i] *= volumeControl;
      }
      aaAudio.feedDAC(0, AUDIO_BUFFER_SIZE);
    } else {
      myFile.read(aaAudio.dacBuffer16, AUDIO_BUFFER_SIZE);
      for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE / 2; i++) {
        int16_t sample = aaAudio.dacBuffer16[i];
        sample *= volumeControl;
        aaAudio.dacBuffer16[i] = (uint16_t)sample;
      }
      aaAudio.feedDAC(0, AUDIO_BUFFER_SIZE / 2);
    }

  } else {
    myFile.seek(44);
  }
}



Thursday

AutoAnalogAudio Library & I2S Output Now Working on nRF52840

 AutoAnalogAudio Library & I2S Output Now Working on nRF52840

Playing around with high quality audio on the XIAO Sense 52840

Its been a while since my last post regarding I2S audio on the nRF52840, but I finally got it working!

It came down to too small of buffer sizes, plus incorrect pins used for the MAX98357A breakout board. Now that the main problems are figured out, I have it working. There are still some issues with buffering, as there are small clicks or pops here or there throughout playback if the buffer sizes are too small.



To get it working with the current code from GitHub users need to enable I2S by calling the begin(); function a little differently:

aaAudio.begin(0, 1, 1);  //Setup aaAudio using DAC and I2S

This example enables the 'DAC' output using I2S within the AutoAnalogAudio library.

Valid sample rates have now been modified to standard sample rates: 16kHz, 24kHz, 32kHz & 44kHz. These are the only accepted sample rates.

I've decided to leave the PWM output as the default behavior since it is simpler in nature, gives good results and works OK with smaller buffer sizes. This is important when transmitting or receiving audio over radio link, since you need pretty large buffers with I2S.

Users can set the I2S pins prior to calling the begin() function for other boards that use different pins.

aaAudio.I2S_PIN_LRCK = 28;

Default Arduino Pin-Out for MAX98357A on XIAO Sense 52840:

BCLK: D1 (P0.03)

LRCK: D3 (P0.29)

DIN: D5 (P0.05)

SD Pin needs to be set HIGH for left output

GAIN: VIN

Use buffer sizes from 3200 to 6400 samples with higher sample rates / bit-rates.

Sunday

Recording and Playback of Audio on the XIAO NRF52840 Sense - Auto Analog Audio

 Recording and Playback of Audio on the XIAO NRF52840 Sense

Auto Analog Audio Library

So I've been struggling with the I2S interface of the NRF52 devices, and have given up for the time-being trying to get it to work properly. In the meantime I've made some decent headway with the PWM interface and reproducing audio that way. This is similar to the TMRpcm library for AVR devices, which also uses Pulse-Width-Modulation to reproduce audio. 

So far the AutoAnalogAudio library is in a very basic but functional state with an included example to demonstrate how to record and playback audio on the XIAO 52840 Sense. It is designed to input audio from the PDM microphone directly and output using Pin5 of the XIAO board via PWM. The audio signal is 16-bit, 16kHz audio, so of reasonable quality, and cannot currently be modified. The code is still in its infancy.

This makes it easy to record and transmit audio over radio link, since with the nrf_to_nrf radio library, users can broadcast the audio to another device very easily. 

There are still a few problems with it, mainly some synchronization issues, which result in a clicking sound when audio is fed directly from the microphone into the PWM output (Amp & Speaker). I'm not quite sure how to resolve it currently, so will leave things as-is. Update: Adjusting the timers slightly to make the PWM a bit slower than PDM input results in a smooth output signal.

A new release will not be made for a little while, so to try it out, just install the AAAudio library directly from ZIP. See GitHub at  https://github.com/TMRh20/AutoAnalogAudio 

Saturday

AutoAnalogAudio Arduino Library: Updated with recording support for XIAO Sense via PDM

 AutoAnalogAudio Arduino Library

Updated with recording support for XIAO BLE SENSE - NRF52840 via PDM microphone

Its been a while since I received my first NRF52840 device, and I finally got around to publishing what I have so far with the AAAudio libray. The XIAO Sense board that I have has a built in PDM microphone, so I managed to get it working with AAAudio. The results are pretty good, I tested it as a wireless microphone and it seems to hold up well. This is all kind of preliminary, full functionality isn't quite there yet, but it does function.

I've struggled with getting I2S output to work so far, but eventually I should be able to figure it out. There seems to be some sort of problem with it, I would like to blame the board and say it just won't work properly, but there is probably something I'm missing in the code.

In any case, the library has been updated, but it will probably be a while before I do an official release, so users will have to get the source code directly from GitHub.

https://github.com/TMRh20/AutoAnalogAudio/archive/refs/heads/master.zip



AutoAnalogAudio Library - nRF52 Now supports Successive Approximation Analog-to-Digital Converter for Audio Input

 AutoAnalogAudio Library - nRF52 Now supports SAADC Support for Successive Approximation Analog-to-Digital Converter for Audio Input I'v...