ivãstival

ESP32 · 03-audio

Architecture: ESP32 Voice Hardware

Note: This document was generated by an AI agent.

Overview

Adding voice to the ESP32 robot face requires solving two opposite electrical problems:

  • A microphone produces an analog signal too small and noisy for the ESP32 to measure directly.
  • A speaker requires far more current, and a smoother waveform, than an ESP32 GPIO can provide.

The project crosses those boundaries with an INMP441 digital microphone and a MAX98357A digital amplifier. Both exchange PCM samples with the ESP32 over I2S, allowing DMA to move audio without consuming the face renderer's 33 ms frame budget.

Two mirrored lanes. Capture runs left to right from air pressure through the INMP441, I2S0 with DMA, captureTask and Agent sendAudio. Playback runs right to left from the agent's reply audio through a RingBuffer, playbackTask, I2S1 with DMA and the MAX98357A.

The two directions are mirror images. Both cross from analog to digital inside a dedicated chip, and everything downstream of that crossing is numbers moving under DMA.

For the firmware boundary and task-level implementation, see ESP32 I2S Audio Runtime. For the timing constraint audio must protect, see Face rendering and effects.


Why a Bare Microphone Does Not Work

Sound pressure is extremely small

Atmospheric pressure in a room is approximately 101,325 Pa. Ordinary speech at about one metre adds a pressure variation of roughly 0.02 Pa. The microphone must reject the static atmospheric load and detect a variation about five million times smaller.

Two bars: atmospheric pressure at 101,325 pascals filling the full width, and a speaking voice at 0.02 pascals reduced to a sliver, itself drawn far wider than true scale.

An illustrative electret microphone sensitivity of -44 dBV/Pa is equivalent to approximately 6.3 mV/Pa:

44 / 20       = 2.2
10^2.2        ≈ 158
1 V / 158     ≈ 0.0063 V
              = 6.3 mV/Pa

If the decibel notation or the conversion above is unfamiliar, Decibels, from scratch explains both from first principles and walks those four lines one at a time.

At normal speaking pressure:

0.02 Pa × 6.3 mV/Pa ≈ 0.13 mV    speaking about one metre away
                                  0.42 mV    speaking about 30 cm away

The ESP32 ADC is too coarse and noisy for that signal

An ideal 12-bit conversion across 0 to 3.3 V has 4,096 steps:

3.3 V / 4,096 ≈ 0.8 mV per step

A ruler spanning 0 to 3,300 millivolts divided into evenly spaced marks, with the voice signal drawn as a thin line barely wider than the leftmost mark.

A voice signal around 0.42 mV does not span even one ideal step. Real ESP32 ADC noise is also several steps, so wiring a bare capsule to the ADC produces noise rather than usable quiet speech.

An analog design would therefore require a low-noise preamplifier with roughly 100x to 500x gain before conversion. The INMP441 instead integrates the sensing element, preamplification, and a higher-quality converter, then puts already-digital audio on the wire. This removes the vulnerable low-level analog trace from the ESP32 board and reduces coupling from nearby Wi-Fi activity.



The level ladder

The electret arithmetic above shows why an analogue design would need a preamplifier. The INMP441 avoids that by being digital — but the signal is still weak, and it stays weak right up to the point something deliberately amplifies it. Tracing one voice through the whole system:

A ladder of levels in two halves. Capture: speech at one metre is 0.02 pascals, which is 60 dB SPL; the INMP441 produces −60 dBFS, a code of 8,409 of 8,388,607; narrowing to 16 bits at unity gain keeps −60 dBFS, or 33 of 32,767; MIC_GAIN 8 adds 18.1 dB to reach −42 dBFS. Playback: the Piper reply measures 0 dBFS peak against −16 dBFS RMS; the compressor adds 8.9 dB of makeup; VOICE_VOLUME_PERCENT 70 removes 3.1 dB; and the MAX98357A delivers 2.83 V RMS into 8 ohms, which is 1 watt.

The capture half is the one worth following, because it explains a bug report that has now been filed twice.

speech at 1 m              0.02 Pa
                           94 + 20·log₁₀(0.02)          =  60 dB SPL

