Stereo DSP Amplifier


reduce the board size so all components can fit inside maybe I would suggest you go with 100x100
Got it — I’ll switch the board to 100 × 100 mm and redo placement for that smaller outline before routing.
I’m blocked because your account has no available ACUs, so AI execution tools are unavailable and I can’t continue routing or running final checks right now.
Accomplished so far:
  • Applied the uploaded BOM MPNs/footprint fields to the project properties as provided.
  • Changed the PCB from 200 × 200 mm to 100 × 100 mm, 4-layer stackup with Layer 2 as ground and Layer 3 as power.
  • Re-placed all 141 components on the 100 × 100 mm board with functional separation: analog inputs left, ESP32 top edge, Class-D/output stage right, power/regulators bottom/right.
  • Placement is mostly cleaned up, but 3 decoupling-loop warnings remained after the last placement pass: C14, C26, C33.
Open items:
  • Route every net.
  • Resolve remaining placement/DRC warnings.
  • Run final ERC/DRC.
  • Confirm whether the custom footprint names from the spreadsheet are accepted by manufacturing/export, since some were set exactly but reported as non-standard property values.
Suggested next steps once ACUs are available:
  1. Fix C14/C26/C33 placement warnings.
  2. Run pre-route board check.
  3. Auto-route the board.
  4. Run final ERC/DRC and clean remaining issues.
Fix capacitor placement
Check footprint exports
Manual capacitor help
Check board boundary

Firmware Starter — ESP32-S3-WROOM-1-N16R8
Platform & Toolchain
  • MCU module: ESP32-S3-WROOM-1-N16R8
  • Framework: Arduino-ESP32 3.x under PlatformIO
  • Purpose: bring up I2C configuration, I2S audio passthrough/DSP placeholder, Wi-Fi control scaffold, TAS5825M FAULT/PDN handling.
Pin Mapping

Table


FunctionGPIONetDirectionNotes
I2S BCLK4I2S_BCLKOutput3.072 MHz for 48 kHz × 64 BCLK.
I2S LRCLK5I2S_LRCLKOutput48 kHz.
ADC DOUT6ADC_DOUTInputPCM1863 DOUT through 33Ω.
Amp SDIN7AMP_SDINOutputTAS5825M SDIN through 33Ω.
I2C SDA8I2C_SDABidirectionalShared PCM1863/TAS5825M bus.
I2C SCL9I2C_SCLOutput400 kHz target.
Amp FAULT10AMP_FAULTInputFrom TAS5825M GPIO0.
Amp PDN11AMP_PDNOutputPulled low in hardware; drive high only after init.
Amp warn/mute12AMP_WARN_OR_MUTEInput/OutputFrom/to TAS5825M GPIO1 depending register config.
BOOT0ESP_BOOTInputBOOT switch/header.
RESETENESP_EN_RESETInputReset switch/header/test point.
UART0 TX43ESP_TXD0OutputDebug header J6.
UART0 RX44ESP_RXD0InputDebug header J6.
platformio.ini

Ini


[env:esp32-s3-devkitc-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
monitor_speed = 115200
build_flags =
  -DARDUINO_USB_MODE=1
  -DARDUINO_USB_CDC_ON_BOOT=1
lib_deps =
Complete Starter Source — src/main.cpp

Cpp


#include <Arduino.h>
#include <Wire.h>
#include <WiFi.h>
#include "driver/i2s_std.h"

// Pin definitions from schematic
static constexpr int PIN_I2S_BCLK   = 4;
static constexpr int PIN_I2S_LRCLK  = 5;
static constexpr int PIN_ADC_DOUT   = 6;
static constexpr int PIN_AMP_SDIN   = 7;
static constexpr int PIN_I2C_SDA    = 8;
static constexpr int PIN_I2C_SCL    = 9;
static constexpr int PIN_AMP_FAULT  = 10;
static constexpr int PIN_AMP_PDN    = 11;
static constexpr int PIN_AMP_WARN   = 12;

static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000;
static constexpr size_t AUDIO_FRAMES_PER_BLOCK = 64;
static constexpr uint8_t PCM1863_ADDR = 0x4A;  // verify AD strap/register map before production
static constexpr uint8_t TAS5825M_ADDR = 0x4C; // ADR0 typical; verify with TI address table

const char* WIFI_SSID = "YOUR_SSID";
const char* WIFI_PASSWORD = "YOUR_PASSWORD";

i2s_chan_handle_t i2s_tx = nullptr;
i2s_chan_handle_t i2s_rx = nullptr;

struct StereoFrame32 {
  int32_t left;
  int32_t right;
};

bool i2cWrite8(uint8_t addr, uint8_t reg, uint8_t value) {
  Wire.beginTransmission(addr);
  Wire.write(reg);
  Wire.write(value);
  return Wire.endTransmission() == 0;
}

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("WiFi connecting");
  for (int i = 0; i < 20 && WiFi.status() != WL_CONNECTED; ++i) {
    delay(250);
    Serial.print('.');
  }
  Serial.println();
  if (WiFi.status() == WL_CONNECTED) {
    Serial.printf("WiFi connected: %s\n", WiFi.localIP().toString().c_str());
  } else {
    Serial.println("WiFi not connected; continuing local audio path.");
  }
}

