Step 31 of 56
ES8311: the audio codec
Control over I2C, audio over I2S, and a clocking relationship you have to get right — the ESP is the master, the codec follows.
Two buses, one device
The Everest ES8311 is a low-power mono codec that is controlled over I2C and carries audio over I2S. Both have to be right before a sound comes out, which is what makes it a more instructive device than it first looks.
subtype Address is ESP32S3.I2C.Slave_Address; -- 0x18 with CE/AD0 low, 0x19 with CE high
The clocking relationship
The ESP is the I2S master and generates MCLK,
BCLK and WS; the codec runs as an I2S slave clocked from that
MCLK. The driver fixes MCLK = 256 × Sample_Rate with 16-bit
samples, and the register coefficients are calculated for that ratio — it
is rate-independent, but not ratio-independent. This is why
I2S's Mclk pin exists and why it is only
available on I2S0.
procedure Setup (...; Sample_Rate : ...; Sda, Scl : ...; Asdout : ... := No_Pin;
Ok : out Boolean);
Ok is False if the codec never ACKed on I2C — the first
thing to check is the address strap, since 0x18 and
0x19 differ only by the CE pin. Asdout is the codec's
ADC data-out (the ESP's data-in): leave it No_Pin for
output only, or wire it to bring up the microphone path as well, with PGA gain
in 6 dB steps from 0 to 42 dB.
Playing
Audio output goes through a limited, controlled Output handle
that owns the I2S port exclusively and releases it on scope exit. The playback
calls mirror I2S's exactly, because they are built on
them:
| Call | Use |
|---|---|
Play | One blocking buffer. |
Play_Continuous | Self-looping DMA — a steady tone with no CPU involvement and no gap at the wrap. |
Play_Stream + Await_Half | Gapless double-buffered playback: refill the half the hardware is not reading. |
Capture / Capture_Stream + Await_Capture_Half | The microphone path, including while playback runs. |
Duplex | Play and record simultaneously. |
procedure Set_Volume (Percent : Natural; Ok : out Boolean); -- 0 .. 100, after Setup
The register-init sequence and clock coefficients are ported from
Espressif's own es8311 driver — this is one place where the
"from scratch" claim is honestly a port, because the sequence is a hardware
recipe rather than a design decision.