RP2040 + audio + play (WIP)¶
RP2040 Memory Overview¶
- Flash Memory: 2 MB
- Used to store program code and static data (like sound_data.h)
- SRAM (RAM): 264 KB total
Opetion 1: mp3 to WAV¶
Why Use WAV Instead of MP3
- Uncompressed format: WAV uses raw PCM data, which can be played directly without decoding.
- No decoder required: Unlike MP3, WAV doesn’t need a software or hardware decoder.
- Lower CPU usage: WAV playback requires minimal processing, ideal for microcontrollers like the RP2040.
- Easy to implement: You can play WAV (PCM) data using simple PWM output code (e.g., analogWrite()).
- Real-time playback: WAV data can be streamed in real-time with low latency.
- Simpler file structure: WAV is easier to parse and convert (e.g., with FFmpeg).
- Better for prototyping and education: Easy to understand, modify, and test in microcontroller environments.
Step 1¶
% ffmpeg -i input.mp3 -ar 22050 -ac 1 -f u8 output.raw
- -ac 1: one audio channel (mono)
- -f u8: 8bit (0–255) unsigned PCM
- output.raw: raw PCM file
What is PCM?
PCM (Pulse Code Modulation = パルス符号変調) is a method used to digitize analog audio signals by sampling them at regular intervals and converting each sample into a numeric value.
- Measures the amplitude (volume level) of the analog wave at fixed intervals
- The resolution of each sample (e.g. 8-bit, 16-bit)
- Raw and uncompressed, resulting in high-quality audio
- WAV files, raw audio (.raw), CD audio, etc.
Note
22,050 samples/sec × 1 byte/sample × 1 channel = 22KB/sec
22KB × 10sec = 220KB
- Total Flash: 2 MB = 2,048 KB
- Some space used for your program and system code (~100–300 KB)
- Safe usable space for audio data (C arrays): ~1.7 MB (1,700 KB) $$ \frac{1700 \text{ KB}}{22 \text{ KB/sec}} ≈ 77 \text{ sec} $$
Step 2¶
% xxd -i output.raw > sound_data.h
Note
xxd is a command-line tool that converts binary files into hexadecimal (hex) and/or C language array format.
It’s commonly used on Linux and macOS (pre-installed), and also available for Windows with a little setup.
% xxd --version
xxd 2024-09-15 by Juergen Weigert et al.
Step 3¶
#include "sound_data.h"
const int audioPin = 0; // PWM output pin (GPIO 0–11 on XIAO RP2040)
const int sampleRate = 22050; // Sampling rate in Hz
void setup() {
analogWriteFreq(sampleRate); // Set PWM frequency (specific to XIAO RP2040)
analogWriteResolution(8); // Set PWM resolution to 8-bit (matches u8 audio data)
pinMode(audioPin, OUTPUT);
Serial.begin(115200); // Start serial communication for Serial Plotter
while (!Serial); // Wait for Serial to be ready (important for some boards)
}
void loop() {
for (unsigned int i = 0; i < output_raw_len; i++) {
uint8_t sample = output_raw[i];
analogWrite(audioPin, sample); // Output sample via PWM
Serial.println(sample); // Send sample to Serial Plotter
delayMicroseconds(1000000 / sampleRate); // Delay between samples
}
delay(1000); // Wait 1 second before repeating the playback
}
% cd to/the/folder
% tree
├── thisCode.ino
└── sound_data.h
output.raw
sound_data.h
thisCode.ino
Step 4¶
To convert the PWM signal from the RP2040 into an analog audio-like signal, an RC filter (resistor + capacitor) is used to reduce noise and smooth the waveform.
PWM Output → [1kΩ] →───┬──→ [Speaker(+)]
│
[0.1µF]
│
GND────→ [Speaker(-)]
Step 5¶
Low side switching with an N-channel MOSFET
5V
│
[Speaker(+)]──┐
[Speaker]
[Speaker(-)]──┘
│
Drain
PWM Output ── [50Ω] ─┬─ Gate [N-MOSFET]
│ Source
[10kΩ] │
│ │
GND GND
Advantages of Low Side Switching Compared to High Side Switching
High side switch:
A switch (such as a MOSFET) is placed between the power supply (Vcc) and the load.
Low side switch:
A switch is placed between the load and ground (GND).
Simpler Gate Drive:
Low side switches are much easier to drive because the control signal can be referenced directly to ground. No level shifting or charge pump circuits are needed, unlike high side N-channel MOSFETs, which require the gate voltage to be higher than the supply voltage.
Lower Cost and Complexity:
The circuit is less complex and typically cheaper, since you can use standard N-channel MOSFETs and drive them directly from microcontroller outputs without extra components.
Better Performance (Lower Losses):
N-channel MOSFETs used on the low side generally have lower on-resistance (Rds(on)) and can handle higher currents than P-channel MOSFETs or high side configurations. This results in less power loss and better efficiency, especially for high-current loads.
Robustness to Ground Noise:
Low side switching is more robust against ground noise and avoids ground potential differences between the load and controller, which is important in systems with high currents.
Easier to Find Suitable Components:
There are more options and availability for low side drivers and N-channel MOSFETs, making design and sourcing easier.
Low side switching with an N-channel MOSFET is generally easier, cheaper, and more efficient than high side switching, unless your application specifically requires the load’s ground to remain uninterrupted or has special safety requirements