void initControlPins() {
  pinMode(PIN_AMP_PDN, OUTPUT);
  digitalWrite(PIN_AMP_PDN, LOW); // hold TAS5825M powered down until configured
  pinMode(PIN_AMP_FAULT, INPUT_PULLUP);
  pinMode(PIN_AMP_WARN, INPUT_PULLUP);
}

void initI2C() {
  Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL, 400000);
}

void initPCM1863() {
  // Minimal placeholder register writes; verify final register map/settings from TI PPC3 or datasheet.
  // MD0 is strapped low for I2C mode; ESP32 supplies BCLK/LRCLK as I2S master.
  i2cWrite8(PCM1863_ADDR, 0x00, 0xFE); // software reset register write per datasheet
  delay(5);
  // TODO: configure VINL1/VINR1 single-ended inputs, 24-bit I2S, slave PLL from BCLK/LRCLK.
}

void initTAS5825M() {
  digitalWrite(PIN_AMP_PDN, LOW);
  delay(10);
  // TODO: add TI TAS5825M register sequence generated from PPC3 for desired DSP/limiter/EQ.
  // Keep amp muted until clocks and configuration are valid.
  digitalWrite(PIN_AMP_PDN, HIGH);
  delay(10);
}

void initI2S() {
  i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
  esp_err_t err = i2s_new_channel(&chan_cfg, &i2s_tx, &i2s_rx);
  if (err != ESP_OK) {
    Serial.printf("i2s_new_channel failed: %d\n", err);
    return;
  }

  i2s_std_config_t std_cfg = {};
  std_cfg.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE);
  std_cfg.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO);
  std_cfg.gpio_cfg.mclk = I2S_GPIO_UNUSED;
  std_cfg.gpio_cfg.bclk = static_cast<gpio_num_t>(PIN_I2S_BCLK);
  std_cfg.gpio_cfg.ws   = static_cast<gpio_num_t>(PIN_I2S_LRCLK);
  std_cfg.gpio_cfg.dout = static_cast<gpio_num_t>(PIN_AMP_SDIN);
  std_cfg.gpio_cfg.din  = static_cast<gpio_num_t>(PIN_ADC_DOUT);
  std_cfg.gpio_cfg.invert_flags.mclk_inv = false;
  std_cfg.gpio_cfg.invert_flags.bclk_inv = false;
  std_cfg.gpio_cfg.invert_flags.ws_inv = false;

  err = i2s_channel_init_std_mode(i2s_tx, &std_cfg);
  if (err != ESP_OK) Serial.printf("i2s tx init failed: %d\n", err);
  err = i2s_channel_init_std_mode(i2s_rx, &std_cfg);
  if (err != ESP_OK) Serial.printf("i2s rx init failed: %d\n", err);

  i2s_channel_enable(i2s_rx);
  i2s_channel_enable(i2s_tx);
}

void processAudioBlock(StereoFrame32* frames, size_t count) {
  // Permanent DSP path placeholder: gain/mute/limiter/EQ/delay code goes here.
  static float gain = 0.5f;
  for (size_t i = 0; i < count; ++i) {
    int64_t l = static_cast<int64_t>(frames[i].left * gain);
    int64_t r = static_cast<int64_t>(frames[i].right * gain);
    frames[i].left  = constrain(l, INT32_MIN, INT32_MAX);
    frames[i].right = constrain(r, INT32_MIN, INT32_MAX);
  }
}

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("Stereo DSP amplifier firmware starting");

  initControlPins();
  initI2C();
  initPCM1863();
  initI2S();
  initTAS5825M();
  initWiFi();
}

void loop() {
  static StereoFrame32 audio[AUDIO_FRAMES_PER_BLOCK];
  size_t bytes_read = 0;
  size_t bytes_written = 0;

  if (digitalRead(PIN_AMP_FAULT) == LOW) {
    Serial.println("TAS5825M FAULT asserted; muting amp");
    digitalWrite(PIN_AMP_PDN, LOW);
    delay(100);
    return;
  }

  esp_err_t err = i2s_channel_read(i2s_rx, audio, sizeof(audio), &bytes_read, 20);
  if (err == ESP_OK && bytes_read > 0) {
    size_t frames = bytes_read / sizeof(StereoFrame32);
    processAudioBlock(audio, frames);
    i2s_channel_write(i2s_tx, audio, frames * sizeof(StereoFrame32), &bytes_written, 20);
  }

  if (WiFi.status() != WL_CONNECTED) {
    // Keep audio running even if Wi-Fi is unavailable; reconnect opportunistically later.
  }
}
Build & Flash
  1. Hold BOOT (SW2), tap RESET (SW1), then release BOOT to enter bootloader if needed.
  2. Build: pio run
  3. Flash: pio run -t upload
  4. Monitor: pio device monitor
Open Firmware Items
  • Replace placeholder PCM1863/TAS5825M register writes with final TI register sequences.
  • Add real biquad EQ, high-pass, delay, gain/mute, limiter, and preset storage.
  • Confirm I2C addresses after measuring/reading actual devices on the assembled board.
  • Platform & Toolchain

  • Pin Mapping

  • `platformio.ini`

  • Complete Starter Source — `src/main.cpp`

  • Build & Flash

  • Open Firmware Items