INMP441 sensitivity        −26 dBFS at 94 dB SPL (datasheet)
                           −26 + 20·log₁₀(0.02)         = −60 dBFS
                           8,388,607 × 10^(−60/20)      =  8,409   (24-bit)

narrowed to 16 bits        8,409 / 256                  =     33   of 32,767
with MIC_GAIN 8            × 8                          =    263   of 32,767

Thirty-three out of 32,767. That is not a quiet recording; it is three thousandths of the available range, which plays back as silence with a noise floor on any speaker you own. The microphone is working exactly to specification, and it sounds broken.

This is the entire justification for the microphone gain setting, and for applying it before the narrowing — at 24-bit width there are still 8,409 counts of real signal to scale, where after narrowing there are 33. Audio diagnostics records how long that took to work out on real hardware, and the I2S runtime covers the arithmetic that does it.

The measured figure on this board — ordinary room ambience peaking near −50 dBFS — sits comfortably above the −60 dBFS this predicts for speech at a metre, which is what a room with a refrigerator in it should look like.

Why a GPIO Cannot Drive the Speaker

For 1 W into an 8-ohm speaker:

RMS voltage = sqrt(1 W × 8 ohm) ≈ 2.83 V
RMS current = 2.83 V / 8 ohm   ≈ 354 mA
Peak current = 354 mA × 1.41   ≈ 500 mA

The arithmetic for 1 watt into 8 ohms, above two bars comparing the 500 milliamp peak the speaker demands against the roughly 20 milliamps one ESP32 pin can supply.

A single ESP32 pin is expected to supply only about 20 mA in this design. The speaker can demand approximately 25 times more. Attempting to source speaker current from a GPIO can damage the chip.

The signal shape is a separate problem. A GPIO normally switches between off and 3.3 V, while speech and music require continuously varying sample amplitudes. Direct toggling produces a square wave, not intelligible playback.

The MAX98357A solves both constraints:

  • Its DAC converts PCM sample values into an analog waveform.
  • Its power stage supplies the speaker current.
  • It can deliver about 1.8 W into 8 ohms from 5 V.
  • Its class-D architecture is efficient enough to operate without a heatsink.

Why class-D matters here is thermal, and it follows from how the output stage works. A class-AB amplifier holds its transistors partly on, dropping the difference between the supply and the output across them as heat; efficiency around 50% at best means roughly a watt of heat for a watt of sound. A class-D stage instead switches fully on or fully off at a few hundred kilohertz and varies the duty cycle, then lets the speaker's own inductance average the result back into an analogue waveform. A switch that is fully on drops almost no voltage, and one that is fully off carries almost no current, so either way it dissipates very little — over 90% efficiency in practice.

For a sealed desk object with no airflow and no heatsink, that is the difference between a warm chip and a thermal-shutdown one.


Why Both Devices Use I2S

I2S is a synchronous digital audio bus with three signal roles:

SignalCommon namesResponsibility
Bit clockBCLK, SCKAdvances one transmitted bit per tick
Word selectWS, LRCMarks the left and right sample slots
Serial dataSD, DIN, DOUTCarries sample bits, most-significant bit first

The ESP32 generates the clocks in both directions. The INMP441 drives its data output toward the ESP32; the ESP32 drives a separate data line toward the MAX98357A.

Three signal rows over sixteen bit periods: BCLK ticking once per bit, WS held low for the whole left slot, and DATA carrying the bit pattern 0000100100000010 most-significant bit first.

There is no volume wire and nothing analog anywhere on the bus — just numbers marched across one bit at a time, fast enough that the numbers are the sound.

Digital transport prevents analog noise from entering along these connections. More importantly, the ESP32's I2S peripherals have DMA engines. Audio moves between peripherals and memory without waking the CPU for each bit or sample, so capture and playback do not compete directly with 30 fps animation.


Capture Data Path

The microphone runs at 16,000 samples per second. Each retained PCM sample is signed 16-bit data, or two bytes.

1 sample               = 16 retained bits = 2 bytes
16,000 samples/s × 2 B = 32,000 B/s        = 32 KB/s
1 sample interval      = 1 / 16,000        = 62.5 microseconds

