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):

    • analogRead() for polling version

    • adc_init(), adc_fifo_setup(), and adc_set_clkdiv() for ADC configuration

    • dma_channel_configure(), dma_channel_set_irq0_enabled() for DMA

    • IRQ-based buffer handling for efficient data collection

  • Python (Host-Side):

    • pyserial for USB serial communication

    • struct and numpy for binary packing and array handling

    • PCM 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.

GitHub

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.

Previous
Previous

Auto Shades

Next
Next

Video Projects