seveibar/nema17-stepper-motor-driver-tmc2209-usb-pd
RP2040-based USB-C PD stepper-motor controller with TMC2209 drive, AS5600 position feedback, TMP102 thermal shutdown, current/voltage telemetry, RGB status LED, and protected buzzer alarm circuitry.
- Version
- 0.2.0
- License
- unset
- Stars
- 0
firmware/power_telemetry.py
"""ADC2: PD VBUS / 11. ADC3: positive motor-supply current at 1 V/A.
ADC reference, resistor tolerances and amplifier offset affect accuracy.
This reports supply current, not individual winding currents or regeneration.
The 100 ms monitor is not a replacement for the fuse/TMC hardware protection.
"""
DIVIDER_RATIO = 11.0
SHUNT_OHMS = 0.05
CURRENT_GAIN = 20.0
def convert_adc(voltage_raw, current_raw, reference_v=3.3, current_zero_v=0.0):
if not (0 <= voltage_raw <= 65535 and 0 <= current_raw <= 65535):
raise ValueError("ADC value out of range")
if not 2.7 <= reference_v <= 3.6:
raise ValueError("Invalid calibrated ADC reference")
voltage = voltage_raw * reference_v / 65535 * DIVIDER_RATIO
current = max(0.0, (current_raw * reference_v / 65535 - current_zero_v)
/ (SHUNT_OHMS * CURRENT_GAIN))
return voltage, current
def power_acceptable(voltage, current):
# Allow supply and measurement tolerance; reject 5/9 V fallback and 15/20 V.
return 10.8 <= voltage <= 13.2 and 0 <= current < 1.8
class PowerTelemetry:
def __init__(self):
from machine import ADC, Pin
from time import sleep_ms
self.voltage_adc = ADC(Pin(28))
self.current_adc = ADC(Pin(29))
self.reference_v = 3.3 # Calibrate against the measured ADC reference.
self.current_zero_v = 0.0
self.voltage = self.current = None
self.ok = False
sleep_ms(10) # Switched voltage divider + RC settle.
def sample(self):
# Discard the first conversion after switching channels.
self.voltage_adc.read_u16()
v = sum(self.voltage_adc.read_u16() for _ in range(16)) / 16
self.current_adc.read_u16()
i = sum(self.current_adc.read_u16() for _ in range(16)) / 16
self.voltage, self.current = convert_adc(v, i, self.reference_v, self.current_zero_v)
self.ok = power_acceptable(self.voltage, self.current)
return self.ok