Generate audio output for a speaker for Particle devices (Photon, Electron)
Connect a speaker amplifier like
this one from Adafruit to the
digital to analog converter DAC
pin of a Photon or Electron and run
this code to play a sawtooth wave. Optional stereo playback is
available via a second DAC
, pin A3 on the Photon or Electron.
#include "speaker.h"
uint16_t bufferSize = 128;
Speaker speaker(bufferSize);
void setup() {
uint16_t audioFrequency = 22050; // Hz
speaker.begin(audioFrequency);
}
uint16_t audioSignal = 0;
void loop() {
if (speaker.ready()) {
uint16_t *buffer = speaker.getBuffer();
// Produces a 1 kHz sawtooth wave
for (uint16_t i = 0; i < bufferSize; i++) {
buffer[i] = audioSignal;
audioSignal += 2267;
if (audioSignal > 50000) {
audioSignal = 0;
}
}
}
}
A 1 kHz sawtooth signal played from a Photon
See complete example in the examples directory.
See another example for stereo operation.
Speaker speaker(bufferSize);
Creates a speaker object with 2 buffers of the same size (double buffering).
While the library plays the sound in one buffer your application fills the second one.
The larger the buffer, the more delay there will be in between your application filling a buffer and it being played. The shorter the buffer, the less time your code has to fill the next buffer. Short buffers work best for real-time audio synthesis and longer buffer for playback from an SD card.
The application has bufferSize / audioFrequency
seconds to fill the next buffer. For example, this is 2.9 ms at 44100 Hz with a 128 sample buffer.
The copy from memory to the DAC(s) is done using direct memory access (DMA) so the CPU is free to do other tasks.
speaker.begin(audioFrequency);
Sets up the DAC
pin(s) and TIM6
timer to trigger at the correct audio freqency. Common frequencies are 44100 Hz, 22050 Hz, 11025 Hz and 8000 Hz.
Starts playing the content of the buffer immediately so you may want to fill the audio buffer before calling speaker.begin
. The buffer is zero by default so not filling the buffer first would still be OK.
Note: Do not call analogWrite(DAC, ...);
when using this library since it completely takes over the DAC peripheral.`
speaker.end();
Stops the audio playback.
bool readyForMoreAudio = speaker.ready();
Returns true
once when the audio buffer is ready to be filled with more audio samples. Will return false
when called again until the buffer has finished playing.
uint16_t *buffer = speaker.getBuffer();
Returns a pointer to an array of bufferSize
audio samples.
The audio samples are 16 bit integers but the DAC on the Photon and Electron only has 12 bits to the least significant 4 bits are ignored.
You must only write to this array when speaker.ready()
is true
.
uint32_t *buffer = speaker.getStereoBuffer();
Returns a pointer to an array of bufferSize
stereo audio
samples, packed with the upper 16-bits for DAC2 and the lower
16-bits for DAC1. The lower 4 bits of each channel are ignored.
You must only write to this array when speaker.ready()
is true
.
This library uses the DAC1
digital to analog converter, TIM6
basic
timer and DMA1
stream 5 direct memory access. For stereo operation
DAC2
is also used.
Read the STM Application note AN3126 - Audio and waveform generation using the DAC in STM32 microcontrollers for more background on using the DAC and DMA for audio generation.
Copyright 2016 Julien Vanier
Released under the MIT license