Skip to content

Commit 202fcfe

Browse files
tyethclaude
andcommitted
espressif: add audiopwmio.PWMAudioOut for the ESP32-S2
The espressif port had no audiopwmio at all, so boards whose speaker is not wired to a DAC pin had no way to play samples. On the Adafruit FunHouse the piezo is on GPIO42, while the ESP32-S2 DAC is hardwired to GPIO17/GPIO18 (and GPIO18 is the light sensor), so audioio cannot reach it. LEDC has no DMA path for its duty registers, and the S2's I2S has no PDM transmitter (no SOC_I2S_SUPPORTS_PDM_TX), so samples are pushed from a GPTimer alarm ISR running at the sample rate. The ISR drains one of two device buffers; audiopwmout_background(), called from port_background_task(), refills the other from the audiosample protocol. The ISR deliberately touches nothing but its own object's volatile state. It must not queue a background callback: on this port that macro is taskENTER_CRITICAL(), which aborts when called from ISR context. Driving the refill by polling instead also means a buffer the ISR found empty is always picked up again, rather than relying on the ISR to have queued the refill before it stalled. Every gptimer call is checked, so a timer that cannot be configured raises instead of leaving `playing` true forever. alarm_config is static because CircuitPython builds with CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM, under which gptimer_set_alarm_action() rejects a config outside internal RAM. The carrier is APB_CLK / 2**10 = 78.125 kHz, which keeps it out of the audio band while leaving 10 bits of amplitude resolution. The GPTimer runs at 40 MHz (the finest the timer group divider allows), putting the sample-rate error below 0.01% at 8k/11k/22k/44.1k. A single-buffer sample that loops wraps inside the ISR rather than round-tripping through the background task, so looping RawSamples do not click. ledc_ll.h lives in the per-target esp_hal_ledc directory, which was not on the include path, so add it. Enabled for esp32s2 only; the S3 has neither DAC nor audiopwmio and could reuse this later. Costs 2336 bytes of flash and 648 bytes of internal SRAM on adafruit_funhouse, and nothing on boards that leave it off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent cfe5624 commit 202fcfe

7 files changed

Lines changed: 527 additions & 0 deletions

File tree

‎ports/espressif/Makefile‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ INC += \
123123
-isystem esp-idf/components/esp_hal_i2s/include \
124124
-isystem esp-idf/components/esp_hal_i2s/$(IDF_TARGET)/include \
125125
-isystem esp-idf/components/esp_hal_ledc/include \
126+
-isystem esp-idf/components/esp_hal_ledc/$(IDF_TARGET)/include \
126127
-isystem esp-idf/components/esp_hal_pcnt/include \
127128
-isystem esp-idf/components/esp_hal_rmt/include \
128129
-isystem esp-idf/components/esp_hal_rmt/$(IDF_TARGET)/include \

‎ports/espressif/background.c‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include "supervisor/filesystem.h"
99
#include "supervisor/port.h"
1010
#include "supervisor/shared/stack.h"
11+
#if CIRCUITPY_AUDIOPWMIO
12+
#include "common-hal/audiopwmio/PWMAudioOut.h"
13+
#endif
1114
#if CIRCUITPY_USB_HOST
1215
#include "supervisor/usb.h"
1316
#include "tusb.h"
@@ -28,6 +31,9 @@ void port_background_tick(void) {
2831
}
2932

3033
void port_background_task(void) {
34+
#if CIRCUITPY_AUDIOPWMIO
35+
audiopwmout_background();
36+
#endif
3137
}
3238

3339
void port_start_background_tick(void) {

0 commit comments

Comments
 (0)