💬 Sample prompts Paste any of these into Claude Code to use this skill
Map a molecule Map the pins of the RP2350B_RM2 molecule
Make a pin map Make a pin map for this KiCad project tying U1 pins to the MC contacts
Trace MC contacts Trace the MC perimeter contacts on this board to the main IC pins and silkscreen labels
Castellated mapping Extract the castellated-pad mapping for my molecule
Chip-to-firmware pinout Build one document tying chip package pins to PCB perimeter pads to firmware board_config.h
Install this skill

Paste this into Claude Code (VS Code panel, Adom editor, or terminal) to install:

Search the Adom Wiki for the skill "Molecule Pin Mapping" (slug: adom-pin-mapping) at https://wiki-ufypy5dpx93o.adom.cloud/wiki/skills/adom-pin-mapping and install it into my local ~/.claude/skills/adom-pin-mapping/ directory. Fetch the skill_source content from the wiki page and save it as SKILL.md. Then confirm it's installed by showing the first 5 lines.
?
What is a skill? Skills are instructions that teach AI assistants like Claude Code how to perform specific tasks. The description below is loaded into the AI as context when you invoke this skill. Well-written skills make the AI significantly more effective. Like Wikipedia, anyone can improve a skill by clicking Edit AI Skill — or have your AI submit an edit on your behalf.

Description

Edit AI Skill

Molecule Pin Mapping

Produce one canonical markdown file that, for a given molecule (KiCad project in adom-inc/adom-molecules or any .kicad_sch + .kicad_pcb pair), shows:

  1. Main IC (e.g. U1) pin number → net → silkscreen label on the PCB perimeter contact (MCx) → datasheet alt-functions (F1 SPI / F2 UART / F3 I2C / F4 PWM / F9 misc / ADC).
  2. For each chip wired through the molecule (sensors, PMICs, etc.): package Pin # / Pin Name / Net / "Connects to (host GPIO or rail)" / strap notes — pulled from the chip's datasheet and cross-checked against the firmware's board_config.h.

Output goes to a single markdown file, normally MoleculePinMapping.md at the repo root the user is working in.

What the user asked

$ARGUMENTS

If $ARGUMENTS names a molecule path (GitHub URL, local dir, or molecule name), use it directly. Otherwise ask once with AskUserQuestion which molecule + which firmware tree to cross-reference; do not loop on clarifying questions.

Phase 1 — Acquire the KiCad files

Two cases:

A. Molecule lives in adom-inc/adom-molecules on GitHub

gh api repos/adom-inc/adom-molecules/contents/"<CATEGORY>/<MOLECULE_DIR>" \
  --jq '.[] | {name, sha, size, type}'

Then pull the schematic and the PCB. The PCB is usually >1 MB so the --jq .content route hits a payload limit; use the git blob API instead with the sha you got above:

mkdir -p /tmp/mol && cd /tmp/mol

# small file: contents endpoint is fine
gh api repos/adom-inc/adom-molecules/contents/"<PATH>/<NAME>.kicad_sch" \
  --jq .content | base64 -d > sch.kicad_sch

# large PCB: use git blob
gh api "repos/adom-inc/adom-molecules/git/blobs/<SHA>" \
  --jq .content | base64 -d > pcb.kicad_pcb

Do not try curl on raw.githubusercontent.com for private repos — it 404s without auth. gh api carries the user's token.

B. Local files

If the user gives a path, just Read the .kicad_sch and .kicad_pcb directly (or use Bash cp to a working dir).

Phase 2 — Parse the PCB for net connectivity

The PCB is the authoritative source for pad ↔ net binding (the schematic uses hierarchical labels which are harder to resolve). Use this Python parser — it has worked on every Ray-style and JLCPCB-style KiCad 7/8 PCB tested so far:

import re

with open('pcb.kicad_pcb') as f:
    text = f.read()

# net id -> name
nets = {int(m[1]): m[2] for m in re.finditer(r'\(net (\d+) "([^"]*)"\)', text)}

