Saturday

Asynchronous WAV/PCM: Arduino Audio Library Update:

 This library allows asynchronous playback of WAV files using only an Arduino, SD module, and a speaker.

 A little while ago, I decided to create a library for simple wav file playback using an Arduino, since I couldn't find any that fit my needs

Logical Functionality: 

I posted two previous versions of this libary, one that used a buffer, and one that used interrupts to load the data. Each had its tradeoffs, and neither were perfect. The interrupt based version had noticeable sound quality issues, and the buffering version could not be easily stopped during playback, or the volume adjusted, etc.
 The problem as I understand it, is that a read from the SD card will actually read 512 bytes at a time, so the buffering interrupt would not always complete before the music interrupt was set to trigger next. Since only 1 interrupt will trigger at a time, timing was an issue and so created other issues.

Searching through the datasheet for some functionality that would allow me to do what I wanted, I stumbled across mention of 'nested' interrupts. It took a little bit of time to figure out exactly how to use them in this application, but here is a brief overview of how the timer and interrupts work together:

OVF: This is an interrupt overflow vector that is triggered everytime the timer 'overflows'. (every cycle) Here, it reads a byte from the buffer into OCR1A, and therefore changes the pwm duty every cycle (@16khz)

COMPB: This is an interrupt compare match vector that is triggered when compare match is made during the timing cycle (TCNT1 == ICR1). This interrupt vector is used to read data into the buffers. Can be interrupted by other interrupts via 'nested interrupts'.

a: Interrupt vectors enabled: OVF, COMPB
b: When COMPB is triggered, it disables itself, but leaves OVF enabled. Global interrupts are automatically disabled while an interrupt completes. To enable nested interrupts, global interrupts are enabled manually before reading from the SD card.
c: If ready to buffer data, it begins (OVF can now interrupt COMPB while it bufferrs data)
d: COMPB completes, and re-enables itself to trigger again while it waits to buffer more data

Thanks to nested interrupts, I finally have what I wanted, with the basic functionality one would expect. I think the code can still use a bit of tweaking though, since I haven't fully tested its limits.

Updated Features:
- Sound Quality/Distortion issues have been resolved
- Uses a single timer (timer1)
- Asynchronous (interrupt driven) playback and buffering allows other code to run while music plays 

iTunes Conversion: 
a: Click Edit > Preferences > Import Settings
b: Change the dropdown to WAV Encoder and Setting: Custom > 16.000kHz, 8-bit, Mono

c: Right click any file in iTunes, and select "Create WAV Version"

d: Copy file to SD card using computer

Function Usage:
tmrpcm.play("filename"); //plays a file
tmrpcm.speakerPin = 11; // set to 11 for Mega, 9 for Uno, Nano, etc
tmrpcm.volume(1); //raises or lowers the volume: 1 or -1
tmrpcm.disable(); //disables the timer on output pin and stops the music
tmrpcm.stopPlayback(); //stops the music, but leaves the timer running

Individual Files:

Library Package:
TMRpcm.zip (OLD)
(now hosted on GitHub here)

Updated: 
Added Functionality:
Automatic detection of sample rate (8000 - 22000Hz)
WAV format verification
Memory buffer 300 bytes
Phase/Frequency-Correct and Fast PWM modes
 
Added functions: 
tmrpcm.isPlaying();  //returns 1 if music playing, 0 if not
tmrpcm.pause();  //pauses/unpauses playback
tmrpcm.pwmMode = 1; //set to 1 for phase/frequency correct mode, 0 for fast pwm 
tmrpcm.volume(0); //CHANGED from prev version, now uses either a 1(up) or 0(down)

Tested with: Arduino Nano/328 and Mega2560 
TMRpcm.zip  (OLD)

(Current version on GitHub here)

Auto Analog Audio & NRF52840: Now working on non-Mbed cores

 Auto Analog Audio & NRF52840: Now working on non-Mbed cores Playing around with the AAAudio library So I finally decided to make the ne...