imrishabh18/rp2040-motor-controller

This circuit module provides a microcontroller-based NEMA17 stepper motor driver with integrated USB-C Power Delivery, temperature sensing, and safety interlocks.

Version
1.0.16
License
unset
Stars
0

README.md

# RP2040 NEMA 17 motor cap with temperature protection

A 42.30 × 42.32 mm, four-layer, 1.6 mm PCB based on the [PD-Stepper V1.1 mechanical outline](https://github.com/joshr120/PD-Stepper). Four 3.3 mm mounting holes sit on a 31 × 31 mm square. The four mounting rings, MCU, driver and temperature circuit share one GND net.

The smaller board replaces the original screw terminal with a top-entry **JST PH 4-pin, 2 mm-pitch connector**, B4B-PH-K-S(LF)(SN). Pin order is A+, A−, B+, B−; use a matching PHR-4 motor cable. USB and component placement have been rearranged. Top and bottom have ground pours; the two inner layers carry routed connections.

Use [the 1:1 mounting template](mechanical/mounting-template.svg) to check your motor. The reference targets NEMA 17 and uses replacement motor tie screws. This design assumes 6 mm insulated spacers with components facing away from the motor. Confirm the actual rear screw pattern, shaft/bearing clearance and screw length before fabrication. The reference's cover and heatspreader do not fit this component layout directly.

This extends [imrishabh18/rp2040-motor-controller](https://tscircuit.com/imrishabh18/rp2040-motor-controller) with a TMP102 sensor beside the DRV8847 and a hardware temperature interlock. The sensor measures nearby PCB temperature. See [verification.md](verification.md) for the current automated results. The circuit has not been tested on physical hardware, and the reference firmware has not been flashed.

## Behavior

| Condition | Reference firmware response |
|---|---|
| Boot, reset or watchdog reset | Motor disabled; user must send `arm` |
| Valid temperature below 60°C, followed by `arm` | Enable permitted, subject to USB-PD power and driver fault checks |
| Temperature at least 65°C | USB temperature warning; slow status-LED blink |
| Temperature at least 75°C, or active temperature ALERT | Motor disabled and fault latched; fast status-LED blink |
| Cooling below 60°C | Motor remains stopped until another explicit `arm` |
| Missing sensor, I2C failure, changed sensor configuration or invalid reading | Motor disabled and fault latched |
| Firmware stops servicing the loop | 1-second watchdog resets the RP2040; startup remains disabled |

**These are provisional board-temperature limits.** Validate and adjust them with the actual motor, current, enclosure and cooling. The nearby sensor has thermal lag; its reading can be lower than the driver junction temperature. The DRV8847's built-in protection remains the last line of defense for rapid die heating. Temperature protection cannot prevent every electrical failure.

## Added circuit

`GPIO22 → existing USB-PD enable transistor → AND gate A`

`TMP102 ALERT → AND gate B and GPIO24`

`AND gate Y → DRV8847 nSLEEP`

The 3.3 V gate drives nSLEEP; the sensor's open-drain output does not fight an MCU output. Pull-down resistors keep the MCU enable and gate input inactive during reset or loss of PD approval. The original nSLEEP pull-down stays at the driver. SDA/SCL and ALERT have external pull-ups. Each new IC has local supply bypassing.

| Component | Role | Part / value | JLCPCB |
|---|---|---|---|
| U_TEMP | Board temperature and autonomous threshold output | TI TMP102AIDRLR, SOT563 | C99269 |
| U_THERM_GATE | Temperature interlock | TI SN74LVC1G08DBVR, SOT-23-5 | C7666 |
| C_TEMP, C_THERM_GATE | 3.3 V bypass | 100 nF, 0402 | C1525 |
| R_TEMP_SDA, R_TEMP_SCL | I2C pull-ups | 4.7 kΩ, 0402 | C25900 |
| R_TEMP_ALERT | ALERT pull-up | 10 kΩ, 0402 | C25744 |
| R_ENABLE_PD, R_MCU_ENABLE_PD | Default disabled state | 100 kΩ, 0402 | C25741 |

The sensor is at (8.000, −10.750) mm, 4.125 mm from the driver center on the same layer. U_TEMP's grounded pins face the driver, with a direct 0.3 mm ground trace to the driver's exposed ground pad. Keep the intervening ground copper thermally coupled when editing the layout. Verify this coupling on the fabricated board.

| Signal | RP2040 GPIO | Physical RP2040 pin |
|---|---:|---:|
| I2C1 SDA | 26 | 38 |
| I2C1 SCL | 27 | 39 |
| Active-low temperature alert | 24 | 36 |
| Existing motor enable | 22 | 34 |
| Existing driver fault | 23 | 35 |
| Existing status LED | 25 | 37 |

## Firmware integration

No existing motor-control firmware was included in the source project. `firmware/` supplies a tested MicroPython protection module and a USB monitoring example; it has **not been flashed or tested on physical hardware**. The example deliberately leaves motor motion generation to the application's existing motor code.

Copy `tmp102.py`, `thermal_policy.py`, `thermal_guard.py` and `main.py` to a compatible RP2040 MicroPython filesystem. The example accepts `status`, `arm` and `stop` over USB serial, and prints the temperature once per second. `arm` enables the driver with its coil inputs initially low; it does not start stepping by itself.

For an existing application, initialize `ThermalGuard` before configuring motor outputs, call `poll()` at least every 100 ms, and allow motion only while `guard.policy.enabled` is true. Stop PWM/PIO motion on faults and route all enable requests through `guard.arm()`. Do not write GPIO22 elsewhere. Keep the watchdog feed in the serviced application loop, after protection processing. Reset and errors must never restore a saved motion command automatically.

The sensor operates continuously at 8 Hz with an active-low comparator, a single-sample fault threshold, THIGH = 75°C and TLOW = 60°C. Firmware verifies these registers before accepting a reading, including when arming. A falling ALERT interrupt captures a stop even if the pin later recovers. The hardware gate responds to ALERT independently of I2C polling. Firmware provides the persistent stop until user rearm; the gate itself is not a hardware latch.

Before firmware configuration, the TMP102 defaults to an 80°C high limit and a 75°C low limit at 4 Hz. Running old firmware therefore does **not** provide the documented warning, shutdown or restart policy. A missing/unpowered sensor cannot assert ALERT: detection of that fault relies on the new firmware and watchdog.

## Build and verify

```sh
bun install --frozen-lockfile
bun run typecheck
bun run build
bun run validate:build
bun run test:built
bun run check:built
python3 -m unittest discover -s firmware -p 'test_*.py' -v
bun run render:schematic
bun scripts/render-pcb.ts
```

The completed layout is stored in `routing/route-plan.json` and loaded through tscircuit's documented local `algorithmFn` interface. The routes were produced with Pipeline 7 and then corrected for clearance and trace width. A fresh build reconstructs the copper, vias and pours and runs the normal checks. The saved plan rejects changes to its input geometry, connections or routing rules; it must be regenerated and validated after an electrical or placement change. No checker is disabled or error record removed by the build.

The toolchain versions, common-module patch and lockfile are pinned. The entire four-layer board routes as one group. The common-module patch contains RP2040 footprint, placement and schematic fixes; preserve it alongside `bun.lock` and `routing/route-plan.json`. The BOOT/RUN schematic symbols are separated to avoid the schematic router's oversized ground-wire detour.

Warnings remain for catalog lookup, component metadata and trace-length guidance. Motor-trace width and clearance regressions are checked separately; the current measurements are in `verification.md`. No DRC check is disabled. `check:built` checks both the CLI's printed error count and Gerber-derived copper shorts across all four layers.

The electrical regression follows source traces and physical package pins. It verifies the sensor bus, grounded address pin, supply/return paths and distinct interlock nets; deliberate disconnection and bypass mutations must fail. The existing ground, output separation and routing checks also remain active. Firmware tests exercise signed temperature decoding, sensor resets and errors, exact thresholds, latched stops and the MicroPython adapter with mocked GPIO/I2C. These are software checks, not thermal or hardware measurements.

## Hardware acceptance before use

1. With the motor disconnected, confirm 3.3 V at both new ICs and detect I2C address 0x48. Confirm nSLEEP is low on boot and remains low until a cool, valid `arm` request.
2. Heat the sensor/driver area while recording an external temperature reference and USB readings. Verify the warning, nSLEEP cutoff and the requirement to rearm after cooling. Test by forcing ALERT low as well.
3. Check that absent PD power, a disconnected sensor, a bus fault, changed thresholds and a stalled firmware loop all prevent or stop operation. Measure watchdog response and nSLEEP on a scope.
4. Under worst-case motor load and stall, measure driver case/board temperatures, winding current and cooldown. Set limits with allowance for sensor error, thermal gradients and thermal lag. Confirm stopping the motor is appropriate for the application; sleep removes holding torque.

## Sources

Pinouts, electrical behavior and component limits were checked against the [TI TMP102 datasheet](https://www.ti.com/lit/ds/symlink/tmp102.pdf), [TI SN74LVC1G08 datasheet](https://www.ti.com/lit/ds/symlink/sn74lvc1g08.pdf), and [TI DRV8847 datasheet](https://www.ti.com/lit/ds/symlink/drv8847.pdf). GPIO function assignments follow the [RP2040 datasheet](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf). Firmware APIs follow the [MicroPython RP2 reference](https://docs.micropython.org/en/latest/rp2/quickref.html) and [watchdog documentation](https://docs.micropython.org/en/latest/library/machine.WDT.html). Imported footprints were checked for package pin-number consistency; supplier inventory is not reserved.

The customized RP2040 module is bundled in `vendor/rp2040.js` (MIT license alongside it), so registry builds preserve the local footprint and layout fixes without requiring dependency patch installation.