# walk balanced parens to extract every (footprint ...) block
def blocks(tag, src):
    out = []; i = 0
    while True:
        idx = src.find(f'({tag} ', i)
        if idx == -1: return out
        d = 0; j = idx
        while j < len(src):
            c = src[j]
            if c == '(': d += 1
            elif c == ')':
                d -= 1
                if d == 0: out.append(src[idx:j+1]); i = j+1; break
            j += 1
        else: return out

footprints = blocks('footprint', text)

def get_ref(fp):
    m = re.search(r'\(property "Reference" "([^"]*)"', fp); return m and m.group(1)

def get_value(fp):
    m = re.search(r'\(property "Value" "([^"]*)"', fp); return m and m.group(1)

def get_pos(fp):
    m = re.search(r'\n\s*\(at ([-\d.]+) ([-\d.]+)', fp)
    return (float(m.group(1)), float(m.group(2))) if m else None

def get_pads(fp):
    pads = []
    for pm in re.finditer(r'\(pad "([^"]*)"', fp):
        s = pm.start(); d = 0; k = s
        while k < len(fp):
            c = fp[k]
            if c == '(': d += 1
            elif c == ')':
                d -= 1
                if d == 0: break
            k += 1
        block = fp[s:k+1]
        nm = re.search(r'\(net (\d+)', block)
        pads.append((pm.group(1), int(nm.group(1)) if nm else None))
    return pads

fps = {get_ref(fp): {'value': get_value(fp), 'pos': get_pos(fp), 'pads': get_pads(fp)}
       for fp in footprints if get_ref(fp)}

Now you have a ref → {value, pos, pads:[(padname, netid)]} map plus a netid → name map. Everything else is queries.

Phase 3 — Identify the main IC and the perimeter contacts

  • Main IC: usually U1. Confirm by checking value (e.g. RP2350_80QFN).
  • Perimeter contacts: reference designators starting with MC (machine contact). They are placed footprints on the board edge. Sometimes the schematic declares more MC references than are physically placed (those will be in the .kicad_sch but absent from .kicad_pcb — call that out as "(pad not placed)").

Build the mapping table by joining U1's pads to MC pads via shared netid:

# net -> [MCs on that net]
mc_on_net = {}
for ref, fp in fps.items():
    if ref.startswith('MC'):
        for p, n in fp['pads']:
            if n: mc_on_net.setdefault(n, []).append(ref)

for padname, netid in fps['U1']['pads']:
    netname = nets.get(netid, '')
    mcs = mc_on_net.get(netid, [])
    # → row: padname, netname, mcs

Phase 4 — Match silkscreen labels to perimeter contacts

The numbers/names you see printed on the board next to each MC live as (gr_text "..." (at X Y) (layer "F.SilkS")) entries (and sometimes B.SilkS). They are not stored on the footprint — you must spatial-match.

The trick that actually works:

  1. Compute the bounding box of all MC positions; this gives xmin/xmax/ymin/ymax.
  2. For each MC, decide which edge it sits on by which extreme it's closest to (Top / Bottom / Left / Right).
  3. Search inward from that edge for the nearest silk text, with a tight perpendicular window (≤ 0.9 mm) and a wider axial window (≤ 2.5 mm). The asymmetric window is what disambiguates between adjacent rows of labels — a centered nearest-neighbor search picks the wrong one when alt-function labels (e.g. Tx0, Rx1) and bare numbers are stacked in the same column.
import math
labels = [(m.group(1), float(m.group(2)), float(m.group(3)), m.group(4))
          for m in re.finditer(
            r'\(gr_text\s+"([^"]*)"\s*\(at ([-\d.]+) ([-\d.]+)(?:\s+[-\d.]+)?\)[^()]*\(layer "([^"]*)"',
            text)]

xs = [p['pos'][0] for r,p in fps.items() if r.startswith('MC')]
ys = [p['pos'][1] for r,p in fps.items() if r.startswith('MC')]
xmin,xmax,ymin,ymax = min(xs),max(xs),min(ys),max(ys)

