← Commit history

sections: pinout and tools get their own blocks (adom/wiki#148); the readme is reference material again

Ray ·7b7f382872 ·2mo ago ·parent c8f4ca8
4 files changed +611−23
page.json+9−3
@@ -4,7 +4,7 @@   "slug": "stm32f103c8t6",   "title": "STM32F103C8T6 - Arm Cortex-M3 MCU (Blue Pill)",   "brief": "STMicroelectronics mainstream Arm Cortex-M3 MCU. 72 MHz, 64 KB Flash, 20 KB SRAM, USB, CAN, LQFP-48. The workhorse Blue Pill microcontroller.",-  "version": "0.2.8",+  "version": "0.3.0",   "tags": [     "component",     "microcontroller",@@ -160,7 +160,7 @@     "stm32f103c8t6-board.glb",     "thumbnails/**"   ],-  "changelog": "0.2.8: Fusion/EAGLE library applet, built on Linux where adom-lbr runs.",+  "changelog": "0.3.0: pinout and tools become their own sections (adom/wiki#148); the readme is reference material only.",   "applet_connect": [     "https://verify-3i7rt4do98l3.adom.cloud",     "https://component-ocean-jk89eeqplwfl.adom.cloud",@@ -169,7 +169,13 @@   "sections": [     "hero",     "viewers",+    "pinout",     "readme",+    "tools",     "info"-  ]+  ],+  "section_sources": {+    "pinout": "sections/pinout.html",+    "tools": "sections/tools.html"+  } }
readme.html−20
@@ -130,26 +130,6 @@ tr[data-pin].hl td,tr[data-pin].hl td.data{color:var(--text)} <div class=callout>The <b>3D, symbol, and footprint viewers at the top of the page</b> are a single cross-linked set (hover a pin, pad, or 3D lead and they light up together, with layer toggles and datasheet tooltips). The <b>datasheet pin map</b> below is cross-linked to them too &mdash; hover a row to light the matching pin in the viewers above. Downloadable CAD and the datasheet PDF are on the Files tab (<code>.kicad_sym</code>, <code>.kicad_mod</code>, <code>.step</code>, <code>.glb</code>).</div> </div> -<h2 id=pinout>Datasheet pin map <span class=s>hover a row to light the matching pin in the viewers above &mdash; grouped by function, with the datasheet description for every pin</span></h2>-<div class=pinout>-  <div class=pintbl><div class=pingroup><h3>POWER <span style="color:var(--text-3);font-weight:400">(9)</span></h3><table><thead><tr><th style=width:44px>Pin</th><th style=width:170px>Name</th><th style=width:70px>Type</th><th>Function (datasheet)</th></tr></thead><tbody><tr data-pin="1"><td class=data>1</td><td class=data>VBAT</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Backup battery supply for RTC and backup registers. Typical operating range 1.8 to 3.6 V. Supplies the RTC and backup domain when VDD is off.</td></tr><tr data-pin="8"><td class=data>8</td><td class=data>VSSA</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Analog ground reference for ADC, reset block, PLL, and analog peripherals. Connect to digital ground at a single point.</td></tr><tr data-pin="9"><td class=data>9</td><td class=data>VDDA</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Analog supply for ADC, reset block, PLL, and analog I/O. 2.0 to 3.6 V. Decouple with 1 µF + 10 nF close to the pin.</td></tr><tr data-pin="23"><td class=data>23</td><td class=data>VSS_1</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Digital ground, group 1. Connect to the ground plane; keep short return path to VDD_1 decoupling.</td></tr><tr data-pin="24"><td class=data>24</td><td class=data>VDD_1</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Digital supply, group 1. 2.0 to 3.6 V. Decouple with 100 nF close to the pin.</td></tr><tr data-pin="35"><td class=data>35</td><td class=data>VSS_2</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Digital ground, group 2. Connect to the ground plane; pair with VDD_2 decoupling.</td></tr><tr data-pin="36"><td class=data>36</td><td class=data>VDD_2</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Digital supply, group 2. 2.0 to 3.6 V. Decouple with 100 nF close to the pin.</td></tr><tr data-pin="47"><td class=data>47</td><td class=data>VSS_3</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Digital ground, group 3. Connect to the ground plane; pair with VDD_3 decoupling.</td></tr><tr data-pin="48"><td class=data>48</td><td class=data>VDD_3</td><td><span class="tbadge t-power">Power</span></td><td class=note style="color:var(--text-2)">Digital supply, group 3. 2.0 to 3.6 V. Decouple with 100 nF close to the pin.</td></tr></tbody></table></div><div class=pingroup><h3>GPIO <span style="color:var(--text-3);font-weight:400">(26)</span></h3><table><thead><tr><th style=width:44px>Pin</th><th style=width:170px>Name</th><th style=width:70px>Type</th><th>Function (datasheet)</th></tr></thead><tbody><tr data-pin="2"><td class=data>2</td><td class=data>PC13-TAMPER-RTC</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port C bit 13, muxed with TAMPER input and RTC output. Supplied through the backup power switch (limited to 3 mA sink); output speed limited to 2 MHz with max 30 pF load; must not source current.</td></tr><tr data-pin="10"><td class=data>10</td><td class=data>PA0-WKUP</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 0, 5 V-tolerant when configured as digital input. Alternate functions: standby WKUP, USART2_CTS (remap), ADC12_IN0, TIM2_CH1_ETR.</td></tr><tr data-pin="11"><td class=data>11</td><td class=data>PA1</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 1. Alternate functions: USART2_RTS, ADC12_IN1, TIM2_CH2.</td></tr><tr data-pin="12"><td class=data>12</td><td class=data>PA2</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 2. Alternate functions: USART2_TX, ADC12_IN2, TIM2_CH3.</td></tr><tr data-pin="13"><td class=data>13</td><td class=data>PA3</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 3. Alternate functions: USART2_RX, ADC12_IN3, TIM2_CH4.</td></tr><tr data-pin="14"><td class=data>14</td><td class=data>PA4</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 4. Alternate functions: SPI1_NSS, USART2_CK, ADC12_IN4.</td></tr><tr data-pin="15"><td class=data>15</td><td class=data>PA5</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 5. Alternate functions: SPI1_SCK, ADC12_IN5.</td></tr><tr data-pin="16"><td class=data>16</td><td class=data>PA6</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 6. Alternate functions: SPI1_MISO, ADC12_IN6, TIM3_CH1; remap: TIM1_BKIN.</td></tr><tr data-pin="17"><td class=data>17</td><td class=data>PA7</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 7. Alternate functions: SPI1_MOSI, ADC12_IN7, TIM3_CH2; remap: TIM1_CH1N.</td></tr><tr data-pin="18"><td class=data>18</td><td class=data>PB0</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 0. Alternate functions: ADC12_IN8, TIM3_CH3; remap: TIM1_CH2N.</td></tr><tr data-pin="19"><td class=data>19</td><td class=data>PB1</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 1. Alternate functions: ADC12_IN9, TIM3_CH4; remap: TIM1_CH3N.</td></tr><tr data-pin="20"><td class=data>20</td><td class=data>PB2</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 2, 5 V-tolerant. Doubles as BOOT1 boot mode selection input sampled at reset.</td></tr><tr data-pin="21"><td class=data>21</td><td class=data>PB10</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 10, 5 V-tolerant. Alternate functions: I2C2_SCL, USART3_TX; remap: TIM2_CH3.</td></tr><tr data-pin="22"><td class=data>22</td><td class=data>PB11</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 11, 5 V-tolerant. Alternate functions: I2C2_SDA, USART3_RX; remap: TIM2_CH4.</td></tr><tr data-pin="25"><td class=data>25</td><td class=data>PB12</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 12, 5 V-tolerant. Alternate functions: SPI2_NSS, I2C2_SMBAl, USART3_CK, TIM1_BKIN.</td></tr><tr data-pin="26"><td class=data>26</td><td class=data>PB13</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 13, 5 V-tolerant. Alternate functions: SPI2_SCK, USART3_CTS, TIM1_CH1N.</td></tr><tr data-pin="27"><td class=data>27</td><td class=data>PB14</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 14, 5 V-tolerant. Alternate functions: SPI2_MISO, USART3_RTS, TIM1_CH2N.</td></tr><tr data-pin="28"><td class=data>28</td><td class=data>PB15</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 15, 5 V-tolerant. Alternate functions: SPI2_MOSI, TIM1_CH3N.</td></tr><tr data-pin="29"><td class=data>29</td><td class=data>PA8</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 8, 5 V-tolerant. Alternate functions: USART1_CK, TIM1_CH1, MCO (master clock output).</td></tr><tr data-pin="30"><td class=data>30</td><td class=data>PA9</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 9, 5 V-tolerant. Alternate functions: USART1_TX, TIM1_CH2.</td></tr><tr data-pin="31"><td class=data>31</td><td class=data>PA10</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 10, 5 V-tolerant. Alternate functions: USART1_RX, TIM1_CH3.</td></tr><tr data-pin="41"><td class=data>41</td><td class=data>PB5</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 5 (NOT 5 V-tolerant on this pin). Alternate functions: I2C1_SMBAl; remap: TIM3_CH2, SPI1_MOSI.</td></tr><tr data-pin="42"><td class=data>42</td><td class=data>PB6</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 6, 5 V-tolerant. Alternate functions: I2C1_SCL, TIM4_CH1; remap: USART1_TX.</td></tr><tr data-pin="43"><td class=data>43</td><td class=data>PB7</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 7, 5 V-tolerant. Alternate functions: I2C1_SDA, TIM4_CH2; remap: USART1_RX.</td></tr><tr data-pin="45"><td class=data>45</td><td class=data>PB8</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 8, 5 V-tolerant. Alternate functions: TIM4_CH3; remap: I2C1_SCL, CANRX.</td></tr><tr data-pin="46"><td class=data>46</td><td class=data>PB9</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 9, 5 V-tolerant. Alternate functions: TIM4_CH4; remap: I2C1_SDA, CANTX.</td></tr></tbody></table></div><div class=pingroup><h3>TIMING <span style="color:var(--text-3);font-weight:400">(4)</span></h3><table><thead><tr><th style=width:44px>Pin</th><th style=width:170px>Name</th><th style=width:70px>Type</th><th>Function (datasheet)</th></tr></thead><tbody><tr data-pin="3"><td class=data>3</td><td class=data>PC14-OSC32_IN</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port C bit 14, muxed with 32 kHz LSE oscillator input (OSC32_IN). Backup-domain pin routed through the power switch; same 2 MHz / 30 pF drive limitation as PC13.</td></tr><tr data-pin="4"><td class=data>4</td><td class=data>PC15-OSC32_OUT</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port C bit 15, muxed with 32 kHz LSE oscillator output (OSC32_OUT). Backup-domain pin routed through the power switch; same 2 MHz / 30 pF drive limitation as PC13/PC14.</td></tr><tr data-pin="5"><td class=data>5</td><td class=data>PD0-OSC_IN</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">HSE crystal oscillator input (OSC_IN) after reset; remappable to GPIO PD0 by software. In GPIO mode limited to 50 MHz output. Connect to 4-16 MHz crystal or external clock.</td></tr><tr data-pin="6"><td class=data>6</td><td class=data>PD1-OSC_OUT</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">HSE crystal oscillator output (OSC_OUT) after reset; remappable to GPIO PD1 by software. In GPIO mode limited to 50 MHz output.</td></tr></tbody></table></div><div class=pingroup><h3>CONTROL <span style="color:var(--text-3);font-weight:400">(2)</span></h3><table><thead><tr><th style=width:44px>Pin</th><th style=width:170px>Name</th><th style=width:70px>Type</th><th>Function (datasheet)</th></tr></thead><tbody><tr data-pin="7"><td class=data>7</td><td class=data>NRST</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">Active-low bidirectional device reset. Pulled low by internal or external reset sources; external pull-up recommended (typ 40 kΩ internal weak pull-up).</td></tr><tr data-pin="44"><td class=data>44</td><td class=data>BOOT0</td><td></td><td class=note style="color:var(--text-2)">Boot mode selection input sampled at reset (with BOOT1/PB2): selects boot from Flash, System memory (bootloader), or embedded SRAM. Must be tied to a defined logic level.</td></tr></tbody></table></div><div class=pingroup><h3>USB <span style="color:var(--text-3);font-weight:400">(2)</span></h3><table><thead><tr><th style=width:44px>Pin</th><th style=width:170px>Name</th><th style=width:70px>Type</th><th>Function (datasheet)</th></tr></thead><tbody><tr data-pin="32"><td class=data>32</td><td class=data>PA11</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 11, 5 V-tolerant. Alternate functions: USART1_CTS, CANRX, USBDM (USB D-), TIM1_CH4.</td></tr><tr data-pin="33"><td class=data>33</td><td class=data>PA12</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 12, 5 V-tolerant. Alternate functions: USART1_RTS, CANTX, USBDP (USB D+), TIM1_ETR.</td></tr></tbody></table></div><div class=pingroup><h3>DEBUG <span style="color:var(--text-3);font-weight:400">(5)</span></h3><table><thead><tr><th style=width:44px>Pin</th><th style=width:170px>Name</th><th style=width:70px>Type</th><th>Function (datasheet)</th></tr></thead><tbody><tr data-pin="34"><td class=data>34</td><td class=data>PA13</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 13, 5 V-tolerant. Default after reset: JTMS/SWDIO (serial-wire debug data/JTAG mode select). Can be released to GPIO via SWJ-DP disable.</td></tr><tr data-pin="37"><td class=data>37</td><td class=data>PA14</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 14, 5 V-tolerant. Default after reset: JTCK/SWCLK (serial-wire debug clock/JTAG clock).</td></tr><tr data-pin="38"><td class=data>38</td><td class=data>PA15</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port A bit 15, 5 V-tolerant. Default after reset: JTDI (JTAG data in). Remappable to TIM2_CH1_ETR/PA15/SPI1_NSS.</td></tr><tr data-pin="39"><td class=data>39</td><td class=data>PB3</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 3, 5 V-tolerant. Default after reset: JTDO / TRACESWO. Remappable to TIM2_CH2, PB3, SPI1_SCK.</td></tr><tr data-pin="40"><td class=data>40</td><td class=data>PB4</td><td><span class="tbadge t-io">I/O</span></td><td class=note style="color:var(--text-2)">GPIO port B bit 4, 5 V-tolerant. Default after reset: NJTRST (JTAG reset, active low). Remappable to TIM3_CH1, PB4, SPI1_MISO.</td></tr></tbody></table></div></div>-</div>--<h2 id=pin1>Pin 1, chip against footprint <span class=s>the datasheet already says which pad is pin 1; what matters is whether pin 1 on the chip lands on pin 1 of the footprint, because when they disagree the part goes down rotated</span></h2>-<script src="https://verify-3i7rt4do98l3.adom.cloud/applet.js"></script>-<adom-verify-  page="STM32F103C8T6" fact="pin-1-registration" wiki-page="adom/stm32f103c8t6"-  chip-image="https://wiki.adom.inc/blob/component/stm32f103c8t6/pin1/chip-top.png"-  footprint-svg="https://wiki.adom.inc/blob/component/stm32f103c8t6/pin1/footprint.svg"></adom-verify>--<h2 id=fusion-lbr>Fusion / EAGLE library <span class=s>web control cannot build one: a bridge runs on Windows or macOS, adom-lbr is Linux-only, and a browser runs no binaries. So this button asks a Linux service that has it</span></h2>-<script src="https://lbr-5o0yi1odd4w1.adom.cloud/applet.js"></script>-<adom-fusion-lbr page="adom/stm32f103c8t6"></adom-fusion-lbr>--<h2 id=sourcing>Price and stock <span class=s>the one thing on this page that cannot be baked: it changes without the page changing, so the button asks Component Ocean live</span></h2>-<script src="https://component-ocean-jk89eeqplwfl.adom.cloud/applet.js"></script>-<adom-sourcing mpn="STM32F103C8T6" wiki-page="adom/stm32f103c8t6"></adom-sourcing>- <h2>Datasheet key pages <span class=s>the pages worth looking at first &middot; pick a page, click it to go full screen</span></h2> <div class=dsviewer>   <div class=dsrail><button data-i="0" class="on" title="Features (datasheet p.1)"><img src="https://wiki.adom.inc/blob/component/stm32f103c8t6/keypages/features.png" loading=lazy alt="Features"><span class=rl>Features</span></button><button data-i="1" class="" title="Block diagram (datasheet p.11)"><img src="https://wiki.adom.inc/blob/component/stm32f103c8t6/keypages/block-diagram.png" loading=lazy alt="Block diagram"><span class=rl>Block diagram</span></button><button data-i="2" class="" title="Pinout (datasheet p.29)"><img src="https://wiki.adom.inc/blob/component/stm32f103c8t6/keypages/pinout.png" loading=lazy alt="Pinout"><span class=rl>Pinout</span></button><button data-i="3" class="" title="Pin table (datasheet p.28)"><img src="https://wiki.adom.inc/blob/component/stm32f103c8t6/keypages/pin-table.png" loading=lazy alt="Pin table"><span class=rl>Pin table</span></button><button data-i="4" class="" title="Package (datasheet p.101)"><img src="https://wiki.adom.inc/blob/component/stm32f103c8t6/keypages/package.png" loading=lazy alt="Package"><span class=rl>Package</span></button></div>
sections/pinout.htmladded+567
@@ -0,0 +1,567 @@+<!doctype html><html lang=en><head><meta charset=utf-8>+<meta name=viewport content="width=device-width,initial-scale=1"><title>STM32F103C8T6 pinout</title>+<style>+:root{color-scheme:dark}+body{margin:0;padding:4px 0 10px;background:transparent;+  font-family:'Satoshi',system-ui,-apple-system,'Segoe UI',sans-serif;color:#e6edf3}+</style></head><body>+<adom-pinout><script type="application/json">{+ "mpn": "STM32F103C8T6",+ "package": "LQFP-48",+ "pins": [+  {+   "number": 1,+   "name": "VBAT",+   "type": "power"+  },+  {+   "number": 2,+   "name": "PC13-TAMPER-RTC",+   "type": "io"+  },+  {+   "number": 3,+   "name": "PC14-OSC32_IN",+   "type": "io"+  },+  {+   "number": 4,+   "name": "PC15-OSC32_OUT",+   "type": "io"+  },+  {+   "number": 5,+   "name": "PD0-OSC_IN",+   "type": "io"+  },+  {+   "number": 6,+   "name": "PD1-OSC_OUT",+   "type": "io"+  },+  {+   "number": 7,+   "name": "NRST",+   "type": "io"+  },+  {+   "number": 8,+   "name": "VSSA",+   "type": "power"+  },+  {+   "number": 9,+   "name": "VDDA",+   "type": "power"+  },+  {+   "number": 10,+   "name": "PA0-WKUP",+   "type": "io"+  },+  {+   "number": 11,+   "name": "PA1",+   "type": "io"+  },+  {+   "number": 12,+   "name": "PA2",+   "type": "io"+  },+  {+   "number": 13,+   "name": "PA3",+   "type": "io"+  },+  {+   "number": 14,+   "name": "PA4",+   "type": "io"+  },+  {+   "number": 15,+   "name": "PA5",+   "type": "io"+  },+  {+   "number": 16,+   "name": "PA6",+   "type": "io"+  },+  {+   "number": 17,+   "name": "PA7",+   "type": "io"+  },+  {+   "number": 18,+   "name": "PB0",+   "type": "io"+  },+  {+   "number": 19,+   "name": "PB1",+   "type": "io"+  },+  {+   "number": 20,+   "name": "PB2",+   "type": "io"+  },+  {+   "number": 21,+   "name": "PB10",+   "type": "io"+  },+  {+   "number": 22,+   "name": "PB11",+   "type": "io"+  },+  {+   "number": 23,+   "name": "VSS_1",+   "type": "power"+  },+  {+   "number": 24,+   "name": "VDD_1",+   "type": "power"+  },+  {+   "number": 25,+   "name": "PB12",+   "type": "io"+  },+  {+   "number": 26,+   "name": "PB13",+   "type": "io"+  },+  {+   "number": 27,+   "name": "PB14",+   "type": "io"+  },+  {+   "number": 28,+   "name": "PB15",+   "type": "io"+  },+  {+   "number": 29,+   "name": "PA8",+   "type": "io"+  },+  {+   "number": 30,+   "name": "PA9",+   "type": "io"+  },+  {+   "number": 31,+   "name": "PA10",+   "type": "io"+  },+  {+   "number": 32,+   "name": "PA11",+   "type": "io"+  },+  {+   "number": 33,+   "name": "PA12",+   "type": "io"+  },+  {+   "number": 34,+   "name": "PA13",+   "type": "io"+  },+  {+   "number": 35,+   "name": "VSS_2",+   "type": "power"+  },+  {+   "number": 36,+   "name": "VDD_2",+   "type": "power"+  },+  {+   "number": 37,+   "name": "PA14",+   "type": "io"+  },+  {+   "number": 38,+   "name": "PA15",+   "type": "io"+  },+  {+   "number": 39,+   "name": "PB3",+   "type": "io"+  },+  {+   "number": 40,+   "name": "PB4",+   "type": "io"+  },+  {+   "number": 41,+   "name": "PB5",+   "type": "io"+  },+  {+   "number": 42,+   "name": "PB6",+   "type": "io"+  },+  {+   "number": 43,+   "name": "PB7",+   "type": "io"+  },+  {+   "number": 44,+   "name": "BOOT0",+   "type": "io"+  },+  {+   "number": 45,+   "name": "PB8",+   "type": "io"+  },+  {+   "number": 46,+   "name": "PB9",+   "type": "io"+  },+  {+   "number": 47,+   "name": "VSS_3",+   "type": "power"+  },+  {+   "number": 48,+   "name": "VDD_3",+   "type": "power"+  }+ ]+}</script></adom-pinout>+<script>/*!+ * <adom-pinout> — a reusable, dependency-free pinout widget.+ *+ * Drop-in:+ *   <script src="pinout-widget.js"></script>+ *   <adom-pinout src="part.json"></adom-pinout>+ *   <adom-pinout><script type="application/json">{ ...pin data... }</script></adom-pinout>+ *   // or: document.querySelector('adom-pinout').data = { ... }+ *+ * Data contract (everything except pins[].name is optional):+ *   {+ *     "mpn": "STM32F103C8T6",           // label shown in the chip body+ *     "package": "LQFP-48",             // label + hints the inferred layout (quad vs dual)+ *     "pins": [+ *       { "number": 1, "name": "VBAT",  // number+name are the essentials+ *         "type": "power",              // power|io|clock|ctrl|other  (auto-inferred from name if omitted)+ *         "xy": [-2.75, 4.25] }         // mm pad centre (footprint frame, +y up) — best placement.+ *                                       // omit xy → placed by inferred quad/dual layout.+ *     ]+ *   }+ *+ * Attributes: src (fetch JSON), layout ("auto"|"quad"|"dual"), heading (override title).+ * Self-contained (Shadow DOM), themes to the host via prefers-color-scheme.+ */+(() => {+  const TYPE_COLORS = {+    power: '#ff5c5c', io: '#00d3c8', clock: '#4c9dff', ctrl: '#b57cff', control: '#b57cff', other: '#8b97ac',+  };+  const TYPE_LABEL = { power: 'power', io: 'I/O', clock: 'clock', ctrl: 'control', control: 'control', other: 'other' };++  function inferType(name) {+    const n = String(name || '').toUpperCase();+    if (n === 'NC' || n === '') return 'other';+    if (/^(VDD|VSS|VCC|GND|VBAT|VDDA|VSSA|AVDD|AVSS|VREF|VEE|VBUS|V\+|V-|AGND|DGND)/.test(n)) return 'power';+    if (/(OSC|XTAL|CLKIN|CLKOUT|\bCLK\b|SCLK|MCLK)/.test(n)) return 'clock';+    if (/^(NRST|~?RESET|RST|BOOT|EN\b|~?CE|~?CS|MODE|TEST|WAKE|SHDN|~?SHDN|PDN)/.test(n)) return 'ctrl';+    return 'io';+  }++  // Exposed / thermal pad (QFN/DFN/SON/PowerPAD) — belongs in the chip centre, not on an edge.+  const isCenterPad = p => {+    const n = String(p.name || '').trim().toUpperCase();+    return /^(EP|EPAD|PAD|TAB|THERMAL|E[-_]?PAD|EXP|EXPPAD)$/.test(n) || /EXPOSED\s*PAD|THERMAL\s*PAD/.test(n);+  };++  // Return each pin as { ...pin, x, y, side } in a S×S box. Center pads get side:'center'.+  function layout(pins, pkg, forced) {+    const S = 400, pad = 60, mid = S / 2;+    const centers = pins.filter(isCenterPad);+    const edge = pins.filter(p => !isCenterPad(p));+    let laid;+    const hasXY = edge.length > 0 && edge.every(p => Array.isArray(p.xy) && p.xy.length === 2);+    if (hasXY && forced !== 'quad' && forced !== 'dual') {+      const xs = edge.map(p => p.xy[0]), ys = edge.map(p => p.xy[1]);+      const minx = Math.min(...xs), maxx = Math.max(...xs), miny = Math.min(...ys), maxy = Math.max(...ys);+      const span = Math.max(maxx - minx, maxy - miny) || 1, sc = (S - 2 * pad) / span;+      const cx = (maxx + minx) / 2, cy = (maxy + miny) / 2, off = (v, c) => mid + (v - c) * sc;+      laid = edge.map(p => {+        const x = off(p.xy[0], cx), y = S - off(p.xy[1], cy); // flip y (mm +y up → screen down)+        const side = p.xy[1] === maxy ? 'top' : p.xy[1] === miny ? 'bottom' : p.xy[0] === maxx ? 'right' : 'left';+        return { ...p, x, y, side };+      });+    } else {+      const N = edge.length, inner = pad, outer = S - pad, at = (a, b, t) => a + (b - a) * t;+      const quad = forced === 'quad' || (forced !== 'dual' && /QF|BGA|LGA|LCC|QFN|QFP/i.test(pkg || ''));+      if (quad) {+        const per = Math.ceil(N / 4);+        laid = edge.map((p, i) => {+          const s = Math.floor(i / per), t = ((i % per) + 0.5) / per;+          if (s === 0) return { ...p, x: inner, y: at(inner, outer, t), side: 'left' };+          if (s === 1) return { ...p, x: at(inner, outer, t), y: outer, side: 'bottom' };+          if (s === 2) return { ...p, x: outer, y: at(outer, inner, t), side: 'right' };+          return { ...p, x: at(outer, inner, t), y: inner, side: 'top' };+        });+      } else {+        const half = Math.ceil(N / 2); // DIP-style: left top→bottom, right bottom→top+        laid = edge.map((p, i) => i < half+          ? { ...p, x: inner, y: at(inner, outer, (i + 0.5) / half), side: 'left' }+          : { ...p, x: outer, y: at(outer, inner, (i - half + 0.5) / (N - half)), side: 'right' });+      }+    }+    centers.forEach(p => laid.push({ ...p, x: mid, y: mid, side: 'center' }));+    return laid;+  }++  const esc = s => String(s).replace(/[&<>"]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));++  class AdomPinout extends HTMLElement {+    set data(d) { this._data = d; if (this.shadowRoot) this._render(); }+    get data() { return this._data; }++    async connectedCallback() {+      if (this._init) return; this._init = true;+      this.attachShadow({ mode: 'open' });+      this._busInit();+      if (!this._data) {+        const inline = this.querySelector('script[type="application/json"]');+        if (inline) { try { this._data = JSON.parse(inline.textContent); } catch (e) { /* ignore */ } }+        const src = this.getAttribute('src');+        if (!this._data && src) { try { this._data = await (await fetch(src)).json(); } catch (e) { this._err = 'could not load ' + src; } }+      }+      this._render();+    }++    _render() {+      const d = this._data;+      const root = this.shadowRoot;+      if (this._err || !d || !Array.isArray(d.pins)) {+        root.innerHTML = `<style>${this._css()}</style><div class="card"><div class="empty">${esc(this._err || 'no pin data')}</div></div>`;+        return;+      }+      const pins = d.pins.map(p => ({ ...p, type: (p.type || inferType(p.name)).toLowerCase() }));+      const laid = layout(pins, d.package, this.getAttribute('layout'));+      const typesPresent = [...new Set(pins.map(p => p.type))];+      const heading = this.getAttribute('heading') || d.mpn || '';+      root.innerHTML = `<style>${this._css()}</style>+        <div class="card">+          <div class="hd">${heading ? `<span class="mpn">${esc(heading)}</span>` : ''}${d.package ? `<span class="pkg">${esc(d.package)}</span>` : ''}<span class="count">${pins.length} pins</span><span class="tools"><button class="tbtn" data-act="copy" title="Copy the pin map as JSON">copy</button><button class="tbtn" data-act="dl" title="Download the pin map as JSON">JSON&nbsp;↓</button></span></div>+          <div class="body">+            <div class="diagram">+              <div class="readout" data-readout>hover a pin&nbsp;→</div>+              ${this._svg(laid, d)}+              <div class="legend">${typesPresent.map(t => `<span><i style="background:${TYPE_COLORS[t] || TYPE_COLORS.other}"></i>${TYPE_LABEL[t] || t}</span>`).join('')}</div>+            </div>+            <div class="tablewrap"><table>+              <thead><tr><th>#</th><th>Name</th><th>Type</th></tr></thead>+              <tbody>${pins.slice().sort((a, b) => a.number - b.number).map(p => `+                <tr data-pin="${esc(p.number)}"><td class="num">${esc(p.number)}</td><td class="nm">${esc(p.name)}</td>+                <td><span class="tp" style="color:${TYPE_COLORS[p.type] || TYPE_COLORS.other}">${TYPE_LABEL[p.type] || p.type}</span></td></tr>`).join('')}</tbody>+            </table></div>+          </div>+        </div>`;+      this._wire(pins);+    }++    _svg(laid, d) {+      const S = 400;+      const edge = laid.filter(p => p.side !== 'center');+      const cen = laid.filter(p => p.side === 'center');+      const xs = edge.map(p => p.x), ys = edge.map(p => p.y);+      const pminX = Math.min(...xs), pmaxX = Math.max(...xs), pminY = Math.min(...ys), pmaxY = Math.max(...ys);+      const sides = new Set(edge.map(p => p.side)), hasTB = sides.has('top') || sides.has('bottom');+      const bL = pminX + 16, bR = pmaxX - 16, bT = hasTB ? pminY + 16 : pminY - 12, bB = hasTB ? pmaxY - 16 : pmaxY + 12;+      const cx = (bL + bR) / 2, cyB = (bT + bB) / 2;+      let s = `<svg viewBox="0 0 ${S} ${S}" class="chip">`;+      s += `<rect x="${bL}" y="${bT}" width="${bR - bL}" height="${bB - bT}" rx="10" class="pkgbody"/>`;+      s += `<circle cx="${bL + 15}" cy="${bT + 15}" r="4" class="pin1"/>`;+      const lY = cen.length ? bT + 32 : cyB - 3;+      s += `<text x="${cx}" y="${lY}" text-anchor="middle" class="lbl">${esc(d.mpn || '')}</text>`;+      if (d.package) s += `<text x="${cx}" y="${lY + 13}" text-anchor="middle" class="lbl2">${esc(d.package)}</text>`;+      // center pad(s) — exposed/thermal pad, drawn in the body centre+      cen.forEach((p, i) => {+        const col = TYPE_COLORS[p.type] || TYPE_COLORS.other;+        const ex = cx + (i - (cen.length - 1) / 2) * 40, ey = cyB + (cen.length ? 22 : 0);+        s += `<g class="pin" data-pin="${esc(p.number)}">`+          + `<rect class="ep" x="${ex - 19}" y="${ey - 13}" width="38" height="26" rx="4" fill="${col}" fill-opacity="0.15" stroke="${col}"/>`+          + `<text class="ept" x="${ex}" y="${ey + 3}" text-anchor="middle">${esc(p.name)}·${esc(p.number)}</text></g>`;+      });+      for (const p of edge) {+        const col = TYPE_COLORS[p.type] || TYPE_COLORS.other;+        let ex = p.x, ey = p.y, lx = p.x, ly = p.y, anc = 'middle';+        if (p.side === 'left') { ex = bL; lx = p.x - 11; anc = 'end'; ly = p.y + 3; }+        else if (p.side === 'right') { ex = bR; lx = p.x + 11; anc = 'start'; ly = p.y + 3; }+        else if (p.side === 'top') { ey = bT; ly = p.y - 9; }+        else { ey = bB; ly = p.y + 14; }+        s += `<g class="pin" data-pin="${esc(p.number)}">`+          + `<line class="stub" x1="${p.x}" y1="${p.y}" x2="${ex}" y2="${ey}" stroke="${col}"/>`+          + `<circle class="dot" cx="${p.x}" cy="${p.y}" r="3.1" fill="${col}"/>`+          + `<text class="pn" x="${lx}" y="${ly}" text-anchor="${anc}">${esc(p.number)}</text></g>`;+      }+      return s + `</svg>`;+    }++    // Set the highlighted pin. `emit` fires a `pinhover` event (internal hover);+    // external callers use highlight() which does NOT emit (avoids feedback loops).+    _set(n, emit) {+      const root = this.shadowRoot; if (!root) return;+      const s = (n == null ? '' : String(n));+      root.querySelectorAll('tr[data-pin]').forEach(r => r.classList.toggle('hot', r.dataset.pin === s));+      root.querySelectorAll('svg .pin[data-pin]').forEach(g => g.classList.toggle('hot', g.dataset.pin === s));+      const p = (this._pinsRendered || []).find(x => String(x.number) === s);+      const ro = root.querySelector('[data-readout]');+      if (ro) ro.innerHTML = p+        ? `<b>PIN ${esc(p.number)}</b> · ${esc(p.name)}<span class="rt" style="color:${TYPE_COLORS[p.type] || TYPE_COLORS.other}">${TYPE_LABEL[p.type] || p.type}</span>`+        : 'hover a pin&nbsp;→';+      if (emit) { this.dispatchEvent(new CustomEvent('pinhover', { detail: p || null, bubbles: true })); this._emitBus(s); }+    }++    /** Public: drive the highlight from outside (e.g. a linked footprint/symbol widget). */+    highlight(n) { this._set(n, false); }++    /** Public: the canonical pin map as a plain object — the structured handle for code/AI.+     *  Types are resolved (inferred filled in) so consumers get a complete map. No fabricated fields. */+    toJSON() {+      const d = this._data || {};+      const pins = (Array.isArray(d.pins) ? d.pins : [])+        .map(p => ({ number: p.number, name: p.name, type: (p.type || inferType(p.name)).toLowerCase(), ...(p.xy ? { xy: p.xy } : {}) }))+        .sort((a, b) => (Number(a.number) - Number(b.number)) || String(a.number).localeCompare(String(b.number)));+      const out = {};+      if (d.mpn) out.mpn = d.mpn;+      if (d.package) out.package = d.package;+      out.pins = pins;+      return out;+    }++    _exportJson() { return JSON.stringify(this.toJSON(), null, 2); }+    _exportName() { const d = this._data || {}; return ((d.mpn || 'pinout') + (d.package ? '-' + d.package : '')).replace(/[^\w.-]+/g, '_') + '.pins.json'; }+    _download() {+      const blob = new Blob([this._exportJson()], { type: 'application/json' });+      const url = URL.createObjectURL(blob), a = document.createElement('a');+      a.href = url; a.download = this._exportName(); document.body.appendChild(a); a.click();+      a.remove(); setTimeout(() => URL.revokeObjectURL(url), 1000);+    }+    async _copy(btn) {+      const txt = this._exportJson(), done = () => { if (!btn) return; const o = btn.textContent; btn.textContent = 'copied'; btn.classList.add('ok'); setTimeout(() => { btn.textContent = o; btn.classList.remove('ok'); }, 1100); };+      try { await navigator.clipboard.writeText(txt); done(); return; } catch (e) { /* sandboxed / denied — fall back */ }+      try { const ta = document.createElement('textarea'); ta.value = txt; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); ta.remove(); done(); }+      catch (e2) { this._download(); }   // last resort: hand them the file+    }++    // adom-lbr shared cross-highlight bus: BroadcastChannel('lbr-hover') + parent relay.+    _busInit() {+      this._self = 'w' + Math.random().toString(36).slice(2);+      this._bus = ('BroadcastChannel' in window) ? new BroadcastChannel('lbr-hover') : null;+      const on = e => { const d = e.data || {}; if (d.type === 'lbr-hover' && d.src !== this._self) this._set(d.pin == null ? '' : d.pin, false); };+      if (this._bus) this._bus.onmessage = on;+      this._winmsg = on; window.addEventListener('message', on);+    }+    disconnectedCallback() { try { this._bus && this._bus.close(); } catch (_) { /*noop*/ } if (this._winmsg) window.removeEventListener('message', this._winmsg); }+    _emitBus(n) {+      const m = { type: 'lbr-hover', pin: (n === '' || n == null) ? null : String(n), mpn: (this._data && this._data.mpn) || '', src: this._self };+      try { this._bus && this._bus.postMessage(m); } catch (_) { /*noop*/ }+      try { if (window.parent && window.parent !== window) window.parent.postMessage(m, '*'); } catch (_) { /*noop*/ }+    }++    _wire(pins) {+      this._pinsRendered = pins;+      const root = this.shadowRoot;+      const dl = root.querySelector('.tbtn[data-act="dl"]'); if (dl) dl.onclick = () => this._download();+      const cp = root.querySelector('.tbtn[data-act="copy"]'); if (cp) cp.onclick = () => this._copy(cp);+      root.querySelectorAll('tr[data-pin]').forEach(r => { r.onmouseenter = () => this._set(r.dataset.pin, true); r.onmouseleave = () => this._set('', true); });+      root.querySelectorAll('svg .pin[data-pin]').forEach(g => { g.onmouseenter = () => this._set(g.dataset.pin, true); g.onmouseleave = () => this._set('', true); });+      // Match the pin table's height to the chip diagram column so it fills the+      // space and scrolls, instead of a fixed short box next to a taller chip.+      const dia = root.querySelector('.diagram'), tw = root.querySelector('.tablewrap');+      if (dia && tw) {+        const fit = () => { const h = dia.getBoundingClientRect().height; if (h > 40) tw.style.maxHeight = Math.round(h) + 'px'; };+        requestAnimationFrame(fit); setTimeout(fit, 60);+        try { if (this._ro) this._ro.disconnect(); this._ro = new ResizeObserver(fit); this._ro.observe(dia); } catch (e) { /* */ }+      }+    }++    _css() {+      return `+      :host{display:block;+        --bg:#0d1420;--panel:#121a26;--line:#26324a;--line2:#33425f;--text:#dbe2ec;--dim:#8b97ac;--dim2:#66738c;--accent:#00e6dc;+        --hot:rgba(0,230,220,.13)}+      @media (prefers-color-scheme:light){:host{--bg:#f6f8fc;--panel:#fff;--line:#dbe2ee;--line2:#c3cede;--text:#1a2230;--dim:#5a6678;--dim2:#8592a6;--accent:#0d8f88;--hot:rgba(13,143,136,.10)}}+      :host([theme="dark"]){--bg:#0d1420;--panel:#121a26;--line:#26324a;--line2:#33425f;--text:#dbe2ec;--dim:#8b97ac;--dim2:#66738c;--accent:#00e6dc;--hot:rgba(0,230,220,.13)}+      :host([theme="light"]){--bg:#f6f8fc;--panel:#fff;--line:#dbe2ee;--line2:#c3cede;--text:#1a2230;--dim:#5a6678;--dim2:#8592a6;--accent:#0d8f88;--hot:rgba(13,143,136,.10)}+      *{box-sizing:border-box}+      .card{background:var(--bg);border:1px solid var(--line);border-radius:14px;padding:16px;color:var(--text);+        font:14px/1.5 -apple-system,'Segoe UI',Roboto,Arial,sans-serif;container-type:inline-size}+      .hd{display:flex;align-items:baseline;gap:10px;margin-bottom:12px}+      .hd .mpn{font:700 17px ui-monospace,'SF Mono',Menlo,monospace;letter-spacing:-.2px}+      .hd .pkg{font:600 11px ui-monospace,monospace;color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent);border:1px solid color-mix(in srgb,var(--accent) 30%,transparent);padding:2px 8px;border-radius:6px}+      .hd .count{margin-left:auto;font:12px ui-monospace,monospace;color:var(--dim2)}+      .hd .tools{display:flex;gap:6px;align-self:center}+      .tbtn{font:600 10.5px ui-monospace,monospace;letter-spacing:.03em;color:var(--dim);background:var(--panel);+        border:1px solid var(--line);border-radius:6px;padding:3px 8px;cursor:pointer;transition:color .12s,border-color .12s,background .12s;white-space:nowrap}+      .tbtn:hover{color:var(--text);border-color:var(--line2)}+      .tbtn.ok{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 45%,transparent)}+      .body{display:grid;grid-template-columns:minmax(300px,1fr) minmax(220px,1fr);gap:20px;align-items:start}+      /* stack diagram over table when the WIDGET (not the viewport) is narrow —+         e.g. side-by-side in a cross-link row — so the table never clips */+      @container (max-width:580px){.body{grid-template-columns:1fr}}+      .readout{height:24px;display:flex;align-items:center;gap:9px;font:600 13px ui-monospace,monospace;color:var(--dim);padding:0 4px}+      .readout b{color:var(--accent)} .readout .rt{margin-left:auto;font-size:11px;text-transform:uppercase;letter-spacing:.08em}+      .diagram{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:8px}+      svg.chip{width:100%;height:auto;display:block;max-height:440px}+      .pkgbody{fill:color-mix(in srgb,var(--text) 6%,var(--panel));stroke:var(--line2);stroke-width:1}+      .pin1{fill:var(--accent)}+      .lbl{fill:var(--dim);font:600 11px ui-monospace,monospace} .lbl2{fill:var(--dim2);font:9px ui-monospace,monospace}+      .pin .stub{stroke-width:2} .pin .pn{fill:var(--dim2);font:8px ui-monospace,monospace}+      .pin:hover .stub,.pin.hot .stub{stroke-width:3.6} .pin:hover .pn,.pin.hot .pn{fill:var(--text);font-weight:700}+      .pin .ep{stroke-width:1.2} .pin .ept{fill:var(--dim);font:8px ui-monospace,monospace}+      .pin:hover .ep,.pin.hot .ep{fill-opacity:.34;stroke-width:2} .pin:hover .ept,.pin.hot .ept{fill:var(--text);font-weight:700}+      .pin{cursor:default}+      .legend{display:flex;flex-wrap:wrap;gap:13px;margin:8px 2px 2px;font-size:11.5px;color:var(--dim)}+      .legend i{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:5px;vertical-align:middle}+      .tablewrap{max-height:440px;overflow:auto;border:1px solid var(--line);border-radius:10px;scrollbar-width:thin;scrollbar-color:var(--line2) transparent}+      .tablewrap::-webkit-scrollbar{width:9px;height:9px}+      .tablewrap::-webkit-scrollbar-track{background:transparent}+      .tablewrap::-webkit-scrollbar-thumb{background:var(--line2);border-radius:9px;border:2px solid transparent;background-clip:padding-box}+      .tablewrap::-webkit-scrollbar-thumb:hover{background:var(--dim2);border:2px solid transparent;background-clip:padding-box}+      .tablewrap::-webkit-scrollbar-button{display:none;width:0;height:0}+      .tablewrap::-webkit-scrollbar-corner{background:transparent}+      table{width:100%;border-collapse:collapse;font-size:12.5px}+      thead th{position:sticky;top:0;background:var(--panel);text-align:left;color:var(--dim2);font:600 10px ui-monospace,monospace;letter-spacing:.08em;text-transform:uppercase;padding:7px 9px;border-bottom:1px solid var(--line)}+      td{padding:4px 9px;border-bottom:1px solid color-mix(in srgb,var(--line) 55%,transparent);font-family:ui-monospace,monospace}+      td.num{color:var(--dim2)} td.nm{color:var(--text)}+      tr[data-pin]{cursor:default} tr.hot td{background:var(--hot)}+      .tp{font-size:10px;text-transform:uppercase;letter-spacing:.05em}+      .empty{color:var(--dim2);padding:30px;text-align:center;font-family:ui-monospace,monospace}`;+    }+  }+  if (!customElements.get('adom-pinout')) customElements.define('adom-pinout', AdomPinout);+})();+</script>+<script>+function fit(){parent.postMessage({type:'readme-height',height:document.documentElement.scrollHeight},'*')}+addEventListener('load',fit);new ResizeObserver(fit).observe(document.documentElement);+</script>+</body></html>\ No newline at end of file
sections/tools.htmladded+35
@@ -0,0 +1,35 @@+<!doctype html><html lang=en><head><meta charset=utf-8>+<meta name=viewport content="width=device-width,initial-scale=1"><title>STM32F103C8T6 tools</title>+<style>+:root{--bg:#0d1117;--surface:#161b22;--elevated:#1c2128;--border:#30363d;--text:#e6edf3;+  --text-2:#8b949e;--text-3:#484f58;--accent:#00b8b0;--accent-bright:#00e6dc;--green:#3fb950;+  --red:#f85149;--blue:#58a6ff;color-scheme:dark}+body{margin:0;padding:2px 0 10px;background:transparent;color:var(--text);+  font-family:'Satoshi',system-ui,-apple-system,'Segoe UI',sans-serif;font-size:14px;line-height:1.55}+h3{margin:14px 0 2px;font-size:13px;font-weight:600}+h3:first-child{margin-top:2px}+p.s{margin:0 0 6px;font-size:12px;color:var(--text-3);line-height:1.5}+</style></head><body>++<h3>Pin 1, chip against footprint</h3>+<p class=s>The datasheet already says which pad is pin 1. What matters is whether pin 1 on the chip lands on pin 1 of the footprint, because when they disagree the part goes down rotated.</p>+<script src="https://verify-3i7rt4do98l3.adom.cloud/applet.js"></script>+<adom-verify page="STM32F103C8T6" fact="pin-1-registration" wiki-page="adom/stm32f103c8t6"+  chip-image="https://wiki.adom.inc/blob/component/stm32f103c8t6/pin1/chip-top.png"+  footprint-svg="https://wiki.adom.inc/blob/component/stm32f103c8t6/pin1/footprint.svg"></adom-verify>++<h3>Fusion / EAGLE library</h3>+<p class=s>Web control cannot build one: a bridge runs on Windows or macOS, adom-lbr is Linux-only, and a browser runs no binaries. This asks a Linux service that has it.</p>+<script src="https://lbr-5o0yi1odd4w1.adom.cloud/applet.js"></script>+<adom-fusion-lbr page="adom/stm32f103c8t6"></adom-fusion-lbr>++<h3>Price and stock</h3>+<p class=s>The one thing here that cannot be baked, because it changes without the page changing.</p>+<script src="https://component-ocean-jk89eeqplwfl.adom.cloud/applet.js"></script>+<adom-sourcing mpn="STM32F103C8T6" wiki-page="adom/stm32f103c8t6"></adom-sourcing>++<script>+function fit(){parent.postMessage({type:'readme-height',height:document.documentElement.scrollHeight},'*')}+addEventListener('load',fit);new ResizeObserver(fit).observe(document.documentElement);+</script>+</body></html>\ No newline at end of file