I don't know if I have enough pins on my Xiao ESP32-C3 I have three DRV8255's, and SD Card Reader (SPI), 4x push buttons, 2x endstops, 1x mosfet pin to fire a connected dc fan --- Probably not, at least not directly from GPIOs alone on a Seeed Studio XIAO ESP32-C3. Here’s the rough pin budget. Available GPIOs on the XIAO ESP32-C3 You realistically get about 11 usable GPIOs once you account for boot/USB considerations. Your devices 3× DRV8255 motor drivers A DRV8255 brushed DC driver usually needs: 2 pins per motor (IN1 + IN2) for direction/PWM or sometimes 1 PWM + 1 DIR So: Minimum realistic: 6 GPIOs Could become 9 if using enable/fault/sleep separately SD Card Reader (SPI) SPI shares most lines: MOSI MISO SCK CS That is: 4 GPIOs total Push buttons 4 GPIOs (Unless multiplexed) Endstops 2 GPIOs MOSFET for fan 1 GPIO Total Device Pins 3× DRV8255 6 SD Card SPI 4 4 buttons 4 2 endstops 2 Fan MOSFET 1 Total 17 GPIOs And that’s before considering: UART debug reserved boot pins fault pins LEDs future expansion So on a XIAO ESP32-C3, you are short by roughly 6 pins. Best solutions Option 1 — Add an I/O expander (recommended) Use: MCP23017 or PCF8574 This is the cleanest approach. Move: buttons endstops maybe fan control onto the expander. Then you only use: SDA SCL from the ESP32. Option 2 — Use resistor ladders for buttons 4 buttons can become: 1 analog pin using different resistor values. Good if you are desperate for pins. Option 3 — Use fewer control pins per motor If you only need: forward/off no braking no reverse then each DRV8255 could use: 1 PWM pin But if you need full bidirectional control, assume 2 pins each. Option 4 — Bigger ESP32 board Honestly, depending on enclosure constraints, something like: ESP32 DevKit V1 ESP32-S3 DevKitC may save you a lot of pain. The XIAO is excellent for compact builds, but you’re already beyond its comfortable GPIO budget. My recommendation For your setup: Keep the XIAO ESP32-C3 Add an MCP23017 Put buttons + endstops on the expander Keep motors and SPI directly on ESP32 pins That should fit comfortably. --- I have designed a resistor ladder for buttons and endstops. Should resistor values increase or does it matter? The remaining ESP32C3 pins? --- For a resistor ladder used with a single ADC pin on the Seeed Studio XIAO ESP32-C3, the actual direction of resistor values does not fundamentally matter — what matters is: each button/endstop produces a distinct, well-separated voltage the voltages stay within ADC range the impedance is not excessively high The important part You want ADC readings that are: stable far apart monotonic/predictable For example: Button ADC Voltage None pressed 3.3V Button 1 2.7V Button 2 2.1V Button 3 1.5V Button 4 0.9V Button 5 0.3V The resistor ordering itself is irrelevant if those voltages are clean. Recommended topology The usual approach is: pull-up resistor to 3.3V each button switches a different resistor to GND Like: 3.3V | [10k] | ADC ---- button1 ---[1k]--- GND | +---- button2 ---[2.2k]--- GND | +---- button3 ---[4.7k]--- GND | +---- button4 ---[10k]---- GND This works well because: “no press” = full 3.3V each press lowers voltage differently Important ESP32-C3 caveat The ESP32 ADC is: noisy non-linear not precision-grade So: do NOT make voltages too close together avoid equal spacing assumptions leave generous margins Aim for: at least ~300–400 ADC counts separation maybe more Resistor sizing guidance Avoid: extremely small resistors (<220Ω) wastes power extremely large values (>100kΩ effective impedance) ADC becomes unstable Good practical range: pull-up: 4.7k–22k ladder resistors: 1k–47k A total impedance around: 5k–20k effective is usually comfortable. Important limitation A resistor ladder only works reliably if: ONE button/endstop is active at a time If multiple switches can trigger simultaneously: voltages combine decoding becomes ambiguous For endstops this may matter depending on mechanics. About your remaining ESP32-C3 pins Assuming: Use Pins 3 DRV8255s 6 SPI SD card 4 resistor ladder ADC 1 fan MOSFET 1 Total: about 12 pins That is very close to the practical limit on the XIAO ESP32-C3, but now potentially achievable depending on: which pins are usable whether SD card and boot pins overlap safely whether you need UART/debugging You are now in “careful pin assignment” territory rather than “impossible.” --- redo diagram with button5 and button6 (endstops) --- Here’s a corrected resistor ladder diagram including Button 1–4 + Button 5/6 (endstops). I’ll assume: 1 ADC input pin on the Seeed Studio XIAO ESP32-C3 pull-up to 3.3V each button pulls the ADC to GND through a unique resistor value only one input active at a time (important assumption) Updated resistor ladder (6 inputs) 3.3V | [10k pull-up] | +-------------------- ADC (ESP32-C3) | |---- Button 1 ----[1k]----- GND | |---- Button 2 ----[2.2k]--- GND | |---- Button 3 ----[4.7k]--- GND | |---- Button 4 ----[10k]---- GND | |---- Button 5 ----[22k]---- GND (Endstop A) | |---- Button 6 ----[47k]---- GND (Endstop B) How this behaves Input Approx voltage trend none pressed ~3.3V BTN1 highest drop BTN2 slightly higher BTN3 mid BTN4 lower-mid BTN5 low BTN6 very low (closest to GND) Why resistor spacing is OK here Your ESP32-C3 ADC: is noisy has non-linear regions near extremes So the key design choice is: non-linear spacing is GOOD bigger gaps at low voltages help stability Your ladder is actually better than evenly spaced values. Critical improvement (strong recommendation) Add one of these: Option A — capacitor smoothing (simple) Place: 100nF from ADC pin to GND This: reduces jitter stabilises endstop reads Option B — software hysteresis (required) Use thresholds like: BTN1: 3000–3200 BTN2: 2500–2900 BTN3: 1900–2400 BTN4: 1200–1800 BTN5: 500–1100 BTN6: 0–400 Add: debounce time (20–50 ms minimum) One more subtle issue (important) Endstops often trigger simultaneously (mechanical safety cases). If both BTN5 + BTN6 can ever be pressed together: the ladder becomes ambiguous (voltages combine) If that is possible in your system, you should: move endstops off the ladder or isolate them digitally (preferred for safety-critical signals) If you want next step I can: map this onto actual ESP32-C3 safe GPIO assignments check your DRV8255 pin budget realistically or redesign the whole system so you don’t run out of pins again (you’re close but still salvageable) --- but I doubt the values are distinct enough, how to make a permutation table for different combination presses? --- You’ve hit the key limitation of resistor-ladder encoding: once multiple switches can be pressed, it stops being a “6-state system” and becomes a 2⁶ = 64-state analog system. So yes — you can build a permutation table, but it only works if: the ADC is stable enough resistor tolerances are tight (1% or better strongly recommended) you accept calibration complexity 1. The core idea: it becomes a parallel resistance problem Each button adds a resistor to GND. The ADC sees: a pull-up resistor to 3.3V multiple possible resistors to GND in parallel So the effective resistance is: R eq ​ =(∑ i=1 n ​ R i ​ 1 ​ ) −1 Then voltage is: Option B — GPIO expander MCP23017 gives 16 clean digital inputs over 2 wires Option C — keep ladder ONLY for buttons, not endstops Endstops should be: binary deterministic safety-critical So they really should NOT share ADC encoding. 7. Bottom line You can build a permutation table, but: mathematically: works (64 states) electrically: fragile practically on ESP32-C3 ADC: unreliable at scale If you want, I can: compress your 6 inputs into a robust 3-pin matrix design or redesign the whole IO map so your DRV8255 + SD + inputs fit cleanly without analog decoding risk --- Compress my 6 inputs into a robust 3-pin matrix design --- assistant Good direction—moving off the ADC ladder and into a digital scan will immediately make the system more deterministic on the Seeed Studio XIAO ESP32-C3. You can compress 6 inputs into 3 GPIOs in two practical ways. One is a true matrix, the other is a hybrid scan that behaves better for endstops. Option 1 (recommended): 3×2 button matrix (6 buttons exactly) Wiring concept You use: 3 GPIOs as columns (outputs) 2 GPIOs as rows (inputs with pull-ups) That gives: 3 × 2 = 6 unique buttons exactly your requirement Wiring diagram Columns (outputs) Rows (inputs w/ pull-ups) GPIO_A ---- BTN1 ----+ GPIO_B ---- BTN2 ----+------ GPIO_R1 GPIO_C ---- BTN3 ----+ GPIO_A ---- BTN4 ----+ GPIO_B ---- BTN5 ----+------ GPIO_R2 GPIO_C ---- BTN6 ----+ Each button connects: one column line one row line So pressing a button shorts one row/column intersection. Pin behaviour Columns: Set HIGH one at a time (scan) Others LOW or Hi-Z Rows: Input with pull-up Read LOW when button in active column is pressed Scan logic Pseudo: C for (col in columns): set_all_columns_low() set(col, HIGH) delay(2-5 microseconds) read rows: if row1 LOW → button (row1,col) if row2 LOW → button (row2,col) Mapping Row \ Col A B C R1 BTN1 BTN2 BTN3 R2 BTN4 BTN5 BTN6 Why this is robust Compared to resistor ladder: Advantages immune to ADC noise deterministic digital reads no calibration needed multiple presses are cleanly identifiable ESP32-C3 friendly uses only GPIO logic no analog quirks no voltage thresholds Option 2: 3-wire “binary encoded ladder” (not recommended here) You could encode 6 states in binary (3 pins → 8 states), but: requires diode isolation per button becomes complex fast endstops + buttons mix poorly So I would not use it for your case. Where endstops go (important) You mentioned endstops earlier. Do NOT put endstops in the matrix. Reason: endstops are safety signals matrix scanning introduces latency (~1–5 ms worst case) ghosting risk if wiring ever changes Best practice: keep buttons in matrix keep endstops as direct GPIO inputs (or GPIO expander) Minimal clean architecture for your system Given your full setup: 3× DRV8255 drivers SD card (SPI) fan MOSFET 2 endstops 6 buttons Recommended split: Matrix (3 GPIO) 6 buttons Direct GPIO 2 endstops fan MOSFET DRV8255 control pins (as needed) SPI SD card (4 pins) This keeps everything deterministic and avoids analog entirely. Key improvement insight What you originally tried (ADC ladder) is: “compress signal space into voltage domain” What matrix gives you is: “expand combinatorial space using time multiplexing” Much more suitable for microcontrollers like ESP32-C3. If you want next step, I can: map your entire ESP32-C3 pinout safely (avoiding boot strapping issues) or optimise DRV8255 pin usage so you don’t run out again or design a “no-conflict wiring plan” for the whole system --- assistant Assuming the standard ladder topology: Pull-up: 10 kΩ to 3.3 V One button pressed at a time → a single resistor to GND ADC reads the divider node So each case is: V ADC ​ =3.3⋅ R pullup ​ +R eq ​ R eq ​ ​ Where R eq ​ is just the pressed resistor (since only one is active). Given values R pullup ​ =10kΩ V CC ​ =3.3V Pressed resistors: B1 = 1kΩ B2 = 2.2kΩ B3 = 4.7kΩ B4 = 10kΩ B5 = 22kΩ B6 = 47kΩ ADC voltages (single press only) B1 = 1kΩ V=3.3⋅ 10000+1000 1000 ​ =3.3⋅0.0909≈0.30V B2 = 2.2kΩ V=3.3⋅ 12200 2200 ​ =3.3⋅0.1803≈0.59V B3 = 4.7kΩ V=3.3⋅ 14700 4700 ​ =3.3⋅0.3197≈1.06V B4 = 10kΩ V=3.3⋅ 20000 10000 ​ =3.3⋅0.5=1.65V B5 = 22kΩ V=3.3⋅ 32000 22000 ​ =3.3⋅0.6875≈2.27V B6 = 47kΩ V=3.3⋅ 57000 47000 ​ =3.3⋅0.8246≈2.72V Final table (clean view) Button Resistance ADC Voltage B1 1kΩ ~0.30 V B2 2.2kΩ ~0.59 V B3 4.7kΩ ~1.06 V B4 10kΩ ~1.65 V B5 22kΩ ~2.27 V B6 47kΩ ~2.72 V Important interpretation (this is the key part) You now have: Range: 0.30 V → 2.72 V Spread: fairly good BUT: ESP32-C3 ADC reality: non-linear curve (especially above ~2.5V) noise ±20–50 mV typical without filtering temperature drift So the danger zones are: B5 vs B6 (closest spacing in ADC “count space”) high end compression near 3.3V Practical recommendation If you want this to be reliable: 1. Add hardware smoothing 100nF capacitor at ADC pin 2. Add software hysteresis ±100–200 ADC counts per button bucket 3. Increase spacing if unstable If B5/B6 collide in testing: change B6 → 68k or 100k If you want next step, I can convert these voltages into ESP32-C3 ADC counts + recommended thresholds, which is usually where this design either becomes solid or breaks. --- user and if no buttons are pressed? --- assistant With your topology (10k pull-up to 3.3 V, and each button connects a resistor to GND), “no button pressed” means: ADC node is only connected to 3.3 V through the pull-up no path to ground so essentially no current flows No-button voltage So the ADC node is simply: V ADC ​ =V CC ​ =3.3V Final state table (including idle) State Resistance to GND ADC Voltage No buttons pressed open circuit 3.3 V B1 1kΩ ~0.30 V B2 2.2kΩ ~0.59 V B3 4.7kΩ ~1.06 V B4 10kΩ ~1.65 V B5 22kΩ ~2.27 V B6 47kΩ ~2.72 V Important implication This is actually very useful: “no press” becomes a distinct top-level state gives you 7 total states (including idle) simplifies firmware classification So your decoder becomes: 1 idle state + 6 button states One caution (important on ESP32-C3 ADC) On the Seeed Studio XIAO ESP32-C3: 3.3 V is near ADC full-scale many ESP32 ADCs saturate or compress near the top end So practically: “no press” might read closer to ~3.0–3.3 V but not perfectly stable 👉 You should treat idle as a range, not a single value: e.g. 2800–4095 ADC counts (depending on attenuation setting) If you want, I can next: convert all of these into actual ESP32-C3 ADC counts (0–4095 scale) and give you robust threshold bands so it never misfires in real firmware --- user Now calculate the voltage read at the adc pin if button 1 and button 2 are pressed. And also in the case that button 1 and button 3 are pressed. --- assistant Now you’re in the parallel-resistance regime, so the node voltage is no longer a simple divider — it depends on the equivalent resistance of the pressed resistors in parallel. We’ll keep your circuit assumptions: Pull-up: R PU ​ =10kΩ V CC ​ =3.3V Buttons connect resistors from ADC node → GND Multiple presses = resistors in parallel Core equations Equivalent resistance: R eq ​ =( R 1 ​ 1 ​ + R 2 ​ 1 ​ ) −1 ADC voltage: V ADC ​ =3.3⋅ R PU ​ +R eq ​ R eq ​ ​ Case 1: B1 + B2 pressed Step 1: parallel resistance B1 = 1kΩ B2 = 2.2kΩ R eq ​ =( 1000 1 ​ + 2200 1 ​ ) −1 =(0.001+0.0004545) −1 =687.5Ω Step 2: ADC voltage V ADC ​ =3.3⋅ 10000+687.5 687.5 ​ =3.3⋅0.0643≈0.212V Case 2: B1 + B3 pressed Step 1: parallel resistance B1 = 1kΩ B3 = 4.7kΩ R eq ​ =( 1000 1 ​ + 4700 1 ​ ) −1 =(0.001+0.0002128) −1 ≈822.8Ω Step 2: ADC voltage V ADC ​ =3.3⋅ 10000+822.8 822.8 ​ =3.3⋅0.0761≈0.251V Summary table Combination Req (Ω) ADC Voltage B1 + B2 ~687 Ω ~0.212 V B1 + B3 ~823 Ω ~0.251 V Critical insight (this is the key engineering point) Notice what happens: B1 alone: ~0.30 V B1 + B2: ~0.21 V B1 + B3: ~0.25 V So combinations: ✔ collapse into lower voltage region ✔ cluster very tightly ❌ become hard to distinguish on ESP32 ADC Why this matters on ESP32-C3 On the Seeed Studio XIAO ESP32-C3: ADC noise ≈ ±20–80 mV typical these differences (0.21 vs 0.25 V) are inside noise band So: multi-button detection with this ladder is not reliably separable in practice Practical conclusion Your design works well for: single-button detection (6 states + idle) But breaks for: multi-button encoding (2⁶ permutation space) If you want next step, I can: compute the full 64-state voltage table (and show actual collision clusters) or redesign this so you can safely detect multi-presses without losing GPIOs (there is a clean hybrid solution for your setup)