Interface Map¶
Board Manifest: mouse-joystick-pcb¶
Single-axis mouse joystick: RP2040 with GPIO isolation, one TMC5130A, torque bridge, brake current sink, analog angle output, InstrumentPort-Digital-50 taps, 36 V protected input with 12 V and 5 V regulators; v1.0 as built.
Project: mouse-joystick-pcb.kicad_pro Netclass profiles: hv-power-24v, instrument-taps Datum: aux axis origin at KiCad (137.425, 95) mm Placements: 15; board sheets: 4; nets: 76; open ports: 36
Placements¶
| Instance | Block | Parent sheet | Anchor (mm) | Rotation | Side | Sheet pins | Note |
|---|---|---|---|---|---|---|---|
instrument_port_digital_50_dut_ffc_boundary_vertical |
orb_weaver_private:instrument_port_digital_50_dut_ffc_boundary_vertical |
/instrument_port |
(0, 36) | 180 | front | own | |
rp2040_with_gpio_isolation_sn74cb3q3245 |
orb_weaver_private:rp2040_with_gpio_isolation_sn74cb3q3245 |
/mcu |
(-32, 19) | 90 | front | own | |
5v_to_3v3_tps73733_1 |
orb_weaver_private:5v_to_3v3_tps73733 |
/mcu |
(-28.5, 2) off-grid | 90 | front | own | |
pycontrol_behavior_port_rj45_boundary_vertical |
orb_weaver_private:pycontrol_behavior_port_rj45_boundary_vertical |
/ |
(-39.98, -8) off-grid | 270 | front | own | |
5v_to_3v3_tps73733_2 |
orb_weaver_private:5v_to_3v3_tps73733 |
/ |
(-14, 1.75) off-grid | 180 | front | own | |
usb2_vertical |
orb_weaver_private:usb2_vertical |
/ |
(-45, 11) | 90 | front | own | |
analog_output_0_3v3_dac80501 |
orb_weaver_private:analog_output_0_3v3_dac80501 |
/motor_encoder_switch |
(-1, 2) | 180 | front | own | |
quadrature_encoder_input_5v_sn74lvc2g17 |
orb_weaver_private:quadrature_encoder_input_5v_sn74lvc2g17 |
/motor_encoder_switch |
(9, -28) | 270 | front | own | |
limit_switch_debounced_input_vertical |
orb_weaver_private:limit_switch_debounced_input_vertical |
/motor_encoder_switch |
(18, -36) | 180 | front | library | |
tmc5130 |
orb_weaver_private:tmc5130 |
/motor_encoder_switch |
(1, -14) | 90 | front | library | |
hv_to_5v_tpsm365r6 |
orb_weaver_private:hv_to_5v_tpsm365r6 |
/ |
(-21.25, -7) | 90 | front | library | |
torque_bridge_0_3v3_ina821 |
orb_weaver_private:torque_bridge_0_3v3_ina821 |
/brake_torque_sensor |
(37, -18) | 180 | front | own | |
hv_to_12v_tpsm365r6 |
orb_weaver_private:hv_to_12v_tpsm365r6 |
/brake_torque_sensor |
(35, -29) | 180 | front | library | |
brake_current_sink_0_49ma_dac80501 |
orb_weaver_private:brake_current_sink_0_49ma_dac80501 |
/brake_torque_sensor |
(37, 12) | 180 | front | own | |
hv_input_36V_terminal_2pos_5p08_protected_vertical |
orb_weaver_private:hv_input_36V_terminal_2pos_5p08_protected_vertical |
/ |
(-44, -24) | 270 | front | own |
Board Sheets¶
Board-authored wrapper sheets: their hierarchical labels and what each meets in the parent.
instrument_port in / (board-authored sheet, 0 parts)¶
| Port | Wired to | Net | Class | Meaning |
|---|---|---|---|---|
+3.3V |
+3.3V_MCU |
/+3.3V_MCU |
PWR_3V3 | |
DAQ_SCL |
DAC_SCL_INST |
/DAC_SCL_INST |
INSTRUMENT | |
DAQ_SDA |
DAC_SDA_INST |
/DAC_SDA_INST |
INSTRUMENT | |
ENCA |
ENCA_INST |
/ENCA_INST |
INSTRUMENT | |
ENCB |
ENCB_INST |
/ENCB_INST |
INSTRUMENT | |
FW_TRIG0 |
FW_TRIG0 |
/FW_TRIG0 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
FW_TRIG1 |
FW_TRIG1 |
/FW_TRIG1 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
GND |
GND |
/GND |
PWR_RETURN_LOCAL | |
HV_DIAG_EN |
HV_DIAG_EN_INST |
/HV_DIAG_EN_INST |
INSTRUMENT | |
HV_EN |
HV_EN_INST |
/HV_EN_INST |
INSTRUMENT | |
LIMIT_SW |
LIMIT_SW_INST |
/LIMIT_SW_INST |
INSTRUMENT | |
PG_5V |
PG_5V |
/PG_5V |
Default | |
PG_12V |
PG_12V |
/PG_12V |
Default | |
PYC_UART_RX |
PYC_UART_RX_INST |
/PYC_UART_RX_INST |
INSTRUMENT | |
PYC_UART_TX |
PYC_UART_TX_INST |
/PYC_UART_TX_INST |
INSTRUMENT | |
TMC_DIAG0 |
TMC_DIAG0_INST |
/TMC_DIAG0_INST |
INSTRUMENT | |
TMC_DIAG1 |
TMC_DIAG1_INST |
/TMC_DIAG1_INST |
INSTRUMENT | |
TMC_SPI_CIPO |
TMC_SPI_CIPO_INST |
/TMC_SPI_CIPO_INST |
INSTRUMENT | |
TMC_SPI_COPI |
TMC_SPI_COPI_INST |
/TMC_SPI_COPI_INST |
INSTRUMENT | |
TMC_SPI_SCK |
TMC_SPI_SCK_INST |
/TMC_SPI_SCK_INST |
INSTRUMENT | |
TQ_CAL_EN |
TQ_CAL_EN_INST |
/TQ_CAL_EN_INST |
INSTRUMENT | |
TQ_CONVST_CS |
TQ_CONVST_CS_INST |
/TQ_CONVST_CS_INST |
INSTRUMENT | |
TQ_SPI_CIPO |
TQ_SPI_CIPO_INST |
/TQ_SPI_CIPO_INST |
INSTRUMENT | |
TQ_SPI_COPI |
TQ_SPI_COPI_INST |
/TQ_SPI_COPI_INST |
INSTRUMENT | |
TQ_SPI_SCK |
TQ_SPI_SCK_INST |
/TQ_SPI_SCK_INST |
INSTRUMENT | |
~{BRAKE_FAULT} |
~{BRAKE_FAULT}_INST |
/~{BRAKE_FAULT}_INST |
INSTRUMENT | |
~{BUS_SW_EN} |
~{BUS_SW_EN}_INST |
/~{BUS_SW_EN}_INST |
INSTRUMENT | |
~{HV_FAULT} |
~{HV_FAULT}_INST |
/~{HV_FAULT}_INST |
INSTRUMENT | |
~{TMC_CS} |
~{TMC_CS}_INST |
/~{TMC_CS}_INST |
INSTRUMENT | |
~{TMC_DRV_EN} |
~{TMC_DRV_EN}_INST |
/~{TMC_DRV_EN}_INST |
INSTRUMENT |
mcu in / (board-authored sheet, 11 parts)¶
| Port | Wired to | Net | Class | Meaning |
|---|---|---|---|---|
+3.3V_MCU |
+3.3V_MCU |
/+3.3V_MCU |
PWR_3V3 | |
+3.3V_SW |
+3.3V_SW |
/+3.3V_SW |
PWR_3V3 | |
+5V_MCU |
+5V_MCU |
/+5V_MCU |
PWR_5V | |
ANGLE_OUT_MON |
ANGLE_OUT_MON |
/ANGLE_OUT_MON |
MCU_FINE | Analog output readback, ADC3¹¹; in as the MCU sees it |
BRAKE_ISENSE |
BRAKE_ISENSE |
/BRAKE_ISENSE |
MCU_FINE | Brake sink current readback, ADC1¹¹; in as the MCU sees it |
DAC_SCL |
DAC_SCL |
/DAC_SCL |
Default | I2C0 SCL — same bus⁷; out as the MCU sees it, via the bus switch |
DAC_SCL_INST |
DAC_SCL_INST |
/DAC_SCL_INST |
INSTRUMENT | |
DAC_SDA |
DAC_SDA |
/DAC_SDA |
Default | I2C0 SDA — analog 0x48, brake 0x49⁷; bidi as the MCU sees it, via the bus switch |
DAC_SDA_INST |
DAC_SDA_INST |
/DAC_SDA_INST |
INSTRUMENT | |
FW_TRIG0 |
FW_TRIG0 |
/FW_TRIG0 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
FW_TRIG1 |
FW_TRIG1 |
/FW_TRIG1 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
GND |
GND |
/GND |
PWR_RETURN_LOCAL | |
HV_DIAG_EN |
HV_DIAG_EN |
/HV_DIAG_EN |
MCU_FINE | 36 V switch diagnostics enable⁵; out as the MCU sees it |
HV_EN |
HV_EN |
/HV_EN |
MCU_FINE | 36 V input switch enable; out as the MCU sees it |
HV_LATCH |
HV_LATCH |
/HV_LATCH |
MCU_FINE | 36 V switch latch-off select¹⁰; out as the MCU sees it |
HV_SNS |
HV_SNS |
/HV_SNS |
MCU_FINE | 36 V input load-current sense, R_SNS = 249 Ω; in as the MCU sees it |
PYC_UART_RX |
PYC_UART_RX |
/PYC_UART_RX |
MCU_FINE | UART RX from pyControl (UART0 RX); in as the MCU sees it |
PYC_UART_TX |
PYC_UART_TX |
/PYC_UART_TX |
MCU_FINE | UART TX to pyControl (UART0 TX); out as the MCU sees it |
TMC_DIAG0 |
TMC_DIAG0 |
/TMC_DIAG0 |
Default | Driver diagnostic 0; in as the MCU sees it, via the bus switch |
TMC_DIAG1 |
TMC_DIAG1 |
/TMC_DIAG1 |
Default | Driver diagnostic 1; in as the MCU sees it, via the bus switch |
TMC_SPI_CIPO |
TMC_SPI_CIPO |
/TMC_SPI_CIPO |
Default | Driver SPI CIPO (SPI0 RX); in as the MCU sees it, via the bus switch |
TMC_SPI_COPI |
TMC_SPI_COPI |
/TMC_SPI_COPI |
Default | Driver SPI COPI (SPI0 TX); out as the MCU sees it, via the bus switch |
TMC_SPI_SCK |
TMC_SPI_SCK |
/TMC_SPI_SCK |
Default | Driver SPI clock (SPI0 SCK); out as the MCU sees it, via the bus switch |
TQ_CAL_EN |
TQ_CAL_EN |
/TQ_CAL_EN |
Default | Torque calibration enable⁷; out as the MCU sees it, via the bus switch |
TQ_CONVST_CS |
TQ_CONVST_CS |
/TQ_CONVST_CS |
Default | ADS8689 convert-start / frame, plain GPIO⁷; out as the MCU sees it, via the bus switch |
TQ_SPI_CIPO |
TQ_SPI_CIPO |
/TQ_SPI_CIPO |
Default | Torque ADC SPI CIPO (SPI1 RX)⁷; in as the MCU sees it, via the bus switch |
TQ_SPI_COPI |
TQ_SPI_COPI |
/TQ_SPI_COPI |
Default | Torque ADC SPI COPI (SPI1 TX)⁷; out as the MCU sees it, via the bus switch |
TQ_SPI_SCK |
TQ_SPI_SCK |
/TQ_SPI_SCK |
Default | Torque ADC SPI clock (SPI1 SCK)⁷; out as the MCU sees it, via the bus switch |
USB_D+ |
USB_D+ |
/USB_D+ |
USB_HS | |
USB_D- |
USB_D- |
/USB_D- |
USB_HS | |
~{BRAKE_FAULT} |
~{BRAKE_FAULT} |
/~{BRAKE_FAULT} |
Default | Brake block fault, active low⁷; in as the MCU sees it, via the bus switch |
~{BUS_SW_EN}_INST |
~{BUS_SW_EN}_INST |
/~{BUS_SW_EN}_INST |
INSTRUMENT | |
~{HV_FAULT} |
~{HV_FAULT} |
/~{HV_FAULT} |
MCU_FINE | 36 V switch fault, open-drain, pull-up 3.3 V¹¹; in as the MCU sees it |
~{TMC_CS} |
~{TMC_CS} |
/~{TMC_CS} |
Default | Driver chip select; out as the MCU sees it, via the bus switch |
~{TMC_DRV_EN} |
~{TMC_DRV_EN} |
/~{TMC_DRV_EN} |
Default | Driver enable, active low; out as the MCU sees it, via the bus switch |
motor_encoder_switch in / (board-authored sheet, 10 parts)¶
| Port | Wired to | Net | Class | Meaning |
|---|---|---|---|---|
+3.3V |
+3.3V_SW |
/+3.3V_SW |
PWR_3V3 | |
+5V |
+5V_SW |
/+5V_SW |
PWR_5V | |
ANGLE_OUT_MON |
ANGLE_OUT_MON |
/ANGLE_OUT_MON |
MCU_FINE | Analog output readback, ADC3¹¹; in as the MCU sees it |
DAC_SCL |
DAC_SCL |
/DAC_SCL |
Default | I2C0 SCL — same bus⁷; out as the MCU sees it, via the bus switch |
DAC_SDA |
DAC_SDA |
/DAC_SDA |
Default | I2C0 SDA — analog 0x48, brake 0x49⁷; bidi as the MCU sees it, via the bus switch |
DIAG0 |
TMC_DIAG0 |
/TMC_DIAG0 |
Default | Driver diagnostic 0; in as the MCU sees it, via the bus switch |
DIAG0_INST |
TMC_DIAG0_INST |
/TMC_DIAG0_INST |
INSTRUMENT | |
DIAG1 |
TMC_DIAG1 |
/TMC_DIAG1 |
Default | Driver diagnostic 1; in as the MCU sees it, via the bus switch |
DIAG1_INST |
TMC_DIAG1_INST |
/TMC_DIAG1_INST |
INSTRUMENT | |
ENCA_INST |
ENCA_INST |
/ENCA_INST |
INSTRUMENT | |
ENCB_INST |
ENCB_INST |
/ENCB_INST |
INSTRUMENT | |
GND |
GND |
/GND |
PWR_RETURN_LOCAL | |
LIMIT_SW_INST |
LIMIT_SW_INST |
/LIMIT_SW_INST |
INSTRUMENT | |
TMC_SPI_CIPO |
TMC_SPI_CIPO |
/TMC_SPI_CIPO |
Default | Driver SPI CIPO (SPI0 RX); in as the MCU sees it, via the bus switch |
TMC_SPI_CIPO_INST |
TMC_SPI_CIPO_INST |
/TMC_SPI_CIPO_INST |
INSTRUMENT | |
TMC_SPI_COPI |
TMC_SPI_COPI |
/TMC_SPI_COPI |
Default | Driver SPI COPI (SPI0 TX); out as the MCU sees it, via the bus switch |
TMC_SPI_COPI_INST |
TMC_SPI_COPI_INST |
/TMC_SPI_COPI_INST |
INSTRUMENT | |
TMC_SPI_SCK |
TMC_SPI_SCK |
/TMC_SPI_SCK |
Default | Driver SPI clock (SPI0 SCK); out as the MCU sees it, via the bus switch |
TMC_SPI_SCK_INST |
TMC_SPI_SCK_INST |
/TMC_SPI_SCK_INST |
INSTRUMENT | |
VM |
+36V_SW |
/+36V_SW |
PWR_HV_BUS | |
~{DRV_EN} |
~{TMC_DRV_EN} |
/~{TMC_DRV_EN} |
Default | Driver enable, active low; out as the MCU sees it, via the bus switch |
~{DRV_EN}_INST |
~{TMC_DRV_EN}_INST |
/~{TMC_DRV_EN}_INST |
INSTRUMENT | |
~{TMC_CS} |
~{TMC_CS} |
/~{TMC_CS} |
Default | Driver chip select; out as the MCU sees it, via the bus switch |
~{TMC_CS}_INST |
~{TMC_CS}_INST |
/~{TMC_CS}_INST |
INSTRUMENT |
brake_torque_sensor in / (board-authored sheet, 6 parts)¶
| Port | Wired to | Net | Class | Meaning |
|---|---|---|---|---|
+3.3V |
+3.3V_SW |
/+3.3V_SW |
PWR_3V3 | |
+5V |
+5V_SW |
/+5V_SW |
PWR_5V | |
+36V |
+36V_SW |
/+36V_SW |
PWR_HV_BUS | |
BRAKE_ISENSE |
BRAKE_ISENSE |
/BRAKE_ISENSE |
MCU_FINE | Brake sink current readback, ADC1¹¹; in as the MCU sees it |
DAC_SCL |
DAC_SCL |
/DAC_SCL |
Default | I2C0 SCL — same bus⁷; out as the MCU sees it, via the bus switch |
DAC_SDA |
DAC_SDA |
/DAC_SDA |
Default | I2C0 SDA — analog 0x48, brake 0x49⁷; bidi as the MCU sees it, via the bus switch |
GND |
GND |
/GND |
PWR_RETURN_LOCAL | |
PG_12V |
PG_12V |
/PG_12V |
Default | |
TQ_AOUT_MON |
open: no-connect flag | |||
TQ_CAL_EN |
TQ_CAL_EN |
/TQ_CAL_EN |
Default | Torque calibration enable⁷; out as the MCU sees it, via the bus switch |
TQ_CAL_EN_INST |
TQ_CAL_EN_INST |
/TQ_CAL_EN_INST |
INSTRUMENT | |
TQ_CONVST_CS |
TQ_CONVST_CS |
/TQ_CONVST_CS |
Default | ADS8689 convert-start / frame, plain GPIO⁷; out as the MCU sees it, via the bus switch |
TQ_CONVST_CS_INST |
TQ_CONVST_CS_INST |
/TQ_CONVST_CS_INST |
INSTRUMENT | |
TQ_SPI_CIPO |
TQ_SPI_CIPO |
/TQ_SPI_CIPO |
Default | Torque ADC SPI CIPO (SPI1 RX)⁷; in as the MCU sees it, via the bus switch |
TQ_SPI_CIPO_INST |
TQ_SPI_CIPO_INST |
/TQ_SPI_CIPO_INST |
INSTRUMENT | |
TQ_SPI_COPI |
TQ_SPI_COPI |
/TQ_SPI_COPI |
Default | Torque ADC SPI COPI (SPI1 TX)⁷; out as the MCU sees it, via the bus switch |
TQ_SPI_COPI_INST |
TQ_SPI_COPI_INST |
/TQ_SPI_COPI_INST |
INSTRUMENT | |
TQ_SPI_SCK |
TQ_SPI_SCK |
/TQ_SPI_SCK |
Default | Torque ADC SPI clock (SPI1 SCK)⁷; out as the MCU sees it, via the bus switch |
TQ_SPI_SCK_INST |
TQ_SPI_SCK_INST |
/TQ_SPI_SCK_INST |
INSTRUMENT | |
~{BRAKE_FAULT} |
~{BRAKE_FAULT} |
/~{BRAKE_FAULT} |
Default | Brake block fault, active low⁷; in as the MCU sees it, via the bus switch |
~{BRAKE_FAULT}_INST |
~{BRAKE_FAULT}_INST |
/~{BRAKE_FAULT}_INST |
INSTRUMENT |
Connections¶
Per placed block: each port, the label it meets in its parent sheet, the net that resolves to and its class.
instrument_port_digital_50_dut_ffc_boundary_vertical (orb_weaver_private:instrument_port_digital_50_dut_ffc_boundary_vertical in /instrument_port)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V |
/+3.3V_MCU |
PWR_3V3 | |
DIG0 |
input | FW_TRIG0 |
/FW_TRIG0 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
DIG1 |
input | FW_TRIG1 |
/FW_TRIG1 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
DIG2 |
input | PYC_UART_TX |
/PYC_UART_TX_INST |
INSTRUMENT | |
DIG3 |
input | PYC_UART_RX |
/PYC_UART_RX_INST |
INSTRUMENT | |
DIG4 |
input | GND |
/GND |
PWR_RETURN_LOCAL | |
DIG5 |
input | GND |
/GND |
PWR_RETURN_LOCAL | |
DIG6 |
input | GND |
/GND |
PWR_RETURN_LOCAL | |
DIG7 |
input | GND |
/GND |
PWR_RETURN_LOCAL | |
DIG8 |
input | TMC_SPI_SCK |
/TMC_SPI_SCK_INST |
INSTRUMENT | |
DIG9 |
input | ~{TMC_CS} |
/~{TMC_CS}_INST |
INSTRUMENT | |
DIG10 |
input | TMC_SPI_COPI |
/TMC_SPI_COPI_INST |
INSTRUMENT | |
DIG11 |
input | TMC_SPI_CIPO |
/TMC_SPI_CIPO_INST |
INSTRUMENT | |
DIG12 |
input | TMC_DIAG0 |
/TMC_DIAG0_INST |
INSTRUMENT | |
DIG13 |
input | TMC_DIAG1 |
/TMC_DIAG1_INST |
INSTRUMENT | |
DIG14 |
input | ~{TMC_DRV_EN} |
/~{TMC_DRV_EN}_INST |
INSTRUMENT | |
DIG15 |
input | LIMIT_SW |
/LIMIT_SW_INST |
INSTRUMENT | |
DIG16 |
input | TQ_SPI_SCK |
/TQ_SPI_SCK_INST |
INSTRUMENT | |
DIG17 |
input | TQ_CONVST_CS |
/TQ_CONVST_CS_INST |
INSTRUMENT | |
DIG18 |
input | TQ_SPI_COPI |
/TQ_SPI_COPI_INST |
INSTRUMENT | |
DIG19 |
input | TQ_SPI_CIPO |
/TQ_SPI_CIPO_INST |
INSTRUMENT | |
DIG20 |
input | TQ_CAL_EN |
/TQ_CAL_EN_INST |
INSTRUMENT | |
DIG21 |
input | ~{BRAKE_FAULT} |
/~{BRAKE_FAULT}_INST |
INSTRUMENT | |
DIG22 |
input | DAQ_SDA |
/DAC_SDA_INST |
INSTRUMENT | |
DIG23 |
input | DAQ_SCL |
/DAC_SCL_INST |
INSTRUMENT | |
DIG24 |
input | HV_EN |
/HV_EN_INST |
INSTRUMENT | |
DIG25 |
input | HV_DIAG_EN |
/HV_DIAG_EN_INST |
INSTRUMENT | |
DIG26 |
input | ~{HV_FAULT} |
/~{HV_FAULT}_INST |
INSTRUMENT | |
DIG27 |
input | ~{BUS_SW_EN} |
/~{BUS_SW_EN}_INST |
INSTRUMENT | |
DIG28 |
input | ENCA |
/ENCA_INST |
INSTRUMENT | |
DIG29 |
input | ENCB |
/ENCB_INST |
INSTRUMENT | |
DIG30 |
input | PG_5V |
/PG_5V |
Default | |
DIG31 |
input | PG_12V |
/PG_12V |
Default | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL |
rp2040_with_gpio_isolation_sn74cb3q3245 (orb_weaver_private:rp2040_with_gpio_isolation_sn74cb3q3245 in /mcu)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V_MCU |
/+3.3V_MCU |
PWR_3V3 | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
GPIO0 |
bidirectional | PYC_UART_TX |
/PYC_UART_TX |
MCU_FINE | UART TX to pyControl (UART0 TX); out as the MCU sees it |
GPIO1 |
bidirectional | PYC_UART_RX |
/PYC_UART_RX |
MCU_FINE | UART RX from pyControl (UART0 RX); in as the MCU sees it |
GPIO2 |
bidirectional | open: no-connect flag | |||
GPIO3 |
bidirectional | open: no-connect flag | |||
GPIO4 |
bidirectional | open: no-connect flag | |||
GPIO5 |
bidirectional | open: no-connect flag | |||
GPIO6 |
bidirectional | open: no-connect flag | |||
GPIO7 |
bidirectional | open: no-connect flag | |||
GPIO8 |
bidirectional | open: no-connect flag | |||
GPIO10 |
bidirectional | open: no-connect flag | |||
GPIO11 |
bidirectional | open: no-connect flag | |||
GPIO12 |
bidirectional | open: no-connect flag | |||
GPIO13 |
bidirectional | open: no-connect flag | |||
GPIO14 |
bidirectional | HV_DIAG_EN |
/HV_DIAG_EN |
MCU_FINE | 36 V switch diagnostics enable⁵; out as the MCU sees it |
GPIO15 |
bidirectional | open: no-connect flag | |||
GPIO16 |
bidirectional | DAC_SDA_BYP |
/mcu/DAC_SDA_BYP |
MCU_FINE | |
GPIO17 |
bidirectional | DAC_SCL_BYP |
/mcu/DAC_SCL_BYP |
MCU_FINE | |
GPIO18 |
bidirectional | open: no-connect flag | |||
GPIO19 |
bidirectional | HV_EN |
/HV_EN |
MCU_FINE | 36 V input switch enable; out as the MCU sees it |
GPIO20 |
bidirectional | open: no-connect flag | |||
GPIO21 |
bidirectional | FW_TRIG1 |
/FW_TRIG1 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
GPIO22 |
bidirectional | open: no-connect flag | |||
GPIO23 |
bidirectional | ~{HV_FAULT} |
/~{HV_FAULT} |
MCU_FINE | 36 V switch fault, open-drain, pull-up 3.3 V¹¹; in as the MCU sees it |
GPIO24 |
bidirectional | HV_LATCH |
/HV_LATCH |
MCU_FINE | 36 V switch latch-off select¹⁰; out as the MCU sees it |
GPIO25 |
bidirectional | FW_TRIG0 |
/FW_TRIG0 |
MCU_FINE | Firmware timing marker; out as the MCU sees it |
GPIO26 |
passive | SW_RAIL_SENSE_DIV_2 |
/mcu/SW_RAIL_SENSE_DIV_2 |
MCU_FINE | +3.3V_SW presence and level, divided by 2 inside mcu (R408/R409); in as the MCU sees it |
GPIO27 |
passive | BRAKE_ISENSE |
/BRAKE_ISENSE |
MCU_FINE | Brake sink current readback, ADC1¹¹; in as the MCU sees it |
GPIO28 |
passive | HV_SNS |
/HV_SNS |
MCU_FINE | 36 V input load-current sense, R_SNS = 249 Ω; in as the MCU sees it |
GPIO29 |
passive | ANGLE_OUT_MON |
/ANGLE_OUT_MON |
MCU_FINE | Analog output readback, ADC3¹¹; in as the MCU sees it |
ISO0 |
passive | open: no-connect flag | |||
ISO1 |
passive | open: no-connect flag | |||
ISO2 |
passive | ~{TMC_CS} |
/~{TMC_CS} |
Default | Driver chip select; out as the MCU sees it, via the bus switch |
ISO3 |
passive | ~{TMC_DRV_EN} |
/~{TMC_DRV_EN} |
Default | Driver enable, active low; out as the MCU sees it, via the bus switch |
ISO4 |
passive | TMC_SPI_CIPO |
/TMC_SPI_CIPO |
Default | Driver SPI CIPO (SPI0 RX); in as the MCU sees it, via the bus switch |
ISO5 |
passive | TMC_DIAG0 |
/TMC_DIAG0 |
Default | Driver diagnostic 0; in as the MCU sees it, via the bus switch |
ISO6 |
passive | TMC_SPI_SCK |
/TMC_SPI_SCK |
Default | Driver SPI clock (SPI0 SCK); out as the MCU sees it, via the bus switch |
ISO7 |
passive | TMC_SPI_COPI |
/TMC_SPI_COPI |
Default | Driver SPI COPI (SPI0 TX); out as the MCU sees it, via the bus switch |
ISO8 |
passive | TMC_DIAG1 |
/TMC_DIAG1 |
Default | Driver diagnostic 1; in as the MCU sees it, via the bus switch |
ISO10 |
passive | TQ_SPI_SCK |
/TQ_SPI_SCK |
Default | Torque ADC SPI clock (SPI1 SCK)⁷; out as the MCU sees it, via the bus switch |
ISO11 |
passive | TQ_SPI_COPI |
/TQ_SPI_COPI |
Default | Torque ADC SPI COPI (SPI1 TX)⁷; out as the MCU sees it, via the bus switch |
ISO12 |
passive | TQ_SPI_CIPO |
/TQ_SPI_CIPO |
Default | Torque ADC SPI CIPO (SPI1 RX)⁷; in as the MCU sees it, via the bus switch |
ISO13 |
passive | ~{BRAKE_FAULT} |
/~{BRAKE_FAULT} |
Default | Brake block fault, active low⁷; in as the MCU sees it, via the bus switch |
ISO14 |
passive | open: no-connect flag | |||
ISO15 |
passive | TQ_CONVST_CS |
/TQ_CONVST_CS |
Default | ADS8689 convert-start / frame, plain GPIO⁷; out as the MCU sees it, via the bus switch |
ISO16 |
passive | DAC_SDA |
/DAC_SDA |
Default | I2C0 SDA — analog 0x48, brake 0x49⁷; bidi as the MCU sees it, via the bus switch |
ISO17 |
passive | DAC_SCL |
/DAC_SCL |
Default | I2C0 SCL — same bus⁷; out as the MCU sees it, via the bus switch |
ISO18 |
passive | TQ_CAL_EN |
/TQ_CAL_EN |
Default | Torque calibration enable⁷; out as the MCU sees it, via the bus switch |
ISO19 |
passive | open: no-connect flag | |||
ISO20 |
passive | open: no-connect flag | |||
ISO21 |
passive | open: no-connect flag | |||
ISO22 |
passive | open: no-connect flag | |||
ISO23 |
passive | open: no-connect flag | |||
ISO24 |
passive | open: no-connect flag | |||
ISO25 |
passive | open: no-connect flag | |||
ISO26 |
passive | open: no-connect flag | |||
ISO27 |
passive | open: no-connect flag | |||
ISO28 |
passive | open: no-connect flag | |||
ISO29 |
passive | open: no-connect flag | |||
USB_D+ |
bidirectional | USB_D+ |
/USB_D+ |
USB_HS | |
USB_D- |
bidirectional | USB_D- |
/USB_D- |
USB_HS | |
~{BUS_SW_EN} |
output | open: no-connect flag | |||
~{BUS_SW_EN}_INST |
output | ~{BUS_SW_EN}_INST |
/~{BUS_SW_EN}_INST |
INSTRUMENT |
5v_to_3v3_tps73733_1 (orb_weaver_private:5v_to_3v3_tps73733 in /mcu)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V_MCU |
/+3.3V_MCU |
PWR_3V3 | |
+5V |
passive | +5V_MCU |
/+5V_MCU |
PWR_5V | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL |
pycontrol_behavior_port_rj45_boundary_vertical (orb_weaver_private:pycontrol_behavior_port_rj45_boundary_vertical in /)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+5V_PYC |
passive | +5V_MCU |
/+5V_MCU |
PWR_5V | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
PYC_CONN_5V |
passive | open: no-connect flag | |||
PYC_DIO_A_HOSTTX_SCL_MOSI |
bidirectional | PYC_UART_RX |
/PYC_UART_RX |
MCU_FINE | UART RX from pyControl (UART0 RX); in as the MCU sees it |
PYC_DIO_A_INST |
output | PYC_UART_RX_INST |
/PYC_UART_RX_INST |
INSTRUMENT | |
PYC_DIO_B_HOSTRX_SDA_MISO |
bidirectional | PYC_UART_TX |
/PYC_UART_TX |
MCU_FINE | UART TX to pyControl (UART0 TX); out as the MCU sees it |
PYC_DIO_B_INST |
output | PYC_UART_TX_INST |
/PYC_UART_TX_INST |
INSTRUMENT |
5v_to_3v3_tps73733_2 (orb_weaver_private:5v_to_3v3_tps73733 in /)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V_SW |
/+3.3V_SW |
PWR_3V3 | |
+5V |
passive | +5V_SW |
/+5V_SW |
PWR_5V | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL |
usb2_vertical (orb_weaver_private:usb2_vertical in /)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+5V_USB |
passive | +5V_MCU |
/+5V_MCU |
PWR_5V | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
USB_D+ |
bidirectional | USB_D+ |
/USB_D+ |
USB_HS | |
USB_D- |
bidirectional | USB_D- |
/USB_D- |
USB_HS | |
VBUS |
passive | open: no-connect flag |
analog_output_0_3v3_dac80501 (orb_weaver_private:analog_output_0_3v3_dac80501 in /motor_encoder_switch)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V |
/+3.3V_SW |
PWR_3V3 | |
+5V |
passive | +5V |
/+5V_SW |
PWR_5V | |
AOUT |
output | ANGLE_OUT |
/motor_encoder_switch/ANGLE_OUT |
Default | |
AOUT_MON |
output | ANGLE_OUT_MON |
/ANGLE_OUT_MON |
MCU_FINE | Analog output readback, ADC3¹¹; in as the MCU sees it |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
SCL |
input | DAC_SCL |
/DAC_SCL |
Default | I2C0 SCL — same bus⁷; out as the MCU sees it, via the bus switch |
SDA |
bidirectional | DAC_SDA |
/DAC_SDA |
Default | I2C0 SDA — analog 0x48, brake 0x49⁷; bidi as the MCU sees it, via the bus switch |
quadrature_encoder_input_5v_sn74lvc2g17 (orb_weaver_private:quadrature_encoder_input_5v_sn74lvc2g17 in /motor_encoder_switch)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V |
/+3.3V_SW |
PWR_3V3 | |
EA |
input | ENCA_5V |
/motor_encoder_switch/ENCA_5V |
Default | |
EB |
input | ENCB_5V |
/motor_encoder_switch/ENCB_5V |
Default | |
ENCA |
output | ENCA |
/motor_encoder_switch/ENCA |
Default | |
ENCA_INST |
output | ENCA_INST |
/ENCA_INST |
INSTRUMENT | |
ENCB |
output | ENCB |
/motor_encoder_switch/ENCB |
Default | |
ENCB_INST |
output | ENCB_INST |
/ENCB_INST |
INSTRUMENT | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
VENC |
passive | +5V |
/+5V_SW |
PWR_5V |
limit_switch_debounced_input_vertical (orb_weaver_private:limit_switch_debounced_input_vertical in /motor_encoder_switch)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V_SW |
passive | +3.3V |
/+3.3V_SW |
PWR_3V3 | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
LIMIT_SW |
output | LIMIT_SW |
/motor_encoder_switch/LIMIT_SW |
Default | |
LIMIT_SW_INST |
output | LIMIT_SW_INST |
/LIMIT_SW_INST |
INSTRUMENT |
tmc5130 (orb_weaver_private:tmc5130 in /motor_encoder_switch)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V |
/+3.3V_SW |
PWR_3V3 | |
+5V |
passive | +5V |
/+5V_SW |
PWR_5V | |
CIPO |
output | TMC_SPI_CIPO |
/TMC_SPI_CIPO |
Default | Driver SPI CIPO (SPI0 RX); in as the MCU sees it, via the bus switch |
CIPO_INST |
output | TMC_SPI_CIPO_INST |
/TMC_SPI_CIPO_INST |
INSTRUMENT | |
COPI |
input | TMC_SPI_COPI |
/TMC_SPI_COPI |
Default | Driver SPI COPI (SPI0 TX); out as the MCU sees it, via the bus switch |
COPI_INST |
output | TMC_SPI_COPI_INST |
/TMC_SPI_COPI_INST |
INSTRUMENT | |
ENCA |
input | ENCA |
/motor_encoder_switch/ENCA |
Default | |
ENCB |
input | ENCB |
/motor_encoder_switch/ENCB |
Default | |
ENCN |
input | open: no-connect flag | |||
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
OA1 |
passive | OA1 |
/motor_encoder_switch/OA1 |
MOTOR_2A | |
OA2 |
passive | OA2 |
/motor_encoder_switch/OA2 |
MOTOR_2A | |
OB1 |
passive | OB1 |
/motor_encoder_switch/OB1 |
MOTOR_2A | |
OB2 |
passive | OB2 |
/motor_encoder_switch/OB2 |
MOTOR_2A | |
REFL |
input | LIMIT_SW |
/motor_encoder_switch/LIMIT_SW |
Default | |
REFR |
input | GND |
/GND |
PWR_RETURN_LOCAL | |
SCK |
output | TMC_SPI_SCK |
/TMC_SPI_SCK |
Default | Driver SPI clock (SPI0 SCK); out as the MCU sees it, via the bus switch |
SCK_INST |
output | TMC_SPI_SCK_INST |
/TMC_SPI_SCK_INST |
INSTRUMENT | |
SWN_DIAG0 |
bidirectional | DIAG0 |
/TMC_DIAG0 |
Default | Driver diagnostic 0; in as the MCU sees it, via the bus switch |
SWN_DIAG0_INST |
output | DIAG0_INST |
/TMC_DIAG0_INST |
INSTRUMENT | |
SWP_DIAG1 |
bidirectional | DIAG1 |
/TMC_DIAG1 |
Default | Driver diagnostic 1; in as the MCU sees it, via the bus switch |
SWP_DIAG1_INST |
output | DIAG1_INST |
/TMC_DIAG1_INST |
INSTRUMENT | |
SWSEL |
input | open: no-connect flag | |||
VM |
passive | VM |
/+36V_SW |
PWR_HV_BUS | |
~{CS} |
output | ~{TMC_CS} |
/~{TMC_CS} |
Default | Driver chip select; out as the MCU sees it, via the bus switch |
~{CS}_INST |
output | ~{TMC_CS}_INST |
/~{TMC_CS}_INST |
INSTRUMENT | |
~{DRV_EN} |
input | ~{DRV_EN} |
/~{TMC_DRV_EN} |
Default | Driver enable, active low; out as the MCU sees it, via the bus switch |
~{DRV_EN}_INST |
output | ~{DRV_EN}_INST |
/~{TMC_DRV_EN}_INST |
INSTRUMENT |
hv_to_5v_tpsm365r6 (orb_weaver_private:hv_to_5v_tpsm365r6 in /)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+5V |
passive | +5V_SW |
/+5V_SW |
PWR_5V | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
PGOOD |
output | PG_5V |
/PG_5V |
Default | |
VIN |
passive | +36V_SW |
/+36V_SW |
PWR_HV_BUS |
torque_bridge_0_3v3_ina821 (orb_weaver_private:torque_bridge_0_3v3_ina821 in /brake_torque_sensor)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V |
/+3.3V_SW |
PWR_3V3 | |
+5V |
passive | +5V |
/+5V_SW |
PWR_5V | |
+12V |
passive | +12V |
/brake_torque_sensor/+12V |
PWR_12V_LOCAL | |
CIPO |
output | TQ_SPI_CIPO |
/TQ_SPI_CIPO |
Default | Torque ADC SPI CIPO (SPI1 RX)⁷; in as the MCU sees it, via the bus switch |
CIPO_INST |
output | TQ_SPI_CIPO_INST |
/TQ_SPI_CIPO_INST |
INSTRUMENT | |
COPI |
input | TQ_SPI_COPI |
/TQ_SPI_COPI |
Default | Torque ADC SPI COPI (SPI1 TX)⁷; out as the MCU sees it, via the bus switch |
COPI_INST |
output | TQ_SPI_COPI_INST |
/TQ_SPI_COPI_INST |
INSTRUMENT | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
SCK |
input | TQ_SPI_SCK |
/TQ_SPI_SCK |
Default | Torque ADC SPI clock (SPI1 SCK)⁷; out as the MCU sees it, via the bus switch |
SCK_INST |
output | TQ_SPI_SCK_INST |
/TQ_SPI_SCK_INST |
INSTRUMENT | |
TQ_AOUT |
output | TQ_AOUT |
/brake_torque_sensor/TQ_AOUT |
Default | |
TQ_AOUT_MON |
output | TQ_AOUT_MON |
/brake_torque_sensor/torque_bridge_0_3v3_ina821/TQ_AOUT_MON |
Default | |
TQ_CAL_EN |
input | TQ_CAL_EN |
/TQ_CAL_EN |
Default | Torque calibration enable⁷; out as the MCU sees it, via the bus switch |
TQ_CAL_EN_INST |
output | TQ_CAL_EN_INST |
/TQ_CAL_EN_INST |
INSTRUMENT | |
TQ_CONVST_CS |
input | TQ_CONVST_CS |
/TQ_CONVST_CS |
Default | ADS8689 convert-start / frame, plain GPIO⁷; out as the MCU sees it, via the bus switch |
TQ_CONVST_CS_INST |
output | TQ_CONVST_CS_INST |
/TQ_CONVST_CS_INST |
INSTRUMENT |
hv_to_12v_tpsm365r6 (orb_weaver_private:hv_to_12v_tpsm365r6 in /brake_torque_sensor)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+12V |
passive | +12V |
/brake_torque_sensor/+12V |
PWR_12V_LOCAL | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
PGOOD |
output | PG_12V |
/PG_12V |
Default | |
VIN |
passive | +36V |
/+36V_SW |
PWR_HV_BUS |
brake_current_sink_0_49ma_dac80501 (orb_weaver_private:brake_current_sink_0_49ma_dac80501 in /brake_torque_sensor)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V |
passive | +3.3V |
/+3.3V_SW |
PWR_3V3 | |
+5V |
passive | +5V |
/+5V_SW |
PWR_5V | |
+12V |
passive | +12V |
/brake_torque_sensor/+12V |
PWR_12V_LOCAL | |
+36V |
passive | +36V |
/+36V_SW |
PWR_HV_BUS | |
BRAKE_ISENSE |
output | BRAKE_ISENSE |
/BRAKE_ISENSE |
MCU_FINE | Brake sink current readback, ADC1¹¹; in as the MCU sees it |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
SCL |
input | DAC_SCL |
/DAC_SCL |
Default | I2C0 SCL — same bus⁷; out as the MCU sees it, via the bus switch |
SDA |
bidirectional | DAC_SDA |
/DAC_SDA |
Default | I2C0 SDA — analog 0x48, brake 0x49⁷; bidi as the MCU sees it, via the bus switch |
~{BRAKE_FAULT} |
output | ~{BRAKE_FAULT} |
/~{BRAKE_FAULT} |
Default | Brake block fault, active low⁷; in as the MCU sees it, via the bus switch |
~{BRAKE_FAULT}_INST |
output | ~{BRAKE_FAULT}_INST |
/~{BRAKE_FAULT}_INST |
INSTRUMENT |
hv_input_36V_terminal_2pos_5p08_protected_vertical (orb_weaver_private:hv_input_36V_terminal_2pos_5p08_protected_vertical in /)¶
| Port | Shape | Wired to | Net | Class | Meaning |
|---|---|---|---|---|---|
+3.3V_MCU |
passive | +3.3V_MCU |
/+3.3V_MCU |
PWR_3V3 | |
+36V |
passive | +36V_SW |
/+36V_SW |
PWR_HV_BUS | |
DIAG_ENABLE |
input | HV_DIAG_EN |
/HV_DIAG_EN |
MCU_FINE | 36 V switch diagnostics enable⁵; out as the MCU sees it |
DIAG_ENABLE_INST |
output | HV_DIAG_EN_INST |
/HV_DIAG_EN_INST |
INSTRUMENT | |
ENABLE |
input | HV_EN |
/HV_EN |
MCU_FINE | 36 V input switch enable; out as the MCU sees it |
ENABLE_INST |
output | HV_EN_INST |
/HV_EN_INST |
INSTRUMENT | |
GND |
passive | GND |
/GND |
PWR_RETURN_LOCAL | |
HV_IN |
passive | open: no-connect flag | |||
LATCH |
input | HV_LATCH |
/HV_LATCH |
MCU_FINE | 36 V switch latch-off select¹⁰; out as the MCU sees it |
SNS |
output | HV_SNS |
/HV_SNS |
MCU_FINE | 36 V input load-current sense, R_SNS = 249 Ω; in as the MCU sees it |
~{FAULT} |
output | ~{HV_FAULT} |
/~{HV_FAULT} |
MCU_FINE | 36 V switch fault, open-drain, pull-up 3.3 V¹¹; in as the MCU sees it |
~{FAULT}_INST |
output | ~{HV_FAULT}_INST |
/~{HV_FAULT}_INST |
INSTRUMENT |
Nets¶
Every net a block port or a board sheet's port reaches, by its qualified name.
| Net | Class | GPIO | Ports | Meaning |
|---|---|---|---|---|
/+3.3V_MCU |
PWR_3V3 | instrument_port (sheet)/+3.3V, mcu (sheet)/+3.3V_MCU, instrument_port_digital_50_dut_ffc_boundary_vertical/+3.3V, rp2040_with_gpio_isolation_sn74cb3q3245/+3.3V, 5v_to_3v3_tps73733_1/+3.3V, hv_input_36V_terminal_2pos_5p08_protected_vertical/+3.3V_MCU |
||
/+3.3V_SW |
PWR_3V3 | mcu (sheet)/+3.3V_SW, motor_encoder_switch (sheet)/+3.3V, brake_torque_sensor (sheet)/+3.3V, 5v_to_3v3_tps73733_2/+3.3V, analog_output_0_3v3_dac80501/+3.3V, quadrature_encoder_input_5v_sn74lvc2g17/+3.3V, limit_switch_debounced_input_vertical/+3.3V_SW, tmc5130/+3.3V, torque_bridge_0_3v3_ina821/+3.3V, brake_current_sink_0_49ma_dac80501/+3.3V |
||
/+36V_SW |
PWR_HV_BUS | motor_encoder_switch (sheet)/VM, brake_torque_sensor (sheet)/+36V, tmc5130/VM, hv_to_5v_tpsm365r6/VIN, hv_to_12v_tpsm365r6/VIN, brake_current_sink_0_49ma_dac80501/+36V, hv_input_36V_terminal_2pos_5p08_protected_vertical/+36V |
||
/+5V_MCU |
PWR_5V | mcu (sheet)/+5V_MCU, 5v_to_3v3_tps73733_1/+5V, pycontrol_behavior_port_rj45_boundary_vertical/+5V_PYC, usb2_vertical/+5V_USB |
||
/+5V_SW |
PWR_5V | motor_encoder_switch (sheet)/+5V, brake_torque_sensor (sheet)/+5V, 5v_to_3v3_tps73733_2/+5V, analog_output_0_3v3_dac80501/+5V, quadrature_encoder_input_5v_sn74lvc2g17/VENC, tmc5130/+5V, hv_to_5v_tpsm365r6/+5V, torque_bridge_0_3v3_ina821/+5V, brake_current_sink_0_49ma_dac80501/+5V |
||
/ANGLE_OUT_MON |
MCU_FINE | GP29 |
mcu (sheet)/ANGLE_OUT_MON, motor_encoder_switch (sheet)/ANGLE_OUT_MON, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO29, analog_output_0_3v3_dac80501/AOUT_MON |
Analog output readback, ADC3¹¹; in as the MCU sees it |
/BRAKE_ISENSE |
MCU_FINE | GP27 |
mcu (sheet)/BRAKE_ISENSE, brake_torque_sensor (sheet)/BRAKE_ISENSE, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO27, brake_current_sink_0_49ma_dac80501/BRAKE_ISENSE |
Brake sink current readback, ADC1¹¹; in as the MCU sees it |
/DAC_SCL |
Default | GP17 |
mcu (sheet)/DAC_SCL, motor_encoder_switch (sheet)/DAC_SCL, brake_torque_sensor (sheet)/DAC_SCL, rp2040_with_gpio_isolation_sn74cb3q3245/ISO17, analog_output_0_3v3_dac80501/SCL, brake_current_sink_0_49ma_dac80501/SCL |
I2C0 SCL — same bus⁷; out as the MCU sees it, via the bus switch |
/DAC_SCL_INST |
INSTRUMENT | instrument_port (sheet)/DAQ_SCL, mcu (sheet)/DAC_SCL_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG23 |
||
/DAC_SDA |
Default | GP16 |
mcu (sheet)/DAC_SDA, motor_encoder_switch (sheet)/DAC_SDA, brake_torque_sensor (sheet)/DAC_SDA, rp2040_with_gpio_isolation_sn74cb3q3245/ISO16, analog_output_0_3v3_dac80501/SDA, brake_current_sink_0_49ma_dac80501/SDA |
I2C0 SDA — analog 0x48, brake 0x49⁷; bidi as the MCU sees it, via the bus switch |
/DAC_SDA_INST |
INSTRUMENT | instrument_port (sheet)/DAQ_SDA, mcu (sheet)/DAC_SDA_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG22 |
||
/ENCA_INST |
INSTRUMENT | instrument_port (sheet)/ENCA, motor_encoder_switch (sheet)/ENCA_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG28, quadrature_encoder_input_5v_sn74lvc2g17/ENCA_INST |
||
/ENCB_INST |
INSTRUMENT | instrument_port (sheet)/ENCB, motor_encoder_switch (sheet)/ENCB_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG29, quadrature_encoder_input_5v_sn74lvc2g17/ENCB_INST |
||
/FW_TRIG0 |
MCU_FINE | GP25 |
instrument_port (sheet)/FW_TRIG0, mcu (sheet)/FW_TRIG0, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG0, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO25 |
Firmware timing marker; out as the MCU sees it |
/FW_TRIG1 |
MCU_FINE | GP21 |
instrument_port (sheet)/FW_TRIG1, mcu (sheet)/FW_TRIG1, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG1, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO21 |
Firmware timing marker; out as the MCU sees it |
/GND |
PWR_RETURN_LOCAL | instrument_port (sheet)/GND, mcu (sheet)/GND, motor_encoder_switch (sheet)/GND, brake_torque_sensor (sheet)/GND, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG4, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG5, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG6, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG7, instrument_port_digital_50_dut_ffc_boundary_vertical/GND, rp2040_with_gpio_isolation_sn74cb3q3245/GND, 5v_to_3v3_tps73733_1/GND, pycontrol_behavior_port_rj45_boundary_vertical/GND, 5v_to_3v3_tps73733_2/GND, usb2_vertical/GND, analog_output_0_3v3_dac80501/GND, quadrature_encoder_input_5v_sn74lvc2g17/GND, limit_switch_debounced_input_vertical/GND, tmc5130/GND, tmc5130/REFR, hv_to_5v_tpsm365r6/GND, torque_bridge_0_3v3_ina821/GND, hv_to_12v_tpsm365r6/GND, brake_current_sink_0_49ma_dac80501/GND, hv_input_36V_terminal_2pos_5p08_protected_vertical/GND |
||
/HV_DIAG_EN |
MCU_FINE | GP14 |
mcu (sheet)/HV_DIAG_EN, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO14, hv_input_36V_terminal_2pos_5p08_protected_vertical/DIAG_ENABLE |
36 V switch diagnostics enable⁵; out as the MCU sees it |
/HV_DIAG_EN_INST |
INSTRUMENT | instrument_port (sheet)/HV_DIAG_EN, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG25, hv_input_36V_terminal_2pos_5p08_protected_vertical/DIAG_ENABLE_INST |
||
/HV_EN |
MCU_FINE | GP19 |
mcu (sheet)/HV_EN, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO19, hv_input_36V_terminal_2pos_5p08_protected_vertical/ENABLE |
36 V input switch enable; out as the MCU sees it |
/HV_EN_INST |
INSTRUMENT | instrument_port (sheet)/HV_EN, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG24, hv_input_36V_terminal_2pos_5p08_protected_vertical/ENABLE_INST |
||
/HV_LATCH |
MCU_FINE | GP24 |
mcu (sheet)/HV_LATCH, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO24, hv_input_36V_terminal_2pos_5p08_protected_vertical/LATCH |
36 V switch latch-off select¹⁰; out as the MCU sees it |
/HV_SNS |
MCU_FINE | GP28 |
mcu (sheet)/HV_SNS, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO28, hv_input_36V_terminal_2pos_5p08_protected_vertical/SNS |
36 V input load-current sense, R_SNS = 249 Ω; in as the MCU sees it |
/LIMIT_SW_INST |
INSTRUMENT | instrument_port (sheet)/LIMIT_SW, motor_encoder_switch (sheet)/LIMIT_SW_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG15, limit_switch_debounced_input_vertical/LIMIT_SW_INST |
||
/PG_12V |
Default | instrument_port (sheet)/PG_12V, brake_torque_sensor (sheet)/PG_12V, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG31, hv_to_12v_tpsm365r6/PGOOD |
||
/PG_5V |
Default | instrument_port (sheet)/PG_5V, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG30, hv_to_5v_tpsm365r6/PGOOD |
||
/PYC_UART_RX |
MCU_FINE | GP1 |
mcu (sheet)/PYC_UART_RX, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO1, pycontrol_behavior_port_rj45_boundary_vertical/PYC_DIO_A_HOSTTX_SCL_MOSI |
UART RX from pyControl (UART0 RX); in as the MCU sees it |
/PYC_UART_RX_INST |
INSTRUMENT | instrument_port (sheet)/PYC_UART_RX, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG3, pycontrol_behavior_port_rj45_boundary_vertical/PYC_DIO_A_INST |
||
/PYC_UART_TX |
MCU_FINE | GP0 |
mcu (sheet)/PYC_UART_TX, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO0, pycontrol_behavior_port_rj45_boundary_vertical/PYC_DIO_B_HOSTRX_SDA_MISO |
UART TX to pyControl (UART0 TX); out as the MCU sees it |
/PYC_UART_TX_INST |
INSTRUMENT | instrument_port (sheet)/PYC_UART_TX, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG2, pycontrol_behavior_port_rj45_boundary_vertical/PYC_DIO_B_INST |
||
/TMC_DIAG0 |
Default | GP5 |
mcu (sheet)/TMC_DIAG0, motor_encoder_switch (sheet)/DIAG0, rp2040_with_gpio_isolation_sn74cb3q3245/ISO5, tmc5130/SWN_DIAG0 |
Driver diagnostic 0; in as the MCU sees it, via the bus switch |
/TMC_DIAG0_INST |
INSTRUMENT | instrument_port (sheet)/TMC_DIAG0, motor_encoder_switch (sheet)/DIAG0_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG12, tmc5130/SWN_DIAG0_INST |
||
/TMC_DIAG1 |
Default | GP8 |
mcu (sheet)/TMC_DIAG1, motor_encoder_switch (sheet)/DIAG1, rp2040_with_gpio_isolation_sn74cb3q3245/ISO8, tmc5130/SWP_DIAG1 |
Driver diagnostic 1; in as the MCU sees it, via the bus switch |
/TMC_DIAG1_INST |
INSTRUMENT | instrument_port (sheet)/TMC_DIAG1, motor_encoder_switch (sheet)/DIAG1_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG13, tmc5130/SWP_DIAG1_INST |
||
/TMC_SPI_CIPO |
Default | GP4 |
mcu (sheet)/TMC_SPI_CIPO, motor_encoder_switch (sheet)/TMC_SPI_CIPO, rp2040_with_gpio_isolation_sn74cb3q3245/ISO4, tmc5130/CIPO |
Driver SPI CIPO (SPI0 RX); in as the MCU sees it, via the bus switch |
/TMC_SPI_CIPO_INST |
INSTRUMENT | instrument_port (sheet)/TMC_SPI_CIPO, motor_encoder_switch (sheet)/TMC_SPI_CIPO_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG11, tmc5130/CIPO_INST |
||
/TMC_SPI_COPI |
Default | GP7 |
mcu (sheet)/TMC_SPI_COPI, motor_encoder_switch (sheet)/TMC_SPI_COPI, rp2040_with_gpio_isolation_sn74cb3q3245/ISO7, tmc5130/COPI |
Driver SPI COPI (SPI0 TX); out as the MCU sees it, via the bus switch |
/TMC_SPI_COPI_INST |
INSTRUMENT | instrument_port (sheet)/TMC_SPI_COPI, motor_encoder_switch (sheet)/TMC_SPI_COPI_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG10, tmc5130/COPI_INST |
||
/TMC_SPI_SCK |
Default | GP6 |
mcu (sheet)/TMC_SPI_SCK, motor_encoder_switch (sheet)/TMC_SPI_SCK, rp2040_with_gpio_isolation_sn74cb3q3245/ISO6, tmc5130/SCK |
Driver SPI clock (SPI0 SCK); out as the MCU sees it, via the bus switch |
/TMC_SPI_SCK_INST |
INSTRUMENT | instrument_port (sheet)/TMC_SPI_SCK, motor_encoder_switch (sheet)/TMC_SPI_SCK_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG8, tmc5130/SCK_INST |
||
/TQ_CAL_EN |
Default | GP18 |
mcu (sheet)/TQ_CAL_EN, brake_torque_sensor (sheet)/TQ_CAL_EN, rp2040_with_gpio_isolation_sn74cb3q3245/ISO18, torque_bridge_0_3v3_ina821/TQ_CAL_EN |
Torque calibration enable⁷; out as the MCU sees it, via the bus switch |
/TQ_CAL_EN_INST |
INSTRUMENT | instrument_port (sheet)/TQ_CAL_EN, brake_torque_sensor (sheet)/TQ_CAL_EN_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG20, torque_bridge_0_3v3_ina821/TQ_CAL_EN_INST |
||
/TQ_CONVST_CS |
Default | GP15 |
mcu (sheet)/TQ_CONVST_CS, brake_torque_sensor (sheet)/TQ_CONVST_CS, rp2040_with_gpio_isolation_sn74cb3q3245/ISO15, torque_bridge_0_3v3_ina821/TQ_CONVST_CS |
ADS8689 convert-start / frame, plain GPIO⁷; out as the MCU sees it, via the bus switch |
/TQ_CONVST_CS_INST |
INSTRUMENT | instrument_port (sheet)/TQ_CONVST_CS, brake_torque_sensor (sheet)/TQ_CONVST_CS_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG17, torque_bridge_0_3v3_ina821/TQ_CONVST_CS_INST |
||
/TQ_SPI_CIPO |
Default | GP12 |
mcu (sheet)/TQ_SPI_CIPO, brake_torque_sensor (sheet)/TQ_SPI_CIPO, rp2040_with_gpio_isolation_sn74cb3q3245/ISO12, torque_bridge_0_3v3_ina821/CIPO |
Torque ADC SPI CIPO (SPI1 RX)⁷; in as the MCU sees it, via the bus switch |
/TQ_SPI_CIPO_INST |
INSTRUMENT | instrument_port (sheet)/TQ_SPI_CIPO, brake_torque_sensor (sheet)/TQ_SPI_CIPO_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG19, torque_bridge_0_3v3_ina821/CIPO_INST |
||
/TQ_SPI_COPI |
Default | GP11 |
mcu (sheet)/TQ_SPI_COPI, brake_torque_sensor (sheet)/TQ_SPI_COPI, rp2040_with_gpio_isolation_sn74cb3q3245/ISO11, torque_bridge_0_3v3_ina821/COPI |
Torque ADC SPI COPI (SPI1 TX)⁷; out as the MCU sees it, via the bus switch |
/TQ_SPI_COPI_INST |
INSTRUMENT | instrument_port (sheet)/TQ_SPI_COPI, brake_torque_sensor (sheet)/TQ_SPI_COPI_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG18, torque_bridge_0_3v3_ina821/COPI_INST |
||
/TQ_SPI_SCK |
Default | GP10 |
mcu (sheet)/TQ_SPI_SCK, brake_torque_sensor (sheet)/TQ_SPI_SCK, rp2040_with_gpio_isolation_sn74cb3q3245/ISO10, torque_bridge_0_3v3_ina821/SCK |
Torque ADC SPI clock (SPI1 SCK)⁷; out as the MCU sees it, via the bus switch |
/TQ_SPI_SCK_INST |
INSTRUMENT | instrument_port (sheet)/TQ_SPI_SCK, brake_torque_sensor (sheet)/TQ_SPI_SCK_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG16, torque_bridge_0_3v3_ina821/SCK_INST |
||
/USB_D+ |
USB_HS | mcu (sheet)/USB_D+, rp2040_with_gpio_isolation_sn74cb3q3245/USB_D+, usb2_vertical/USB_D+ |
||
/USB_D- |
USB_HS | mcu (sheet)/USB_D-, rp2040_with_gpio_isolation_sn74cb3q3245/USB_D-, usb2_vertical/USB_D- |
||
/~{BRAKE_FAULT} |
Default | GP13 |
mcu (sheet)/~{BRAKE_FAULT}, brake_torque_sensor (sheet)/~{BRAKE_FAULT}, rp2040_with_gpio_isolation_sn74cb3q3245/ISO13, brake_current_sink_0_49ma_dac80501/~{BRAKE_FAULT} |
Brake block fault, active low⁷; in as the MCU sees it, via the bus switch |
/~{BRAKE_FAULT}_INST |
INSTRUMENT | instrument_port (sheet)/~{BRAKE_FAULT}, brake_torque_sensor (sheet)/~{BRAKE_FAULT}_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG21, brake_current_sink_0_49ma_dac80501/~{BRAKE_FAULT}_INST |
||
/~{BUS_SW_EN}_INST |
INSTRUMENT | instrument_port (sheet)/~{BUS_SW_EN}, mcu (sheet)/~{BUS_SW_EN}_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG27, rp2040_with_gpio_isolation_sn74cb3q3245/~{BUS_SW_EN}_INST |
||
/~{HV_FAULT} |
MCU_FINE | GP23 |
mcu (sheet)/~{HV_FAULT}, rp2040_with_gpio_isolation_sn74cb3q3245/GPIO23, hv_input_36V_terminal_2pos_5p08_protected_vertical/~{FAULT} |
36 V switch fault, open-drain, pull-up 3.3 V¹¹; in as the MCU sees it |
/~{HV_FAULT}_INST |
INSTRUMENT | instrument_port (sheet)/~{HV_FAULT}, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG26, hv_input_36V_terminal_2pos_5p08_protected_vertical/~{FAULT}_INST |
||
/~{TMC_CS} |
Default | GP2 |
mcu (sheet)/~{TMC_CS}, motor_encoder_switch (sheet)/~{TMC_CS}, rp2040_with_gpio_isolation_sn74cb3q3245/ISO2, tmc5130/~{CS} |
Driver chip select; out as the MCU sees it, via the bus switch |
/~{TMC_CS}_INST |
INSTRUMENT | instrument_port (sheet)/~{TMC_CS}, motor_encoder_switch (sheet)/~{TMC_CS}_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG9, tmc5130/~{CS}_INST |
||
/~{TMC_DRV_EN} |
Default | GP3 |
mcu (sheet)/~{TMC_DRV_EN}, motor_encoder_switch (sheet)/~{DRV_EN}, rp2040_with_gpio_isolation_sn74cb3q3245/ISO3, tmc5130/~{DRV_EN} |
Driver enable, active low; out as the MCU sees it, via the bus switch |
/~{TMC_DRV_EN}_INST |
INSTRUMENT | instrument_port (sheet)/~{TMC_DRV_EN}, motor_encoder_switch (sheet)/~{DRV_EN}_INST, instrument_port_digital_50_dut_ffc_boundary_vertical/DIG14, tmc5130/~{DRV_EN}_INST |
||
/brake_torque_sensor/+12V |
PWR_12V_LOCAL | torque_bridge_0_3v3_ina821/+12V, hv_to_12v_tpsm365r6/+12V, brake_current_sink_0_49ma_dac80501/+12V |
||
/brake_torque_sensor/TQ_AOUT |
Default | torque_bridge_0_3v3_ina821/TQ_AOUT |
||
/mcu/DAC_SCL_BYP |
MCU_FINE | rp2040_with_gpio_isolation_sn74cb3q3245/GPIO17 |
||
/mcu/DAC_SDA_BYP |
MCU_FINE | rp2040_with_gpio_isolation_sn74cb3q3245/GPIO16 |
||
/mcu/SW_RAIL_SENSE_DIV_2 |
MCU_FINE | GP26 |
rp2040_with_gpio_isolation_sn74cb3q3245/GPIO26 |
+3.3V_SW presence and level, divided by 2 inside mcu (R408/R409); in as the MCU sees it |
/motor_encoder_switch/ANGLE_OUT |
Default | analog_output_0_3v3_dac80501/AOUT |
||
/motor_encoder_switch/ENCA |
Default | quadrature_encoder_input_5v_sn74lvc2g17/ENCA, tmc5130/ENCA |
||
/motor_encoder_switch/ENCA_5V |
Default | quadrature_encoder_input_5v_sn74lvc2g17/EA |
||
/motor_encoder_switch/ENCB |
Default | quadrature_encoder_input_5v_sn74lvc2g17/ENCB, tmc5130/ENCB |
||
/motor_encoder_switch/ENCB_5V |
Default | quadrature_encoder_input_5v_sn74lvc2g17/EB |
||
/motor_encoder_switch/LIMIT_SW |
Default | limit_switch_debounced_input_vertical/LIMIT_SW, tmc5130/REFL |
||
/motor_encoder_switch/OA1 |
MOTOR_2A | tmc5130/OA1 |
||
/motor_encoder_switch/OA2 |
MOTOR_2A | tmc5130/OA2 |
||
/motor_encoder_switch/OB1 |
MOTOR_2A | tmc5130/OB1 |
||
/motor_encoder_switch/OB2 |
MOTOR_2A | tmc5130/OB2 |
||
/brake_torque_sensor/torque_bridge_0_3v3_ina821/TQ_AOUT_MON |
Default | torque_bridge_0_3v3_ina821/TQ_AOUT_MON |
Open Ports¶
| Instance | Port | Why |
|---|---|---|
brake_torque_sensor |
TQ_AOUT_MON |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO2 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO3 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO4 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO5 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO6 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO7 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO8 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO10 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO11 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO12 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO13 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO15 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO18 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO20 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
GPIO22 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO0 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO1 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO14 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO19 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO20 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO21 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO22 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO23 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO24 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO25 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO26 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO27 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO28 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
ISO29 |
no-connect flag |
rp2040_with_gpio_isolation_sn74cb3q3245 |
~{BUS_SW_EN} |
no-connect flag |
pycontrol_behavior_port_rj45_boundary_vertical |
PYC_CONN_5V |
no-connect flag |
usb2_vertical |
VBUS |
no-connect flag |
tmc5130 |
ENCN |
no-connect flag |
tmc5130 |
SWSEL |
no-connect flag |
hv_input_36V_terminal_2pos_5p08_protected_vertical |
HV_IN |
no-connect flag |
v1.0 allocation adopted 2026-09-16. The table below is now the v1.0 allocation, not the legacy 40-pin one. Eight pins changed function and one left the sheet entirely; every change is listed in The v1.0 GPIO Changes and marked in the table. The digital-50 channel pinout is in InstrumentPort-Digital-50 Pinout, which is now the only instrument-port pinout here: the 40-pin overlay section was deleted on 2026-09-17 rather than kept alongside it.
Status: v1.0 allocation adopted; schematic mid-rebuild. Blocks were removed
from the board on 2026-09-16 to be replaced with updated versions, all traces
and vias deleted, and the board-level TMC input biases moved into
motor_encoder_switch and renumbered R1104-R1107 (the range was written as -R1108; there are seven, not eight). Rev 0's reviewed,
ERC-clean state is the 2026-08-17 snapshot in git, not the working tree.
Date: 2026-09-16
Board: single-axis, RP2040, one TMC5130A
Source profile: board-interfaces/docs/instrument-port-digital.md (v1.0).
The legacy 40-pin profile is board-interfaces/docs/instrument-port-40.md; this
board no longer implements it.
This document records this board's RP2040 GPIO allocation. It covers two
scopes at once: what Rev 0 populates, and the full scope that later revisions
grow into. The InstrumentPort-Digital-50 profile itself belongs in
board-interfaces and is not redefined here.
Rev 0 Is A Strict Subset¶
Rev 0 was scaled back to get testable hardware in the researcher's hands sooner.
See docs/rev0-plan.md for what it contains and why.
The allocation below is written so that no pin moves between Rev 0 and full scope. Rev 0 populates 18 of the 24 allocated GPIOs; the other 6 are reserved, routed nowhere, and become live in later revisions without disturbing anything Rev 0 established. Firmware written against Rev 0 keeps working.
GP24 ~{INSTR_BUF_OE} became live on 2026-08-16 when the InstrumentPort moved
into Rev 0; it was already allocated and already in the bypass group. The same
day, GP14-GP16 and GP18 left the allocation entirely when the encoder and
limit switch stopped reaching the MCU, which is why the denominator dropped from
29 to 25. GP14 came back on 2026-08-17 as HV_DIAG_EN, taking the
denominator to 26. GP12 and GP17 left it on 2026-08-26 when the analog
output block was built against a part with no LDAC or CLR pin, which takes
the denominator to 24 and leaves six spares.
That property is not free, and it cost exactly one trade — see The Bus Switch Costs A Pin.
RP2040 GPIO Allocation¶
Checked against RP2040 peripheral pin muxing. UART0 is the pyControl link,
SPI0 serves the TMC5130A, SPI1 serves the torque ADC, and I2C0 serves
the two DAC blocks at 0x48 and 0x49. Chip selects are plain GPIO, not
hardware CSn — RP2040's PL022 hardware chip select does not hold CS low
across the TMC5130A's 40-bit multi-byte datagrams, and the ADS8689's
CONVST/CS both starts the conversion and frames the read, so firmware needs
direct control of its timing.
SPI1 SCK exists only on GP10, GP14 and GP26, and 14 and 26 are
spent. That single constraint is why the freed DAC-SPI pins became the torque
bus and the I2C pair moved to GP16/GP17 rather than the other way round.
The rp2040_with_gpio_isolation_sn74cb3q3245 block exposes these as two
label banks: raw GPIO0-GPIO8 and GPIO10-GPIO29, and switched ISO0-ISO8
and ISO10-ISO29. There is no GPIO9, no ISO9 and no ~{OE} port — GP9
is consumed inside the block. The ADC pins are plain GPIO26-GPIO29, not the
old GPIO26_ADC0 names.
Iso column: sw = wire the board net to the block's ISOn pin, so the
signal crosses the bus switch; byp = wire it to the raw GPIOn pin. Per
index they are the same node whenever the bus is enabled — use one or the
other, never both. The rule is the powered domain of the far end, not
convenience — see GPIO Isolation.
Dir column: direction as seen by the RP2040. out = the MCU drives it,
in = the MCU reads it. This is also the KiCad shape to give the matching
hierarchical pin on the mcu sheet — out → Output, in → Input. See
Signal Direction And Sheet Pin Types.
The allocation table itself is generated from kicad/board.yaml's nets (the
gpio and meaning of every MCU net) into
docs/generated/gpio-allocation.md by make
docs, with the class and every block or sheet port each net reaches; it
replaced the hand-written table here on 2026-10-13. The numbered notes below
are what its meanings cite, and the Iso and Dir reading above still
applies: a net whose meaning says "via the bus switch" is switched, one that
does not bypasses it, and "out" or "in" is the direction as the MCU sees it.
¹ Rev 0 lands FW_TRIG0/FW_TRIG1 on TRIG0/TRIG1 of the InstrumentPort.
They are the cheapest bring-up instrumentation on the board and the natural
trigger source for a long capture. They were also to get labelled test points;
as of 2026-08-17 no test points exist on the board — see Test Points —
Outstanding.
² ~{BUS_SW_EN} is driven only inside the MCU block. GP9 drives all four
~OE inputs plus the 7.87 kΩ pull-up inside
rp2040_with_gpio_isolation_sn74cb3q3245, so the board must never drive it —
the pull-up is the only thing defining the reset state, and a second driver
fights the MCU. A read-only port was added to the block on 2026-09-17, shape
output, so a capture can witness the isolation state on DIG27. It is a
declaration, not a connection: the netlist still shows exactly six nodes on that
net (R40006, GP9, and the four ~OE pins). Because the port is an output
on both sides of the sheet boundary, ERC reports a pin conflict if anything on
the board ever tries to drive it. The mcu sheet still needs the matching pin.
See InstrumentPort-Digital-50 Pinout.
³ See The Encoder And Limit Switch Do Not Reach The MCU.
⁴ Was V5_SENSE on divided +5V_SW until 2026-08-16. See What The Rail Sense
Is Actually For. The mcu sheet pin named
SW_RAIL_SENSE carries the raw +3.3V_SW rail into the sheet; R408/R409
(1 kΩ/1 kΩ) divide it inside mcu, and the divided node on GP26 is
SW_RAIL_SENSE_DIV_2.
⁵ Added 2026-08-17; designator settled 2026-09-16. GP14 drives the
TPS1HTC100-Q1's DIAG_EN through a 1 kΩ series RPROT that lives inside
the vertical HV input block as R502, so the board owes only the wiring.
Earlier text called it R502; that number now belongs to a USB-C CC
pull-down. The block's port is named DIAG_ENABLE, not HV_DIAG_EN — the
HV_ prefix is the board's, applied at the root. See the note on DIAG_EN
below.
⁶ Freed 2026-08-26 when the rev 1 analog output block was built. The
DAC80501 has no hardware LDAC and no hardware CLR pin at all — synchronous
update is the DAC_SYNC_EN bit plus the TRIGGER register's LDAC bit, and a
soft reset writes 0x1010 to TRIGGER. Both functions survive; they cost zero
pins instead of two. See docs/encoder-analog-output.md. No table row cites
this footnote any more — GP12 and GP17 were re-spent in v1.0 — but the
reasoning is why they were available.
⁷ New in v1.0, 2026-09-16. The analog output and brake blocks are both
I2C now, not SPI, and they share one bus: two pins instead of the three the
SPI DAC needed, and the brake block arrives for the cost of one fault input.
The freed GP10/GP11 plus GP12 became the torque ADC's SPI1, and
GP15/GP18 became its convert-start and calibration-enable. Do not carry the
old DAC_SPI_* / ~{DAC_CS} names forward anywhere.
⁸ Recorded 2026-09-16, and this is a real gap, not a note. The
pycontrol_behavior_port_rj45_boundary_vertical block exposes exactly two
signal pins — PYC_DIO_A_HOSTTX_SCL_MOSI and PYC_DIO_B_HOSTRX_SDA_MISO — and
both are spent on the UART through R301/R302. There is no third or fourth
line, and the board's only BNC is J1101 (ANGLE_OUT), so PYC_PULL_EVENT,
PYC_FAULT and PYC_RSYNC_IN have no physical destination on this board.
They stay allocated so no pin moves, and the two outputs are still worth
observing on the InstrumentPort, but PYC_RSYNC_IN has no source and gets no
channel. Either add connectors in a later revision or retire the three.
PYC_RSYNC_IN is now retired — decided 2026-09-18. Its GP23 was spent on
~{HV_FAULT}, which had to vacate an ADC pin. Of the three it was the right one
to take: it is the only one with no source and no instrument channel, while
PYC_PULL_EVENT and PYC_FAULT are outputs still worth observing. GP20 and
GP22 remain reserved for those two.
⁹ Freed 2026-09-16, and immediately re-spent on HV_LATCH. The digital-50
DUT block is default-enabled with both ~OE inputs held low and no port, so
~{INSTR_BUF_OE} no longer exists. Its pull-up circuit and firmware init are
deleted rather than ported. See
the migration plan.
¹⁰ Added 2026-09-16, and this pin was owed since 2026-09-02. The
TPS1HTC100-Q1's LATCH was strapped high through a 1 kΩ RPROT until the
bench showed that latch-off and power-up are in direct conflict on this board:
the switch trips relative thermal shutdown 1-2 ms into charging +36V_SW's
208 µF, so auto-retry is the only mechanism that can bring the rail up at
all. docs/power.md → LATCH — Tie It High For
Latch-Off recorded the fix as
"LATCH on a spare GPIO" but no pin was ever allocated here; this is that
allocation. Drive it low for the power-up ramp and high once the rail is
established — that buys retry-based soft-start and latch-off, and the
device's internal 0.7-1.3 MΩ pull-down makes auto-retry the default whenever the
MCU is unpowered or in reset, which is exactly when the rail has to be able to
charge. Do not strap it either way. The 1 kΩ RPROT is R503 inside the HV
input block, so the board owes only the wiring.
¹¹ The ADC reshuffle, 2026-09-18. Only GP26-GP29 can reach the ADC, and
~{HV_FAULT} — a digital open-drain input — was occupying GP29/ADC3. It moved
to GP23, spending the PYC_RSYNC_IN reservation (footnote 8) and freeing ADC3.
GP27/ADC1 and GP29/ADC3 are now assigned to BRAKE_ISENSE and
ANGLE_OUT_MON respectively, and both bypass the isolation switch — see
The Rule. The ~{HV_FAULT} move is
wired, and so are both monitors — verified at U601 pins 39 and 41. Levels, source impedances, the sheet pins still owed and the accuracy
limits are in The Four ADC Channels, And The v1.0 Analog
Readback.
v1.0: 29 connected (27 with a destination, 2 reserved per footnote 8), 0 spare,
1 internal (GP9). The MCU is now fully allocated — there is no spare GPIO
left. Updated twice on 2026-09-18: the line read 25 with a destination, 3
reserved and 1 spare before ~{HV_FAULT} moved onto GP23 (retiring
PYC_RSYNC_IN and freeing GP29), and the last two went to BRAKE_ISENSE and
ANGLE_OUT_MON. If more pins are
ever needed, retiring the remaining two footnote-8 signals is the cheapest
reclaim available — they have no connector, so nothing on the board changes.
Switched: 15 channels — ISO2-ISO8, ISO10-ISO13, ISO15-ISO18.
Bypass: 13 — GPIO0, GPIO1, GPIO14, GPIO19-GPIO26, GPIO28,
GPIO29. The remaining 30 block pins get no-connect flags: the 15 raw pins
whose index is switched, GPIO27, and the 14 unused ISO pins (ISO0, ISO1,
ISO14, ISO19-ISO29).
Verified against the schematic 2026-09-16. Every switched signal sits on its
index-matched ISO pin and every bypass signal on the matching raw GPIO pin,
checked at pad level through the netlist — ~{TMC_CS} on ISO2 through
TQ_CAL_EN on ISO18, and GPIO0/GPIO1/GPIO14/GPIO19/GPIO21/GPIO25/
GPIO26/GPIO28/GPIO29 on the raw side. Note that a raw GPIOn net always
shows two nodes at the RP2040 end — the MCU pad and the switch's B pin —
because the block wires all 29 channels 1:1 internally. That is the block
working as designed, not a stray connection.
Four pins were freed on 2026-08-16 and the allocation went from comfortable to
roomy. That matters for more than tidiness — see the note on rev 2 below. One of
the four, GP14, was spent again on 2026-08-17.
Two more were freed on 2026-08-26, and unlike every earlier reclaim these
cost nothing at all. GP12 and GP17 were not traded away or descoped — the
part chosen for the analog output simply does not have the pins they were
reserved for. That is the difference between this reclaim and the
TMC_REF_STIM trade below, and it is why the rev 2 arithmetic changes sign.
DIAG_EN on the input block's switch is on GP14, through R502 10 kΩ.
Reversed 2026-08-17; earlier guidance said tie it to +3.3V, not to a GPIO,
because diagnostics have no reason to be gated and tying it costs no pin. That
reasoning was right about diagnostics and wrong about the cost. Held high, the
TPS1HTC100-Q1's OFF-state open-load detection keeps an internal ~150 kΩ pull-up
from VS to VOUT permanently enabled (ROL_OFF 110-166 kΩ), injecting ~240 µA
into +36V_SW. Against that rail's ~208 µF the voltage creeps at ~1.2 V/s and
crosses the TPSM365R6's 3.6 V minimum VIN in about 3 s, so the buck starts,
collapses, and hiccups — the switched domain never cleanly powers off. That
breaks the property that HV_EN power-cycles every resettable chip, and it
corrupts SW_RAIL_SENSE. DIAG_EN has an internal pull-down, so with GP14
high-Z at reset diagnostics are off and +36V_SW sits at true zero. Per the
device's Table 7-1 the current limit and thermal shutdown are unaffected by
DIAG_EN — only reporting is gated — so firmware must raise GP14 before
reading HV_SNS or ~{HV_FAULT}. Without it neither works at all; see
docs/power.md.
The v1.0 GPIO Changes¶
Eight pins changed and one left the sheet. Nothing else moved, so firmware written against Rev 0's bypass group, TMC bus and power-monitoring group keeps working unchanged.
| Pin | Rev 0 / rev 1 | v1.0 | Why |
|---|---|---|---|
GP9 |
~{BUS_SW_EN}, board-wired |
same signal, internal to the block, with a read-only monitor port from 2026-09-17 | the combined MCU block owns the enable and its pull-up |
GP10 |
DAC_SPI_SCK |
TQ_SPI_SCK |
DACs went I2C; SPI1 SCK exists nowhere else |
GP11 |
DAC_SPI_COPI |
TQ_SPI_COPI |
same |
GP12 |
spare | TQ_SPI_CIPO |
SPI1 RX |
GP13 |
~{DAC_CS} |
~{BRAKE_FAULT} |
I2C needs no chip select |
GP15 |
spare | TQ_CONVST_CS |
plain GPIO, timing-critical |
GP16 |
spare | DAC_SDA |
I2C0 adjacent pair |
GP17 |
spare | DAC_SCL |
same |
GP18 |
spare | TQ_CAL_EN |
plain GPIO |
GP24 |
~{INSTR_BUF_OE} |
HV_LATCH |
digital-50 has no enable; the bench-proven latch pin took the slot |
Net naming: COPI/CIPO, never MOSI/MISO or SDI/SDO. Board net names and the
comments describing them use COPI/CIPO throughout. SDI/SDO/SDIN appear
in this document only where a device's own pin is meant — the TMC5130A's
SDI/SDO pins, the DAC80501's SDIN, the block ports of
torque_bridge_0_3v3_ina821 — and those are quoted as-is because renaming a
datasheet pin would be worse than the inconsistency.
That makes one mapping worth stating explicitly, because crossing it is
invisible to ERC and DRC: at the parent sheet, board net TQ_SPI_COPI wires
to the torque block's SDI port and TQ_SPI_CIPO wires to its SDO
port. Both nets stay driven and terminated either way round, exactly like the
AOUT/AOUT_MON crossing that block family already warns about — verify it on
the netlist, not by eye. The same holds at the TMC: TMC_SPI_COPI → SDI,
TMC_SPI_CIPO → SDO, which the direction table further down already records.
Two of the three analog monitors now reach the MCU — revised 2026-09-18.
ANGLE_OUT_MON and BRAKE_ISENSE are assigned to GP29/ADC3 and GP27/ADC1;
see The Four ADC
Channels. TQ_AOUT_MON
still does not and does not need to — torque arrives digitally over SPI1, so
digitising its analog monitor would add nothing, and there is no ADC channel left
anyway. None of the three goes near the digital-50 connector: it has no AIN
tail and the migration plan forbids putting slow analog into a CMOS port buffer,
so instrument access to all three is still by test point.
What changed the calculus for the other two is that neither had any readback at
all. DAC health over I2C STATUS tells you the DAC acknowledged a write, not
that the amplifier downstream of it produced a voltage; BRAKE_ISENSE had only
the digital ~{BRAKE_FAULT} bit. The ADC is far too coarse to measure either —
see the accuracy note in that section — but it distinguishes a live chain from a
dead one, which nothing else on the board did.
InstrumentPort-Digital-50 Pinout¶
This is the only instrument-port pinout for v1.0, and it is one table in
DUT-side pin order covering every contact. The 40-pin overlay that used to
follow was deleted on 2026-09-17; board-interfaces/docs/instrument-port-40.md
and the git history hold it for boards already built.
Connector: J1301, Hirose FH12-50S-0.5SVA(54),
OW-CONN-FH12-50S-0-5SVA-54 — 50 contacts, 0.5 mm pitch, vertical ZIF, 3.6 mm
closed height, straight-ended 0.30 ±0.05 mm FFC. Footprint
orb_weaver_connectors:Hirose_FH12-50S-0.5SVA_1x50-4MP_P0.5mm_Vertical.
The board never wires a connector pin. The design block
instrument_port_digital_50_dut_ffc_boundary_vertical owns J1301, the four
SN74LV541A buffers and their ~OE pull-downs. What the board wires is the
block's ports: DIG0-DIG31, all thirty-two present and every one shape
input, plus +3.3V and GND. Bind +3.3V to +3.3V_MCU, the always-on
rail — a buffer on the switched rail cannot observe the domain it is powering
down with. So the Strand column below is what you connect in the schematic,
one row per sheet pin, and Pin and Bank are reference information for cable,
probe and skew work — Bank names the SN74LV541A that carries the channel.
Read-only, and enabled by hardware with no way to disable it. Both ~OE
inputs of each package are held low inside the block by R39001-R39004, there
is no enable port, and nothing on this connector may be driven inward. Every
unused input still has to be tied, because ~OE does not gate the input
stage — see Board-Level Input Biases.
Cable orientation remains an open risk rather than a settled fact. The
mapping is correct given a reversing cable assembly, and no straight-ended FFC
has been bought or continuity-checked. Under a complete end-to-end reversal
ground still meets ground and channel order reverses (DIGn to DIG31-n); that
symmetry is a convenience, not evidence that a given cable is correct.
Tap column: MCU taps the always-on MCU net directly, ISO taps the
ISO/A side of the bus switch so the capture shows what the peripheral actually
receives, and block means a design block drives the net in its own domain. The
reasoning is in Where Each Signal Is
Tapped.
| Strand | Pin | Bank | Board net | Tap | State |
|---|---|---|---|---|---|
DIG0 |
2 | U1301 |
FW_TRIG0 |
MCU |
wired — hold on the upstream marker freeze |
DIG1 |
3 | U1301 |
FW_TRIG1 |
MCU |
wired — hold on the upstream marker freeze |
DIG2 |
5 | U1301 |
PYC_UART_TX |
MCU |
wired |
DIG3 |
6 | U1301 |
PYC_UART_RX |
MCU |
wired |
DIG4 |
8 | U1301 |
unused | — | tied to GND — PYC_PULL_EVENT retired |
DIG5 |
9 | U1301 |
unused | — | tied to GND — PYC_FAULT retired |
DIG6 |
11 | U1301 |
unused | — | tied to GND — spare |
DIG7 |
12 | U1301 |
unused | — | tied to GND — spare |
DIG8 |
14 | U1302 |
TMC_SPI_SCK |
ISO |
wired |
DIG9 |
15 | U1302 |
~{TMC_CS} |
ISO |
wired |
DIG10 |
17 | U1302 |
TMC_SPI_COPI |
ISO |
wired |
DIG11 |
18 | U1302 |
TMC_SPI_CIPO |
ISO |
wired |
DIG12 |
20 | U1302 |
TMC_DIAG0 |
ISO |
wired |
DIG13 |
21 | U1302 |
TMC_DIAG1 |
ISO |
wired |
DIG14 |
23 | U1302 |
~{TMC_DRV_EN} |
ISO |
wired |
DIG15 |
24 | U1302 |
LIMIT_SW |
block |
wired — debouncer output, never crosses the bus switch |
DIG16 |
27 | U1303 |
TQ_SPI_SCK |
ISO |
switch side wired; awaiting the torque block |
DIG17 |
28 | U1303 |
TQ_CONVST_CS |
ISO |
switch side wired; awaiting the torque block |
DIG18 |
30 | U1303 |
TQ_SPI_COPI |
ISO |
switch side wired; awaiting the torque block |
DIG19 |
31 | U1303 |
TQ_SPI_CIPO |
ISO |
switch side wired; awaiting the torque block |
DIG20 |
33 | U1303 |
TQ_CAL_EN |
ISO |
switch side wired; awaiting the torque block |
DIG21 |
34 | U1303 |
~{BRAKE_FAULT} |
ISO |
switch side wired; awaiting the brake block |
DIG22 |
36 | U1303 |
DAC_SDA |
ISO |
wired |
DIG23 |
37 | U1303 |
DAC_SCL |
ISO |
wired |
DIG24 |
39 | U1304 |
HV_EN |
MCU |
wired |
DIG25 |
40 | U1304 |
HV_DIAG_EN |
MCU |
wired |
DIG26 |
42 | U1304 |
~{HV_FAULT} |
MCU |
wired |
DIG27 |
43 | U1304 |
~{BUS_SW_EN} |
MCU |
wired |
DIG28 |
45 | U1304 |
ENCA |
block |
wired — conditioned 3.3 V output |
DIG29 |
46 | U1304 |
ENCB |
block |
wired — conditioned 3.3 V output |
DIG30 |
48 | U1304 |
PG_5V |
block |
wired — power-good witness, hv_to_5v_tpsm365r6 |
DIG31 |
49 | U1304 |
PG_12V |
block |
wired — power-good witness, hv_to_12v_tpsm365r6 |
Twenty-eight assigned, four tied to GND. DIG4 and DIG5 joined the spares
when the three phantom pyControl signals were retired — footnote 8 offered that
choice and the schematic took it. Every unused input is explicitly tied, which is
what the block requires.
The eighteen grounds are deliberately not in this table, and they need no sheet
pin. Pins 1, 4, 7, 10, 13, 16, 19, 22, 25, 26, 29, 32, 35, 38, 41, 44, 47 and
50 are wired to GND inside the design block; the board supplies ground once,
through the block's single GND port, and the buffer supply once through its
+3.3V port. One row here is one sheet pin to wire.
One thing is still owed from outside: the DIG0/DIG1 marker pair is not frozen
in board-interfaces/docs/instrument-port-digital.md,
so hold FW_TRIG0/FW_TRIG1 until it is.
Why The Channels Are Grouped The Way They Are¶
Regrouped 2026-09-18. Nine strands changed role; no signal moved between
banks. The profile lays each bank out as GND, signal, signal, so channels
arrive in pairs that share a gap with no ground between them — pins (14,15),
(17,18), (20,21) and so on. Coupling inside a pair is much higher than across a
ground, so what sits next to what is a real choice, and
board-interfaces/docs/instrument-port-digital.md
designed the pair unit for it: "Pairs suit UART TX/RX, I2C clock/data, encoder
A/B, and beacon clock/data." That same paragraph is honest about the limit —
"The two signals within a pair can still couple; nearby returns are not a
guarantee of impedance, crosstalk, or bandwidth."
Four pairs broke the rule before this change and now do not:
| Pins | Was | Now |
|---|---|---|
| 14,15 | TMC_SPI_SCK + its own TMC_SPI_COPI |
TMC_SPI_SCK + ~{TMC_CS} |
| 17,18 | TMC_SPI_CIPO + ~{TMC_CS} |
TMC_SPI_COPI + TMC_SPI_CIPO |
| 27,28 | TQ_SPI_SCK + its own TQ_SPI_COPI |
TQ_SPI_SCK + TQ_CONVST_CS |
| 30,31 | TQ_SPI_CIPO + TQ_CONVST_CS |
TQ_SPI_COPI + TQ_SPI_CIPO |
| 33,34 | TQ_CAL_EN + DAC_SDA |
TQ_CAL_EN + ~{BRAKE_FAULT} |
| 36,37 | DAC_SCL + ~{BRAKE_FAULT} |
DAC_SDA + DAC_SCL |
A clock beside its own data was the one adjacency worth fixing. Not because
it endangers the board — nothing on this connector drives anything, the port is
read-only into a high-Z analyser — but because the coupled pulse arrives exactly
at the instant that data line is sampled against that clock, so it corrupts the
measurement you would be taking. COPI beside CIPO is the better pairing:
both transition just after a clock edge, so a coupled glitch lands mid-window
where the margin is widest. Pairing SCK with a static chip-select removes the
correlation entirely.
DAC_SDA and DAC_SCL are together for a different reason, and not to reduce
noise. I2C is the least noise-sensitive traffic here — open-drain, pulled up
through 4.7 kΩ, RC-shaped edges at 100–400 kHz — so coupling between clock and
data is negligible either way. Pairing them matters because it vacates the two
slots the split occupied, which is what let DAC_SDA stop sitting beside
TQ_CAL_EN and DAC_SCL beside ~{BRAKE_FAULT}, and because a two-wire bus
that is always decoded as a unit should travel as a unit.
Magnitude, so this is not mistaken for a defect. Nothing here is measured.
With ~5 ns SN74LV541A edges and ~1.5–2 ns one-way delay through ~300 mm of
FFC, the line is electrically short, so near-end crosstalk never saturates and
the coupled amplitude scales by roughly 2·T_prop/t_r ≈ 0.7. With a ground
flanking every pair, the worst glitch is somewhere in the low hundreds of
millivolts against an analyser threshold near 1.5 V. It will not flip a
captured bit from idle. This is hygiene, done while the sheet pins were being
wired and the PCB had no traces, not a fix for an observed problem.
The bank assignment was already right and did not change. Each subsystem
sits entirely inside one SN74LV541A, so within-bus skew stays package-matched;
every one of the nine changes stayed inside its own bank. U1303 carries three
subsystems only because a five-channel bus cannot fill a bank alone.
The analyser imposes no constraint of its own. CH0-CH31 map one-to-one to
DIG0-DIG31, and nothing in instrument-control binds a signal type to a
channel index — capture takes channel indices as arguments and the beacon's
--clock/--data are explicit overrides. The "preferred SPI SCK overlay"-style
language in
board-interfaces/docs/la5032-instrument-port-40-mapping.md
belongs to the legacy 40-pin adapter; the digital-50 draft says outright that
DIG names are "not fixed assignments to SPI, UART, or particular MCU pins."
The only block-of-eight that matters is the buffer package on this board.
Name the witnesses PG_*, not after the rail — this is a netclass trap, not
a style preference. This board's netclass patterns include /+5V_* →
PWR_5V, a wildcard meant for /+5V_SW and /+5V_MCU. A net called
+5V_SW_PGOOD matches it and is silently graded as a 5 V power rail: 0.25 mm
clearance and a 0.5 mm minimum track width on a status line carrying ≤1 µA,
in the most congested copper on the board. Renamed to PG_5V on 2026-09-18,
which matches no pattern and lands in Default at 0.2 mm. PG_12V is clear for
the same reason — every 12 V pattern is either exact (+12V, /+12V, 12V,
/12V) or */-prefixed, and there is no /+12V_*. Note docs/power.md calls
the rail +12V, not +12V_SW, so +12V_SW_PGOOD would have been wrong twice.
Levels, so neither witness is re-derived. SN74LV541A inputs are 0-5.5 V
independent of V_CC and its thresholds are 0.7/0.3 x V_CC, so V_IH is
2.31 V at 3.3 V and 2.52 V at the top of the 3.0-3.6 V range. The 12 V block
divides with R18002 10 kΩ / R18003 4.7 kΩ, giving 3.84 V nominal and
3.67-4.01 V worst case — 1.5 V below the input maximum and 1.15 V above the
worst-case threshold, from a 3.2 kΩ source that is far inside the part's
100 ns/V transition limit. PG_5V is the tighter of the two: hv_to_5v
pulls up through R13001 10 kΩ with no divider, so its high level is the 5 V
rail itself, ~5.07 V worst case — 0.43 V from the 5.5 V maximum — at ~67 ns/V
against that 100 ns/V limit. Both legal; suspect PG_5V first if a witness
ever misreads.
DIG31 is still tied to GND, deliberately. It is the intended home for the
12 V power-good witness, and it stays a ground tie until
hv_to_12v_tpsm365r6 is placed, because wiring an input sheet pin to a net
with no driver would put an ERC error on the board until then. When that block
lands, this is one edit: swap the GND label at (129.54, 139.7) in
instrument_port.kicad_sch for a hierarchical label naming the 12 V
power-good net, and add the matching sheet pin on the root. DIG30 is the
worked example — and U1304 is the right bank for both, because the edges you
are timing are timed against HV_EN, which is package-matched here.
No channel on this port needs a bias resistor of its own. The always-on taps
are driven whenever the board is powered; the switched taps are defined by the
resistors in Board-Level Input Biases, which is why
the switched-side I2C pull-ups must reference +3.3V_SW; and LIMIT_SW,
ENC_A and ENC_B are defined by pull-downs inside their own blocks.
Board-Level Input Biases¶
Read with
docs/instrument-port-tap-resistors.mdfrom 2026-09-19. Every bias below stays exactly where it is, on the functional side of the new tap resistors. Each tap then inherits its functional net's defined level through the resistor, so no_INSTnet needs a pull of its own — but the "every net reaching anSN74LV541Ainput has a DC-defining resistor" sweep has to be re-run across the split nets.
Renumbered and rehomed 2026-09-16. All eight TMC input biases now live in
motor_encoder_switch, next to each other, because what they actually do is
keep the TMC5130A's inputs defined while the bus switch is open — the instrument
taps were always a secondary beneficiary. They were R1104-R1601 in
instrument_port; that sheet now holds none of them. Note that R1104 is a
reused designator: it previously named the REFR_DIR pull-down that was
deleted in favour of a hard GND tie, so older text describing R1104 is about a
different part.
| Designator | Net | Termination |
|---|---|---|
R1101 |
TMC_DIAG0 |
10 kΩ up to +3.3V_SW |
R1102 |
TMC_DIAG1 |
10 kΩ up to +3.3V_SW |
R1103 |
~{TMC_DRV_EN} |
10 kΩ up to +3.3V_SW |
R1104 |
TMC_SPI_SCK |
10 kΩ down |
R1105 |
TMC_SPI_COPI |
10 kΩ down |
R1106 |
TMC_SPI_CIPO |
10 kΩ down |
R1107 |
~{TMC_CS} |
10 kΩ up to +3.3V_SW — load-bearing |
R1601 |
LIMIT_SW |
100 kΩ down — inside the limit-switch block, correctly: it defines that block's own output |
Nine more are owed by the new blocks, and none of them may live inside a block:
a twin-axis board placing the same block twice would halve every pull, which is
the same argument that keeps SCL/SDA termination out of the DAC blocks.
| Net | Termination | Why |
|---|---|---|
DAC_SDA, DAC_SCL (MCU side) |
4.7 kΩ up to +3.3V_MCU |
the bus switch is open by default, so the MCU side floats otherwise |
DAC_SDA, DAC_SCL (ISO side) |
4.7 kΩ up to +3.3V_SW |
a switched-domain pull never references the always-on rail |
TQ_SPI_SCK, TQ_SPI_COPI, TQ_SPI_CIPO |
10 kΩ down | the block refuses to terminate; also defines the tap when the ADC is dark |
TQ_CONVST_CS |
10 kΩ up to +3.3V_SW |
must idle high — load-bearing, same as ~{DAC_CS} was |
TQ_CAL_EN |
10 kΩ down | calibration must be off, not floating |
All fitted as of 2026-09-18, and three more besides. As built, verified from the netlist:
| Net | Termination | As built | Sheet |
|---|---|---|---|
DAC_SCL_BYP, DAC_SDA_BYP |
4.7 kΩ up to +3.3V_MCU |
R402, R403 |
/mcu/ |
DAC_SCL, DAC_SDA |
4.7 kΩ up to +3.3V_SW |
R406, R407 |
/mcu/ |
TQ_SPI_SCK, TQ_SPI_COPI |
10 kΩ down | R902, R903 |
/brake_torque_sensor/ |
TQ_SPI_CIPO |
10 kΩ down | R2012 |
torque block — correct, see the rule |
TQ_CONVST_CS |
10 kΩ up to +3.3V_SW |
R904 |
/brake_torque_sensor/ |
TQ_CAL_EN |
10 kΩ down | R905 |
/brake_torque_sensor/ |
~{BRAKE_FAULT} |
10 kΩ down | R901 |
/brake_torque_sensor/ |
FW_TRIG0, FW_TRIG1 |
10 kΩ down | R404, R405 |
/mcu/ |
The last three are beyond the original nine. ~{BRAKE_FAULT} belongs to the same
class and was simply missing from the list; the FW_TRIG pair closes the final
floating-input window, the ~143 ms between reset and firmware driving the
markers. Every net reaching an SN74LV541A input now has a DC-defining
resistor — verified by sweeping all 28 of them.
Which sheet a pull belongs on¶
The rule above — "none of them may live inside a block" — reads as though it
contradicts the statement further up that "LIMIT_SW, ENC_A and ENC_B are
defined by pull-downs inside their own blocks." Both are right. The test is not
which sheet, it is who drives the net:
A pull belongs inside a block when it defines that block's own output or an internal node. It belongs at board level when it biases a net the board drives, or shares between blocks.
The reason is placement-count, not electricity: a reusable block instantiated twice onto one shared bus parallels its internal pulls and halves them. A net the block alone owns cannot be doubled that way, so its pull is safe inside.
Board sheets are board level. mcu, motor_encoder_switch and
brake_torque_sensor are board-owned wrapper sheets, not design blocks — they
exist exactly once, so a termination on any of them satisfies the rule. Choosing
between them is organisational, and grouping a pull with the subsystem it serves
is preferred: it keeps select-by-sheet useful during placement, and these parts
want to sit near the net they define rather than clustered at the MCU.
Every placement on this board follows the rule. Inside their blocks, correctly:
R1505/R1506 (ENCA/ENCB), R1601 (LIMIT_SW), R1701 (PG_5V),
R1902/R1903 (PG_12V) and R2012 (TQ_SPI_CIPO) all define their own
block's output; R1301-R1304 on the buffer ~OE pins, R2011 on the ADC's
~{RST} and R606 on ~{BUS_SW_EN} are internal nodes — R606 included,
because the RP2040 that drives it lives in that same block.
Checking clearance while it is ignored¶
rule_severities.clearance is ignore on this project, so DRC cannot report a
clearance violation. make clearance-check restores it on a throwaway copy
and diffs the result against kicad/clearance-baseline.json; the real
.kicad_pro is never modified. make clearance-baseline re-records the
baseline. Run the baseline before routing and the check after — it exists
because Freerouting's characteristic failure is exactly the class of violation
this board is blind to.
Baseline recorded 2026-09-18, pre-autoroute: 499 clearance findings, 156
unconnected items, of which 10 net pairs are voltage-bearing — including
GND ↔ HV_IN at 0.2331 mm against 0.5 mm required, and +36V_SW ↔ PG_5V at
0.2919 mm against 0.4 mm. Those are placement, not routing, and an autorouter
will not fix them.
The check gates only on what is reproducible, and that was measured rather
than assumed. Three consecutive runs on identical copper gave 499 findings
every time but attributed them across 149, 151 and 148 net pairs, with 10 of
~270 positions moving: KiCad's DRC picks a different counterpart item where nets
crowd. Stable across runs, and therefore what fails the check: the total count,
the voltage-bearing subset, the unconnected count, and the non-clearance
violation tallies. The per-pair breakdown is printed for orientation only.
--all-track-errors is passed for the same reason — without it KiCad reports
one error per track and the choice varies.
Corrected 2026-09-18: TQ_CAL_EN and TQ_CONVST_CS were pulled from inside
the torque block, which was wrong — both are MCU-driven inputs. They are now
R905 and R904 on /brake_torque_sensor/. Removing them cascade-renumbered
the whole 20xx band and shifted R901-R903; the electrical topology was
confirmed unchanged by comparing every net-pair and value before and after.
4.7 kΩ, not the 2.2 kΩ the analog block's note suggests — that note is right
for one segment and this board has two in parallel the moment the bus switch
closes. Use OW-RES-4K7-0402, four of them; the catalog entry is already
annotated for exactly this.
The arithmetic, with measured part capacitances rather than a guess. Switched
segment: two DAC80501 at 10 pF max per pin (DACx0501 datasheet), the
SN74LV541A tap at 2 pF, the SN74CB3Q3245 channel at 11 pF max Cio(ON),
plus ~12 pF of trace — about 45 pF. MCU segment: an RP2040 pad and a short
run, about 15 pF. Connected, call it 70 pF with margin.
| Pull-ups per side | Effective when connected | t_r = 0.8473·R·C at 70 pF | Sink to hold 0.4 V |
|---|---|---|---|
| 2.2 kΩ | 1.1 kΩ | 65 ns | 2.64 mA — 88% of the 3 mA floor |
| 4.7 kΩ | 2.35 kΩ | 139 ns | 1.23 mA |
| 10 kΩ | 5.0 kΩ | 297 ns — at the limit | 0.58 mA |
Fast mode allows 300 ns of rise and the I²C-bus specification requires a device
to sink 3 mA at V_OL ≤ 0.4 V; the DACx0501 datasheet specifies no V_OL at
all, it only requires an external pull-up, so that 3 mA is the floor. 4.7 kΩ
clears both with room at 400 kHz, which is the design target — the analog
block's 987 Hz reconstruction filter caps the useful update rate near 2 kHz, so
fast-mode-plus buys nothing here. If it were ever wanted, 3.3 kΩ per side gives
98 ns and 1.76 mA, at the cost of a new internal part.
A third reason to stay at 4.7 kΩ rather than going lower: if firmware ever
closes the bus switch with +3.3V_SW down, the MCU-side pull-ups feed the dead
DACs' input clamps. 4.7 kΩ bounds that to ~0.6 mA per line instead of handing it
an unlimited source. It does not make the sequencing error safe — it makes it
survivable.
Neither pair is optional. The MCU-side pair is what defines GPIO16/GPIO17
while the bus is open; the RP2040's internal 50-80 kΩ pull-ups are a
firmware-dependent second layer, not a substitute. The switched-side pair must
reference +3.3V_SW so both lines sit at a true 0 V when that rail is down —
which is simultaneously what gives the always-on DIG21/DIG22 taps a defined
low, and why those two channels need no pull-downs of their own.
Before adding a ~{BRAKE_FAULT} pull-up, check the brake block's netlist —
R36001 or R36017 may already be it, and a second one in parallel halves it.
The Encoder And Limit Switch Do Not Reach The MCU¶
Decided 2026-08-16. ENC_A, ENC_B, and LIMIT_SW are the TMC5130A's
business. The encoder goes from J1103 through the board's conditioning chain to
ENCA/ENCB; the debounced limit switch goes to REFL. Neither reaches an
RP2040 pin, in any revision. Firmware gets position from the driver's
X_ENC/XACTUAL register and homing state from the driver's status, both over
SPI.
There is no ENC_N net on the board. Earlier drafts of this section listed
one alongside ENC_A/ENC_B; as built (2026-08-17) J1103 pin 2 is a reserved
index no-connect and the TMC5130A's ENCN pin is terminated by R1201 10 kΩ
to GND, which is what the datasheet asks for on an unused encoder input. The
index is a rev-1 decision, not a Rev 0 signal.
This frees GP14, GP15, GP16, and GP18. GP14 was spent again on
2026-08-17 on HV_DIAG_EN.
What it deletes, permanently rather than deferring:
- The RP2040 PIO encoder cross-check. It is not "rev 1" any more, it is gone.
ENCODER_MISMATCHindocs/uart-protocol.md. There is no second count to disagree with and there never will be, so the fault code should be retired rather than left reserved.- The
GP14/GP15/GP16contiguity constraint. It existed only to let one PIO state machine read A, B, and the index with a single input mapping. Those three pins are now ordinary spares with no adjacency requirement — which is precisely what madeGP14available forHV_DIAG_ENon 2026-08-17. - The MCU's independent copy of the limit switch. Firmware learns a homing
event from the driver, one SPI poll later than the hardware
REFLlatch — which is the same latency the design already accepted, sinceREFLwas always the hardware path andGP18was always just a witness.
What replaces the witness: the InstrumentPort. ENC_A, ENC_B, and
LIMIT_SW are all on it in Rev 0, which is now the only way to see those
signals independently of the driver's own report. That is a stronger reason for
them to be on the port than existed when the MCU also had copies.
Settled 2026-09-16 and it no longer "fits with room". What was rev-2 planning is now the v1.0 allocation above: brake and torque cost eight pins between them, not six —
SDA,SCL,~{BRAKE_FAULT}, three forSPI1,TQ_CONVST_CSandTQ_CAL_EN— andHV_LATCHtook the last spare after that. One pin is left,GP27, and it is ADC-capable. The paragraphs below are the arithmetic that got us here and every one of their premises has since changed: the brake is I2C with no chip select, so~{BRAKE_CS}does not exist;~{BRAKE_FAULT}is not optional; the current monitor stays off the MCU entirely; and the torque bus needs five pins, not two. Read them as history.
Rev 2 fits on RP2040 with room, as of 2026-08-26. Full scope is 24 of 30
with six spares, and the brake plus torque front end for a single axis needs
about six GPIOs — BRAKE_DIM, ~{BRAKE_FAULT}, a brake current monitor on ADC,
two for the torque bus, and TQ_DRDY. That is six wanted against six spare
even keeping TQ_DRDY, with GP27 ADC-capable for the current monitor. Drop
TQ_DRDY, which the bus capture already implies, and there is a pin left over.
Got easier 2026-08-31. The settled brake driver needs one new GPIO, not
two or three: ~{BRAKE_CS} for its DAC, sharing SCK and SDI with the angle
DAC — both are write-only 3-wire devices, so bus sharing carries no contention
risk. ~{BRAKE_FAULT} is optional and only exists if the SN74LVC2G17 fault
buffer is populated; BRAKE_ENABLE is a stuffing option and largely redundant
with HV_EN. So the brake side is 1 GPIO plus 1 ADC, against the 3 GPIOs plus
1 ADC this paragraph budgeted. That leaves more slack for the torque bus, which is
where it is actually wanted.
This reversed twice. Until GP14 became HV_DIAG_EN on 2026-08-17 it was
five for five with nothing to reclaim; that day it became five wanted against
four spare, one pin short of free, and the fix was to spend reclaim-order item 1.
On 2026-08-26 the analog output block landed on a part with no LDAC or CLR
pin and returned GP12 and GP17 for nothing, which closes the gap outright
rather than by trading a function away. Reclaim-order item 1 is now void —
see below.
The twin-axis board needs RP2354B because it carries two of everything; this board may not. Do not treat that as settled — it is an observation to check when the rev 2 circuits are actually specified, not a commitment. It is a stronger observation than it was, but the rev 2 circuits are still unspecified.
What The Rail Sense Is Actually For¶
GP26 senses +3.3V_SW through a ÷2 divider as of 2026-08-16, replacing a
divided +5V_SW sense. Same two resistors, better measurement — sensing the end
of the chain confirms 36 V, 5 V, and 3.3 V in one reading, and +3.3V_SW is the
rail that actually gates the decision, because it is what powers the far side of
the bus switch.
Where the divider physically sits, as built 2026-08-17. The mcu sheet pin
called SW_RAIL_SENSE carries the raw +3.3V_SW rail across the sheet
boundary; R408/R409 (1 kΩ/1 kΩ) divide it inside mcu, and the ADC pin sees
SW_RAIL_SENSE_DIV_2. Two consequences worth holding on to. The mcu sheet pin
is therefore a rail tap, not a signal, so do not expect a 1.65 V node at the sheet
boundary. And R408/R409 are also what holds +3.3V_SW at 0 V when the
switched domain is off — a 2 kΩ bleed to GND — which is the property the
board-level pull-ups to +3.3V_SW depend on. Removing the divider would leave
~{TMC_CS}, both DIAG lines, and ~{TMC_DRV_EN} undefined in the off state.
Why not delete it, given the TMC answers SPI when the rails are up? Because of
a circularity. docs/power.md makes the rail sense one of three supporting
measures for the isolation architecture: reconnect only after the rails are
confirmed up. SPI reaches the TMC5130A through the bus switch you are deciding
whether to enable, so it cannot confirm anything before that decision. Enabling
the bus into an unpowered driver is precisely the back-power failure the whole
architecture exists to prevent. The sense must bypass the bus switch, and GP26
does.
It is substantially redundant with HV_SNS, though, and that is worth knowing
if the pin is ever wanted elsewhere. GP28 also bypasses the bus switch, and the
buck, the LDO, and the driver draw quiescent current whenever the rail is really
up, so a near-zero HV_SNS after raising HV_EN already means "the rail did not
come up." Gating on HV_SNS plus a timeout would be defensible.
~{HV_FAULT} does not cover this, and it is worth being explicit about why:
with no 36 V present the TPS1HTC100-Q1 is itself unpowered, so its open-drain
fault output floats and the pull-up reads it as no fault. The most likely
failure on the bench — nobody plugged the supply in — is invisible to ~{HV_FAULT}
and obvious to either SW_RAIL_SENSE or HV_SNS.
Firmware rule: after raising HV_EN, confirm SW_RAIL_SENSE_DIV_2 reads a
valid +3.3V_SW before deasserting ~{BUS_SW_EN}. Refuse ARM with a specific
reason when it does not, and report the reading in STATUS.
Signal Direction And Sheet Pin Types¶
A hierarchical pin's direction is stated from the point of view of the sheet
that owns it. Output means the signal leaves this sheet; Input means it
enters. The same net is Output on the sheet that drives it and Input on every
sheet that reads it. Nothing about the direction is global — TMC_SPI_SCK is an
Output on mcu and an Input on the tmc5130 sheet, and both are correct.
DIO-A Is This Board's RX. DIO-B Is This Board's TX.¶
This is the one crossover on the board that reliably gets wired backwards, and the trap is that the alphabetical order reverses:
RJ-45 pin 1 DIO-A host TX ──▶ PYC_DIO_A ──▶ PYC_UART_RX ──▶ GP1 (UART0 RX)
RJ-45 pin 4 DIO-B host RX ◀── PYC_DIO_B ◀── PYC_UART_TX ◀── GP0 (UART0 TX)
A → RX, B → TX. Both names are right; they are named from different ends.
The pyControl block names its pins by connector position on purpose, so a
board cannot mirror them by accident — that is exactly what the block's own
description warns about. This board names its nets by MCU function. The
crossover happens once, at the mcu sheet boundary, and nowhere else.
Sanity check that needs no documentation: PYC_UART_TX must be an Output on
mcu. If a sheet pin named *_TX is an Input, it is wrong.
mcu Sheet Pins¶
Designator warning, reconciled 2026-09-18. The 4xx band shifted when the
FW_TRIG pull-downs were inserted, and some of this drift predates that. The
netlist is authoritative; this is the as-built map:
| As built | Value | Function | Docs used to call it |
|---|---|---|---|
R401 |
10 kΩ | PYC_UART_RX pull-up to +3.3V_MCU |
R403 |
R402, R403 |
4.7 kΩ | MCU-side I2C pull-ups to +3.3V_MCU |
unchanged |
R404, R405 |
10 kΩ | FW_TRIG0/FW_TRIG1 pull-downs |
new |
R406, R407 |
4.7 kΩ | switched-side I2C pull-ups to +3.3V_SW |
R404/R405 |
R408, R409 |
1 kΩ | SW_RAIL_SENSE ÷2 divider |
R401/R402 |
This file has been updated throughout. docs/power.md,
docs/validation-plan.md, docs/design-block-map.md,
docs/instrument-strategy.md and docs/rev0-plan.md still use the old names
and need the same pass. docs/bringup-log.md must be left alone — it records
measurements taken on boards where the old designators were real.
Everything crossing the mcu sheet boundary in Rev 0. The Far side column is
what the mating block already declares, so a mismatch here is a wiring error.
mcu pin |
Type | Mates with | Far side declares |
|---|---|---|---|
PYC_UART_TX |
Output | pycontrol_behavior_port_rj45_boundary PYC_DIO_B |
passive |
PYC_UART_RX |
Input | pycontrol_behavior_port_rj45_boundary PYC_DIO_A |
passive |
~{TMC_CS} |
Output | tmc5130 ~{CS} |
input |
~{TMC_DRV_EN} |
Output | tmc5130 ~{DRV_EN} |
input |
TMC_SPI_SCK |
Output | tmc5130 SCK |
input |
TMC_SPI_COPI |
Output | tmc5130 SDI |
input |
TMC_SPI_CIPO |
Input | tmc5130 SDO |
output |
TMC_DIAG0 |
Input | tmc5130 SWN_DIAG0 |
bidirectional |
TMC_DIAG1 |
Input | tmc5130 SWP_DIAG1 |
bidirectional |
HV_EN |
Output | hv_input_36V_terminal_2pos_5p08_protected ENABLE |
input |
HV_SNS |
Input | hv_input_36V_terminal_2pos_5p08_protected SNS |
output |
~{HV_FAULT} |
Input | hv_input_36V_terminal_2pos_5p08_protected ~{FAULT} |
output |
SW_RAIL_SENSE |
Input | the raw +3.3V_SW rail; R408/R409 divide it inside mcu |
passive |
FW_TRIG0 |
Output | buffer U1801 — no test pad exists, see below |
input |
FW_TRIG1 |
Output | buffer U1801 — no test pad exists, see below |
input |
~{INSTR_BUF_OE} |
Output | ~{OE} on all three buffer instances |
input |
USB_D+ |
Bidirectional | usb2 USB_D+ |
bidirectional |
USB_D- |
Bidirectional | usb2 USB_D- |
bidirectional |
+5V_MCU |
Passive | the ORed USB / pyControl 5 V node | passive |
+3.3V_MCU |
Passive | GP1 pull-up, buffers, and the input block's +3.3V_MCU |
passive |
HV_DIAG_EN |
Output | input block DIAG_ENABLE; GP14 through R502 10 kΩ |
input |
GND |
Passive | board ground | passive |
BRAKE_ISENSE |
Input | brake_current_sink_0_49ma_dac80501 BRAKE_ISENSE; GP27 |
passive |
ANGLE_OUT_MON |
Input | analog_output_0_3v3_dac80501 ANGLE_OUT_MON; GP29 |
passive |
Twenty-two pins in Rev 0 — ten Output, seven Input, two Bidirectional, three
Passive. (Corrected 2026-08-17; the sentence used to say twenty pins and six
Input against twenty-one rows, and HV_DIAG_EN was added the same day.) Verified
directly against mouse-joystick-pcb.kicad_sch: the mcu sheet carries 22 pins,
and the far side is named DIAG_ENABLE, not DIAG_EN, on
hv_input_36V_terminal_2pos_5p08_protected. Note there is no LIMIT_SW and no
encoder pin on this sheet; those signals never reach the MCU.
Reserved signals get no pin until their far end exists. Corrected 2026-08-17:
they are not pre-wired inside mcu either. The earlier text said their A-side
channels are wired and stop at the bus switch; as built the unused bus-switch
channels have their A pins open and their B (MCU-side) pins tied to GND, so
rev 1 has to edit the isolation block regardless — see The Block Is Oversized For
This Board. When they arrive:
DAC_SPI_SCK, DAC_SPI_COPI, ~{DAC_CS}, PYC_PULL_EVENT, and PYC_FAULT
are Output; PYC_RSYNC_IN is Input. (Updated 2026-08-26:
~{DAC_LDAC} and ~{DAC_CLR} are gone from this list — the part has neither
pin.)
Rev 1 also adds three pins that are not GPIOs and are easy to miss when
counting: the analog output block needs +5V_SW and GND, and its AOUT
leaves as an Output on whatever sheet holds it. AOUT does not cross the
mcu boundary at all — it goes from the block to the BNC (J1101).
The Bus Switch Does Not Change Direction¶
Seven of the Rev 0 pins above — the sw group, GP2-GP8 — leave
mcu from the A side of the isolation bus switch, whose A and B pins the
block correctly declares passive, because a FET pass gate is passive silicon.
That means the A-side net inside mcu has no driver of its own, and the sheet
pin is what tells KiCad the net is driven. Give it the MCU's direction anyway:
the switch passes the signal, it does not reverse it.
Corrected 2026-08-17. This paragraph used to say the pins leave from the B side. As built the orientation is the other way round — A is the TMC / switched side and B is the MCU side — so it is the A-side nets that cross the sheet boundary. Nothing about the direction argument changes; the part is a symmetric FET pass gate.
Do not reach for Tri-state to express the isolated state. It is closer to
literally true, but KiCad has no shape meaning "sometimes disconnected", it adds
no ERC value, and it would make the sw and byp groups look different for a
reason that is about the switch rather than about the signal.
Every Net Wants Exactly One Driver¶
Output and Bidirectional drive; Input and Passive do not. Three families
on this board were flagged as having no on-board driver at all, because the
source is off-board or a passive network, and KiCad's "input not driven" check
says so. Two of the three are settled as of 2026-08-17; ERC now reports zero
violations at every severity.
| Net | Why it has no driver | What to do |
|---|---|---|
PYC_UART_RX |
Driven by the pyControl host through an all-passive block boundary | Done 2026-08-17 — PYC_DIO_A/PYC_DIO_B are now bidirectional |
ENC_A/ENC_B |
Driven on-board by U801's Schmitt outputs as of 2026-08-17 |
No longer applies. And there is no ENC_N net at all — see below |
SW_RAIL_SENSE_DIV_2 |
A ÷2 divider off +3.3V_SW is a genuinely passive net |
Accept. HV_SNS is fine — the input block declares SNS as output |
The decision was to change the source pin types rather than exclude the ERC item,
and it is recorded here. Do not lower the rule's severity board-wide — it is the
check that catches a *_TX pin wired as an Input.
kicad-libs change — done 2026-08-17. PYC_DIO_A and PYC_DIO_B on
pycontrol_behavior_port_rj45_boundary are now bidirectional in both the
library block and this board's placed copy. The reasoning is kept below because
it is the precedent for the next connector boundary that needs it. The
reasoning for leaving them undirected is right — those lines genuinely could go
either way until a board assigns them — but bidirectional is the KiCad shape
that means that, whereas passive means "no active device here", which is what
a resistor or a shield tab is. It also matches house precedent: usb2 declares
USB_D+/USB_D- bidirectional and instrument_port_40_dut_ffc_boundary
declares all eighteen DIG*/TRIG* bidirectional. The pyControl block is the
only connector boundary in the library that is all-passive. Two shape edits, no
topology change, no PCB impact.
The Bus Switch Costs A Pin¶
Rev 0 adds the rp2040_gpio_isolation_sn74cb3q3245 block, whose shared
active-low enable needs one GPIO. The allocation was at 29 of 30 with a single
spare when this was decided on 2026-08-13, so the enable had to come from
somewhere. The 2026-08-16 encoder and limit-switch cut has since freed four more
pins, which makes the trade below look cheap in hindsight — it was not cheap at
the time, and TMC_REF_STIM is not coming back regardless.
It is paid for by permanently dropping TMC_REF_STIM, the synthetic homing
stimulus that used to sit on GP9. That was already item 2 in the reclaim order
below, and it is the right one to spend: the limit switch now reaches REFL
through a real debouncer on its own terminal block, so homing is exercised by
closing the actual switch rather than by a GPIO impersonating one. Leave a test
pad on the REFL net so a jumper can still force a closure — still outstanding
as of 2026-08-17; no test pads exist anywhere on the board.
Net effect: the trade was one-for-one. Full scope is now 24 of 30 with six spares, and that headroom arrived by two later routes: four pins on 2026-08-16 from the encoder and limit-switch cut, and two more on 2026-08-26 from the analog output part.
Reclaim Order If More Pins Are Needed¶
Item 2 of the previous list has been spent on ~{BUS_SW_EN}. Item 1 became
void on 2026-08-26. What remains:
- ~~Tie
~{DAC_CLR}high in hardware, freeingGP17.~~ Void. TheDAC80501has noCLRpin, soGP17is already spare and there is no software clear to give up — the function moved into theTRIGGERregister.GP12came back the same way. This is the only entry ever removed from this list without being spent. - Drop
TMC_DIAG1, freeingGP8.DIAG0alone, configured to report what matters. RouteDIAG1to a test point.
Neither is needed today, and the list is now one item long. Corrected
2026-09-18 against the exported netlist: there are four spares, not six, and they
were GP20, GP22, GP27 and GP29 — and as of the same day GP27 and
GP29 went to BRAKE_ISENSE and ANGLE_OUT_MON, so only the two reserved
pyControl pins are left and there is no true spare. The sentence here used to name GP12,
GP15, GP16, GP17, GP18 and GP27; v1.0 spent five of those — GP10-GP12
on the torque SPI1, GP15 on TQ_CONVST_CS, GP18 on TQ_CAL_EN, GP13 on
~{BRAKE_FAULT}, and GP16/GP17 on the shared DAC I2C pair. Spend a spare
before spending a function, but count them from the netlist, not from this
paragraph's history.
Reading spare-ness off the MCU-side net name does not work, and this is the
trap. The isolation block names the MCU half of every channel GPIOn and the
peripheral half ISOn, and a board assigns the peripheral half — so GPIO4
looks unassigned while its A side is TMC_SPI_CIPO. A channel is spare only
when both halves still carry the generic names. Measured, channel by channel:
| MCU-side net | A (peripheral) side | Status |
|---|---|---|
GPIO2-GPIO8 |
~{TMC_CS}, ~{TMC_DRV_EN}, TMC_SPI_CIPO, TMC_DIAG0, TMC_SPI_SCK, TMC_SPI_COPI, TMC_DIAG1 |
assigned |
GPIO10-GPIO13, GPIO15, GPIO18 |
TQ_SPI_SCK, TQ_SPI_COPI, TQ_SPI_CIPO, ~{BRAKE_FAULT}, TQ_CONVST_CS, TQ_CAL_EN |
assigned |
GPIO20, GPIO22, GPIO27, GPIO29 |
ISO20, ISO22, ISO27, ISO29 |
spare |
The two that remain are electrically free but doctrinally reserved. GP20
and GP22 are held for PYC_PULL_EVENT and PYC_FAULT (footnote 8); the
netlist cannot see a paper reservation, so do not treat a netlist sweep as the
whole answer. Taking either one retires a pyControl signal, exactly as GP23
retired PYC_RSYNC_IN.
Notes:
GP23,GP24, andGP25are free on the bare RP2040 QFN-56. They are reserved on Raspberry Pi Pico modules but not on a custom board.tmc51x0-driver-dev-pcbalready usesGP23this way, and since 2026-09-18 so does this board —GP23carries~{HV_FAULT}.GP15/GP16no longer need to be contiguous withGP14. That constraint existed only for a single PIO input mapping, and the PIO cross-check is gone. They are ordinary spares — and because the constraint went away,GP14was free to takeHV_DIAG_ENon 2026-08-17.- The encoder reaches the TMC5130A only, in every revision. It does not go
straight from the connector to the driver, contrary to what this note used to
say. As built (2026-08-17) the path is
J1103→R801/R802100 kΩ harness-side pull-downs →R803/R8044.7 kΩ series →C802/C803470 pF →U801SN74LVC2G17dual Schmitt on+3.3V_SW→R805/R806100 kΩ output pull-downs →ENC_A/ENC_B→ENCA/ENCB. See The Encoder And Limit Switch Do Not Reach The MCU and Where Each Signal Is Tapped. - The limit switch reaches the TMC5130A
REFLpin through the debouncer, and goes nowhere else on the MCU.REFLis the hardware-latched homing path; firmware reads homing state from the driver over SPI. GP19drives thehv_input_36V_terminal_2pos_5p08_protectedblock'sENABLEinput. That block pullsENABLElow, so the 36 V rail is off until firmware drives it — and so the board's power-on state is the idle state, with the MCU up on USB or pyControl and everything switched dark. Firmware cyclingGP19is also the board's chip-reset mechanism; seedocs/power.md.GP28reads the TPS1HTC100-Q1SNSoutput. Done 2026-08-17: the block'sR_SNSisR509= 249 Ω —R509before the vertical block was re-placed (OW-PASS-CRCW0402249RFKED, stocked), down from the 1 kΩ the block shipped with — the pin signals faults by sourcing 5.2-6.4 mA intoR_SNS, which at 1 kΩ lands at 3.3-4.4 V, above the RP2040'sVDD + 0.3 Vlimit. At 249 Ω the fault level is 1.29-1.59 V and current reads 0.311 V/A. No divider needed. The safe upper bound is about 594 Ω, so ~470 Ω is available if ADC resolution ever matters. Seedocs/power.md.GP23reads the switch's~FAULTopen-drain output — moved fromGP29on 2026-09-18 to free ADC3; see The Four ADC Channels below: overload, short-circuit, and thermal shutdown. Needs an external pull-up to+3.3V; fitted 2026-08-17 asR50710 kΩ to+3.3V_MCU—R507until the vertical block was re-placed. The design block leaves this pin unconnected; this board routes it because it has the pin and because the motor rail can shut itself off. Note it reads nothing useful untilGP14raisesDIAG_EN.GP26senses+3.3V_SWthrough a divider — corrected 2026-08-17; this note still said+5V_SW, which the 2026-08-16 change had already superseded. That rail is dead wheneverHV_ENis low or the 36 V supply is absent, which is the board's normal idle state, so this is the MCU's primary evidence that the switched domain is actually up. It gates step 3 of the sequencing rule above.+5V_SWis still required in Rev 0 — the TMC5130A'sVCCminimum is 4.6 V — even though the analog output that also needs it is deferred to rev 1. Updated 2026-08-26: when it arrives, itsOPA197needs 4.5 V minimum, so+5V_SWacquires a second independent reason to be a real regulated rail rather than the ORed MCU one. Seedocs/power.md.GP1needs an external 10 kΩ pull-up to+3.3V_MCU; fitted 2026-08-17 asR401. SeeGP1Gets A Hardware Pull-Up below. This is a board-level part on the MCU side of the port block's series resistor, not part ofpycontrol_behavior_port_rj45_boundary.
The Four ADC Channels, And The v1.0 Analog Readback¶
Status: COMPLETE as of 2026-09-18. Verified from the exported netlist —
~{HV_FAULT} is on U601 pin 35 (GP23) through U605 B8; BRAKE_ISENSE is a
4-node net reaching U601 pin 39 (GP27/ADC1); ANGLE_OUT_MON is a 3-node net
reaching U601 pin 41 (GP29/ADC3). Both monitors bypass the switch, with only
the U606 B-side stub on the node, exactly as HV_SNS does.
Only GPIO26-GPIO29 can reach the ADC, so there are exactly four channels and
no more. As built, one of them is spent on a digital signal:
| Channel | Assigned to | Drawn? | Signal | Iso |
|---|---|---|---|---|
GP26 / ADC0 |
SW_RAIL_SENSE_DIV_2 |
yes | +3.3V_SW through R408/R409 |
byp |
GP27 / ADC1 |
BRAKE_ISENSE |
yes | brake current-sink readback | byp |
GP28 / ADC2 |
HV_SNS |
yes | TPS1HTC100-Q1 SNS across R509 249 Ω |
byp |
GP29 / ADC3 |
ANGLE_OUT_MON |
yes | analog output readback | byp |
~{HV_FAULT} moved to GP23, pin 35 — done¶
~{HV_FAULT} is an open-drain digital input that was sitting on the last free
ADC pin, so it had to move before ANGLE_OUT_MON could land. It is now on the
isolation block's GPIO23 port instead of GPIO29; nothing else about the net
changed. It spent the PYC_RSYNC_IN reservation — see footnote 8, which
nominates that signal as the expendable one of the three. Why GP23:
- Pin 35 is on the same side of the QFN-56 as pin 41 (pins 29-42 are one
side), so the move does not cross the package.
GP20(pin 31) andGP22(pin 34) also qualify;GP23was the closest to where the signal had been. - It lands beside its own group. Pin 36 is
GP24/HV_LATCH, withHV_ENat pin 30 andHV_SNSat pin 40. GP23is usable on a bare RP2040 — reserved only on Pico modules, andtmc51x0-driver-dev-pcbalready uses it this way. See the note above.- Nothing is lost on the bus switch. It moves from
U606ch6, whoseAsideISO29is unconnected, toU605ch8, whoseAsideISO23is likewise unconnected — an unused switched path either way. - The instrument port does not change.
DIG26carries~{HV_FAULT}by net name, so the channel map andU1304pin 7 are untouched.
The move freed GP29, and GP29 and GP27 are now assigned to the two
monitors below. GP20 and GP22 stay reserved for PYC_PULL_EVENT and
PYC_FAULT, and are the only pins left to take.
The two sheet pins these needed — done¶
The MCU lives inside the mcu sheet, so both monitor nets have to cross that
boundary: mcu gains sheet pins ANGLE_OUT_MON and BRAKE_ISENSE, both
input. On the other side, ANGLE_OUT_MON already reaches the
motor_encoder_switch level and needs one more hop to the root, while
BRAKE_ISENSE is still inside the brake block and needs a pin on the
brake_torque_sensor wrapper. The ~{HV_FAULT} half needed no new sheet pin and
is done. Do not tick "Re-link footprints to schematic symbols based on their
reference designators" afterwards.
What the two monitor signals are¶
| Net | Span | Source impedance | Today |
|---|---|---|---|
ANGLE_OUT_MON |
0-1.650 V | 2.6 kΩ — R807||R811 1.6 kΩ plus R810 1 kΩ |
wired to GP29/ADC3 |
BRAKE_ISENSE |
0-1.006 V | 1.849 kΩ — 1.6 kΩ divider plus R1819 249 Ω |
wired to GP27/ADC1 |
Both are low enough to drive the ADC directly with no buffer. Route them to the
block's GPIO27 / GPIO29 ports; the switch's B-side pin then hangs off the
node as an unused stub, which is exactly what HV_SNS already does on GP28.
When the switched domain is off the nodes sit at 0 V, held by R805 100 kΩ and
R1818 110 kΩ, and the series resistance limits anything regardless.
This is a self-test, not a measurement¶
12 bits over a 3.3 V range is 806 µV/LSB, so ANGLE_OUT_MON spans 2048 counts
and BRAKE_ISENSE 1249. The binding limit is not resolution but the reference:
docs/bringup-log.md records ADC_AVDD tied directly to +3.3V_MCU with no
separate reference and no filter, "so absolute accuracy is bounded by that
rail." Against the DAC's own 50.35 µV LSB at the BNC, the ADC is 16×
coarser and rail-referenced, so this readback cannot validate the analog
output's gain and offset — that still wants a DMM on the BNC. What it buys is a
firmware-visible answer to "is the DAC-amp-BNC chain alive and roughly right",
which today is unanswerable: the bring-up log notes ANGLE_OUT reaches no ADC at
all. ADC linearity on this part is uncharacterised on this board; only low-level
readings have ever been taken.
BRAKE_ISENSE is the more valuable of the two and the cheaper. The brake is a
current sink whose actual current is invisible to firmware except through the
digital ~{BRAKE_FAULT} bit, so reading it closes command-versus-actual, and the
net has no other consumer to perturb. ANGLE_OUT_MON has a cost worth naming:
R810 1 kΩ does not isolate much, so ADC input leakage flows through 1 kΩ + 1.6 kΩ
onto the divider midpoint — the same node the BNC output comes from. Order a
millivolt of error on ANGLE_OUT per microamp of leakage, roughly 0.1 % of full
scale. That is precisely what the "≥1 MΩ load" rule in the analog design docs
exists to protect, so pull the RP2040's input-leakage figure before assuming it is
negligible. If only one channel is wired, wire BRAKE_ISENSE.
GP1 Gets A Hardware Pull-Up¶
Decided 2026-08-14; fitted 2026-08-17 as R401. A 10 kΩ 0402
(OW-RES-10K-0402, stocked) from PYC_UART_RX to +3.3V_MCU, on the MCU
side of the port block's R29001, placed near the RP2040, in the board-authored
mcu sheet so a design-block re-place cannot lose it.
GP1 is the pyControl UART RX. It is driven by the host's DIO-A, so it floats
whenever the cable is unplugged, whenever pyControl is powered down with the
cable connected, and — the case that matters — between this board's
power-on-reset and the instruction where firmware configures the pad. A UART RX
line that drifts low reads as a start bit or a break, so the RX FIFO fills with
framing errors before the first line of protocol code runs.
An internal pull does not cover that window. This is the same argument that keeps
the external 10 kΩ pulldown on the 36 V block's EN — see docs/power.md — and
the same one behind .agents/AGENTS.md's rule that the board must reach a safe
state without firmware's cooperation. A defined idle level on the link carrying
the safety heartbeat belongs in that category.
The floating level is genuinely indeterminate rather than merely "probably high":
the USBLC6-2P6 on that line leaks 150 nA max, against the RP2040's own ~1 µA
input leakage.
| Choice | Why |
|---|---|
| 10 kΩ | 330 µA load when the host drives low, trivial for an STM32 GPIO rated 8-20 mA. Wins against a ~50 kΩ internal pull-down if one is active |
+3.3V_MCU, not +3.3V_SW |
The pyControl UART bypasses the bus switch precisely so it works with the switched domain dark. Pulling to the switched rail would defeat that |
MCU side of R29001 |
The point is to define the RP2040's input, so it must hold when the connector path is open — which is the unplugged-cable case. On the connector side it would only load the cable |
| Board level, not in the block | The block's boundary has no 3.3 V pin, and which 3.3 V domain is a board decision. Keep the block's interface at five pins |
Keep the firmware pull enabled as well. They parallel to ~8.3 kΩ and cost nothing.
GP0 (TX) deliberately gets none. A matching pull-up would keep the host
seeing idle-high while this board is in reset or BOOTSEL, but it fails
differently: with +3.3V_MCU dead and the cable connected, 10 kΩ to a 0 V rail
holds the host's RX low, a continuous break, which is arguably worse than
floating. That needs both USB absent and the pyControl 5 V branch open, so it is
a corner — but fit TX only if host-side framing noise actually shows up at
Gate B.
Resolved 2026-08-17, and it made this recommendation mandatory rather than
prudent. docs/power.md used to state that RP2040 GPIOs are "inputs with pulls
disabled at reset." That is wrong: every RP2040 GPIO resets with its internal
pull-down enabled — PUE = 0, PDE = 1 in PADS_BANK0. So the right-hand
column below is the one that applies, and docs/power.md needs the correction.
The same fact is why the bus switch's MCU (B) side needs no termination of its
own, and why GP1 is the one pin that needs a hardware pull the other way.
| If pulls are disabled at reset | If a pull-down is enabled at reset — this one |
|---|---|
| The external pull-up is belt-and-braces | The external pull-up is required — GP1 is otherwise actively held low until firmware runs |
10 kΩ is the right value either way: against a ~50 kΩ internal pull-down it gives
3.3 × 50/60 ≈ 2.75 V, comfortably over a 2.31 V VIH. The same claim is
load-bearing in docs/power.md for the EN divider, where it is harmless — the
external pulldown pulls the same direction — but the document should still say
the right thing.
EXT_FAULT_IN — Still Deferred, Still Cheap¶
If the rig runs two of these boards, one board's fault should be able to stop
the other without depending on the pyControl task to notice. Reserving GP27 as
EXT_FAULT_IN and bringing it out — cross-wired to the other board's FAULT
output, or to a rig-level disable line — costs one GPIO and one connector
position, and reports as fault bit 8 EXT_STOP.
Rev 0 has no FAULT output to cross-wire, so this is a rev 1 decision that
arrives with the pyControl event lines. GP27 stays unallocated until then. See
the cross-board fault discussion in docs/pycontrol-interface.md.
Peripheral Summary¶
| Peripheral | Use | Pins | Rev 0 |
|---|---|---|---|
UART0 |
pyControl link, 115200 8N1 | GP0, GP1 |
yes |
SPI0 |
TMC5130A | GP6 SCK, GP7 TX, GP4 RX, GP2 CS as GPIO |
yes |
SPI1 |
DAC80501, write-only | GP10 SCK, GP11 TX, GP13 CS as GPIO |
rev 1 |
| PIO0 | Unallocated — the encoder cross-check was deleted | — | — |
| ADC | SW_RAIL_SENSE_DIV_2, HV_SNS, BRAKE_ISENSE, ANGLE_OUT_MON¹¹ |
GP26-GP29 |
yes |
| USB | Debug console, CDC | dedicated USB pins | yes |
| QSPI | External flash | dedicated QSPI pins | yes |
There is no second UART. The debug console is USB CDC, because UART0
belongs to pyControl. Rev 0's other rich observation path is the InstrumentPort,
which carries the TMC SPI bus and both directions of the pyControl link; the
event BNCs are still rev 1.
GPIO Isolation¶
v1.0 places orb_weaver_private:rp2040_with_gpio_isolation_sn74cb3q3245, which
contains the RP2040 core and the four SN74CB3Q3245 8-channel bidirectional
FET bus switches with all 29 MCU-to-switch routes pre-made — 32 channels, 29
wired 1:1 by index, one shared active-low ~OE pulled up by 7.87 kΩ to the
always-on +3.3V so the bus is isolated at power-on until firmware enables
it. Rev 0's separate rp2040 + rp2040_gpio_isolation_sn74cb3q3245 pair is
superseded; the standalone companion is expected to be retired from kicad-libs
once this board is verified.
Corrected 2026-08-17: there is no Ioff second line of defence. All four
VCC pins are on +3.3V_MCU, the always-on rail, so the packages are never
unpowered and Ioff never engages. Isolation rests entirely on the MCU holding
~{BUS_SW_EN} high, which R601 makes the reset default. That is the deliberate
consequence of The Bus Switch Runs From
+3.3V_MCU below — it is the price of being
able to isolate before switching off — but it means the enable is the only
mechanism, not the outer of two.
Orientation, as built 2026-08-17: A is the TMC / switched side and B is the
MCU side. This is inverted from what this document said before, and it matters
in two places — which side the sheet pins leave from, and which side the
instrument taps sit on. Channel pairing on the RGY-20 package is A_n = pin
(n+1), B_n = pin (19−n).
The Rule: Follow The Far End's Power Domain¶
This heading is kept for link stability — kicad-libs links to its anchor —
but the rule it names was restated on 2026-09-18 and the text below supersedes
it. Following the far end's power domain is the right instinct for anything the
MCU drives, and wrong for a high-impedance analog sense node; see the restatement
after the table.
The TPS1HTC100-Q1 high-side switch exists so the researcher can power-cycle the
board's chips to a known state without unplugging anything, while the MCU stays
alive on USB or pyControl. See docs/power.md. That makes "MCU running, switched
rails at 0 V" the board's normal idle state, not an edge case — and an MCU pin
driving into an unpowered chip forward-biases its input ESD clamps and
back-powers a dead rail through them.
The bus switch exists to prevent exactly that, which gives a single mechanical rule:
A GPIO goes through the bus switch if and only if its far end sits on the switched domain (
+36V_SW,+5V_SW,+3.3V_SW). Everything else bypasses.
| Iso | Applies to | Because |
|---|---|---|
sw |
TMC5130A SPI, enable and diagnostics; the I2C DAC bus; ~{BRAKE_FAULT}; the torque ADC's SPI1, TQ_CONVST_CS and TQ_CAL_EN |
All of them are parts that lose power when HV_EN drops |
byp |
pyControl UART; the reserved pyControl event lines; HV_EN, HV_DIAG_EN, HV_SNS, ~{HV_FAULT}; SW_RAIL_SENSE; FW_TRIG0/FW_TRIG1; BRAKE_ISENSE, ANGLE_OUT_MON |
No current path into an unpowered far end — see below |
The byp test is not "is the far end always powered" — restated 2026-09-18.
That wording held until the two analog monitors arrived, and it would have put
them on the switch: ANGLE_OUT_MON and BRAKE_ISENSE are buffered by U802 and
U1804/U1806, all of which run from block-local +5V_FILT off the switched
+5V_SW, so their far ends do die with HV_EN. The real test is whether the
MCU side can push or pull current into a dead far end. Switch a channel when it
can: every MCU output, and every MCU input that might carry a pull-up — which is
why the I2C pair (pulled up to +3.3V_MCU on the MCU side) and ~{BRAKE_FAULT}
(a push-pull 2G17 output) are both sw. Bypass a channel when the MCU side is
high-impedance and the far-end node is resistively tied to ground, because then
there is no path and no hazard. Both monitors qualify: the ADC pin sources
nothing, and R805 100 kΩ and R1818 110 kΩ hold their nodes at 0 V whenever
the domain is down.
Bypassing them is also the only way they stay useful. Behind the switch they
would be unreadable exactly when the interesting question is asked — is the
brake current zero because I commanded zero, or because the rail never came up?
— and worse, a disabled CB3Q channel leaves the MCU pin floating, so the ADC
would return an arbitrary value rather than a true zero. HV_SNS is the
precedent: an analog sense node read by the same ADC, on byp.
v1.0 isolates 15 of the 29 available channels, up from 7 in Rev 0: seven TMC,
two I2C, one brake fault, five torque. ~{BUS_SW_EN} left the byp row because
it is internal to the block now, and ~{INSTR_BUF_OE} left it because the
signal no longer exists. The arithmetic in the rest of this section is Rev 0
history, superseded by that sentence and by The v1.0 GPIO
Changes.
Rev 0 isolated 7 channels; full scope isolated 10. Both dropped by four on
2026-08-16, when the encoder and limit switch stopped reaching the MCU — those
were sw entries, which is why the sw row above no longer names the debouncer
copy or the encoder PIO tap. Full scope dropped by two more on 2026-08-26,
when the analog output turned out to need three channels rather than five: the
DAC80501 has no LDAC and no CLR pin. The as-built netlist confirms the 7:
six channels on U601 and one on U602. The bypass group is 14 at full
scope — 13 until HV_DIAG_EN arrived on 2026-08-17 — which is larger than a
first pass suggests, and each entry earns it:
| Net | Why it bypasses |
|---|---|
PYC_UART_TX, PYC_UART_RX |
The whole point of the architecture. pyControl is externally powered and must stay reachable when the switched domain is off — that is how the researcher talks to a board that is deliberately powered down |
~{BUS_SW_EN} |
Circular otherwise — the enable cannot be behind the switch it enables |
HV_EN |
The TPS1HTC100-Q1 runs from HV_IN and is never switched off. Rail control must not depend on bus state, and the MCU must be able to switch the rail back on while everything downstream is dark |
HV_SNS, ~{HV_FAULT}, HV_DIAG_EN |
Same device, same always-on supply, and their pull-ups sit on +3.3V_MCU. Fault status must be readable when the rail is off, and DIAG_EN has to be raisable to get it. Direct MCU connections, all three |
SW_RAIL_SENSE |
It reports whether +3.3V_SW came up, which is the precondition for enabling the bus. Reading it through the bus would be circular |
FW_TRIG0, FW_TRIG1 |
No chip at the far end — only the InstrumentPort buffers — and they must stay observable while the bus is isolated. The test pads do not exist yet |
PYC_PULL_EVENT, PYC_FAULT, PYC_RSYNC_IN (rev 1) |
BNC connectors and pyControl, both outside the switched domain |
~{INSTR_BUF_OE} |
The SN74LVC125A buffers sit on +3.3V_MCU so the board can be observed while the switched domain is off |
tmc51x0-driver-dev-pcb bypasses the same kind of set — its netlist shows
~{BUS_SW_EN} on GPIO19, ~{INSTR_BUF_OE} on GPIO23, and HV_EN and both
FW_TRIG markers wired straight to the MCU, with 27 GPIO nets through the switch.
This board bypasses considerably more, because it has a genuinely two-domain
power tree and that board does not. Do not "align" the two.
This board puts ~{BUS_SW_EN} on GP9, not GP19. The proven board uses
GP19 because it has no 36 V enable there; here GP19 is HV_EN and is already
wired into mcu.kicad_sch. Deliberate divergence, noted so nobody "fixes" it.
The Block Is Oversized For This Board — Closed 2026-09-16¶
This whole question is closed and the section below is history. The combined
rp2040_with_gpio_isolation_sn74cb3q3245 block wires all 29 usable GPIOs to a
channel 1:1, so there are no un-wired channels left to argue about and no block
edit is owed at any future revision — which was the one cost that killed option
A and then option B in turn. The four packages stay, and the price is now stated
honestly as current rather than as wasted area: I_CC is 1 mA typ / 2 mA max
per package with the switch on or off, because the charge pump runs
regardless, so the four draw ~4 mA typ and ~8 mA max continuously from the
always-on rail even with every channel isolated. Accepted.
Rev 0 History — Option A Versus Option B¶
The block is four packages because it is built to isolate all 30 GPIOs. Under the
rule above this board isolates 7 in Rev 0 and 10 at full scope, so two of
the four SN74CB3Q3245 packages are dead weight in Rev 0 and at full scope
too. The 2026-08-16 encoder and limit-switch cut made this worse, not better,
and the 2026-08-26 analog output part made it worse again — ten channels fit
in two packages with six to spare, so U603 and U604 now have no path to
ever carrying a signal on this board. The decision to place the proven block
whole still stands on schedule grounds, but it is carrying twice the packages it
needs and the second half is no longer "reserved for later".
As built 2026-08-17, the seven live channels land on U601 (six: ~{TMC_CS}
A3, ~{TMC_DRV_EN} A4, TMC_SPI_CIPO A5, TMC_DIAG0 A6, TMC_SPI_SCK A7,
TMC_SPI_COPI A8) and U602 (one: TMC_DIAG1, A1/B1). U603 and U604 carry
no channels at all and are an open decision before placement. The earlier
crossed-label defect that put TMC_DIAG1 on a hard ground is fixed; all 32
channels were audited.
| Option | Cost | Benefit |
|---|---|---|
| A. Place the block whole, wire 16 channels, leave 16 unused | 3 unnecessary ICs, their decoupling, and the board area | Proven block, zero design work, obvious upgrade path |
B. Board-local section with two SN74CB3Q3245 |
Two ICs, a new schematic section to verify | Half the parts and area; matches what the board actually needs |
Decided 2026-08-13: option A. Place the proven block whole and leave the
unused channels alone — 25 of its 32 as built, not the 16 this option's row
predicted, because the encoder and limit-switch cut landed after the decision.
Two SN74CB3Q3245 packages and their decoupling are
wasted, and that is accepted — the block is already placed, already proven, and
Rev 0 is optimising for schedule. Option B remains the right answer for a later
revision if board area becomes the binding constraint.
Reversed 2026-08-17. Earlier guidance said to wire the A (MCU) side of all 16 isolated GPIOs now, including the 8 reserved for rev 1, leave the B side of the reserved channels unconnected, and let a later revision add board-side wiring only — no re-place, no re-pin, no firmware change. Neither half of that is what the board does. A is the switched side, not the MCU side, and the unused channels are not pre-wired at all: their A pins are open and their B (MCU-side) pins are tied to GND. Tying the MCU side down is the right treatment for an unused FET pass gate — it leaves no floating node on the always-on rail — but it means rev 1 has to edit this block to reach the DAC channels, so the "adds them without moving anything" property was never delivered. Plan for a block edit at rev 1, and prefer option B if that edit is happening anyway. Bypass-group signals stay off the switch entirely, which is unchanged.
Updated 2026-08-26 — option B is now the clear answer. The rev 1 edit needs
only three channels (DAC_SPI_SCK, DAC_SPI_COPI, ~{DAC_CS}), which fit
in U602's seven free channels without touching U603 or U604. Since the
block has to be edited anyway, and since the full-scope requirement is now ten
channels against thirty-two placed, the schedule argument that carried option A
has expired. Do the swap when rev 1 opens the block, not before — Rev 0 is
already ERC-clean with option A placed.
The DAC Bus Terminations — Superseded 2026-09-16¶
The SPI DAC bus does not exist any more. Both DAC blocks are I2C at 0x48 and
0x49, so ~{DAC_CS}, DAC_SPI_SCK and DAC_SPI_COPI are gone along with the
three in-block terminations described below, and the analog block's own note that
it owns no bus terminations now applies to SDA/SCL as well. What replaces
them is two board-level pull-up pairs — one per bus segment, MCU side on the
always-on rail and DAC side on +3.3V_SW — listed in Board-Level Input
Biases. The reasoning below is retained because the
rule it establishes is unchanged: a switched-domain pull must never reference
+3.3V_MCU, and nothing may be pulled to 5 V through a symmetric FET pass gate.
Rev 1 History — The Three SPI DAC Terminations¶
Corrected 2026-08-27. This section previously said one was in the block and two were board-level. All three now live in the block, and the board owns none of them:
| Net | Termination | Where | Required? |
|---|---|---|---|
~{DAC_CS} |
10 kΩ pull-up +3.3V_SW |
In block (R2006) |
Yes |
DAC_SPI_SCK |
10 kΩ pull-down to GND | In block (R2010) |
Hygiene |
DAC_SPI_COPI |
10 kΩ pull-down to GND | In block (R2009) |
Hygiene |
So the board's nine 10 kΩ terminations stay nine, not eleven. The two pull-downs moved into the block on 2026-08-27 because nothing about them is board-dependent — 10 kΩ to GND is right on any board — and a block re-place cannot then lose them.
Do not add board-level copies when the DIG9/DIG10/DIG6 instrument taps go
in. Those taps sit on the A / switched side of the bus switch and need defined
levels for exactly the reason R1104-R1107 exist on the TMC taps, but these
three resistors already provide them. A second set in parallel would halve them.
Only the pull-up is load-bearing: the DAC80501 blocks SCLK and SDIN
entirely while SYNC is high, and a frame interrupted before its 24th SCLK
falling edge is discarded with no register update. The other two prevent
floating CMOS inputs, not a functional failure. Because the required one is
functional rather than board-dependent, hosting it in the block means no board
can omit it — the trade is a boundary pin.
The +3.3V pin is that trade, and it must bind to +3.3V_SW. Binding it to
+3.3V_MCU would hold ~{DAC_CS} at 3.3 V while the DAC's own VDD is dead,
pushing roughly 260 µA through the DAC's input clamp into +5V_SW — the exact
back-power mechanism the bus switch exists to prevent, reintroduced inside a
block where the bus switch cannot see it. This is the same rule the board
already applies to the buffer terminations: the switched-domain nets
deliberately do not reference +3.3V_MCU.
Do not pull any of the three to the DAC's 5 V rail. The SN74CB3Q3245 is a
symmetric FET pass gate, so a 5 V pull-up on the switched side lands on an
RP2040 pad and exceeds its IOVDD + 0.3 V limit. +3.3V_SW is correct and
sufficient — the DAC80501's VIH is 1.62 V, so even against the RP2040's
internal pull-down the ~2.75 V divider result has margin, the same arithmetic
that justifies R401 on GP1.
The Bus Switch Runs From +3.3V_MCU¶
It has to. Powering it from +3.3V_SW would give free isolation through Ioff
whenever HV_EN is low and would cost no GPIO at all — but it would hand the
sequencing to a rail ramp instead of to firmware, and it would remove the ability
to isolate before switching off. Rejected deliberately; recorded in
docs/power.md so it is not rediscovered as a clever idea.
Sequencing Rule¶
Falls straight out of the architecture, and firmware must follow it:
Powering the switched domain down
- Assert
~{BUS_SW_EN}high — isolate first. - Drive
HV_ENlow.
Powering it back up
- Drive
HV_ENhigh. - Wait for the buck and LDO to settle.
- Confirm
+3.3V_SWis up onSW_RAIL_SENSE_DIV_2— readable because it bypasses. - Assert
~{BUS_SW_EN}low — connect last.
Isolating first and connecting last means no MCU pin is ever driving a rail that
is on its way down or not yet up. Getting this backwards is the failure this
whole arrangement exists to prevent, so test it at Gate B with a scope on
+3.3V_SW and one TMC input.
Firmware Consequences¶
Properties of the hardware, not choices:
- The pyControl link works with the bus isolated.
GP0/GP1bypass, so the board answersID/STATUSin its idle state and can report why the motor rail is off. This is the behaviour the architecture is for. - The USB CDC console is likewise unaffected — USB uses dedicated pins, not the GPIO matrix.
- The power-monitoring group is readable at all times.
SW_RAIL_SENSE_DIV_2,HV_SNS, and~{HV_FAULT}all bypass, so firmware can diagnose the switched domain without enabling anything. The earlier boot-order awkwardness is gone.HV_SNSand~{HV_FAULT}needGP14(HV_DIAG_EN) raised first — the smart switch gates reporting onDIAG_EN, andGP14is high-Z at reset. - Nothing on the switched domain is reachable until the bus is enabled. SPI to
the driver, and in rev 1 the DAC. Firmware must treat a read from either as
invalid while
~{BUS_SW_EN}is high rather than returning stale or floating data. - Position and homing come only from the driver. The encoder and the limit
switch never reach a GPIO, so while the bus is isolated firmware has no
position and no homing state at all — not stale data, none. Report that
honestly in
STATUSrather than caching the last value. GP1has a hardware pull-up, and firmware should still enable its own. The external 10 kΩ defines RX before firmware runs; the internal pull is the second layer. Do not treat the hardware part as permission to skip it. SeeGP1Gets A Hardware Pull-Up.- Report both
~{BUS_SW_EN}andHV_ENstate inID/STATUS. A session that silently runs isolated should be impossible to mistake for a working one.
Connector Complement¶
Designators are assigned for the full scope and Rev 0 populates a subset.
Renumbered 2026-08-17 to the as-built annotation. The flat J1-J11
sequence this section used is not what the board carries; annotation is
sheet-scoped, so the 36 V terminal is J201 and USB-C is J301.
Renumbered again 2026-08-27, and the no-renumbering policy is withdrawn. This paragraph used to say that gaps within each sheet's hundred were deliberate and that "renumbering later would break the silkscreen, the documentation, and the bring-up log for no benefit." A global re-annotation then happened by choice, when the analog output block gained its filter and the decision was taken to use KiCad's automatic annotation rather than hand-preserving numbers. Automatic annotation orders by sheet position, so inserting parts rotates everything after them.
Three connectors in the motor_encoder_switch sheet rotated:
| Carries | Was | Now |
|---|---|---|
| Analog angle out, BNC | J7 (placeholder) |
J1101 |
| Stepper coils, 4-pos 3.5 mm | J1101 |
J1102 |
| Encoder, 5-pos 3.5 mm | J1102 |
J1103 |
| Limit switch, 2-pos 3.5 mm | J1301 |
J1301 (unchanged) |
The 4-, 5- and 2-position housings are not mechanically interchangeable, so no harness can be plugged into the wrong terminal. The hazard is documentary, not electrical.
Rev-0 boards in hand carry the old silkscreen. A technician holding a rev-0
board reads J1101 = motor while this document says J1101 = BNC. docs/bringup-log.md
keeps one section set per board serial; record the designator scheme in each
board's section rather than assuming the current table applies to older units.
The consequence for this document, and every other one: designator numbers are
no longer stable across revisions. Name things by role and net — "the encoder
terminal", "the ~{DAC_CS} pull-up" — and give the designator as a
current-as-of-date convenience rather than as the identifier. Tables like the one
below are the right place for designators; prose is not.
Designator warning, reconciled 2026-09-20. The whole J band was reassigned
when the v1.0 board was rebuilt from design blocks; the numbers below are read
from the exported netlist and supersede every earlier J number in this file.
The netlist is authoritative. Same caution as the mcu sheet band above.
| As built | Connector | Carries | Rev 0 | Docs used to call it |
|---|---|---|---|---|
J201 |
USB-C receptacle (usb2_vertical block) |
Firmware load, USB CDC console, logic-rail power source | yes | J301 |
J301 |
RJ-45, OW-CONN-J1B1211CCD or OW-CONN-438600001 |
pyControl port: UART + GND only in Rev 0 | yes | J1901 |
J501 |
2-pos 5.08 mm pluggable terminal, Phoenix 1757242 (OW-CONN-1757242) |
36 V motor supply in | yes | J201 |
J901 |
Single BNC, OW-CONN-HL-BNC-KHDA (vertical) |
TQ_AOUT — torque analog out |
yes | new in v1.0 |
J1101 |
Single BNC, OW-CONN-HL-BNC-KHDA (vertical) |
ANGLE_OUT |
rev 1 | unchanged |
J1102 |
4-pos 3.5 mm terminal, OW-CONN-TBH-1X04-3P5-VERT |
Stepper coils | yes | unchanged |
J1103 |
5-pos 3.5 mm terminal, OW-CONN-TBH-1X05-3P5-VERT |
Encoder: supply, return, A, B; pin 2 reserved |
yes | unchanged |
J1301 |
50-pin 0.5 mm FFC vertical ZIF, OW-CONN-FH12-50S-0-5SVA-54 |
InstrumentPort-Digital-50 | yes | J1501 |
J1601 |
2-pos 3.5 mm terminal, OW-CONN-TBH-1X02-3P5-VERT |
Limit switch, inside the debounced input block | yes | J1301 |
J1801 |
2-pos 3.5 mm terminal, OW-CONN-TBH-1X02-3P5-VERT |
Brake coil: COIL_LO and +36V_SW |
yes | new in v1.0 |
J2001 |
5-pos 3.5 mm terminal, OW-CONN-TBH-1X05-3P5-VERT |
Torque bridge: SIG_N, SIG_P, VEXC, GND, TQ_SHLD |
yes | new in v1.0 |
J8 |
Dual BNC, DOSIN-801-0095 |
PYC_PULL_EVENT, PYC_FAULT |
rev 1 | placeholder |
J9 |
Dual BNC, DOSIN-801-0095 |
PYC_RSYNC_IN, spare |
rev 1 | placeholder |
J10 |
SWD header | Debug — not implemented, see below | no | placeholder |
Eleven connectors populated in v1.0, three deferred (J8, J9, J10).
J8 and J9 keep placeholder numbers until their sheets exist — expect them to
renumber when they do. The brake and torque terminals (J1801, J2001) and the
torque BNC (J901) are new in v1.0 and have no Rev 0 equivalent.
Earlier counts in this file are historical. "Seven connectors in Rev 0, three
deferred" described the 2026-08-27 state, when the InstrumentPort FFC was J1501
and the analog BNC had just been placed as J1101.
The three terminals switched to the vertical OW-CONN-TBH-*-VERT family in the
same pass that made the other connectors vertical; the horizontal Phoenix
OW-CONN-1844236/1844249/1844210 parts this table used to name are no longer
what the board carries.
AUX_ANALOG_OUT And The Dual BNC — Closed 2026-08-27¶
~~J7 Dual Versus Single — Reopened 2026-08-26.~~ Closed by construction.
The board carries a single vertical HL-BNC-KHDA as J1101 — neither of the
two options this section debated. The dual DOSIN-801-0095 was specified when the
analog output was going to be a dual DAC8563 and the second channel cost a
footprint and two passives. The built block is single-channel, so
AUX_ANALOG_OUT costs a second full instance — one more DAC80501, one more
OPA197, and the passives — and it is not populated. The stocked single
DOSIN-801-0050 was the fallback but was not what got placed; the vertical
HL-BNC-KHDA matches the rest of the board's vertical connector direction and has
four ground pins at ±5 mm around the centre pin, which is what lets D2001's
ground via land on a connector ground pin.
AUX_ANALOG_OUT is therefore not on this board at rev 1, and AIN1_P/N stay
no-connect. If it is ever wanted, it is a second block instance on its own
hierarchical sheet plus a second jack, not a stuffing option.
The related question — whether a second channel would carry a validity signal —
is in docs/encoder-analog-output.md. It was nearly free and is now not, so the
argument for encoding validity into the angle signal's own out-of-band levels
correspondingly got stronger.
The SWD Header Is Deferred, By Decision¶
Decided 2026-08-17. J10 is not on the board. SWCLK, SWD, and RUN on
the RP2040 are left unconnected and explicitly NC-flagged, and the header waits
for a future board revision.
This is an access limitation, not an electrical defect. RP2040 RUN has an
internal pull-up of 50-80 kΩ and the datasheet permits leaving it floating or
tying it to IOVDD, so the part boots correctly with nothing attached; the
NC flags are there so ERC agrees that the omission is intentional rather than an
unfinished net.
What it costs, stated plainly so bring-up does not discover it:
- No debugger. No SWD means no breakpoints, no single-stepping, and no post-mortem of a hung core. Firmware debugging is USB CDC prints and the InstrumentPort capture, which is exactly why the port was pulled forward.
- No hardware reset line. BOOTSEL recovery means holding
SW501while power cycles, and with the ORing diodes that requires both USB and pyControl unplugged before power returns — pulling the USB cable alone leaves the board alive on pyControl 5 V. Write that into the bring-up procedure.
The motor terminal (J1102), the encoder terminal (J1103), and the limit-switch
terminal (J1301) are one stocked 3.5 mm screw-terminal family
(OW-CONN-TBH-1X04-3P5-VERT, -1X05-, -1X02-), which keeps the harness story
uniform and needs no purchase. Updated 2026-08-27: these are the vertical
TBH parts, not the horizontal Phoenix OW-CONN-1844236/-1844249/-1844210
this paragraph used to name, and the motor and encoder designators rotated — see
the renumbering note above.
They are screw terminals, not locking. The earlier plan called for a locking motor connector because the rig gets handled. Screw terminals unblock Rev 0 today; if the rig proves that insufficient, sourcing a locking 4-pos motor connector is a rev 1 change confined to the motor terminal. Decide before the harness is built, not after.
pyControl Port In Rev 0¶
Only the serial link is populated. See docs/pycontrol-port-pinout.md for the
full pinout and its provenance.
| RJ-45 pin | Signal | Rev 0 |
|---|---|---|
| 1 | DIO-A |
RP2040 UART0 RX (GP1) |
| 2 | GND |
Ground |
| 4 | DIO-B |
RP2040 UART0 TX (GP0) |
| 6 | 5V |
Footprint for the ORing branch; population gated on the port's 5 V budget |
| 3, 5, 7, 8 | POW-A, SPECIAL, POW-B, 12V |
Not connected |
Series resistors and ESD protection on every populated port signal.
PYC_PULL_EVENT, PYC_FAULT, and PYC_RSYNC_IN are rev 1. Both DIO lines are
consumed by the UART, so when those lines arrive they still land on BNCs — that
analysis is unchanged and is why J8 and J9 keep their designators.
What Rev 0 Gives Up¶
Stated plainly so nobody discovers it during bring-up:
- No independent encoder cross-check, ever. As of 2026-08-16 this is
permanent rather than deferred: the encoder reaches the TMC5130A only, in every
revision.
ENCODER_MISMATCHindocs/uart-protocol.mdhas no second count to compare against and should be retired rather than left reserved. Encoder integrity rests on the driver's own count plus the index pulse. The InstrumentPort narrows this —ENC_AandENC_Bare captured alongside the SPI reads ofX_ENC, so the decoding can be checked by hand. That is a bench capability, not a runtime fault, and it goes away at rev 2. - No MCU copy of the limit switch. Firmware learns a homing event from the
driver over SPI, not from a GPIO.
LIMIT_SWis on the InstrumentPort in Rev 0; the test pad it was also meant to have does not exist yet. - No analog angle output. The researcher-facing 0-5 V BNC is rev 1. Angle is available over the UART only.
- Seven of the eighteen InstrumentPort digital Strands are unrouted, and the two rev-1 buffer packages were never placed at all. Rev 0 captures the TMC SPI bus, both directions of the pyControl serial link, the two firmware triggers, the two encoder channels, and the limit switch — enough for firmware development, which is why the port was pulled forward, but not the event, DAC, brake, or torque groups.
- No pyControl TTL event lines.
PULL_EVENT,FAULT, andRSYNCare rev 1, so there is no hardware-timed event or fault path and no time-alignment signal. Everything is in UART time, with UART latency, for Rev 0. - No synthetic homing stimulus. Permanently, not deferred — homing is exercised with the real switch.
None of these block the stated Rev 0 purpose, which is to exercise the interfaces. All of them matter for experiments with animals, and none of that is in Rev 0's scope either.
Test Points — Outstanding¶
None of this is on the board. As of 2026-08-17 there are no test points anywhere on
mouse-joystick-pcb. Everything below is a requirement to satisfy, not a description. It is the largest single gap between this document and the board, and with no SWD header either it is also the board's only remaining bring-up access besides the InstrumentPort and USB CDC.
TMC_DIAG0 did not earn a slot because a driver fault reaches the capture
through PYC_FAULT anyway, one firmware latency later. It goes to a test point.
Labelled test pads, not bare vias: TMC_DIAG0,
TMC_DIAG1, ~{TMC_DRV_EN}, HV_EN, HV_SNS, REFL, and in later revisions
TQ_DRDY. (~{INSTR_BUF_OE} left this list on 2026-09-16 with the net itself.) TQ_DRDY has no slot
because the I2C capture already shows when the host reads a conversion.
Two more entries left this list on 2026-08-26. ~{DAC_LDAC} and
~{DAC_CLR} are moot for the same reason SWSEL is: the nets do not exist,
because the DAC80501 has neither pin. What replaces them is better — the
analog output block exposes VREFIO, AMP_VOUT and AOUT as distinct nets, so
one probe each would verify the 2.500 V reference, the 1.32 gain, and the 249 Ω
drop.
Corrected 2026-08-27: the block carries no test pads. This paragraph claimed
it did. Checked against the block schematic and its layout fragment — there is no
TestPoint symbol or pad anywhere in analog_output_0_3v3_dac80501, which agrees
with docs/bringup-log.md's standing note that no test points exist anywhere on
this board. The three nets are still the right ones to pad; they are simply not
padded yet, and adding them is a block change, not a board change.
One thing is owed at board level for the analog section, contrary to the last
sentence this paragraph used to carry: AIN0_N to AGND. The instrument tap's
series 1 kΩ started out board-level (R1409) and moved into the block on
2026-08-27 as R2008 behind the new AOUT_MON port, so the isolation resistor
now travels with the thing it protects.
Two entries left this list on 2026-08-17. SWSEL is moot: the TMC5130A's pin
28 is tied directly to GND with no net, so there is nothing to pad and nothing a
jumper could change — SPI mode is strapped, not selected. ENC_N is moot: the
net does not exist, J1103 pin 2 is a reserved no-connect, and ENCN is
terminated at R1201.
Also pad ENC_A, ENC_B, and LIMIT_SW. They hold DIG28, DIG29 and
DIG15 permanently now that the 32-channel map has room — the rev-2 eviction
that used to threaten them is gone — but none of them reaches the MCU, so a pad
is the only access that does not depend on the port being cabled.
Where Each Signal Is Tapped¶
Superseded in part, 2026-09-19. Every tap listed here is being split off its functional net by a series resistor. Which node is tapped does not change — the reasoning below still governs that — but the branch becomes its own net. Values, owning blocks and naming are in
docs/instrument-port-tap-resistors.md.
Two tap points are decisions, not details, and getting either wrong makes the capture answer a different question than the one being asked.
pyControl serial: the block's existing PYC_DIO_A/PYC_DIO_B pins, the MCU
side of R29001/R29002. No block change, no new boundary pins.
An earlier draft of this section put the tap on the connector side of those
resistors. That was wrong and is recorded here so it does not get re-proposed.
On a digital instrument channel the two nodes are indistinguishable by
construction. The only current in the resistor is the 330 µA the 10 kΩ GP1
pull-up sinks when the host drives low, so the drop across 100 Ω is 33 mV —
three orders of magnitude below any logic threshold. The two sides differ only
when the resistor is open or something is actively fighting on the line, and both
of those are hard faults a meter finds faster than a capture does. A logic
analyzer cannot resolve the distinction the extra pin would expose.
Three reasons the MCU side is the better tap, not merely the cheaper one:
- It answers the question actually being asked. "Is what the RP2040 receives what the breakout board sent?" is a question about the signal presented to the pin. That is the MCU-side node. The capture is still fully independent of firmware — it is hardware observation, not a log — which is what "observe the link directly" needs to mean.
- The 100 Ω becomes series protection for the buffer. Tapping the connector
side would put the
SN74LVC125Ainput on the unprotected node, between theUSBLC6-2P6and the resistor, with no series element between it and the cable. - It keeps the ESD node short. The block deliberately routes each line in one
USBLC6I/O pad and out the other so the clamp connection stays short. Hanging a stub off that node to reach a buffer elsewhere on the board adds capacitance and antenna to the one node that most wants neither.
Exposing both sides of the resistor would also present the board with a distinction it cannot use, which is the opposite of the discipline the rest of that block's interface follows. If a future board genuinely needs the raw cable node — a bias network, a different clamp, a transceiver — add the pin then, when there is a consumer to define it against.
TMC5130A: the A side of the bus switch, not the chip pins. Corrected
2026-08-17 — the A side is the TMC / switched side and B is the MCU side, the
reverse of what this section originally assumed. The taps are on A, so the
capture shows the driver's end of the link. When the bus switch is enabled, A and
B are the same node through a few ohms, so the capture shows what the chip sees.
When it is isolated, the taps sit at their terminated idle levels and go quiet —
which still diagnoses the bus-switch state instead of hiding it, and that is
exactly the failure mode a firmware author needs to recognise. It diagnoses it
from the far end rather than the near one: the earlier wording promised MCU
traffic with TMC_SPI_CIPO silent, and that is what a B-side tap would show.
This looks like the opposite of the pyControl decision above and is not. A 100 Ω resistor cannot make its two nodes read differently on a digital channel; a bus switch that can be open absolutely can. Where the series element has two distinguishable states, which side you tap is a real choice.
Reversed 2026-08-17; earlier guidance said to prefer the near side, "the one
that stays in the always-on domain and stays driven", which on the as-built
orientation means the B side. The 2026-08-17 schematic review raised the
disagreement as finding 7 and offered two remediations — move the taps to the
MCU-side nets, or keep the orientation and terminate the tapped nets.
Resolution: the taps stayed on the A side and the nets were terminated. Three
reasons. The A side is where the driver actually sees the signal, which is the
question the capture is being asked. Termination is nine passives in
board-authored sheets against re-pinning seven channels inside a proven
kicad-libs design block that would then diverge from its source. And the
terminations were wanted regardless of the instrument port — the TMC's SDO
tri-states between transactions, its DIAG pins are open-drain, and its
CSN/SCK/SDI are only weakly pulled internally.
What the old objection got right is that tapping the switched side puts always-on
buffer inputs on nets that are dead whenever HV_EN is low, which is this board's
normal idle state. That is the floating-CMOS-input problem the design avoids
everywhere else, arriving by a new route — and closing it is exactly what the
table below is for.
Pull And Termination Resistors — Moved¶
Superseded 2026-09-16, and the table that used to sit here is deleted rather
than corrected. It listed R1104-R1601 in the instrument_port sheet,
defining the inputs of buffers U1701/U1801 that no longer exist, and a
motor_encoder_limit sheet that has since been renamed. The live list is
Board-Level Input Biases: eight TMC biases now live
in motor_encoder_switch as R1101-R1107, and nine more are owed by the new
blocks. The reasoning below still stands and is the reason those resistors are
sized and referenced the way they are.
Not a resistor, but it belongs with them: TMC5130A REFR_DIR (pin 9) is tied
directly to GND as of 2026-08-27. It is a plain DI with no internal pull,
unlike SD_MODE/SPI_MODE (pu) and SWSEL (pd), and it was floating before
rev 1 — a floating right-stop input next to a 36 V bridge can trip a stop and
draws ΔICC. A 10 kΩ pull-down (R1104) was fitted first and then replaced by the
hard tie.
Why some reference +3.3V_SW and some GND. A pull that must read HIGH while
the driver is powered — ~{TMC_CS}, both DIAG lines, ~{TMC_DRV_EN} —
references +3.3V_SW, so it collapses to 0 V with the domain instead of
injecting current into a dead rail. Pulls that may read LOW go straight to GND.
Referencing +3.3V_MCU would be the wrong answer for the HIGH group: it would
back-power +3.3V_SW to roughly 1.3 V through the TMC's protection diodes,
defeating the HV_EN power-cycle and corrupting the rail sense.
+3.3V_SW is held at 0 V when off by R408/R409 — the rail-sense divider,
2 kΩ to GND — and that is what makes a pull-up to that rail a valid LOW in the off
state. If the SW_RAIL_SENSE divider is ever removed, R1107, R1101,
R1102, and R1103 stop defining their nets. Those two circuits are coupled;
treat them as one decision.
Do not use 100 kΩ pull-downs on the TMC SPI lines. This is why the earlier
prescription had to change rather than simply move. CSN, SCK, SDI, and SDO
are marked (tpu) in the TMC5130A datasheet with RPU = 132/166/200 kΩ. A 100 kΩ
pull-down against that parks the node at roughly 1.9 V — straddling the
SN74LVC125A's 2.0 V VIH and sitting between the TMC's own 0.99 V V_INLO and
2.31 V V_INHI. It is the worst available answer: an indeterminate level on both
sides. 10 kΩ gives 5 V × 10/176 = 0.28 V, an unambiguous LOW.
~OE does not gate the buffer input stage, so disabling the buffers is not a
substitute for terminating their inputs. SCAS290T specifies ΔICC at 500 µA
typical and 5 mA maximum per partially biased input, independent of OE,
against 40 µA maximum for the whole device with valid levels on every input. A
floating buffer input costs current and invites oscillation whether or not the
outputs are high-Z.
Encoder: between the input conditioning and the TMC5130A. ENC_A and ENC_B
are tapped on the board-local encoder section on the driver side of the chain, so
the capture shows what the TMC5130A's ENCA/ENCB pins actually receive. That is
the point of having them: the comparison is against the driver's own decoded
count, so the tap belongs where the driver sees the signal, not where the cable
delivers it. Corrected 2026-08-17: the chain is J1103, not J6, and it is
filtering only — there is no ESD device anywhere in the encoder path, contrary
to what this paragraph used to say. The taps need no pull-down of their own
because U801 drives them and R805/R806 hold them low when it does not.
The conditioning is a real, placed design block, not a gap:
orb_weaver_private:quadrature_encoder_input_5v_sn74lvc2g17. It imposes three
constraints that the still-unchosen encoder has to satisfy, and they are the
reason the encoder part remains the open decision that can invalidate the board:
- Push-pull, not open-collector.
R801/R802are 100 kΩ pull-downs on the harness side. An open-collector encoder needs them changed to pull-ups. - 72 kHz filter corner.
R803/R8044.7 kΩ withC802/C803470 pF gives τ = 2.2 µs. Check it against the encoder's maximum output frequency at the fastest sweep the rig will command. - The 5-position pin order is fixed by the block.
J1103pin 1 = GND, pin 2 = reserved index no-connect, pin 3 =ENC_A_RAW, pin 4 =+5V_SW, pin 5 =ENC_B_RAW. A 5 V encoder is assumed. If the chosen part wants a different order or a different supply, the harness or the block changes.
Limit switch: the LIMIT_SW net between the debouncer and the TMC5130A
REFL pin. Same reasoning — the capture should show what the driver's homing
input receives. R1601 defines the buffer input.
With the ÷2 divider on SW_RAIL_SENSE, the nine resistors above are the whole
passive cost of the instrumentation and of the isolation architecture's off-state
behaviour together.
What Carries Forward To The Twin-Axis Board¶
If this board is later superseded by mouse-joysticks-pcb, these carry over
unchanged:
- the pyControl port pinout and signal set;
- the UART protocol, with an axis argument added;
- the analog output design and its calibration semantics, once rev 1 builds it;
- the InstrumentPort-Digital-50 buffering pattern and its hardware-enabled default;
- the GPIO isolation pattern, including the bypass group, which is the newest and most reusable thing this board contributes;
- the power chain, sized for one motor instead of two.
What does not carry over: this GPIO table and this instrument overlay. The twin board re-derives both, and its overlay is already written.