Overview

In this tutorial, we’ll create a development circuit based on the ESP32-D0WD microcontroller. This circuit includes all essential components needed for proper operation, including decoupling capacitors, crystal oscillator, flash memory, and antenna components.

Components Overview

The main components in this circuit are:

  • ESP32-D0WD microcontroller (U2)
  • ATS400B 40MHz Crystal oscillator (U1)
  • W25Q32JVSSIQ Flash memory (U3)
  • LY68L6400SLIT PSRAM memory (U4)
  • ANT-2.4-CW-RCL 2.4GHz Antenna (ANT1)
  • Various capacitors and resistors for proper operation

Creating the Circuit

First, let’s create our ESP32 module component:

import { useESP32_D0WD } from "@tsci/AnasSarkiz.ESP32_D0WD"
import { useResistor, useCapacitor } from "@tscircuit/core"

export const ESP32Module = (props: { name: string }) => {
  const ESP32 = useESP32("U2")

  // Capacitors
  const C1 = useCapacitor("C1", { capacitance: "0F" }) //TDB
  const C2 = useCapacitor("C2", { capacitance: "0F" }) //TDB
  const C3 = useCapacitor("C3", { capacitance: "100pF" })
  const C4 = useCapacitor("C4", { capacitance: "0.1uF" })
  const C5 = useCapacitor("C5", { capacitance: "10nF" }) // 10nF/6.3V (10%)
  const C6 = useCapacitor("C6", { capacitance: "3.3nF" }) // 3.3nf/6.3V (10%)
  const C9 = useCapacitor("C9", { capacitance: "1nF" })
  const C10 = useCapacitor("C10", { capacitance: "0.1uF" })
  const C11 = useCapacitor("C11", { capacitance: "1uF" })
  const C13 = useCapacitor("C13", { capacitance: "10uF" })
  const C14 = useCapacitor("C14", { capacitance: "0" }) // TBD
  const C15 = useCapacitor("C15", { capacitance: "0" }) // TBD
  const C19 = useCapacitor("C19", { capacitance: "0.1uF" })
  const C20 = useCapacitor("C20", { capacitance: "1uF" })
  const C21 = useCapacitor("C21", { capacitance: "0" }) // NC
  const C24 = useCapacitor("C24", { capacitance: "1uF" })

  // Resistors
  const R1 = useResistor("R1", { resistance: "20k" })
  const R2 = useResistor("R2", { resistance: "0Ω" }) //TDB
  const R3 = useResistor("R3", { resistance: "499Ω" })
  const R4 = useResistor("R4", { resistance: "2k" })
  const R9 = useResistor("R9", { resistance: "10k" })
  const R10 = useResistor("R10", { resistance: "1k" })

  return (
    <group subcircuit routingDisabled>
      <ESP32 />

      {/* Capacitors */}
      <C1 pos=".U1 .XIN" neg="net.GND" schX={0.5} schY={9} schRotation="270deg" />
      <C2 neg="net.GND" pos={ESP32.XTAL_N} schX={4.5} schY={9} schRotation="270deg" />
      <C3 neg="net.GND" pos=".C20 .pos" schX={-10} schY={9.1} schRotation="90deg" />
      <C4 neg="net.GND" pos={ESP32.VDD3P3_CPU} schX={4.8} schY={3} schRotation="270deg" />
      <C5 neg="net.GND" pos=".C6 .pos" schX={-4} schY={5.7} schRotation="270deg" />
      <C6 neg={ESP32.CAP1} pos={ESP32.CAP2} schX={-1.5} schY={5} />
      <C9 neg="net.GND" pos={ESP32.VDDA} schX={-7.8} schY={5.5} schRotation="90deg" />
      <C10 neg="net.GND" pos=".L4 .pin1" schX={-10} schY={3} schRotation="90deg" />
      <C11 neg="net.GND" pos=".C10 .pos" schX={-12} schY={3} schRotation="90deg" />
      <C13 neg="net.GND" pos=".C11 .pos" schX={-14} schY={3} schRotation="90deg" />
      <C14 neg="net.GND" pos={ESP32.pin2} schX={-8} schY={1.1} schRotation="90deg" />
      <C15 neg="net.GND" pos=".L5 .pin1" schX={-10} schY={1.1} schRotation="90deg" />
      <C19 neg="net.GND" pos={ESP32.VDD3P3_RTC} schX={5} schY={-6} schRotation="90deg" />
      <C20 neg="net.GND" pos={ESP32.pin46} schX={-8} schY={9.5} schRotation="90deg" />
      <C21 neg="net.GND" schX={-8} schY={3} schRotation="90deg" />
      <C24 neg="net.GND" pos=".R4 .pin2" schX={7} schY={-3} schRotation="90deg" />

      {/* Resistors */}
      <R1 pin1=".C6 .pos" pin2=".C6 .neg" schX={-1.3} schY={6} />
      <R2 pin1={ESP32.XTAL_P} pin2=".C1 .pos" schX={0.5} schY={5} schRotation="90deg" />
      <R3 pin1={ESP32.U0TXD} pin2="net.U0TXD" schX={4} schY={6} />
      <R4 pin1="net.GND" pin2={ESP32.VDD_SDIO} schX={5} schY={-3} schRotation="90deg" />
      <R9 pin1="net.VDD33" pin2={ESP32.MTDI} schX={-3} schY={-5.58} />
      <R10 pin1=".U4 .pin1" pin2="net.VDD_SDIO" schX={10.5} schY={-1.2} schRotation="90deg" />

      {/* Inductors */}
      <inductor name="L4" inductance="2.0nH" schX={-9} schY={3.5} />
      <inductor name="L5" inductance="TBD" schX={-9} schY={1.58} />

      {/* Antenna */}
      <chip
        name="ANT1"
        schPortArrangement={{
          rightSide: {
            pins: ["pin2", "pin1"],
            direction: "top-to-bottom",
          },
        }}
        schX={-14}
        schY={1.1}
      />

      {/* Crystal */}
      <chip
        name="U1"
        schPortArrangement={{
          topSide: {
            pins: ["pin1", "pin2"],
            direction: "top-to-bottom",
          },
          bottomSide: {
            pins: ["pin3", "pin4"],
            direction: "top-to-bottom",
          },
        }}
        pinLabels={{
          pin1: "XIN",
          pin2: "GND",
          pin3: "XOUT",
          pin4: "GND",
        }}
        schPinSpacing={0.35}
        schHeight={1}
        schWidth={1}
        schX={2.2}
        schY={9}
      />

      {/* Flash Memory */}
      <chip
        name="U3"
        manufacturerPartNumber="FLASH-3V3"
        schPortArrangement={{
          leftSide: {
            pins: ["pin1", "pin6", "pin7"],
            direction: "top-to-bottom",
          },
          bottomSide: {
            pins: ["pin4"],
            direction: "top-to-bottom",
          },
          rightSide: {
            pins: ["pin5", "pin2", "pin3"],
            direction: "top-to-bottom",
          },
          topSide: {
            pins: ["pin8"],
            direction: "top-to-bottom",
          },
        }}
        pinLabels={{
          pin1: "/CS",
          pin2: "DO",
          pin3: "/WP",
          pin4: "GND",
          pin5: "DI",
          pin6: "CLK",
          pin7: "/HOLD",
          pin8: "VDD_SDIO",
        }}
        schPinSpacing={0.35}
        schHeight={1.5}
        schWidth={1}
        schX={12}
        schY={2}
      />

      {/* PSRAM */}
      <chip
        name="U4"
        manufacturerPartNumber="PSRAM-3V3"
        schPortArrangement={{
          leftSide: {
            pins: ["pin1", "pin6", "pin7"],
            direction: "top-to-bottom",
          },
          bottomSide: {
            pins: ["pin4"],
            direction: "top-to-bottom",
          },
          rightSide: {
            pins: ["pin5", "pin2", "pin3"],
            direction: "top-to-bottom",
          },
          topSide: {
            pins: ["pin8"],
            direction: "top-to-bottom",
          },
        }}
        pinLabels={{
          pin1: "CS",
          pin2: "SO/SIO1",
          pin3: "SIO2",
          pin4: "VSS",
          pin5: "SI/SIOO",
          pin6: "SCLK",
          pin7: "SIO3",
          pin8: "VDD_SDIO",
        }}
        schPinSpacing={0.35}
        schHeight={1.5}
        schWidth={1}
        schX={12}
        schY={-3}
      />

      {/* Traces */}
      <trace from=".C21 .pos" to=".L4 .pin2" />
      <trace from=".C14 .pos" to=".L5 .pin2" />
      <trace from=".C3 .pos" to="net.VDD33" />
      <trace from=".C13 .pos" to="net.VDD33" />
      <trace from=".C9 .pos" to="net.VDD33" />
      <trace from=".C19 .pos" to="net.VDD33" />
      <trace from=".C4 .pos" to="net.VDD33" />
      <trace from=".C24 .pos" to="net.VDD_SDIO" />

      {/* ESP32 Pin Connections */}
      <trace from={ESP32.pin3} to={ESP32.pin4} />
      <trace from={ESP32.pin3} to=".C21 .pos" />
      <trace from={ESP32.SENSOR_VP} to="net.SENSOR_VP" />
      <trace from={ESP32.SENSOR_CAPP} to="net.SENSOR_CAPP" />
      <trace from={ESP32.SENSOR_CAPN} to="net.SENSOR_CAPN" />
      <trace from={ESP32.SENSOR_VN} to="net.SENSOR_VN" />
      <trace from={ESP32.CHIP_PU} to="net.EN" />
      <trace from={ESP32.VDET_1} to="net.GPIO34" />
      <trace from={ESP32.VDET_2} to="net.GPIO35" />
      <trace from={ESP32.pin12} to="net.GPIO32" />
      <trace from={ESP32.pin13} to="net.GPIO33" />
      <trace from={ESP32.GPIO25} to="net.GPIO25" />
      <trace from={ESP32.GPIO26} to="net.GPIO26" />
      <trace from={ESP32.GPIO27} to="net.GPIO27" />
      <trace from={ESP32.MTMS} to="net.GPIO14" />
      <trace from={ESP32.MTDI} to="net.GPIO12" />
      <trace from={ESP32.MTCK} to="net.GPIO13" />
      <trace from={ESP32.MTDO} to="net.GPIO15" />
      <trace from={ESP32.GPIO2} to="net.GPIO2" />
      <trace from={ESP32.GPIO0} to="net.GPIO0" />
      <trace from={ESP32.GPIO4} to="net.GPIO4" />
      <trace from={ESP32.GPIO16} to="net.GPIO16" />
      <trace from={ESP32.GPIO17} to="net.GPIO17" />
      <trace from={ESP32.SD_DATA_2} to="net.SHD/SD2" />
      <trace from={ESP32.SD_DATA_3} to="net.SWP/SD3" />
      <trace from={ESP32.SD_CMD} to="net.SCS/SMD" />
      <trace from={ESP32.SD_CLK} to="net.SCK/CLK" />
      <trace from={ESP32.SD_DATA_0} to="net.SDO/SD0" />
      <trace from={ESP32.SD_DATA_1} to="net.SDI/SD1" />
      <trace from={ESP32.GPIO5} to="net.GPIO51" />
      <trace from={ESP32.GPIO18} to="net.GPIO18" />
      <trace from={ESP32.GPIO23} to="net.GPIO23" />
      <trace from={ESP32.GPIO19} to="net.GPIO19" />
      <trace from={ESP32.GPIO19} to={ESP32.VDD3P3_CPU} />
      <trace from={ESP32.GPIO22} to="net.GPIO22" />
      <trace from={ESP32.U0RXD} to="net.U0RXD" />
      <trace from={ESP32.GPIO21} to="net.GPIO21" />
      <trace from={ESP32.pin43} to={ESP32.pin46} />
      <trace from={ESP32.GND} to="net.GND" />

      {/* Peripheral Connections */}
      <trace from=".ANT1 .pin1" to=".C15 .pos" />
      <trace from=".ANT1 .pin2" to="net.GND" />
      <trace from=".U1 .pin3" to=".C2 .pos" />
      <trace from=".U1 .pin2" to="net.GND" />
      <trace from=".U1 .pin4" to="net.GND" />
      <trace from=".U3 .pin1" to="net.SCS/CMD" />
      <trace from=".U3 .pin2" to="net.SDO/SDO" />
      <trace from=".U3 .pin3" to="net.SWP/SD3" />
      <trace from=".U3 .pin4" to="net.GND" />
      <trace from=".U3 .pin5" to="net.SDI/SD1" />
      <trace from=".U3 .pin6" to="net.SCK/CLK" />
      <trace from=".U3 .pin7" to="net.SHD/SD2" />
      <trace from=".U3 .pin8" to="net.VDD_SDIO" />
      <trace from=".U4 .pin1" to="net.GPIO16" />
      <trace from=".U4 .pin2" to="net.SDO/SDO" />
      <trace from=".U4 .pin3" to="net.SWP/SD3" />
      <trace from=".U4 .pin4" to="net.GND" />
      <trace from=".U4 .pin5" to="net.SDI/SD1" />
      <trace from=".U4 .pin6" to="net.PSRAM_CLK" />
      <trace from=".U4 .pin7" to="net.SHD/SD2" />
      <trace from=".U4 .pin8" to="net.VDD_SDIO" />
    </group>
  )
}

