Pico Audio Sampler: Real-Time Microphone Capture with and without DMA
Motivation
This project began as an exploration of real-time analog audio capture using a Raspberry Pi Pico and a basic electret microphone. I wanted to compare traditional CPU-based analog sampling (using polling) with a more efficient, interrupt-driven system using DMA (Direct Memory Access). My goal was to understand the tradeoffs between simplicity and performance in embedded systems — especially when working with constrained microcontrollers — and to lay the groundwork for future signal processing or ML-based audio interaction.
This project was developed for a Human-Computer Interaction Engineering course as a hands-on introduction to embedded systems, low-level data acquisition, and audio interaction. The goal was to explore how microcontrollers like the Raspberry Pi Pico can be used to sample real-world analog signals and transmit them for digital processing and playback.
Technologies Used
Hardware:
Raspberry Pi Pico (RP2040)
Electret microphone with onboard amplifier
USB for serial communication
Firmware (Arduino / RP2040 SDK):
Python (Host-Side):
pyserialfor USB serial communicationstructandnumpyfor binary packing and array handlingPCM playback via Audacity
System Architecture
The system consists of a Raspberry Pi Pico reading analog input from a microphone via its onboard 10-bit ADC (Analog-to-Digital Converter). Two versions of the firmware were developed:
Polling Version: The ADC is sampled at a fixed rate using
micros()timing. The CPU reads the ADC value, sends it over USB serial, and waits until the next sample.DMA Version: The ADC continuously fills a FIFO buffer. A DMA channel is configured to move ADC samples into memory automatically, and an interrupt handler notifies the CPU when a full buffer is ready to send over serial.
On the host computer, a Python script reads serial data, scales it to 16-bit signed PCM format, and writes it to a .pcm file. The audio can then be opened in Audacity.
Using Audacity, I imported the raw .pcm files as 16-bit mono audio at 12 kHz and verified that both implementations captured recognizable audio, with the DMA version clearly outperforming the polling one in stability and fidelity.
This project gave me practical experience with low-level microcontroller programming, real-time data acquisition, interrupt handling, and binary audio formats — a great foundation for future embedded DSP work.
Results
The polling implementation provided a basic functional pipeline but struggled with timing consistency at higher sample rates due to CPU bottlenecks. In contrast, the DMA version was able to reliably capture 12 kHz audio with no dropped samples and minimal CPU overhead, enabling room for real-time processing or classification tasks.