diff --git a/docs/guides/importing-modules-and-chips/using-m2-connectors-for-micromod.mdx b/docs/guides/importing-modules-and-chips/using-m2-connectors-for-micromod.mdx new file mode 100644 index 00000000..b6d445c1 --- /dev/null +++ b/docs/guides/importing-modules-and-chips/using-m2-connectors-for-micromod.mdx @@ -0,0 +1,200 @@ +--- +title: Using M.2 Connectors for MicroMod Modules +description: How to model SparkFun MicroMod M.2 Key E edge connectors in tscircuit for processor-carrier board designs. +--- + +## Overview + +SparkFun's [MicroMod](https://www.sparkfun.com/micromod) ecosystem uses the **M.2 Key E** edge connector (75 pins, 0.5 mm pitch) to create swappable processor modules. A processor board (e.g., RP2040, ESP32, STM32) plugs into any compatible carrier board via a single M.2 edge connector. + +In tscircuit, you model the M.2 connector as a `` component. The same component definition works on both sides: + +- **Processor board** — the processor module exposes signals through the M.2 edge pads. +- **Carrier board** — the carrier hosts the physical M.2 socket and routes those signals to headers, sensors, or other peripherals. + +## Components + +| Ref | Part | Description | Footprint | +|-----|------|-------------|-----------| +| J1 | M.2 Key E connector | 75-pin, 0.5 mm pitch | `edge_connector_75p_m2_key_e` | +| U1 | Processor module | RP2040 / ESP32 / STM32 (varies) | Per-module stamp receiver | + +## MicroMod Signal Map + +The MicroMod specification assigns each M.2 pin a fixed function. Odd-numbered pins are GND; even-numbered pins carry signals: + +| Pin | Signal | Notes | +|-----|--------|-------| +| 2 | 3V3 | Regulated 3.3 V from carrier | +| 4 | 3V3_EN | 3.3 V enable (active high) | +| 6 | RESET | System reset (active low) | +| 8 | BOOT | Bootloader entry | +| 10 | USB_DM | USB D− | +| 12 | USB_DP | USB D+ | +| 16 | UART_TX1 | Primary UART transmit | +| 18 | UART_RX1 | Primary UART receive | +| 24 | I2C_SDA | Primary I²C data | +| 26 | I2C_SCL | Primary I²C clock | +| 34 | SPI_CS | SPI chip select | +| 36 | SPI_SCK | SPI clock | +| 38 | SPI_COPI | SPI controller out | +| 40 | SPI_CIPO | SPI controller in | +| 50 | A0 | Analog input 0 | +| 52 | A1 | Analog input 1 | +| 56 | PWM0 | PWM output 0 | +| 58 | PWM1 | PWM output 1 | +| 60 | D0 | Digital I/O 0 | +| 62 | D1 | Digital I/O 1 | +| 64–74 | G0–G5 | General-purpose I/O | + +All odd pins (1, 3, 5 … 75) are GND. + +## Defining the MicroMod Edge Connector + +Model the connector as a `` with the full 75-pin label map. Because every odd pin is GND, omit them from `schPinArrangement` to keep the schematic readable — only signal pins appear on the schematic side. + +import TscircuitIframe from "@site/src/components/TscircuitIframe" + + ( + +) + +export default () => ( + + + +) +`} /> + +## Connecting a Processor Module + +On the **processor board**, map your MCU's GPIO/peripheral pins to the correct M.2 pin numbers using the `connections` prop. Use pin number references (`sel.U1.pin6`) rather than label names when referencing chip pins — label names are not part of the global `sel` type union. + +```tsx +import { sel } from "@tscircuit/core" + +// RP2040 processor mapped to MicroMod signals + +``` + +## Carrier Board Pattern + +On the **carrier board**, the same connector definition appears but connections go outward to headers, sensors, or other chips: + +```tsx + +``` + +All GND pins connect to `net.GND` via `netlabel`: + +```tsx +{/* Connect all GND pins with net labels instead of individual connections */} + + +{/* ... repeat for all odd pins up to pin75 */} +``` + +## Footprint Note + +The MicroMod Key E footprint string `edge_connector_75p_m2_key_e` is a custom footprint. If the autorouter or renderer does not recognize it, import the footprint from KiCad using the KiCad library importer: + +```ts +import footprint from "@tscircuit/kicad-footprint/SparkFun-MicroMod/MicroMod_Key_E_Connector.kicad_mod" +``` + +See the [Importing from KiCad](./importing-from-kicad.md) guide for details on using `.kicad_mod` files in tscircuit. + +## Full Example: RP2040 Processor Board + +The [SparkFun MicroMod RP2040 Processor](https://www.sparkfun.com/products/17720) is a complete example that uses this connector. The tscircuit implementation is available in the [sparkfun-boards](https://github.com/tscircuit/sparkfun-boards) repository as a reference for both the processor module and the M.2 edge connector wiring pattern. diff --git a/docs/tutorials/draw-any-letter-with-leds.mdx b/docs/tutorials/draw-any-letter-with-leds.mdx new file mode 100644 index 00000000..ea5cadc4 --- /dev/null +++ b/docs/tutorials/draw-any-letter-with-leds.mdx @@ -0,0 +1,396 @@ +--- +title: Draw Any Letter with LEDs +description: >- + Learn how to use tscircuit and the @tscircuit/alphabet package to + automatically place 0402 LEDs along the outline of any capital letter, + producing a reusable LedLetter component. +--- + +## Overview + +In this tutorial you will build a reusable `` component that draws +any capital letter (A–Z) by placing 0402 LEDs along the letter's outline path. +The layout is fully automatic — you supply a letter and a size, and math does +the rest. + +import TscircuitIframe from "@site/src/components/TscircuitIframe" + +## Step 1: Sample points along an SVG path + +The `@tscircuit/alphabet` package exports `svgAlphabet`, a map from each +character to a normalized SVG path string (coordinates in `[0, 1]`). We need +to convert that path into a list of evenly-spaced `{x, y}` points so we know +where to place each LED. + + ( + + {pts.map((p, i) => ( + + ))} + +) +`} /> + +## Step 2: Add current-limiting resistors + +Each LED string needs a resistor (typically 68–100 Ω for a red 0402 LED at +5 V). We add one resistor per LED wired in series. + + { + const pts = samplePath(LETTER_A, 10) + const W = 20 // letter width in mm + const H = 25 // letter height in mm + + return ( + + {pts.map((p, i) => { + const px = (p.x - 0.5) * W + const py = (0.5 - p.y) * H + return ( + <> + + + + ) + })} + + ) +} +`} /> + +## Step 3: Build the reusable LedLetter component + +Now we wrap everything in a component that accepts any capital letter and a +scale factor. All 26 letters (A–Z) are supported using the path data from +`@tscircuit/alphabet`. + + { + const path = svgAlphabet[letter.toUpperCase()] + if (!path) return null + const pts = samplePath(path, nLeds) + + return ( + <> + {pts.map((p, i) => { + const px = offsetX + (p.x - 0.3) * width + const py = offsetY + (0.6 - p.y) * height + const ledName = namePrefix + letter + \`_LED\${i + 1}\` + const resName = namePrefix + letter + \`_R\${i + 1}\` + const midNet = \`net.\${ledName}_A\` + return ( + <> + + + + ) + })} + + ) +} + +export default () => ( + + + + + + + +) +`} /> + +## Step 4: Complete usage example + +Here is the complete `` component with all 26 letters supported, +ready to copy into your own project. + +```tsx +import { svgAlphabet } from "@tscircuit/alphabet" + +function samplePath(pathStr: string, n: number) { + const points: { x: number; y: number }[] = [] + const tokens = pathStr.trim().split(/\s+/) + let i = 0 + while (i < tokens.length) { + const cmd = tokens[i++] + if (cmd === "M" || cmd === "L") { + points.push({ x: parseFloat(tokens[i]), y: parseFloat(tokens[i + 1]) }) + i += 2 + } + } + if (points.length < 2) return points + const arcLen = [0] + for (let j = 1; j < points.length; j++) { + const dx = points[j].x - points[j - 1].x + const dy = points[j].y - points[j - 1].y + arcLen.push(arcLen[j - 1] + Math.sqrt(dx * dx + dy * dy)) + } + const total = arcLen.at(-1)! + const result: { x: number; y: number }[] = [] + for (let k = 0; k < n; k++) { + const target = (k / (n - 1)) * total + let seg = 0 + while (seg < arcLen.length - 1 && arcLen[seg + 1] < target) seg++ + const segLen = arcLen[seg + 1] - arcLen[seg] + const t = segLen === 0 ? 0 : (target - arcLen[seg]) / segLen + result.push({ + x: points[seg].x + t * (points[seg + 1].x - points[seg].x), + y: points[seg].y + t * (points[seg + 1].y - points[seg].y), + }) + } + return result +} + +interface LedLetterProps { + letter: string // Any capital A–Z letter + power: string // Net name for VCC (e.g. "net.PWR") + gnd: string // Net name for GND (e.g. "net.GND") + offsetX?: number // PCB X offset in mm + offsetY?: number // PCB Y offset in mm + width?: number // Letter width in mm (default 18) + height?: number // Letter height in mm (default 24) + nLeds?: number // Number of LEDs (default 14) + namePrefix?: string // Prefix to avoid name collisions +} + +export const LedLetter = ({ + letter, + power, + gnd, + offsetX = 0, + offsetY = 0, + width = 18, + height = 24, + nLeds = 14, + namePrefix = "", +}: LedLetterProps) => { + const path = svgAlphabet[letter.toUpperCase() as keyof typeof svgAlphabet] + if (!path) return null + const pts = samplePath(path, nLeds) + + return ( + <> + {pts.map((p, i) => { + const px = offsetX + (p.x - 0.3) * width + const py = offsetY + (0.6 - p.y) * height + const ledName = `${namePrefix}${letter}_LED${i + 1}` + const resName = `${namePrefix}${letter}_R${i + 1}` + const midNet = `net.${ledName}_A` + return ( + <> + + + + ) + })} + + ) +} +``` + +Usage: + +```tsx +export default () => ( + + + + +) +``` diff --git a/docs/tutorials/esp32-pcb-layout-and-routing.mdx b/docs/tutorials/esp32-pcb-layout-and-routing.mdx new file mode 100644 index 00000000..21f23f3c --- /dev/null +++ b/docs/tutorials/esp32-pcb-layout-and-routing.mdx @@ -0,0 +1,511 @@ +--- +title: ESP32 PCB Layout and Routing +description: Learn how to place and route an ESP32 module board in tscircuit — module placement, antenna keepout, decoupling capacitors, USB power, and autorouting. +--- + +## Overview + +This tutorial builds a complete ESP32 development board PCB step by step. You will +place the ESP32-WROOM-32 module, add power circuitry, wire up a USB-to-UART +bridge for programming, and let the autorouter connect everything. + +Good PCB layout for an ESP32 follows three placement rules: +1. The module antenna must hang over the board edge with no copper beneath it. +2. The 3.3 V supply path (USB connector → regulator → module) should be short. +3. Programming controls (EN reset, IO0 boot) live next to the module with their + pull-up resistors and pushbuttons nearby. + +import TscircuitIframe from "@site/src/components/TscircuitIframe" + +## Step 1: Place the ESP32 Module + +The ESP32-WROOM-32 is a stamp-style module. In tscircuit it is modelled as a +`` with the `stampreceiver` footprint family. The footprint string encodes +the pad count and spacing: + +``` +stampreceiver_left14_right14_bottom10_top0_w18mm_p1.27mm +``` + +Place the module near the **top edge** of the board so the antenna side (the +rounded end of the WROOM module) points outward away from the rest of the +circuitry. + + ( + +) + +export default () => ( + + + +) +`} /> + +The `pcbY={8}` shifts the module toward the top of the 40 mm board, leaving +room below for power and programming components. + +## Step 2: Add USB Power and 3.3 V Regulation + +The ESP32 runs on 3.3 V but USB supplies 5 V. We need: +- A **USB-C connector** for power input +- An **AMS1117-3.3** LDO regulator (SOT-223 package) to step 5 V down to 3.3 V +- **Decoupling capacitors** on both sides of the regulator + +Place the USB connector at the left board edge and the regulator between it and +the module to keep the high-current 5 V path short. + + ( + +) + +export default () => ( + + + + {/* USB-C power input at the left board edge */} + + + {/* AMS1117-3.3 LDO: VIN=VBUS, VOUT=3V3 */} + + + {/* 10 uF input bulk cap (close to regulator VIN) */} + + + {/* 10 uF output bulk cap (close to regulator VOUT) */} + + + {/* 100 nF bypass cap right at the ESP32 3V3 pin */} + + + {/* Power rails to ESP32 */} + + + + + + +) +`} /> + +The regulator at `pcbX={-10}` sits between the USB connector (`pcbX={-22}`) and +the module (`pcbX={0}`), creating a straight left-to-right power flow that is +easy to review. + +## Step 3: Add the USB-to-UART Bridge + +To program the ESP32 over USB you need a serial bridge chip. The **CH340G** +(SOP-16) converts USB signals to the UART RX/TX lines the ESP32 bootloader uses. + +The bridge also drives the **DTR** and **RTS** hardware flow-control lines. +Those connect to the ESP32's EN and IO0 pins through 100 nF capacitors to +implement the automatic reset-into-bootloader sequence that the Arduino IDE and +`esptool` rely on. + + ( + +) + +export default () => ( + + + + + + + + {/* CH340G USB-UART bridge */} + + + {/* UART cross-connect: CH340 TX→ESP RX, CH340 RX←ESP TX */} + + + + {/* Auto-reset: DTR/RTS → 100nF caps → EN/IO0 */} + + + + + + {/* USB D+/D- to CH340 */} + + + + {/* Decoupling on CH340 VCC */} + + + + + + + + + + + + +) +`} /> + +The auto-reset capacitors on C4 and C5 implement the standard ESP32 reset +circuit: when a host asserts DTR and then RTS (or vice versa), the resulting +pulse drives EN low followed by IO0 low, putting the chip into download mode +without you pressing any buttons. + +## Step 4: EN Reset and BOOT Buttons + +Even with automatic reset, physical buttons are important for manual recovery. +Place the **EN** (reset) button and the **IO0** (boot mode) button near the +right edge of the board with their 10 kΩ pull-up resistors right beside them. + + ( + +) + +export default () => ( + + + + + + + + + + {/* 10k pull-up on EN */} + + + {/* EN reset button */} + + + {/* 10k pull-up on IO0 */} + + + {/* BOOT button */} + + + + + + + + + + + + + + + + + + + + + + +) +`} /> + +Pressing SW1 (EN) resets the ESP32. Pressing SW2 (IO0) while holding SW1 puts +it into download mode so you can flash firmware manually without needing the +auto-reset circuit. + +## Step 5: Autorouting + +Once component placement is done, tscircuit can route all the traces automatically. +Add `autorouter="auto-cloud"` to the `` element to use the cloud autorouter, +or `autorouter="sequential-trace"` for the local solver: + +```tsx + + ... + +``` + +The autorouter reads every `connections` prop and every `` you added, +so there is nothing extra to configure. After routing you can switch to the PCB +tab in the preview to inspect trace widths and clearances. + +### Placement tips that help the autorouter + +- **Short nets first**: the regulator-to-module 3V3 path and the UART TX/RX + crossover are the nets most affected by placement order. +- **Avoid crossing power nets**: keep VBUS traces on the left side of the board + and 3V3 traces in the middle so they do not create unnecessary crossings that + require vias. +- **Put bypass caps as close as possible**: C3 (module bypass) and C6 (CH340 + bypass) should be within 2–3 mm of their respective IC's power pin to minimize + the inductance the router must deal with. + +## Pre-fabrication checklist + +Before exporting Gerbers: + +- [ ] The antenna end of the ESP32 module hangs over the board edge, or at least + no copper, vias, or components appear within 3 mm of the antenna window. +- [ ] C1 is within 5 mm of the USB connector VBUS pin. +- [ ] C3 is within 3 mm of U1 pin 2 (3V3). +- [ ] C6 is within 3 mm of U3 pin 16 (VCC). +- [ ] All GND pins on U1 (pins 1, 15, 37, 38) connect to the same GND net. +- [ ] The UART crossover is correct: U3 TXD → U1 RXD0, U3 RXD ← U1 TXD0. +- [ ] Both pushbuttons are reachable from the board edge.