Flipdot Matrix PCB Design Review

Architecture change: switch from ESP32-S3 SuperMini dev board to ESP32-S3-MINI-1 module surface-mounted directly on the PCB. This solves the GPIO shortage (the bare module exposes 33+ usable GPIO vs the SuperMini's ~12), eliminates dev-board header alignment issues, and produces a cleaner single-PCB design. JLCPCB stocks this module and will place it via PCBA. Please remove the ESP32-S3 SuperMini header from the schematic and replace it with the following:
  1. Main module ESP32-S3-MINI-1-N8 — Espressif ESP32-S3 module with 8MB flash, no PSRAM
LCSC part number: C2913201 Package: castellated LGA, 15.4mm × 20.5mm × 2.4mm, 65 pins Built-in PCB antenna, crystal, and flash — no external support needed for those
Critical pin connections:
All VDD3P3 pins (multiple — pins 1, 3, 4, 17, in the module's "P" pins): tie to VCC_3V3 net All GND pins: tie to GND net EN (pin 45): reset input. Pull to VCC_3V3 via 10kΩ, then to reset button → GND IO0 (pin 27): boot strapping pin. Pull to VCC_3V3 via 10kΩ, then to boot button → GND IO19 (pin 23): USB D- IO20 (pin 24): USB D+ IO45 (pin 7): strapping pin, leave at hardware default (pull to GND via 10kΩ for normal flash voltage) IO46 (pin 26): strapping pin, leave at hardware default (no pull, or pull to GND)
All other GPIO pins (IO1, IO2, IO4-8, IO15-18, IO21, IO33-41, IO47, IO48) route to the DRV8833 driver inputs per the original spec — the GPIO assignment table from the project brief stays unchanged. 2. USB-C interface (programming + power) Wire the existing USB-C connector (J1) as follows:
VBUS pins → existing SS14 Schottky → VM_5V net (already in place) CC1, CC2 pins → 5.1kΩ pulldowns each (already in place) D+ pin → through USB ESD protection (see component 3) → ESP32-S3 IO20 D- pin → through USB ESD protection → ESP32-S3 IO19 Shield/GND → GND
  1. USB ESD protection USBLC6-2SC6 — 6-pin USB ESD protection array
LCSC part number: C7136 Package: SOT-23-6 Connections:
Pin 1 (I/O1) → USB D- Pin 6 (I/O2) → USB D+ Pin 3 (Vbus) → VM_5V Pin 2, 4, 5 (GND) → GND
After this chip, D- continues to ESP32 IO19 and D+ to ESP32 IO20
  1. Auto-reset circuit (standard ESP32 bootloader entry) This circuit lets esptool toggle reset and boot pins via USB DTR/RTS signals, so you don't need to press buttons to flash firmware. It's the standard ESP32-S3-DevKitC-1 reference design. Components:
Q1, Q2: 2× MMBT2222ALT1G NPN transistor, SOT-23 (LCSC C8589) R5, R6, R7, R8: 4× 10kΩ 0805 resistors (already in BOM family — LCSC C17414)
Note: this circuit assumes USB-CDC for serial communication (built into ESP32-S3 via native USB). The DTR and RTS lines come from the USB CDC interface internally, not from a separate USB-UART chip. So actually — let me correct this. With ESP32-S3 native USB, you don't need the auto-reset transistor circuit at all. The ESP32-S3 handles reset/boot entry via USB commands internally. Skip the auto-reset transistor circuit. ESP32-S3 native USB handles this automatically. You only need:
Manual reset button (SW1, existing): one side to EN, other side to GND Manual boot button (SW2, new): one side to IO0, other side to GND. Add as a second tactile switch.
  1. Strapping pin pullups Required for the ESP32-S3 to boot correctly:
R9: 10kΩ from EN to VCC_3V3 (so EN is high by default; pressing SW1 pulls low for reset) R10: 10kΩ from IO0 to VCC_3V3 (so IO0 is high by default for normal boot; pressing SW2 pulls low for download mode) R11: 10kΩ from IO45 to GND (selects 3.3V flash voltage — must match the module variant) R12: 10kΩ from IO46 to GND (selects normal boot mode at startup)
All four are 0805 resistors, LCSC C17414. 6. Decoupling for the ESP32-S3-MINI-1 The module has multiple VDD pins that need close decoupling:
1× 10µF 0805 ceramic (LCSC C15850) placed within 2mm of any VDD pin — bulk decoupling 3× 100nF 0805 ceramic (LCSC C49678) one per VDD pin group, placed within 1mm of each VDD pin Reference the Espressif ESP32-S3-MINI-1 datasheet, section "Schematics," for the canonical decoupling pattern
These are in addition to the existing decoupling on VM_5V and VCC_3V3 rails. 7. Antenna keepout zone This is a PCB layout rule, not a schematic addition, but include it as a design note: The ESP32-S3-MINI-1 has a built-in PCB antenna at one edge of the module. On the PCB layout:
Mark an 11mm × 6mm clearance zone extending outward from the antenna edge of the module This zone must contain: no copper traces, no copper pours, no ground plane, no components Both top and bottom layers must be clear in this zone The module should be placed so this clearance extends off the edge of the board if possible — this is the cleanest layout
Refer to the ESP32-S3 Hardware Design Guidelines, section "General Principles of PCB Layout for Modules," for the exact keepout dimensions. 8. Power requirements The ESP32-S3-MINI-1 module only accepts 3.3V on its VDD pins — never 5V. The existing AP2112K-3.3 LDO supplies this. Confirm the schematic doesn't accidentally route VM_5V to any module pin. Module current draw:
Active (Wi-Fi TX peak): up to 500mA momentary Active (no radio): ~80mA typical Light sleep: ~240µA
The AP2112K-3.3 is rated for 600mA output, which is sufficient with margin. Make sure the LDO's output capacitor is at least 10µF (already in BOM). 9. Updated BOM additions DesignatorPartLCSCQuantityU10ESP32-S3-MINI-1-N8C29132011U11USBLC6-2SC6 ESD protectionC71361SW2Tactile switch (boot button)C3188841R9-R1210kΩ 0805 resistorC174144Additional 100nF caps near U10 VDD pins100nF 0805C496783 10. Updated BOM removals DesignatorRemovedH1, H22× 1×9 female header (was for SuperMini) Net BOM change: ~$2-3 cheaper than the SuperMini + 2× MCP23017 fix, and significantly more capable. Confirm before proceeding Please confirm:
ESP32-S3-MINI-1-N8 (C2913201) is in JLCPCB's PCBA library The 11mm × 6mm antenna keepout zone can be accommodated in the current PCB layout (preferably extending off one edge of the board) ERC passes cleanly with the new module footprint and all pins properly connected or marked NC
Once confirmed, proceed with the rest of the schematic exactly as originally specified — GPIO assignments, driver chips, matrix, and power all stay unchanged.
Confirmed — I’ll replace the SuperMini-header approach with the ESP32-S3-MINI-1 module, add USB ESD, boot/reset strapping, module decoupling, update the notes/firmware, then re-run ERC and fix remaining issues.
Implemented the ESP32-S3-MINI-1 architecture change: added U10, USB ESD, boot/reset strapping, module decoupling, native USB wiring, and replaced the power-only USB-C with a USB2-capable connector. ERC is clean with zero warnings/errors, and U10 is powered only from VCC_3V3, not VM_5V.
Notes/caveats are captured in ESP32-S3-MINI-1 Architecture Change, and I updated Firmware Getting Started for the direct-module pinout.
The board has enough area for the 11 mm × 6 mm antenna keepout, but exact keepout validation happens during placement. Ready to proceed to PCB placement when you approve.
Place module at edge
Run post-placement DRC
Review BOM impact
Check antenna keepout

Refine this doc
Ask about this doc
Firmware Getting Started — ESP32-S3-MINI-1 Flipdot 6x8
Platform
  • MCU/module: ESP32-S3-MINI-1-N8 direct-solder module
  • Framework: Arduino / ESP32 board support 3.x
  • Build system: PlatformIO
  • Debug/command interface: native USB Serial/JTAG via board USB-C connector
Hardware Notes
  • U10 VDD is 3.3V only from VCC_3V3; never connect VM_5V to the module.
  • Manual reset: SW1 pulls EN low.
  • Manual boot: SW2 pulls IO0 low for download mode if needed.
  • Native USB: IO19 = USB_D_N, IO20 = USB_D_P.
GPIO Mapping

Table


FunctionGPIOConnected ToDirectionNotes
ROW0_IN11U1 AIN1OutputROW0 rail high/low control input 1
ROW0_IN22U1 AIN2OutputROW0 rail high/low control input 2
ROW1_IN13U1 BIN1OutputROW1 rail input 1
ROW1_IN24U1 BIN2OutputROW1 rail input 2
ROW2_IN15U2 AIN1OutputROW2 rail input 1
ROW2_IN26U2 AIN2OutputROW2 rail input 2
ROW3_IN17U2 BIN1OutputROW3 rail input 1
ROW3_IN28U2 BIN2OutputROW3 rail input 2
ROW4_IN19U3 AIN1OutputROW4 rail input 1
ROW4_IN210U3 AIN2OutputROW4 rail input 2
ROW5_IN111U3 BIN1OutputROW5 rail input 1
ROW5_IN212U3 BIN2OutputROW5 rail input 2
ROW6_IN113U4 AIN1OutputROW6 rail input 1
ROW6_IN214U4 AIN2OutputROW6 rail input 2
ROW7_IN115U4 BIN1OutputROW7 rail input 1
ROW7_IN216U4 BIN2OutputROW7 rail input 2
COL0_IN117U5 AIN1OutputCOL0 rail input 1
COL0_IN218U5 AIN2OutputCOL0 rail input 2
USB_D_N19J1 D- through U11USBNative USB D-
USB_D_P20J1 D+ through U11USBNative USB D+
COL1_IN121U5 BIN1OutputCOL1 rail input 1
COL1_IN233U5 BIN2OutputCOL1 rail input 2
COL2_IN134U6 AIN1OutputCOL2 rail input 1
COL2_IN235U6 AIN2OutputCOL2 rail input 2
COL3_IN136U6 BIN1OutputCOL3 rail input 1
COL3_IN237U6 BIN2OutputCOL3 rail input 2
COL4_IN138U7 AIN1OutputCOL4 rail input 1
COL4_IN239U7 AIN2OutputCOL4 rail input 2
COL5_IN140U7 BIN1OutputCOL5 rail input 1
COL5_IN241U7 BIN2OutputCOL5 rail input 2
STATUS_LED48R_LED -> LED1OutputActive-high status LED
PlatformIO Project Setup

Ini


[env:esp32-s3-mini-1]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
monitor_speed = 115200
upload_speed = 921600
board_build.flash_size = 8MB
board_build.arduino.memory_type = qio_opi
build_flags =
    -D ARDUINO_USB_MODE=1
    -D ARDUINO_USB_CDC_ON_BOOT=1
Complete Firmware Source

Cpp


#include <Arduino.h>

// Matrix geometry
constexpr uint8_t ROWS = 8;
constexpr uint8_t COLS = 6;

// Pulse timing defaults
uint16_t PULSE_MS = 15;
constexpr uint16_t SETTLE_MS = 3;
constexpr uint16_t MAX_PULSE_MS = 50;

// ROW rail control pins: each rail has IN1, IN2 to one DRV8833 half-bridge.
const uint8_t ROW_IN1[ROWS] = {1, 3, 5, 7, 9, 11, 13, 15};
const uint8_t ROW_IN2[ROWS] = {2, 4, 6, 8, 10, 12, 14, 16};

// COL rail control pins.
const uint8_t COL_IN1[COLS] = {17, 21, 34, 36, 38, 40};
const uint8_t COL_IN2[COLS] = {18, 33, 35, 37, 39, 41};

constexpr uint8_t STATUS_LED_PIN = 48;

// DRV8833 single-ended rail states using OUT1 only:
// IN1=0, IN2=0: high-Z / coast
// IN1=1, IN2=0: OUT1 high
// IN1=0, IN2=1: OUT1 low
// IN1=1, IN2=1: brake, avoided
void railHiZ(uint8_t in1, uint8_t in2) {
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
}

void railHigh(uint8_t in1, uint8_t in2) {
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
}

void railLow(uint8_t in1, uint8_t in2) {
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);
}

void allRailsHiZ() {
  for (uint8_t r = 0; r < ROWS; r++) railHiZ(ROW_IN1[r], ROW_IN2[r]);
  for (uint8_t c = 0; c < COLS; c++) railHiZ(COL_IN1[c], COL_IN2[c]);
}

void initMatrixPins() {
  for (uint8_t r = 0; r < ROWS; r++) {
    pinMode(ROW_IN1[r], OUTPUT);
    pinMode(ROW_IN2[r], OUTPUT);
  }
  for (uint8_t c = 0; c < COLS; c++) {
    pinMode(COL_IN1[c], OUTPUT);
    pinMode(COL_IN2[c], OUTPUT);
  }
  allRailsHiZ();
}

void flipCell(uint8_t row, uint8_t col, bool whiteFaceUp) {
  if (row >= ROWS || col >= COLS) return;

  allRailsHiZ();
  delay(SETTLE_MS);

  if (whiteFaceUp) {
    // Forward current: ROW high, COL low.
    railHigh(ROW_IN1[row], ROW_IN2[row]);
    railLow(COL_IN1[col], COL_IN2[col]);
  } else {
    // Reverse current: ROW low, COL high.
    railLow(ROW_IN1[row], ROW_IN2[row]);
    railHigh(COL_IN1[col], COL_IN2[col]);
  }

  delay(PULSE_MS);
  allRailsHiZ();
  delay(SETTLE_MS);
}

void setAll(bool whiteFaceUp) {
  for (uint8_t r = 0; r < ROWS; r++) {
    for (uint8_t c = 0; c < COLS; c++) {
      flipCell(r, c, whiteFaceUp);
    }
  }
}

void checkerboard(bool invert) {
  for (uint8_t r = 0; r < ROWS; r++) {
    for (uint8_t c = 0; c < COLS; c++) {
      flipCell(r, c, ((r + c) & 1) ^ invert);
    }
  }
}

void sweep() {
  for (uint8_t r = 0; r < ROWS; r++) {
    for (uint8_t c = 0; c < COLS; c++) {
      flipCell(r, c, true);
    }
  }
  for (uint8_t r = 0; r < ROWS; r++) {
    for (uint8_t c = 0; c < COLS; c++) {
      flipCell(r, c, false);
    }
  }
}

void halfSelectTest() {
  // Pulses one selected cell repeatedly; surrounding same-row/same-col cells should not move.
  for (uint8_t i = 0; i < 10; i++) {
    flipCell(0, 0, true);
    delay(100);
    flipCell(0, 0, false);
    delay(100);
  }
}

void printHelp() {
  Serial.println("Commands:");
  Serial.println("  c              clear all cells");
  Serial.println("  s              set all cells");
  Serial.println("  k              checkerboard");
  Serial.println("  K              inverse checkerboard");
  Serial.println("  w              sweep");
  Serial.println("  h              half-select test at R0 C0");
  Serial.println("  f R C T        flip row R col C to target T (0/1)");
  Serial.println("  p N            set pulse width in ms, clamped to MAX_PULSE_MS");
}

void handleCommand(String line) {
  line.trim();
  if (line.length() == 0) return;

  if (line == "c") setAll(false);
  else if (line == "s") setAll(true);
  else if (line == "k") checkerboard(false);
  else if (line == "K") checkerboard(true);
  else if (line == "w") sweep();
  else if (line == "h") halfSelectTest();
  else if (line[0] == 'p') {
    int n = line.substring(1).toInt();
    if (n > 0) PULSE_MS = min<uint16_t>(n, MAX_PULSE_MS);
    Serial.printf("PULSE_MS=%u\n", PULSE_MS);
  } else if (line[0] == 'f') {
    int r = -1, c = -1, t = -1;
    if (sscanf(line.c_str(), "f %d %d %d", &r, &c, &t) == 3) {
      flipCell((uint8_t)r, (uint8_t)c, t != 0);
    } else {
      Serial.println("Usage: f R C T");
    }
  } else {
    printHelp();
  }
}

void setup() {
  pinMode(STATUS_LED_PIN, OUTPUT);
  digitalWrite(STATUS_LED_PIN, LOW);

  initMatrixPins();

  Serial.begin(115200);
  unsigned long start = millis();
  while (!Serial && (millis() - start < 1500)) {
    delay(10);
  }

  digitalWrite(STATUS_LED_PIN, HIGH);
  Serial.println("ESP32-S3-MINI-1 Flipdot 6x8 firmware ready.");
  printHelp();
}

void loop() {
  if (Serial.available()) {
    String line = Serial.readStringUntil('\n');
    handleCommand(line);
  }
}
Build & Flash

Bash


pio run
pio run -t upload
pio device monitor -b 115200
If USB download mode is needed manually, hold BOOT (SW2), tap RESET (SW1), then release BOOT before uploading.
  • Platform

  • Hardware Notes

  • GPIO Mapping

  • PlatformIO Project Setup

  • Complete Firmware Source

  • Build & Flash

Flipdot 6x8 Matrix Controller

Flipdot 6x8 Matrix Controller thumbnail
ESP32-S3 based 6x8 flip-dot matrix controller using DRV8833 H-bridges, USB-C 5V input, AP2112K 3.3V logic rail, and a 48-coil row/column inductor matrix.

Properties

Properties describe core aspects of the project.

Pricing & Availability

Distributor

Qty 1

Arrow

$9.01–$11.23

Digi-Key

$50.59–$53.09

HQonline

$108.60–$108.82

LCSC

$17.78–$18.09

Mouser

$97.22–$97.28

TME

$1.32

Verical

$32.45–$37.11

Controls