def silk_for(mx, my):
    edge = min([(mx-xmin,'L'),(xmax-mx,'R'),(my-ymin,'T'),(ymax-my,'B')])[1]
    cands = []
    for t,lx,ly,lay in labels:
        if 'SilkS' not in lay: continue
        dx, dy = lx-mx, ly-my
        if   edge=='T' and 0.3<dy<2.5  and abs(dx)<0.9: cands.append((abs(dx), t))
        elif edge=='B' and -2.5<dy<-0.3 and abs(dx)<0.9: cands.append((abs(dx), t))
        elif edge=='L' and 0.3<dx<2.5  and abs(dy)<0.9: cands.append((abs(dy), t))
        elif edge=='R' and -2.5<dx<-0.3 and abs(dy)<0.9: cands.append((abs(dy), t))
    cands.sort()
    return cands[0][1].replace('\n',' ') if cands else ''

If the windows are too tight, MCs near corners come back empty — widen one axis at a time, never both. If the windows are too loose, alt-function labels on the row above/below leak in.

Phase 5 — Add datasheet alt-functions for the main IC

For RP2350 and RP2040 the GPIO function table (F1 SPI / F2 UART / F3 I2C / F4 PWM / F5 SIO / F6-F8 PIO / F9 clock-USB-XIP / F11 trace) follows a regular pattern:

  • F1 SPI: (GPIO % 4){0: RX, 1: CSn, 2: SCK, 3: TX} and (GPIO // 8) % 2 selects SPI0/SPI1.
  • F2 UART: similar regular pattern, (GPIO // 4) % 2 selects UART0/UART1.
  • F3 I2C: (GPIO % 2) → SDA/SCL; (GPIO // 2) % 2 selects I2C0/I2C1.
  • F4 PWM: GPIO // 2 → channel; GPIO % 2 → A/B.
  • ADC on RP2350B: GPIO40-47 = ADC0-7. (RP2350A has ADC on 26-29.)
  • F9 USB DET / VBUS EN / OVCUR / clock-GPIN / clock-GPOUT: enumerated in datasheet table — quote it as-is rather than computing.

For other ICs, transcribe their datasheet pin description table directly into the per-chip section. Mark "(per datasheet — confirm with current revision)" if you only have a generic family pinout, not the exact rev for that part number.

Phase 6 — Cross-reference firmware

Read <firmware>/include/board_config.h (and any header it includes for pin defs). Pull out:

  • I2C bus assignment (which GPnn is SDA, which is SCL, which I2C peripheral)
  • I2C clock and pull-up strategy
  • Any INT / DRDY / HIRQ / RESET / CS pin assignments
  • I2C addresses (in sensor_common.h or similar)

Put this in a "Firmware expectations" table at the bottom and explicitly mark sensor pins as "Not wired — polling-only" when no GPIO is assigned. Don't invent pin numbers.

If the firmware moves later (e.g. SDA/SCL get reassigned to a different GPIO pair), the only places to edit are: per-sensor tables (the "Connects to" column) and the "Firmware expectations" table at the bottom. Keep those two coherent.

Phase 7 — Compose the markdown

One file, this structure (preserve heading levels — the file is read by humans skimming for ## ChipName):

# Molecule Pin Mapping — <Board / Project Name>

<one-paragraph context: what board, which firmware trees consume it,
which I2C bus / SDA / SCL is shared, pull-up scheme>

---

## <Molecule Name> — Perimeter Contact Pin Map

Source: `<repo>` → `<path>/`. U1 = <chip>. MC1..MCn = castellated machine-pin contacts.

| MC | Silk | Net | RP2350 pin | Functions |
| ...

**RP2350B pins NOT routed to a perimeter contact:**
- Power: ...
- Crystal / VREG / USB / QSPI: ...

---

## <Sensor 1>

Package: <pkg>. I2C address <addr> (<strap>). Pinout per <datasheet section>.

| Pin # | Pin Name | Net on board | Connects to (host GPIO / rail) | Notes |
| ...

---

## <Sensor 2>
...

---

## Firmware expectations (must match wiring)

| Signal | Expected pin | Source |
| ...

**Wiring check — before power-on:**
1. ...

Common pitfalls (worth flagging in the output)

  • MC numbering is not always continuous. Some refs (e.g. MC54-MC57) exist in the schematic but the footprint is not placed. Show them as a single collapsed row with (pad not placed).
  • Pads associated with multiple identical pins. GND pads on a QFN show many pad "81" entries on the same net; collapse to one row in the user-facing table.
  • Silk labels with newlines (e.g. LDO\nEN is a two-line label). Normalize to a single space when displaying.
  • Shared labels like a single SWD covering both MC28 and MC29 — note "(IO)" and "(CLK)" suffixes in the table to distinguish.
  • Address straps: the silk often labels the function (e.g. Rx1, Tx0) rather than the GPIO number; both are correct and worth noting.

When to stop and ask

  • If $ARGUMENTS doesn't name a molecule, ask once for path/URL.
  • If multiple firmware trees could be the host, ask once which to use as the source of truth for board_config.h.
  • Otherwise, don't ask between phases — just produce the file and let the user diff.

Verification

After writing the file:

  1. Open it and spot-check 3 random rows in the U1 → MC table by re-running the Python parser to confirm the netname matches.
  2. Confirm at least one cross-reference back to the firmware (e.g. the SDA/SCL pin numbers in the bottom table appear in the per-sensor "Connects to" columns).
  3. Spot-check that no MC row is missing a silk label except the explicitly "(pad not placed)" ones.

Skill Source

Edit AI Skill
---
name: adom-pin-mapping
user-invocable: true
description: Build a complete pin-mapping markdown document for an Adom molecule (KiCad project) — main IC pin → perimeter machine-pin contact (MCx) → silkscreen label → datasheet alt-functions, plus per-sensor tables populated from datasheets and firmware board_config.h. Use when the user asks to "map the pins of <molecule>", "make a pin map", "trace MC contacts", "extract castellated-pad mapping", or wants a single document tying chip package pins to PCB perimeter pads to firmware.
---

# Molecule Pin Mapping

Produce one canonical markdown file that, for a given molecule (KiCad project in `adom-inc/adom-molecules` or any `.kicad_sch` + `.kicad_pcb` pair), shows:

1. **Main IC** (e.g. `U1`) pin number → net → silkscreen label on the PCB perimeter contact (`MCx`) → datasheet alt-functions (F1 SPI / F2 UART / F3 I2C / F4 PWM / F9 misc / ADC).
2. For each chip wired through the molecule (sensors, PMICs, etc.): package Pin # / Pin Name / Net / "Connects to (host GPIO or rail)" / strap notes — pulled from the chip's datasheet **and** cross-checked against the firmware's `board_config.h`.

Output goes to a single markdown file, normally `MoleculePinMapping.md` at the repo root the user is working in.

## What the user asked

$ARGUMENTS

If `$ARGUMENTS` names a molecule path (GitHub URL, local dir, or molecule name), use it directly. Otherwise ask **once** with `AskUserQuestion` which molecule + which firmware tree to cross-reference; do not loop on clarifying questions.

## Phase 1 — Acquire the KiCad files

Two cases:

### A. Molecule lives in `adom-inc/adom-molecules` on GitHub

```bash
gh api repos/adom-inc/adom-molecules/contents/"<CATEGORY>/<MOLECULE_DIR>" \
  --jq '.[] | {name, sha, size, type}'
```

Then pull the schematic and the PCB. The PCB is usually >1 MB so the `--jq .content` route hits a payload limit; use the **git blob API** instead with the sha you got above:

```bash
mkdir -p /tmp/mol && cd /tmp/mol

# small file: contents endpoint is fine
gh api repos/adom-inc/adom-molecules/contents/"<PATH>/<NAME>.kicad_sch" \
  --jq .content | base64 -d > sch.kicad_sch

# large PCB: use git blob
gh api "repos/adom-inc/adom-molecules/git/blobs/<SHA>" \
  --jq .content | base64 -d > pcb.kicad_pcb
```

Do **not** try `curl` on `raw.githubusercontent.com` for private repos — it 404s without auth. `gh api` carries the user's token.

### B. Local files

If the user gives a path, just `Read` the `.kicad_sch` and `.kicad_pcb` directly (or use Bash `cp` to a working dir).

## Phase 2 — Parse the PCB for net connectivity

The PCB is the authoritative source for pad ↔ net binding (the schematic uses hierarchical labels which are harder to resolve). Use this Python parser — it has worked on every Ray-style and JLCPCB-style KiCad 7/8 PCB tested so far:

```python
import re

with open('pcb.kicad_pcb') as f:
    text = f.read()

# net id -> name
nets = {int(m[1]): m[2] for m in re.finditer(r'\(net (\d+) "([^"]*)"\)', text)}

# walk balanced parens to extract every (footprint ...) block
def blocks(tag, src):
    out = []; i = 0
    while True:
        idx = src.find(f'({tag} ', i)
        if idx == -1: return out
        d = 0; j = idx
        while j < len(src):
            c = src[j]
            if c == '(': d += 1
            elif c == ')':
                d -= 1
                if d == 0: out.append(src[idx:j+1]); i = j+1; break
            j += 1
        else: return out

footprints = blocks('footprint', text)

def get_ref(fp):
    m = re.search(r'\(property "Reference" "([^"]*)"', fp); return m and m.group(1)

def get_value(fp):
    m = re.search(r'\(property "Value" "([^"]*)"', fp); return m and m.group(1)

def get_pos(fp):
    m = re.search(r'\n\s*\(at ([-\d.]+) ([-\d.]+)', fp)
    return (float(m.group(1)), float(m.group(2))) if m else None

def get_pads(fp):
    pads = []
    for pm in re.finditer(r'\(pad "([^"]*)"', fp):
        s = pm.start(); d = 0; k = s
        while k < len(fp):
            c = fp[k]
            if c == '(': d += 1
            elif c == ')':
                d -= 1
                if d == 0: break
            k += 1
        block = fp[s:k+1]
        nm = re.search(r'\(net (\d+)', block)
        pads.append((pm.group(1), int(nm.group(1)) if nm else None))
    return pads

fps = {get_ref(fp): {'value': get_value(fp), 'pos': get_pos(fp), 'pads': get_pads(fp)}
       for fp in footprints if get_ref(fp)}
```

Now you have a ref → `{value, pos, pads:[(padname, netid)]}` map plus a netid → name map. Everything else is queries.

## Phase 3 — Identify the main IC and the perimeter contacts

- **Main IC**: usually `U1`. Confirm by checking `value` (e.g. `RP2350_80QFN`).
- **Perimeter contacts**: reference designators starting with `MC` (machine contact). They are *placed* footprints on the board edge. Sometimes the schematic declares more `MC` references than are physically placed (those will be in the `.kicad_sch` but absent from `.kicad_pcb` — call that out as "(pad not placed)").

Build the mapping table by joining U1's pads to MC pads via shared netid:

```python
# net -> [MCs on that net]
mc_on_net = {}
for ref, fp in fps.items():
    if ref.startswith('MC'):
        for p, n in fp['pads']:
            if n: mc_on_net.setdefault(n, []).append(ref)

for padname, netid in fps['U1']['pads']:
    netname = nets.get(netid, '')
    mcs = mc_on_net.get(netid, [])
    # → row: padname, netname, mcs
```

## Phase 4 — Match silkscreen labels to perimeter contacts

The numbers/names you see printed on the board next to each MC live as `(gr_text "..." (at X Y) (layer "F.SilkS"))` entries (and sometimes `B.SilkS`). They are **not** stored on the footprint — you must spatial-match.

The trick that actually works:

1. Compute the bounding box of all MC positions; this gives `xmin/xmax/ymin/ymax`.
2. For each MC, decide which edge it sits on by which extreme it's closest to (Top / Bottom / Left / Right).
3. Search **inward from that edge** for the nearest silk text, with a tight perpendicular window (≤ 0.9 mm) and a wider axial window (≤ 2.5 mm). The asymmetric window is what disambiguates between adjacent rows of labels — a centered nearest-neighbor search picks the wrong one when alt-function labels (e.g. `Tx0`, `Rx1`) and bare numbers are stacked in the same column.

```python
import math
labels = [(m.group(1), float(m.group(2)), float(m.group(3)), m.group(4))
          for m in re.finditer(
            r'\(gr_text\s+"([^"]*)"\s*\(at ([-\d.]+) ([-\d.]+)(?:\s+[-\d.]+)?\)[^()]*\(layer "([^"]*)"',
            text)]

xs = [p['pos'][0] for r,p in fps.items() if r.startswith('MC')]
ys = [p['pos'][1] for r,p in fps.items() if r.startswith('MC')]
xmin,xmax,ymin,ymax = min(xs),max(xs),min(ys),max(ys)

def silk_for(mx, my):
    edge = min([(mx-xmin,'L'),(xmax-mx,'R'),(my-ymin,'T'),(ymax-my,'B')])[1]
    cands = []
    for t,lx,ly,lay in labels:
        if 'SilkS' not in lay: continue
        dx, dy = lx-mx, ly-my
        if   edge=='T' and 0.3<dy<2.5  and abs(dx)<0.9: cands.append((abs(dx), t))
        elif edge=='B' and -2.5<dy<-0.3 and abs(dx)<0.9: cands.append((abs(dx), t))
        elif edge=='L' and 0.3<dx<2.5  and abs(dy)<0.9: cands.append((abs(dy), t))
        elif edge=='R' and -2.5<dx<-0.3 and abs(dy)<0.9: cands.append((abs(dy), t))
    cands.sort()
    return cands[0][1].replace('\n',' ') if cands else ''
```

If the windows are too tight, MCs near corners come back empty — *widen one axis at a time*, never both. If the windows are too loose, alt-function labels on the row above/below leak in.

## Phase 5 — Add datasheet alt-functions for the main IC

For RP2350 and RP2040 the GPIO function table (F1 SPI / F2 UART / F3 I2C / F4 PWM / F5 SIO / F6-F8 PIO / F9 clock-USB-XIP / F11 trace) follows a regular pattern:

- F1 SPI: `(GPIO % 4)` → `{0: RX, 1: CSn, 2: SCK, 3: TX}` and `(GPIO // 8) % 2` selects SPI0/SPI1.
- F2 UART: similar regular pattern, `(GPIO // 4) % 2` selects UART0/UART1.
- F3 I2C: `(GPIO % 2)` → SDA/SCL; `(GPIO // 2) % 2` selects I2C0/I2C1.
- F4 PWM: `GPIO // 2` → channel; `GPIO % 2` → A/B.
- ADC on RP2350**B**: GPIO40-47 = ADC0-7. (RP2350**A** has ADC on 26-29.)
- F9 USB DET / VBUS EN / OVCUR / clock-GPIN / clock-GPOUT: enumerated in datasheet table — quote it as-is rather than computing.

For other ICs, transcribe their datasheet pin description table directly into the per-chip section. Mark "(per datasheet — confirm with current revision)" if you only have a generic family pinout, not the exact rev for that part number.

## Phase 6 — Cross-reference firmware

Read `<firmware>/include/board_config.h` (and any header it includes for pin defs). Pull out:

- I2C bus assignment (which `GPnn` is SDA, which is SCL, which I2C peripheral)
- I2C clock and pull-up strategy
- Any INT / DRDY / HIRQ / RESET / CS pin assignments
- I2C addresses (in `sensor_common.h` or similar)

Put this in a "Firmware expectations" table at the bottom and explicitly mark sensor pins as **"Not wired — polling-only"** when no GPIO is assigned. Don't invent pin numbers.

If the firmware moves later (e.g. SDA/SCL get reassigned to a different GPIO pair), the only places to edit are: per-sensor tables (the "Connects to" column) and the "Firmware expectations" table at the bottom. Keep those two coherent.

## Phase 7 — Compose the markdown

One file, this structure (preserve heading levels — the file is read by humans skimming for `## ChipName`):

```markdown
# Molecule Pin Mapping — <Board / Project Name>

<one-paragraph context: what board, which firmware trees consume it,
which I2C bus / SDA / SCL is shared, pull-up scheme>

---

## <Molecule Name> — Perimeter Contact Pin Map

Source: `<repo>` → `<path>/`. U1 = <chip>. MC1..MCn = castellated machine-pin contacts.

| MC | Silk | Net | RP2350 pin | Functions |
| ...

**RP2350B pins NOT routed to a perimeter contact:**
- Power: ...
- Crystal / VREG / USB / QSPI: ...

---

## <Sensor 1>

Package: <pkg>. I2C address <addr> (<strap>). Pinout per <datasheet section>.

| Pin # | Pin Name | Net on board | Connects to (host GPIO / rail) | Notes |
| ...

---

## <Sensor 2>
...

---

## Firmware expectations (must match wiring)

| Signal | Expected pin | Source |
| ...

**Wiring check — before power-on:**
1. ...
```

## Common pitfalls (worth flagging in the output)

- **MC numbering is not always continuous.** Some refs (e.g. `MC54-MC57`) exist in the schematic but the footprint is not placed. Show them as a single collapsed row with `(pad not placed)`.
- **Pads associated with multiple identical pins.** GND pads on a QFN show many `pad "81"` entries on the same net; collapse to one row in the user-facing table.
- **Silk labels with newlines** (e.g. `LDO\nEN` is a two-line label). Normalize to a single space when displaying.
- **Shared labels** like a single `SWD` covering both MC28 and MC29 — note "(IO)" and "(CLK)" suffixes in the table to distinguish.
- **Address straps**: the silk often labels the *function* (e.g. `Rx1`, `Tx0`) rather than the GPIO number; both are correct and worth noting.

## When to stop and ask

- If `$ARGUMENTS` doesn't name a molecule, ask once for path/URL.
- If multiple firmware trees could be the host, ask once which to use as the source of truth for `board_config.h`.
- Otherwise, **don't** ask between phases — just produce the file and let the user diff.

## Verification

After writing the file:

1. Open it and spot-check 3 random rows in the U1 → MC table by re-running the Python parser to confirm the netname matches.
2. Confirm at least one cross-reference back to the firmware (e.g. the SDA/SCL pin numbers in the bottom table appear in the per-sensor "Connects to" columns).
3. Spot-check that no MC row is missing a silk label except the explicitly "(pad not placed)" ones.

Sub-Skills
?
What are Sub-Skills?

Sub-skills are community-contributed AI skill extensions for this component. They teach AI assistants about specific tools, configurators, or workflows.

Examples:

  • A manufacturer’s configuration tool for a motor controller
  • A community-written design guide for an amplifier circuit
  • An automated test/validation script for a sensor module

How to add one: Click Add Sub-Skill, provide the URL to your skill and a brief description. Submissions are reviewed by the Adom team before going live.

No sub-skills yet. Be the first to contribute one!

Recent activity

2 commits
  • Edit v1.0.0 Drew Owens 1 month ago
    Add discovery_triggers and discovery_pitch so the skill surfaces for pin-map / MC-contact / castellated-mapping queries
  • 🏷
    Release v1.0.0 Drew Owens 1 month ago
    Initial wiki publish of the adom-pin-mapping skill — already lives in gallia (commits 5520905, eaf0e7c / PR #3) and installs into containers, but was never on the wiki. Publishing so it is discoverable and installable from wiki v1.
0 revisions · Updated 2026-05-28 16:19:56