Adding Decoupling Capacitors

The ESP32 requires several decoupling capacitors for stable operation:

// Capacitors
const C1 = useCapacitor("C1", { capacitance: "0F" }) // Crystal capacitor
const C4 = useCapacitor("C4", { capacitance: "0.1uF" }) // VDD3P3_CPU decoupling
const C19 = useCapacitor("C19", { capacitance: "0.1uF" }) // VDD3P3_RTC decoupling
const C20 = useCapacitor("C20", { capacitance: "1uF" }) // General decoupling

Crystal Oscillator Circuit

The crystal oscillator circuit is essential for providing the clock signal:

<chip
  name="U1"
  schPortArrangement={{
    topSide: {
      pins: ["pin1", "pin2"],
      direction: "top-to-bottom",
    },
    bottomSide: {
      pins: ["pin3", "pin4"],
      direction: "top-to-bottom",
    },
  }}
  pinLabels={{
    pin1: "XIN",
    pin2: "GND",
    pin3: "XOUT",
    pin4: "GND",
  }}
  schPinSpacing={0.35}
  schHeight={1}
  schWidth={1}
  schX={2.2}
  schY={9}
/>

RF Components

The RF section includes the antenna and matching components:

<inductor
  name="L4"
  inductance="2.0nH"
  schX={-9}
  schY={3.5}
