ESP32 Minimum Dev Board
Contents
ESP32 Minimum Dev Board#
Intro#
In this chapter we will build a minimal ESP32 development board with SKiDL
. We will go through the entire PCB workflow including: circuit creation, PCB generation, part placement, routing, and generating manufacturing files.
Basic Example#
Let’s start by creating a folder called skidl_esp32_example
then create a file named skidl_esp32_example.py
. In skidl_esp32_example.py
we will:
Import the
SKiDL
librariesCreate the
ESP32
partGenerate a
netlist
from skidl import *
esp32 = Part('RF_Module','ESP32-WROOM-32', footprint='RF_Module:ESP32-WROOM-32')
generate_pcb()
When you run the code you’ll see a few files created as well as the skidl_esp32_example.kicad_pcb
file:
Open the .kicad_pcb
file in KiCAD.
Peripheral Circuits#
Now let’s add a bit more to this board. We’ll add a few components around the ESP32
Capacitors
on the power railsReset
buttonHeaders
to make all pins available
First, let’s make a bulk
and decoupling
capacitor. You can read more about why we need these 2 capacitors here
from skidl import *
esp32 = Part('RF_Module','ESP32-WROOM-32', footprint='RF_Module:ESP32-WROOM-32')
c_bulk = Part('Device', 'C', value='10uF', footprint='Capacitor_SMD:C_0603_1608Metric')
c_decoupling = Part('Device', 'C', value='100nF', footprint='Capacitor_SMD:C_0603_1608Metric')
generate_pcb()
Next, we’ll make the power nets V3_3
and GND
and attached them to the ESP32 as well as the capacitors:
from skidl import *
esp32 = Part('RF_Module','ESP32-WROOM-32', footprint='RF_Module:ESP32-WROOM-32')
c_bulk = Part('Device', 'C', value='10uF', footprint='Capacitor_SMD:C_0603_1608Metric')
c_decoupling = Part('Device', 'C', value='100nF', footprint='Capacitor_SMD:C_0603_1608Metric')
V3_3 = Net('V3_3')
GND = Net('GND')
V3_3 += esp32['VDD'], c_bulk[1], c_decoupling[1]
GND += esp32['GND'], c_bulk[2], c_decoupling[2]
generate_pcb()
Now we can add a reset button with a pull-up resistor and bypass capacitor circuitry:
from skidl import *
esp32 = Part('RF_Module','ESP32-WROOM-32', footprint='RF_Module:ESP32-WROOM-32')
c_bulk = Part('Device', 'C', value='10uF', footprint='Capacitor_SMD:C_0603_1608Metric')
c_bypass = Part('Device', 'C', value='100nF', footprint='Capacitor_SMD:C_0603_1608Metric')
V3_3 = Net('V3_3')
GND = Net('GND')
V3_3 += esp32['VDD'], c_bulk[1], c_bypass[1]
GND += esp32['GND'], c_bulk[2], c_bypass[2]
# Reset switch circuit
r_en_pullup = Part('Device', 'R', value='10k', footprint='Resistor_SMD:R_0603_1608Metric')
r_en_pullup[1] += esp32['EN']
r_en_pullup[2] += V3_3
c_en_filter = Part('Device', 'C', value='10uF', footprint='Capacitor_SMD:C_0603_1608Metric')
c_en_filter[1] += esp32['EN']
c_en_filter[2] += GND
switch = Part('Switch','SW_DPST', footprint='Button_Switch_THT:SW_Push_2P1T_Toggle_CK_PVA1xxH1xxxxxxV2')
switch[1,2] += esp32['EN']
switch[3,4] += GND
generate_pcb()
Now we’ll use some SKiDL
magic and breakout all the ESP32 pins to headers. We’ll make a function breakout_ic()
to take in any IC
and any header
:
from skidl import *
esp32 = Part('RF_Module','ESP32-WROOM-32', footprint='RF_Module:ESP32-WROOM-32')
c_bulk = Part('Device', 'C', value='10uF', footprint='Capacitor_SMD:C_0603_1608Metric')
c_bypass = Part('Device', 'C', value='100nF', footprint='Capacitor_SMD:C_0603_1608Metric')
V3_3 = Net('V3_3')
GND = Net('GND')
V3_3 += esp32['VDD'], c_bulk[1], c_bypass[1]
GND += esp32['GND'], c_bulk[2], c_bypass[2]
# Reset switch circuit
r_en_pullup = Part('Device', 'R', value='10k', footprint='Resistor_SMD:R_0603_1608Metric')
r_en_pullup[1] += esp32['EN']
r_en_pullup[2] += V3_3
c_en_filter = Part('Device', 'C', value='10uF', footprint='Capacitor_SMD:C_0603_1608Metric')
c_en_filter[1] += esp32['EN']
c_en_filter[2] += GND
switch = Part('Switch','SW_DPST', footprint='Button_Switch_THT:SW_Push_2P1T_Toggle_CK_PVA1xxH1xxxxxxV2')
switch[1,2] += esp32['EN']
switch[3,4] += GND
def breakout_ic(ic, header):
headers=[header()]
counter = 1
# Iterate through IC pins in pin order and connect them to a header
for n in range(1, len(ic.pins) +1): # ic.pins may not be in footprint order
pin = ic[n]
headers[-1][counter] += pin
counter += 1
# Check if we've reached the end of the header
if counter > len(header.pins):
counter = 1
# Add another copy of the header to the list
headers.append(header.copy())
# Disconnect all the pins of the new header
for i in headers[-1].pins:
i.disconnect()
header = Part('Connector', 'Conn_01x05_Male', footprint='Connector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Vertical', dest=TEMPLATE)
breakout_ic(esp32, header)
generate_pcb()
The parts are placed neatly on the PCB by another tool SKiDL runs in the background call HierPlace.
Feel free to move parts around before routing.
Routing#
To route the board we will use the auto-routing tool freerouting.
Create the fill-zone and fill it in
Export the pcb file as a
Specctra DNS
fileImport the
Specctra DNS
file intofreerouting
Auto-route
and export the result as aSpecctra Session File
Import the
Speccta Session File
into the pcb editor
Generate Gerbers#
Lastly, we generate gerber files to send to the board house for manufacturing.
Summary#
In this chapter we walked through the complete workflow to generate a minimal ESP32 development board. We saw how SKiDL
completely eliminates the need for schematic and allowed us to perform an interesting trick for breaking out the ESP32 pins.