The INMP441 produces 24-bit samples inside 32-bit I2S slots. I2S still clocks a left and a right slot per frame even though the microphone is mono. With the INMP441 L/R pin tied to ground, the microphone occupies the left slot and the right slot is empty.

The wire and stored-data rates differ:

clocked on wire = 16,000 × 64 bits = 1,024,000 bit/s = 128 KB/s
retained audio  = 16,000 × 16 bits =   256,000 bit/s =  32 KB/s

Half of the clocked frame is the unused channel, and half of the populated 32-bit slot is precision beyond the selected 16-bit network format. Hardware and DMA discard the unused material; the CPU does not process it sample by sample.

Sixteen-bit signed PCM spans -32768 through 32767, providing 65,536 possible values. The chosen format matches the downstream speech service and uses half the network bandwidth of 24-bit samples.


Playback Data Path

The voice service returns mono speech at 24,000 samples per second. The MAX98357A accepts this rate directly, so the project does not resample it.

1 sample interval      = 1 / 24,000        ≈ 41.7 microseconds
24,000 samples/s × 2 B = 48,000 B/s        = 48 KB/s
I2S clock              = 24,000 × 32 bits  = 768,000 bit/s

The mono sample is presented in both I2S slots. The amplifier combines left and right as (L + R) / 2, recovering the original value.

Before a sample reaches I2S, firmware applies a software volume ceiling:

incoming sample        = 20,000
volume ceiling         = 35%
transmitted sample     = 20,000 × 0.35 = 7,000

The MAX98357A can deliver approximately 1.8 W into a speaker rated for 1 W. Scaling every sample protects the speaker by default rather than relying on the user to maintain a safe volume.


End-to-End Data Budget

StageCapture: question leavingPlayback: answer returning
Physical endpointAbout 0.02 Pa of air pressureAbout 1 W of acoustic output
Codec or converterINMP441 at 16 kHzMAX98357A at 24 kHz
I2S clockAbout 1.024 MHzAbout 768 kHz
PCM in memory32 KB/s48 KB/s
Network representationApproximately 43 KB/s after encodingApproximately 64 KB/s before decoding

Only the endpoints handle sound as a physical pressure wave. Between the microphone and amplifier, the system transports integers through I2S, RAM, encryption, Wi-Fi, and the remote service.


Wiring

The source design reserves GPIO 21 and 22 for the OLED, GPIO 4 for the touch pad, and GPIO 34 for battery sensing. The following audio pins were selected because they were free in that design.

INMP441 microphone

Module pinConnect toPurpose
VDD3.3 VPower
GNDGNDGround
SCKGPIO 32I2S bit clock
WSGPIO 33I2S word select
SDGPIO 35Audio data from microphone
L/RGNDSelect left-slot transmission

MAX98357A amplifier

Module pinConnect toPurpose
VIN5 VAmplifier power and full output range
GNDGNDGround
BCLKGPIO 26I2S bit clock
LRCGPIO 25I2S word select
DINGPIO 27Audio data from ESP32
GAINLeave floatingDefault 9 dB gain
SDLeave floatingIf the board remains silent, tie to VIN as a diagnostic
+ / -8-ohm speakerDifferential speaker output

Verify module labels against the actual board revision before applying power. Similar breakout boards can expose different enable, gain, or supply arrangements.


Power Architecture

Peak current is larger than the average consumption suggests:

ConsumerExpected draw
ESP32 with Wi-Fi transmissionAbout 250 mA, with bursts near 500 mA
Amplifier driving the speakerUp to about 500 mA
OLEDAbout 20 mA
Combined peakApproximately 1,000 mA
Typical USB 2.0 computer port500 mA

If a loud sample coincides with a Wi-Fi burst, an undersized supply can sag and reset the ESP32. The symptom resembles a firmware crash.

Use a regulated 5 V supply rated for at least 1 A; a 2 A phone charger provides additional margin. Place a 470-1000 microfarad electrolytic capacitor across amplifier VIN and GND, physically near the board, to cover short current spikes. Observe capacitor polarity.


Component Selection