/>
<chip
  name="ANT1"
  schPortArrangement={{
    rightSide: {
      pins: ["pin2", "pin1"],
      direction: "top-to-bottom",
    },
  }}
  schX={-14}
  schY={1.1}
/>

Memory Components

The circuit includes both Flash and PSRAM memory:

<chip
  name="U3" // Flash Memory
  manufacturerPartNumber="FLASH-3V3"
  schPortArrangement={{
    leftSide: {
      pins: ["pin1", "pin6", "pin7"],
      direction: "top-to-bottom",
    },
    bottomSide: {
      pins: ["pin4"],
      direction: "top-to-bottom",
    },
    rightSide: {
      pins: ["pin5", "pin2", "pin3"],
      direction: "top-to-bottom",
    },
    topSide: {
      pins: ["pin8"],
      direction: "top-to-bottom",
    },
  }}
  pinLabels={{
    pin1: "/CS",
    pin2: "DO",
    pin3: "/WP",
    pin4: "GND",
    pin5: "DI",
    pin6: "CLK",
    pin7: "/HOLD",
    pin8: "VDD_SDIO",
  }}
/>

Power Supply Considerations

The ESP32 requires several power domains:

  • VDD3P3_CPU: Main CPU power
  • VDD3P3_RTC: RTC power domain
  • VDDA: Analog power supply
  • VDD_SDIO: Memory interface power

