PSRAM causing audio interference

Chip type:          ESP32-S3 (QFN56) (revision v0.2)
Features:           Wi-Fi, BT 5 (LE), Dual Core + LP Core, 240MHz, Embedded PSRAM 8MB (AP_3v3)
Crystal frequency:  40MHz
Manufacturer: 68
Device: 4018
Detected flash size: 16MB
Flash type set in eFuse: quad (4 data lines)
Flash voltage set by eFuse: 3.3V

In the yaml configuration below the microphone audio contains a lot a pops and crackles and hiss. However, if I comment out either the psram or CONFIG_SPIRAM_FETCH_INSTRUCTIONS then the audio is perfectly clear,

I would like to understand why this is happening. Anybody have any ideas?



substitutions:
  name: voice-002
  friendly_name: Voice Test
  ipv6_enable: "false"

esphome:
  name: ${name}
  name_add_mac_suffix: false
  friendly_name: ${friendly_name}
  min_version: 2026.5.0
  on_boot:
    priority: 375
    then:
      - microphone.unmute:
      - microphone.capture:

esp32:
  board: esp32-s3-devkitc-1
  cpu_frequency: 240MHz
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: esp-idf
    version: recommended
    sdkconfig_options:
      #CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
      #CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
      #CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB: "y"
      #CONFIG_SPIRAM_RODATA: "y"
      CONFIG_SPIRAM_FETCH_INSTRUCTIONS: "y"
      #CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST: "y"
      #CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY: "y"
      #CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC: "y"
      #CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y"  # TLS1.3 support isn't enabled by default in IDF 5.1.5

psram:
  mode: octal
  speed: 80MHz
  ignore_not_found: false

ota:
  - platform: esphome
    id: ota_esphome

api:
  encryption:
    key: *REDACTED*

wifi:
  ssid: *REDACTED*
  password: *REDACTED*

logger:
  level: DEBUG

network:
  enable_ipv6: ${ipv6_enable}

external_components:
  - source:
      type: local
      path: ../component

switch:
  - platform: gpio
    id: master_mute_switch
    restore_mode: ALWAYS_OFF
    icon: "mdi:microphone-off"
    name: Mute
    pin:
      number: GPIO4
      mode:
        output: true
    on_turn_on:
      - logger.log: "Turned On Action"
    on_turn_off:
      - logger.log: "Turned Off Action"

binary_sensor:
  - platform: gpio
    id: hardware_mute_switch
    internal: true
    pin:
      number: GPIO2
      mode:
        input: true
        pullup: true
      inverted: true
    on_press:
      - switch.toggle: master_mute_switch
      - if:
          condition:
            - switch.is_off: master_mute_switch
          then:
            - logger.log: "Switch is off"
          else:
            - logger.log: "Switch is on"

i2c:
  - id: internal_i2c
    sda: GPIO5
    scl: GPIO6
    frequency: 400kHz

i2s_audio:
  - id: i2s_input
    i2s_lrclk_pin:
      number: GPIO14
    i2s_bclk_pin:
      number: GPIO13
    i2s_mclk_pin:
      number: GPIO12

globals:
  - id: socket_udp
    type: int
    restore_value: no
    initial_value: '0'

audio_adc:
  - platform: tlv320adc3101
    id: tlv320_adc
    bits_per_sample: 32bit
    sample_rate: 16000
    pin_reset: GPIO42
    mclk_multiple: 512
    address: 0x18

microphone:
  - id: i2s_mics
    platform: i2s_audio
    bits_per_sample: 32bit
    mclk_multiple: 512
    i2s_din_pin: GPIO15
    adc_type: external
    pdm: false
    sample_rate: 16000
    i2s_mode: secondary
    i2s_audio_id: i2s_input
    channel: stereo
    on_data:
      # - udp.write: "Hello World"
      - lambda: |-
          if (x.size()) {
            if(id(socket_udp) == 0) {
              ESP_LOGD("MIC","Opening socket");
              id(socket_udp) = ::socket(AF_INET, SOCK_DGRAM, 0);
            }
            struct sockaddr_in destination;
            destination.sin_family = AF_INET;
            destination.sin_port = htons(18512);  //  UDP receiver port
            destination.sin_addr.s_addr = inet_addr("192.168.1.4");  //  UDP receiver IP

            ::sendto(id(socket_udp), x.data(), x.size(), 0, reinterpret_cast<sockaddr*>(&destination), sizeof(destination));
          }


Buffer overrun? Can buffer be increased

Your board spec says quad and you psram setting says octal, which one is correct? What board are you usins?

Which buffer? There are no messages indicating a buffer overrun. If I switch to 16bit samples instead of 32bit then this (approximately) halves the buffer size for the microphone yet the crackling is still present.

Using octal on psram that supports quad doesn't have an impact. I've also tried octal/quad and different frequencies for the psram
The board is listed as ESP32-S3-Dev-Kit-C-1

I have also used a scope and a logic analyser on the MCLK, LRCLK and BCLK to verify they are running at the correct frequencies and not getting any spurious clock cycles both with the interference and without. The clocks are correct.

I have even resorted to "tinfoil hat" and wrapped both the esp32 dev board and the microphone board in tin foil just in case it is EMI causing the problem.

Turns out it was user error.
The board I'm trying to control with the ESP32 is a mic board from a 2nd Generation Amazon Echo. I have successfully controlled this using a Raspberry Pi and used the same circuitry with the ESP32.
The Mic board uses digital voltage levels of 1.8v and when interfacing with the Pi I used Logic Level Shifters for the MCLK, BCLK and WCLK since they can operate in either direction. The DOUT only goes from the Echo board to the Pi (or ESP32) and the Pi determines that anything over 1.3v is logic level 1 and anything under 0.8v is logic level 0. This meant the Pi would correctly interpret the DOUT signals so DOUT was directly connected to the Pi.
Now the ESP32 has logic level 1 as being anything over 2.5v and logic level 0 being anything under 0.8v. Anything between those 2 values is undetermined.
It turns out that without PSRAM being used the ESP32 was accepting levels around 1.8v as being high and when PSRAM was in use it would occasionally not accept them resulting in data corruption and hence the crackles and pops.
I've now put in another Logic Level Shifter (which I should have done in the first place) and everything works as expected.

1 Like