Thanks for the tips.
It seems like I’ve tried everything at this point, pin combinations etc, but will test with a good battery soon to see if power supply makes the difference.
Thanks for the tips.
It seems like I’ve tried everything at this point, pin combinations etc, but will test with a good battery soon to see if power supply makes the difference.
Still no luck testing from battery.
One odd behaviour is that it gets better with higher quality audio. With 44khz samples, I can almost make out the music/sounds. With 16khz samples its just pure distortion.
Really not sure where to go on this one, I get similar results from all the code I’ve tried…
Hi there,
Can you post a picture of how it is connected and the exact code you are trying?
Which BSP are you using and could you post the compiler output (first 3 lines & last 10 or so) before the upload.
You’ll need to have verbose mode checked in the prefrences.
HTH
GL PJ
Well I’ve tried a lot of different code.
I’ve tried:
To switch to I2S I just un-comment #define USE_I2s in /src/NRF52840/AutoAnalogAudio.cpp
Essentially I can do this with 0 components connected to the XIAO, just an amp, with the XIAO connect to a grove shield etc, so a picture is kind of moot. It is very unlikely to have anything to do with the wiring etc.
I am just using either the MBED or non-MBED core for Arduino via the Arduino IDE v2.3.3. It should work either way.
Exact code I am using: (Just threw this together tonight)
#include <SPI.h>
#include <SD.h>
#include <AutoAnalogAudio.h>
AutoAnalog aaAudio;
/*********************************************************/
/*********************************************************/
uint8_t bigBuffer[16000 * 5];
uint16_t sampleCounter = 0;
bool started = 0;
void setup() {
Serial.begin(115200);
Serial.print("Init SD card...");
if (!SD.begin(4)) {
Serial.println("init failed!");
return;
}
Serial.println("init ok");
Serial.println("Analog Audio Begin");
playAudio("calibrat.wav");
}
void loop() {
loadBuffer();
}
/*********************************************************/
/* A simple function to handle playing audio files
/*********************************************************/
File myFile;
void playAudio(char *audioFile) {
if (myFile) {
myFile.close();
}
//Open the designated file
myFile = SD.open(audioFile);
//Skip past the WAV header
myFile.seek(44);
for (int i = 0; i < (16000 * 5); i++) {
bigBuffer[i] = myFile.read();
}
sampleCounter = 0;
loadBuffer();
if (myFile) {
myFile.close();
}
}
void loadBuffer() {
if (sampleCounter < (16000 * 5)) {
for (int i = 0; i < 32; i++) {
aaAudio.dacBuffer[i] = bigBuffer[sampleCounter];
sampleCounter++;
}
if (!started) {
aaAudio.begin(0, 1); //Setup aaAudio using DAC
aaAudio.autoAdjust = 0;
//Setup for audio at 8-bit, 16khz, mono
aaAudio.dacBitsPerSample = 8;
aaAudio.setSampleRate(16000);
started = true;
}
aaAudio.feedDAC(0, 32);
}
}
FQBN: Seeeduino:nrf52:xiaonRF52840Sense
Using board 'xiaonRF52840Sense' from platform in folder: C:\Users\Owner\AppData\Local\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.8
Using core 'nRF5' from platform in folder: C:\Users\Owner\AppData\Local\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.8
Using library SPI at version 1.0 in folder: C:\Users\Owner\AppData\Local\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.8\libraries\SPI
Using library SD at version 1.2.4 in folder: C:\Users\Owner\AppData\Local\Arduino15\libraries\SD
Using library AutoAnalogAudio at version 1.50.0 in folder: C:\Users\Owner\OneDrive\Documents\Arduino\libraries\AutoAnalogAudio
Using library Adafruit TinyUSB Library at version 1.7.0 in folder: C:\Users\Owner\AppData\Local\Arduino15\packages\Seeeduino\hardware\nrf52\1.1.8\libraries\Adafruit_TinyUSB_Arduino
"C:\\Users\\Owner\\AppData\\Local\\Arduino15\\packages\\Seeeduino\\tools\\arm-none-eabi-gcc\\9-2019q4/bin/arm-none-eabi-size" -A "C:\\Users\\Owner\\AppData\\Local\\Temp\\arduino\\sketches\\1A7D6B52BE3303E647113F8158A60093/XIAO-I2s-Oct2024.ino.elf"
Sketch uses 53048 bytes (6%) of program storage space. Maximum is 811008 bytes.
Global variables use 110408 bytes (46%) of dynamic memory, leaving 127160 bytes for local variables. Maximum is 237568 bytes.
Upgrading target on COM30 with DFU package C:\Users\Owner\AppData\Local\Temp\arduino\sketches\1A7D6B52BE3303E647113F8158A60093\XIAO-I2s-Oct2024.ino.zip. Flow control is disabled, Single bank, Touch disabled
########################################
########################################
########################
Activating new firmware
Device programmed.
Also tested with the following code using the nRF52Audio library with similar non-working results.
#include "Arduino.h"
#include <nRF52Audio.h>
#define PIN_I2S_MCK 14
#define PIN_I2S_BCLK 13 // A4
#define PIN_I2S_LRCK 15 // A5
#define PIN_I2S_DIN 11 // A6
#define PIN_I2S_SD 5 // 27
#define PIN_SPI_CS 4
#define PIN_SCL 16
#define PIN_SDA 15
//Plays a single wave file until it ends
void PlayWavFile()
{
//Wav files to play. Change "22CANT1.WAV" to match the name of
//whatever file you are playing.
SDWavFile* lpWavFile1 = new SDWavFile("M16b24kS.WAV");
//Create a new I2S Player
I2SWavPlayer* lpPlayer = new I2SWavPlayer(PIN_I2S_MCK,
PIN_I2S_BCLK,
PIN_I2S_LRCK,
PIN_I2S_DIN,
PIN_I2S_SD);
lpPlayer->Init(); //Initializes I2S playback hardware
lpPlayer->Configure_I2S_Speed(ee2205); //Set I2S clock speed (sample rate of the file)
//ee2205 = 22.05KHz
//ee4410 = 44.1KHz
lpPlayer->SetWavFile(lpWavFile1); //Set file object to play
lpPlayer->SetVolume(0.5); //set master volume, 0.0 (mute) to 1.0 (full volume)
lpPlayer->StartPlayback(); //Begin playing the wave file
Serial.println("Playback started.");
//Keep playing as long as playback hasn't ended
while(false == lpPlayer->ContinuePlayback())
{
//Wait for playback to end
}
//Cleanup code
Serial.println("Playback ended.");
lpPlayer->StopPlayback();
lpWavFile1->Close();
}
//The setup function is called once at startup of the sketch
void setup()
{
delay(1000);
Serial.begin(115200);
//Initialize SD card. Make sure to do this before creating any SDWavFile objects or
//trying to play anything or we won't be able to read the data from the SD card
}
// The loop function is called in an endless loop
void loop()
{
Serial.println("ok");
delay(1000);
if(Serial.available()){
char c = Serial.read();
if(c == 'p'){
if(!SD.begin(8000000, PIN_SPI_CS))
{
Serial.println("SD init failed.");
//return; //Punt. We can't work without SD card
}
Serial.println("SD init completed.");
PlayWavFile();
}
}
}
Here is an example just using the PDM microphone:
#include <AutoAnalogAudio.h>
AutoAnalog aaAudio;
void setup() {
Serial.begin(115200);
aaAudio.begin(1, 1); //Setup aaAudio using DAC
aaAudio.autoAdjust = 0;
aaAudio.adcBitsPerSample = 16;
aaAudio.dacBitsPerSample = 16;
aaAudio.setSampleRate(16000);
}
void loop() {
aaAudio.getADC(32);
for(int i=0; i<32; i++){
aaAudio.dacBuffer16[i] = aaAudio.adcBuffer16[i];
}
aaAudio.feedDAC(0,32);
}
Hi there,
LOL, If I had a dollar for the many times I’ve heard that statement. OK we’ll go with your web cam is broken.
The code posted compiles with mbed 2.9.2
I see your example is using the Non-Mbed 1.1.8 so given that and only that! I would say have you tried rolling it back to the BSP that was used in the original example your using? I would try 1.1.1 in Non-Mbed and the 2.8.1 of Mbed BSP’s and work forward, You should pick a code set and troubleshoot it , as you see the Throw everything you know at once at it, isn’t the way to go and yield the results your currently getting.
Start with the pin Numbers. Use the GPIO pin names. Are you using the dev board or bare chip and amp ? which? Stay with the I2S pins and code leave the PWM stuff alone that’s not what your wanting, correct?
Take a look at this video… The I2S portion will show you some stuff.
he walks through the code which will give you a better understanding of the tasks execution.
HTH
GL PJ
try that stuff and or wiring and let us know.
Can you attach a zip file with the WAV file or Audio you are attempting to play ?
Hi TMRh20Projects,
nRF52_SimpleWavPlayer.ino from the nRF52Audio library works fine with the MAX98357A breakout board. BSP is mbed 2.9.2 or non-mbed 1.1.8.
Please define the pins as follows.
// XIAO pin --> MAX98357A pin
#define PIN_I2S_MCK 2 // D0 P0_02 2 D0 not use
#define PIN_I2S_BCLK 3 // D1 P0_03 3 D1 BCLK
#define PIN_I2S_LRCK 29 // D3 P0_29 29 D3 LRC
#define PIN_I2S_DIN 4 // D4 P0_04 4 D4 DIN
#define PIN_I2S_SD 5 // D5 P0_05 5 D5 SD
EDIT:
It certainly seems to distort in the louder parts of the sound as you describe.
@msfujino After all that time it now works! Could have sworn I tried these pins before, but now I even got it working with my own library via SD playback as well as microphone!
I knew it had to be something simple, but wow! Thanks for the help folks!
Cha_ching…Glad you got it going a picture is always worth a thousand words.
GL PJ
Hehe, I knew the ‘I told you so’ was coming as soon as I got it working. Thx again for the help!
I found at least a part of my problem was using too small of buffer sizes. This just added to the distortion:
I didn’t realize, but with I2S I had to increase my default buffer size to 6400 (12800 bytes in 16-bit mode) from 1600 (3200 bytes in 16-bit mode) in order to get things working properly.
It also seems that 24kHz samples @ 16-bits is about the maximum the system can handle when reading from SD card (Standard SD lib & FAT16).
In the end I’m choosing to keep PWM as the default output method since it requires only small buffer sizes, and is good enough for voice over radio. I2S can be toggled on/off by advanced users by adding to the begin(0,1,1);
method with the third item specifying whether I2S output is enabled or not. This will allow extension of I2S to include microphones as well eventually by specifying a 2 or 3 for the 3rd option.
My AutoAnalogAudio lib now supports 8 or 16-bit samples @ anywhere from 16khz, 24khz, 32khz or 44khz with I2S! As usual, I published the code I have, but won’t do a release until its ready so peeps need to install from ZIP to try I2S functionality. I will probably put together a couple examples for the 52840 also!
Hi there,
Nice Work LOL , thank you for contributing too…
We all benefit by it.
GL PJ
Hi TMRh20Projects,
I downloaded and installed “AutoAnalogAudio v1.51.0” from Github and tried “NRF52_SD_Playback_Auto.ino".
I have XIAO nRF52840 connected to MAX98357A breakout board and am trying to playback the attached wav file.
When use volumeControl = 0.2; all I get is a loud noise.
If I use ‘=’ and increase the volume to 0.8, the sound comes out normally. Then, once the sound comes out normally, using ‘-’ to lower the volume will also produce normal sound.
Is there a solution?
WavFile.zip (2.0 MB)
Yes!
I messed up on the volume control in that sketch, per nRF52: Fix volume control in example · TMRh20/AutoAnalogAudio@1717717 · GitHub
At the very bottom of the sketch, change the following:
aaAudio.dacBuffer16[i] += 0x8000;
aaAudio.dacBuffer16[i] *= volumeControl;
aaAudio.dacBuffer16[i] -= 0x8000;
to
int16_t sample = aaAudio.dacBuffer16[i];
sample *= volumeControl;
aaAudio.dacBuffer16[i] = (uint16_t)sample;
There are a couple other quirks I’ve worked out since the latest release, you can see here Comparing v1.51.0...master · TMRh20/AutoAnalogAudio · GitHub
Installing from ZIP provides the latest changes.
Edit to add:
I noticed your wav file seems to be 16-bit, 16khz, Stereo, which is probably a little too high quality for reading via SD card per my tests. 16-bit, 16kHz, mono seems to give the best results for me. You would think the XIAO would have faster SPI speeds, but SD card reading doesn’t seem to be the fastest.
The latest ZIP file is installed. I can now play it without problem. Thank you very much.
I also tried 16bit 22kHz stereo, checking with a digital oscilloscope to see if there is enough room to read data from SD, but it seems to be in time. The BSP used is non-mbed and the SPI clock is 32 MHz (waveform confirmed).
Aha, thank you for testing! The non-mbed BSP seems to be much faster! Did not realize that. This allows for much higher quality audio which is very nice!
If you use mbed for BSP, the SPI clock is only 8MHz even if you set SD.begin(SD_CS, 32000000).
Please also refer to the following link.
Good info. Too bad tho, I am liking the standard Arduino BLE library which only seems to work with the mbed core. Will have to play around more with this stuff and see what is possible!
Hi there,
Lurking hard on this thread, but I’m pretty sure you can make the jump to the blufruit BLE or even NimBLE and get the same or better features. You could consider the NRF_SDK also that is PHAT when it comes to everything. The learning your way around is a small curve but it has a lot to offer also.
@msfujino has the receipts when it comes to power and the cores who’s what! a.k.a. the PowerNinja I saved a major improvement and extended battery life (a day to weeks) switching. I was a PITCA but worth every minute (PainInTheChairA$$)
Meanwhile I grabbed a stereo version DAC/amp and will be testing with this.
# CJMCU-1334 DAC Module
CJMCU-1334 UDA1334A I2S DAC Audio Stereo Decoder Module Board for 3.3V - 5V
Hat tip to both of you.
GL PJ
I like to focus on designing and maintaining Arduino libraries, but probably HAVE to look at the SDK now that I’m getting right into things. That will be for another day, as I’ve spent too much time programming already today.
I just did another release of my library, v1.51.1 due to a bunch of important bug-fixes, so I’m bound to find a few more bugs soon lol.
I also got sick of monkeying around with the SD_Auto example and added BLE control examples using either Arduino BLE or Bluefruit BLE. It only has playback and volume controls, but saves me from having to re-upload to test out different sample rates etc. It wasn’t too hard switching to bluefruit after all, and the performance/quality on non-mbed is definitely better.
Pins can also now be defined before calling begin();
Example: aaAudio.I2S_PIN_LRCK = 28; aaAudio.I2S_PORT_LRCK = 0;
Pretty nice having testers for this hehe. Please advise if you find any issues or bugs!
Ahnn great info and useful fr…