Each domain needs proper decoupling:

<trace from=".C4 .pos" to="net.VDD33" />
<trace from=".C19 .pos" to="net.VDD33" />
<trace from=".C9 .pos" to="net.VDD33" />

GPIO Configuration

The ESP32 provides numerous GPIO pins that can be used for various purposes:

<trace from={ESP32.GPIO25} to="net.GPIO25" />
<trace from={ESP32.GPIO26} to="net.GPIO26" />
<trace from={ESP32.GPIO27} to="net.GPIO27" />
<trace from={ESP32.MTMS} to="net.GPIO14" />
<trace from={ESP32.MTDI} to="net.GPIO12" />

Testing Your Circuit

Click “Run” to see your circuit. You can switch between different views:

Schematic view showing the ESP32 and supporting components

Important Considerations

  1. Power Supply: The ESP32 requires a stable 3.3V power supply. Make sure all power domains are properly decoupled.

  2. Crystal Circuit: The crystal oscillator circuit is critical for proper operation. Pay attention to the capacitor values and trace lengths.

  3. RF Layout: The antenna section requires careful layout consideration. Keep traces short and maintain proper impedance matching.

  4. Memory Interface: The SPI flash and PSRAM connections should be kept short to ensure reliable high-speed operation.

Next Steps

Try modifying the design:

  • Add USB-to-UART bridge for programming
  • Include power management IC
  • Add status LEDs
  • Include programming/debug headers

Remember to save your snippet if you want to share it or use it in other projects!

The ESP32 is a complex device with many features. This tutorial covers the basic circuit implementation. For production designs, always refer to the official ESP32 hardware design guidelines.

Want to see this circuit in action? Check out the live example