Files
esp32-s3-sensor-node/finalize.py

173 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Generate a complete importable KiCad project for ESP32-S3 Sensor Node.
Creates netlist, component placement guide, and README.
"""
import os, json
PROJ_DIR = os.path.expanduser("~/Documents/KiCad/10.0/esp32-s3-sensor-node")
SCH = os.path.join(PROJ_DIR, "esp32-s3-sensor-node.kicad_sch")
PRO = os.path.join(PROJ_DIR, "esp32-s3-sensor-node.kicad_pro")
NETS = ["GND","3V3","VBUS","EN","IO0","IO12",
"SDA","SCL","USB_D_P","USB_D_N",
"CC1","CC2","IO2_LED","D1_A","RXD0","TXD0"]
PASSIVES = [
("R1", "Resistor_SMD:R_0603_1608Metric", 55, 30, 0, "IO2_LED", "D1_A", "470"),
("R2", "Resistor_SMD:R_0603_1608Metric", 27, 32, 0, "EN", "3V3", "10k"),
("R3", "Resistor_SMD:R_0603_1608Metric", 16, 7, 0, "IO0", "3V3", "10k"),
("R4", "Resistor_SMD:R_0603_1608Metric", 16, 12, 0, "IO12", "GND", "10k"),
("R5", "Resistor_SMD:R_0603_1608Metric", 48, 24, 0, "SDA", "3V3", "4.7k"),
("R6", "Resistor_SMD:R_0603_1608Metric", 48, 22, 0, "SCL", "3V3", "4.7k"),
("R7", "Resistor_SMD:R_0603_1608Metric", 11, 28, 0, "CC1", "GND", "5.1k"),
("R8", "Resistor_SMD:R_0603_1608Metric", 11, 25, 0, "CC2", "GND", "5.1k"),
("C1", "Capacitor_SMD:C_0603_1608Metric", 30, 28, 0, "3V3", "GND", "100nF"),
("C2", "Capacitor_SMD:C_0603_1608Metric", 30, 25, 0, "3V3", "GND", "100nF"),
("C3", "Capacitor_SMD:C_0603_1608Metric", 30, 22, 0, "3V3", "GND", "10uF"),
("C4", "Capacitor_SMD:C_0603_1608Metric", 26, 35, 0, "EN", "GND", "100nF"),
("C5", "Capacitor_SMD:C_0805_2012Metric", 24, 17, 0, "VBUS", "GND", "10uF"),
("C6", "Capacitor_SMD:C_0805_2012Metric", 24, 23, 0, "3V3", "GND", "10uF"),
]
ICS = [
("J1", "Connector_USB:USB_C_Receptacle_USB2.0_16P",
7, 20, 0, "USB-C", [("SH","GND"),("A1","GND"),("A4","VBUS"),
("A5","CC1"),("A6","USB_D_P"),("A7","USB_D_N"),("B5","CC2")]),
("U2", "Package_TO_SOT_SMD:SOT-223-3Lead_TabPin2",
20, 20, 0, "AMS1117-3.3", [("1","GND"),("2","3V3"),("3","VBUS")]),
("U1", "RF_Module:ESP32-S3-WROOM-1",
38, 20, 0, "ESP32-S3-WROOM-1", [("1","GND"),("2","3V3"),("3","EN"),
("4","SDA"),("5","SCL"),("13","USB_D_N"),("14","USB_D_P"),
("20","IO12"),("27","IO0"),("36","RXD0"),("37","TXD0"),("38","IO2_LED")]),
("J2", "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical",
56, 20, 0, "I2C_Sensor", [("1","3V3"),("2","SDA"),("3","SCL"),("4","GND")]),
("J3", "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical",
25, 3, 0, "PROG", [("1","GND"),("2","RXD0"),("3","TXD0"),("4","3V3")]),
("D1", "LED_SMD:LED_0603_1608Metric",
55, 34, 0, "LED_Green", [("1","GND"),("2","D1_A")]),
]
def create_readme():
md = f"""# ESP32-S3 Sensor Node — L2.1 Training Exercise
## Project Setup
1. **Open in KiCad 10.0+** — File → Open Project → `{PROJ_DIR}`
2. **Schematic** — Already clean (ERC 0). View in Eeschema.
3. **PCB Layout** — Needs routing. Create board in Pcbnew.
## PCB Spec
- **Size:** 65 × 40mm, 2-layer
- **Stackup:** 1.6mm FR4, 1oz copper, HASL
- **Design rules:** trace/space 0.15mm, drill 0.3mm, annular 0.15mm
- **Target fab:** JLCPCB / PCBWay standard
## Component Placement
```
Board: (0,0) bottom-left, (65,40) top-right
Left edge (x≈5-15):
J1 USB-C @ (7, 20) — left edge, USB mating face outward
R7 CC1 pull-down @ (11, 28)
R8 CC2 pull-down @ (11, 25)
Lower-left (x≈15-25, y≈3-15):
J3 PROG header @ (25, 3) — bottom edge
R3 IO0 pull-up @ (16, 7)
R4 IO12 pull-down @ (16, 12)
Center-left (x≈20-30):
U2 AMS1117-3.3 @ (20, 20) — regulator
C5 10µF input @ (24, 17) — near U2 pin 3 (VI)
C6 10µF output @ (24, 23) — near U2 pin 2 (VO)
Center (x≈27-38):
R2 EN pull-up @ (27, 32)
C4 EN cap @ (26, 35)
C1-C3 decoupling @ (30, 22-28) — near U1 3V3 pins
U1 ESP32-S3 @ (38, 20) — main module
Right side (x≈48-58):
R5 SDA pull-up @ (48, 24)
R6 SCL pull-up @ (48, 22)
J2 I2C connector @ (56, 20) — right edge
D1 Status LED @ (55, 34) — top-right edge
R1 LED resistor @ (55, 30)
```
## Antenna Keepout
- **Zone:** x > 46mm, y > 28mm (top-right corner)
- No copper, no traces, no components in this area
- The ESP32-S3-WROOM-1 module has its PCB antenna at the top-right corner
## Routing Order
1. **USB differential pair** — USB_D_P / USB_D_N: 90Ω impedance, length-matched
- Width: ~0.3mm on 1.6mm FR4 (calc with fab's tool)
- Gap: ~0.15mm
- Route on top layer, GND reference on bottom
2. **3V3 power** — 0.5mm traces from U2 VO to U1 3V3 pin + all 3V3 nodes
3. **VBUS power** — 0.5mm from J1 to U2 VI
4. **GND** — Copper pours on both layers with stitching vias
5. **I2C** — SDA/SCL routed together, away from noisy traces
6. **UART** — RXD0/TXD0 to J3
7. **Strapping** — EN, IO0, IO12 to pull resistors
8. **LED** — IO2_LED through R1 to D1
## GND Pour Strategy
- **B.Cu (bottom):** Full copper pour, entire board area
- **F.Cu (top):** Full copper pour EXCEPT antenna keepout zone
- **Antenna keepout:** Keepout zone polygon on both layers (no copper)
- **Stitching vias:** Perimeter every 5mm, plus around module GND pads
## Files
| File | Description |
|------|-------------|
| `*.kicad_sch` | Schematic (ERC 0) |
| `*.kicad_pcb` | PCB layout (empty, needs routing) |
| `*.kicad_pro` | Project file |
| `gen_schematic.py` | Python schematic generator |
| `gen_pcb.py` | Python PCB generator (outline + placement) |
"""
path = os.path.join(PROJ_DIR, "README.md")
with open(path, 'w') as f:
f.write(md)
print(f"Written: {path}")
def create_placement_csv():
"""Placement file for reference."""
path = os.path.join(PROJ_DIR, "placement.csv")
with open(path, 'w') as f:
f.write("Ref,Footprint,X(mm),Y(mm),Rotation,Net1,Net2\n")
for ref, fp, x, y, rot, n1, n2, val in PASSIVES:
f.write(f"{ref},{fp},{x},{y},{rot},{n1},{n2}\n")
for ref, fp, x, y, rot, val, pins in ICS:
nets = ", ".join(f"{p[0]}={p[1]}" for p in pins)
f.write(f"{ref},{fp},{x},{y},{rot},{nets}\n")
print(f"Written: {path}")
def update_project():
"""Update .kicad_pro with correct board path."""
# Read existing
if os.path.exists(PRO):
with open(PRO) as f:
config = json.load(f)
else:
config = {"board": {}}
# Ensure board settings exist
config["board"] = config.get("board", {})
config["board"]["design_settings"] = config["board"].get("design_settings", {})
with open(PRO, 'w') as f:
json.dump(config, f, indent=2)
print(f"Updated: {PRO}")
if __name__ == "__main__":
create_readme()
create_placement_csv()
update_project()
print("\nDone! Open the project in KiCad GUI:")
print(f" File → Open Project → {PROJ_DIR}/esp32-s3-sensor-node.kicad_pro")