This commit is contained in:
Bane Stojkovic
2026-09-06 20:57:26 +02:00
parent 4a4d2c8617
commit e2cddf5954
3 changed files with 141 additions and 27 deletions
@@ -117,33 +117,64 @@ public class ArduinoNano extends AbstractMakerBoard {
public static final String[] PIN_NAMES = new String[] {
// Left row (0..14, top to bottom)
"D1 (TX)", "D0 (RX)", "RESET", "GND1", "D2", "D3 (~)", "D4", "D5 (~)", "D6 (~)", "D7", "D8", "D9 (~)", "D10 (~)", "D11 (~)", "D12",
"D1 (TX)", "D0 (RX)", "RST1", "GND1", "D2", "D3 (~)", "D4", "D5 (~)", "D6 (~)", "D7", "D8", "D9 (~)", "D10 (~)", "D11 (~)", "D12",
// Right row (15..29, top to bottom)
"VIN", "GND2", "RST2", "5V", "A7", "A6", "A5", "A4", "A3", "A2", "A1", "A0", "AREF", "3.3V", "D13",
// ICSP (30..35)
"MISO", "5V_ICSP", "SCK", "MOSI", "RST_ICSP", "GND_ICSP"
};
// The modern Nanos keep the classic 2x15 pin positions and annotate the bus pins on the
// silkscreen, but they have no 2x3 ICSP block: that end of the board carries the radio module or
// USB bridge instead, so they are 30 control points rather than 36.
public static final String[] PIN_NAMES_MODERN = new String[] {
// Every board after the classic keeps the same 2x15 pin positions but has no 2x3 ICSP block --
// that end of the PCB carries the radio module or USB bridge -- so they are 30 control points.
// Each one's PWM set and power pins are taken from its official Arduino pinout diagram; they
// differ more than the shared outline suggests.
// Nano Every (ABX00028): PWM on D3, D5, D6, D9, D10 only, and D13 is SCK.
public static final String[] PIN_NAMES_EVERY = new String[] {
// Left row (0..14, top to bottom)
"D1 (TX)", "D0 (RX)", "RESET", "GND1", "D2", "D3 (~)", "D4", "D5 (~)", "D6 (~)", "D7", "D8", "D9 (~)", "D10 (~)", "D11 (MOSI)", "D12 (MISO)",
"D1 (TX)", "D0 (RX)", "RST1", "GND1", "D2", "D3 (~)", "D4", "D5 (~)", "D6 (~)", "D7", "D8", "D9 (~)", "D10 (~)", "D11 (MOSI)", "D12 (MISO)",
// Right row (15..29, top to bottom)
"VIN", "GND2", "RST2", "5V", "A7", "A6", "A5 (SCL)", "A4 (SDA)", "A3", "A2", "A1", "A0", "AREF", "3.3V", "D13 (SCK)"
"VIN", "GND2", "RST2", "5V", "A7", "A6", "A5 (SCL)", "A4 (SDA)", "A3", "A2", "A1", "A0 (DAC0)", "AREF", "3.3V", "D13 (SCK)"
};
// The Nano ESP32 dual-labels its digital pins with the Espressif GPIO number, which is what the
// Arduino core exposes as Dn and what the ESP-IDF documentation refers to.
// Nano 33 IoT (ABX00027): the SAMD21 adds PWM on D2 relative to the Every.
public static final String[] PIN_NAMES_33_IOT = new String[] {
// Left row (0..14, top to bottom)
"D1 (TX)", "D0 (RX)", "RST1", "GND1", "D2 (~)", "D3 (~)", "D4", "D5 (~)", "D6 (~)", "D7", "D8", "D9 (~)", "D10 (~)", "D11 (MOSI)", "D12 (MISO)",
// Right row (15..29, top to bottom)
"VIN", "GND2", "RST2", "5V", "A7", "A6", "A5 (SCL)", "A4 (SDA)", "A3", "A2", "A1", "A0 (DAC0)", "AREF", "3.3V", "D13 (SCK)"
};
// Nano 33 BLE and BLE Sense (ABX00030): the nRF52840 routes PWM to every digital pin, D13
// included.
public static final String[] PIN_NAMES_33_BLE = new String[] {
// Left row (0..14, top to bottom)
"D1 (TX)", "D0 (RX)", "RST1", "GND1", "D2 (~)", "D3 (~)", "D4 (~)", "D5 (~)", "D6 (~)", "D7 (~)", "D8 (~)", "D9 (~)", "D10 (~)", "D11 (~, MOSI)", "D12 (~, MISO)",
// Right row (15..29, top to bottom)
"VIN", "GND2", "RST2", "5V", "A7", "A6", "A5 (SCL)", "A4 (SDA)", "A3", "A2", "A1", "A0 (DAC0)", "AREF", "3.3V", "D13 (~, SCK)"
};
// Nano RP2040 Connect (ABX00053): every RP2040 GPIO has a PWM slice. Note REC (BOOTSEL) where
// the other boards repeat RESET.
public static final String[] PIN_NAMES_RP2040 = new String[] {
// Left row (0..14, top to bottom)
"D1 (TX)", "D0 (RX)", "RST1", "GND1", "D2 (~)", "D3 (~)", "D4 (~)", "D5 (~)", "D6 (~)", "D7 (~)", "D8 (~)", "D9 (~)", "D10 (~)", "D11 (~, MOSI)", "D12 (~, MISO)",
// Right row (15..29, top to bottom)
"VIN", "GND2", "REC", "5V", "A7", "A6", "A5 (SCL)", "A4 (SDA)", "A3", "A2", "A1", "A0", "AREF", "3.3V", "D13 (~, SCK)"
};
// Nano ESP32 (ABX00083): PWM on every digital and analog pin, and the pins the other boards use
// for RESET and AREF are the B1 / B0 boot-mode pads. Dual-labelled with the Espressif GPIO
// number, which is what the ESP-IDF documentation refers to.
public static final String[] PIN_NAMES_ESP32 = new String[] {
// Left row (0..14, top to bottom)
"D1 (TX/GPIO43)", "D0 (RX/GPIO44)", "RESET", "GND1", "D2 (GPIO5)", "D3 (GPIO6)", "D4 (GPIO7)",
"D5 (GPIO8)", "D6 (GPIO9)", "D7 (GPIO10)", "D8 (GPIO17)", "D9 (GPIO18)", "D10 (GPIO21)",
"D11 (MOSI/GPIO38)", "D12 (MISO/GPIO47)",
"D1 (~, TX/GPIO43)", "D0 (~, RX/GPIO44)", "RST1", "GND1", "D2 (~, GPIO5)", "D3 (~, GPIO6)",
"D4 (~, GPIO7)", "D5 (~, GPIO8)", "D6 (~, GPIO9)", "D7 (~, GPIO10)", "D8 (~, GPIO17)",
"D9 (~, GPIO18)", "D10 (~, GPIO21)", "D11 (~, MOSI/GPIO38)", "D12 (~, MISO/GPIO47)",
// Right row (15..29, top to bottom)
"VIN", "GND2", "RST2", "5V", "A7 (GPIO14)", "A6 (GPIO13)", "A5 (SCL/GPIO12)", "A4 (SDA/GPIO11)",
"A3 (GPIO4)", "A2 (GPIO3)", "A1 (GPIO2)", "A0 (GPIO1)", "AREF", "3.3V", "D13 (SCK/GPIO48)"
"VIN", "GND2", "B1", "VUSB", "A7 (~, GPIO14)", "A6 (~, GPIO13)", "A5 (~, SCL/GPIO12)",
"A4 (~, SDA/GPIO11)", "A3 (~, GPIO4)", "A2 (~, GPIO3)", "A1 (~, GPIO2)", "A0 (~, GPIO1)",
"B0", "3.3V", "D13 (~, SCK/GPIO48)"
};
protected NanoVersion version = NanoVersion.CLASSIC;
@@ -171,12 +202,19 @@ public class ArduinoNano extends AbstractMakerBoard {
private String[] getPinNames() {
switch (getVersion()) {
case CLASSIC:
return PIN_NAMES;
case EVERY:
return PIN_NAMES_EVERY;
case NANO_33_IOT:
return PIN_NAMES_33_IOT;
case NANO_33_BLE:
case NANO_33_BLE_SENSE:
return PIN_NAMES_33_BLE;
case NANO_RP2040_CONNECT:
return PIN_NAMES_RP2040;
case NANO_ESP32:
return PIN_NAMES_ESP32;
default:
return PIN_NAMES_MODERN;
return PIN_NAMES;
}
}
@@ -4,6 +4,7 @@ import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.components.AbstractMakerBoard;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.junit.Assert;
@@ -25,7 +26,7 @@ public class ArduinoNanoTest {
// Left row (0..14)
Assert.assertEquals("D1 (TX)", nano.getControlPointNodeName(0));
Assert.assertEquals("D0 (RX)", nano.getControlPointNodeName(1));
Assert.assertEquals("RESET", nano.getControlPointNodeName(2));
Assert.assertEquals("RST1", nano.getControlPointNodeName(2));
Assert.assertEquals("GND1", nano.getControlPointNodeName(3));
Assert.assertEquals("D2", nano.getControlPointNodeName(4));
Assert.assertEquals("D3 (~)", nano.getControlPointNodeName(5));
@@ -220,8 +221,59 @@ public class ArduinoNanoTest {
// The Nano ESP32 additionally carries the Espressif GPIO number
ArduinoNano esp32 = new ArduinoNano();
esp32.setVersion(ArduinoNano.NanoVersion.NANO_ESP32);
Assert.assertEquals("D2 (GPIO5)", esp32.getControlPointNodeName(4));
Assert.assertEquals("A4 (SDA/GPIO11)", esp32.getControlPointNodeName(22));
Assert.assertEquals("D2 (~, GPIO5)", esp32.getControlPointNodeName(4));
Assert.assertEquals("A4 (~, SDA/GPIO11)", esp32.getControlPointNodeName(22));
}
@Test
public void testPwmMarkingsPerVersion() {
// Each board's PWM set comes from its own Arduino pinout diagram, and they genuinely differ.
// Left row indices 4..14 are D2..D12; index 29 is D13.
assertPwm(ArduinoNano.NanoVersion.CLASSIC, "D3", "D5", "D6", "D9", "D10", "D11");
assertPwm(ArduinoNano.NanoVersion.EVERY, "D3", "D5", "D6", "D9", "D10");
assertPwm(ArduinoNano.NanoVersion.NANO_33_IOT, "D2", "D3", "D5", "D6", "D9", "D10");
assertPwm(ArduinoNano.NanoVersion.NANO_33_BLE,
"D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "D11", "D12", "D13");
assertPwm(ArduinoNano.NanoVersion.NANO_RP2040_CONNECT,
"D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "D11", "D12", "D13");
}
@Test
public void testPowerPinsPerVersion() {
// The RP2040 Connect exposes BOOTSEL where the others repeat RESET, and the Nano ESP32 uses
// that position and the AREF position for its boot-mode pads.
ArduinoNano rp2040 = new ArduinoNano();
rp2040.setVersion(ArduinoNano.NanoVersion.NANO_RP2040_CONNECT);
Assert.assertEquals("REC", rp2040.getControlPointNodeName(17));
Assert.assertEquals("5V", rp2040.getControlPointNodeName(18));
ArduinoNano esp32 = new ArduinoNano();
esp32.setVersion(ArduinoNano.NanoVersion.NANO_ESP32);
Assert.assertEquals("B1", esp32.getControlPointNodeName(17));
Assert.assertEquals("VUSB", esp32.getControlPointNodeName(18));
Assert.assertEquals("B0", esp32.getControlPointNodeName(27));
ArduinoNano classic = new ArduinoNano();
Assert.assertEquals("RST2", classic.getControlPointNodeName(17));
Assert.assertEquals("5V", classic.getControlPointNodeName(18));
Assert.assertEquals("AREF", classic.getControlPointNodeName(27));
}
/** Asserts that exactly the named digital pins carry the PWM tilde for this version. */
private void assertPwm(ArduinoNano.NanoVersion version, String... pwmPins) {
ArduinoNano nano = new ArduinoNano();
nano.setVersion(version);
java.util.Set<String> expected = new java.util.HashSet<String>(java.util.Arrays.asList(pwmPins));
for (int i = 0; i < nano.getControlPointCount(); i++) {
String name = nano.getControlPointNodeName(i);
String base = AbstractMakerBoard.getDisplayPinLabel(name);
if (!base.startsWith("D") || base.length() < 2 || !Character.isDigit(base.charAt(1))) {
continue;
}
boolean hasTilde = name.contains("~");
Assert.assertEquals(version + " " + base + " PWM marking", expected.contains(base), hasTilde);
}
}
@Test
+31 -7
View File
@@ -116,9 +116,21 @@ Extend these in place; add one geometry test and one draw smoke test per new var
### 4.5 Sourcing dimensions and pin names
Every dimension constant and every pin array below must be cross-checked against vendor
documentation (Espressif DevKit schematics, PJRC pinout cards, Arduino product pages, Seeed wiki)
before it is committed. Where this document states a size or a pin count it is an estimate to
scope the work, not a datasheet citation.
documentation before it is committed. Where this document states a size or a pin count without
naming a source, it is an estimate to scope the work, not a datasheet citation.
What actually works as a source:
- **Arduino** — `docs.arduino.cc/resources/pinouts/<SKU>-full-pinout.pdf` is canonical for PWM
tildes and silkscreen names; `docs.arduino.cc/resources/datasheets/<SKU>-datasheet.pdf` carries
the numbered header tables. The HTML product and cheat-sheet pages render client-side and yield
nothing to a fetch.
- **Espressif** — the `esp-dev-kits` user guides carry complete J1/J3 header tables as HTML.
- **PJRC** — pinout cards, not yet used for the Teensy 3.2 bottom cluster (see §5.1 item 4).
Note that these PDFs need downloading and text extraction; a plain fetch returns binary. Do not
assume variants of one board share a pinout — across the Nano family the PWM sets, the bus
annotations and the power pins all differ per variant.
### 4.6 Build and verify
@@ -242,10 +254,22 @@ the module) and whether the end part is a shielded can or a bare QFN.
`drawMiniUsb`, `drawMicroUsb`, `drawUsbC`, `drawMetalConnector` and `drawChip` all already exist
in `AbstractMakerBoard`.
Pin arrays: `PIN_NAMES` keeps the classic 36 entries. `PIN_NAMES_MODERN` is 30 entries — the same
physical positions with the bus pins annotated (`A4 (SDA)` / `A5 (SCL)`, and `MOSI` / `MISO` /
`SCK` where they land) and no ICSP block. `PIN_NAMES_ESP32` is the modern map with the Espressif
GPIO dual-labelled, e.g. `D2 (GPIO5)`.
Pin arrays: `PIN_NAMES` keeps the classic 36 entries. Each later board gets **its own 30-entry
array**, transcribed from its official Arduino pinout diagram (`docs.arduino.cc/resources/pinouts/
<SKU>-full-pinout.pdf`) rather than assumed from the classic. A single shared "modern" array was
wrong: the PWM sets and the power pins genuinely differ.
| Version | PWM pins | Position 17 | Position 18 | Position 27 |
|---|---|---|---|---|
| CLASSIC | D3 D5 D6 D9 D10 D11 | RST2 | 5V | AREF |
| EVERY | D3 D5 D6 D9 D10 | RST2 | 5V | AREF |
| NANO_33_IOT | D2 D3 D5 D6 D9 D10 | RST2 | 5V | AREF |
| NANO_33_BLE / _SENSE | D2–D13 (all) | RST2 | 5V | AREF |
| NANO_RP2040_CONNECT | D2–D13 (all) | **REC** (BOOTSEL) | 5V | AREF |
| NANO_ESP32 | D0–D13 and A0–A7 | **B1** | **VUSB** | **B0** |
`PIN_NAMES_ESP32` additionally dual-labels with the Espressif GPIO number, e.g. `D2 (~, GPIO5)`;
those numbers are taken from the ABX00083 pinout diagram.
`draw()` gains version switches for the MCU chip label (and whether it is drawn rotated 45° like
the classic TQFP or axis-aligned like a QFN), the end module, and the USB connector helper. Board