The reference build uses:

  1. An INMP441 I2S microphone module with VDD, GND, L/R, WS, SCK, and SD pins.
  2. A MAX98357A I2S amplifier module rated around 3.2 W into 4 ohms or 1.8 W into 8 ohms.
  3. A regulated 5 V supply rated for at least 1 A.
  4. A 470-1000 microfarad electrolytic capacitor.
  5. Jumper wires and soldered headers appropriate to the modules.

Analog MAX9814 or MAX4466 microphone modules reintroduce the ESP32 ADC and its noise constraints. A PAM8403 analog amplifier requires an analog source, typically the ESP32's limited internal DAC or an external converter. Use those parts only as a fallback when the I2S modules are unavailable and their quality trade-offs are acceptable.


Units Reference

UnitMeaning
PaPascal, a measure of pressure
V / mVVolt and millivolt, electrical potential
A / mAAmpere and milliampere, electrical current
ohmResistance; the reference speaker is 8 ohms
WElectrical power, voltage multiplied by current
dBLogarithmic ratio; a negative dBV value is below one volt
Hz / kHzEvents per second; audio uses thousands of samples per second
bitOne binary digit; bit depth determines the number of sample values
byteEight bits; one 16-bit PCM sample occupies two bytes
KB/sThousands of bytes transferred each second


The safety limit, in watts

The amplifier can deliver more than the speaker is rated for, which is why playback volume is a software limit rather than a trust exercise:

speaker rating          1.0 W into 8 Ω    →  sqrt(1.0 × 8) = 2.83 V RMS
MAX98357A at 5 V        1.8 W into 8 Ω    →  sqrt(1.8 × 8) = 3.79 V RMS

the amplifier can exceed the driver by       20·log₁₀(3.79/2.83) = 2.6 dB

Two and a half decibels does not sound like much, and as loudness it is not. As sustained power into a 16 mm driver it is the difference between a speaker and a broken speaker. The playback volume setting at 70% removes 3.1 dB, landing just inside the rating with a little margin, and it is a software limit precisely so that it can be changed without rewiring and cannot be forgotten in hardware.

The amplifier's own GAIN strap is a separate control and does not replace this one. Raise the software limit first; it needs no power cycle and no soldering.

Failure modes

SymptomCause
Device resets when playback gets loudSupply sag — a loud sample coinciding with a Wi-Fi burst. Looks exactly like a firmware crash
Capture is silence with a noise floorWorking as specified; this is the gain setting left at its minimum, at −60 dBFS. See the ladder above
Reported microphone peak level permanently exactly zeroThe L/R strap disagrees with the configured input channel setting
Sudden ~33 dB drop to flatline, wiring still passing continuityThe acoustic port was contaminated; the part is dead. See hardware
Amplifier hot enough to noticeNot class-D behaviour — check for a short across the speaker terminals
Playback distorts only on loud passagesClipping above the driver's rating; lower the playback volume setting
Hiss or buzz that tracks Wi-Fi activityAn analogue run too close to the radio, or a shared ground return
Nothing at all from either deviceVoice and I2S support left at its off-by-default setting

Configuration reference

The electrical choices this page argues for, as the firmware states them.

SettingDefaultRelevance here
Voice and I2S supportOffSet to on only once both parts are wired
Input channel selectionLeftMust match the L/R strap
Microphone gain8x+18.1 dB; the answer to −60 dBFS
Input sample rate16,000 HzWhat the speech pipeline expects
Output sample rate24,000 HzWhat the amplifier is clocked at
Playback volume ceiling70%−3.1 dB; the speaker's protection

Pins are listed in hardware; the driver configuration that uses them is in the I2S runtime.


Referenced Hardware and Documents

ReferenceResponsibility
INMP441 datasheetMicrophone sensitivity, digital conversion, I2S timing, and channel selection
MAX98357A datasheetI2S input, gain behavior, supply requirements, and speaker power
ESP32 technical reference manualADC characteristics, I2S peripherals, and DMA behavior
ESP32 I2S Audio RuntimeFirmware tasks, buffers, conversion, and configuration
Face rendering and effectsRenderer design and 33 ms non-blocking constraint