fix(rp2040,stm32): drive digital inputs from the real circuit, like AVR

Extend the source-backed SPICE-driven input fix to the Pico (RP2040) and STM32:
a GP/PA pin wired to a rail or button now reads the right level from the solve,
while floating event-part nets (encoder/keypad/dialer/dip/stepper) stay on the
part layer. RP2040 just opts in (spiceDrivenInputs); STM32 opts in via the
Stm32BridgeShim and connectDigitalInputsToMcu maps PA0/PC13 names to the linear
pin setPinState expects (stm32PinNameToLinear).
This commit is contained in:
David Montero 2026-06-26 18:34:54 +02:00
parent e81450e348
commit f4401cc2dd
3 changed files with 19 additions and 1 deletions

View File

@ -145,6 +145,12 @@ export class IdleSpinDetector {
export type RP2040I2CDevice = I2CDevice;
export class RP2040Simulator {
// Digital inputs are driven from the SPICE solve (connectDigitalInputsToMcu)
// for source-backed nets, so digitalRead reflects real wiring (a GP pin wired
// to a rail / button reads the right level). Floating nets are left to the
// part layer, so event-driven parts (encoder/keypad/…) keep working. Mirrors
// the AVR fix; the connector + sourcedNets gating are board-agnostic.
readonly spiceDrivenInputs = true;
private rp2040: RP2040 | null = null;
private running = false;
private animationFrame: number | null = null;

View File

@ -21,6 +21,8 @@
*/
import { useSimulatorStore, getBoardSimulator, getBoardPinManager } from '../../store/useSimulatorStore';
import { useElectricalStore } from '../../store/useElectricalStore';
import { isStm32BoardKind } from '../../types/board';
import { stm32PinNameToLinear } from '../Stm32Bridge';
// 3.3 V LVCMOS thresholds with a hysteresis band so a node hovering near the
// midpoint doesn't chatter. A pulled-up idle input sits at ~3.3 V and a
@ -53,9 +55,13 @@ export function connectDigitalInputsToMcu(): () => void {
const pm = getBoardPinManager(board.id);
const driven = pm ? pm.getOutputPins() : new Set<number>();
const prefix = `${board.id}:`;
// STM32 names pins PA0/PC13/… and its PinManager + setPinState key on the
// linear pin (port*16+pin); every other board uses plain GPIO numbers.
const isStm32 = isStm32BoardKind(board.boardKind);
for (const [key, net] of pinNetMap) {
if (!key.startsWith(prefix)) continue;
const gpio = gpioFromPinName(key.slice(prefix.length));
const pinName = key.slice(prefix.length);
const gpio = isStm32 ? stm32PinNameToLinear(pinName) : gpioFromPinName(pinName);
if (gpio < 0) continue;
if (driven.has(gpio)) continue; // the MCU drives this pin (digitalWrite)
// Only drive pins whose net is backed by a real source/element (rail,

View File

@ -600,6 +600,12 @@ function makePinPullHandler(boardId: string) {
// minus the ESP32-only WiFi / proxy-resync machinery. ──────────────────────
class Stm32BridgeShim {
pinManager: PinManager;
// Digital inputs are driven from the SPICE solve (connectDigitalInputsToMcu)
// for source-backed nets — digitalRead reflects the real wiring instead of a
// part seed. The connector maps STM32 pin names (PA0, PC13) to the linear pin
// setPinState expects via stm32PinNameToLinear. Floating nets stay with the
// part layer. Mirrors the AVR / RP2040 fix.
readonly spiceDrivenInputs = true;
onSerialData: ((ch: string) => void) | null = null;
onPinChangeWithTime: ((pin: number, state: boolean, timeMs: number) => void) | null = null;
onBaudRateChange: ((baud: number) => void) | null = null;