astra/nema17-stepper-motor-controller-spring-clamp-rp2040

A 4-layer RP2040 controller board that negotiates USB‑C PD motor power and drives a NEMA17 stepper via a DRV8825, with current sensing, thermal shutdown, RGB status LED, buzzer alarm, optional AS5600 encoder, protection/filtering, and test points.

Version
1.4.0
License
unset
Stars
0

schematic/CurrentTelemetrySection.tsx

import { Fragment } from "react";
import { INA241A1IDDFR } from "../imports/INA241A1IDDFR";
import { FRM121WFR100TM } from "../imports/FRM121WFR100TM";
import { revisionPlacement as p } from "../mechanical/revision-placement";

const supply = ".MCU > .L_AVDD > .pin1";

/** Bidirectional, inline winding current. Independent of the DRV8825 current-regulation shunts. */
export const CurrentTelemetrySection = () => <>
  <schematicsheet name="current_telemetry" displayName="Winding Current Measurement" sheetIndex={7}>
    <schematicsection name="phase_A" displayName="Winding A"/>
    <schematicsection name="phase_B" displayName="Winding B"/>
    <schematicsection name="current_supply" displayName="Current-sense Supply Bypass"/>
  </schematicsheet>
  {(["A", "B"] as const).map((phase, index) => {
    const x = index * 14 - 8;
    const sch = {schSheetName:"current_telemetry", schSectionName:`phase_${phase}`};
    const amp = `U_CURRENT_${phase}`;
    const shunt = `R_PHASE_${phase}`;
    const r = `R_ADC_${phase}`;
    const c = `C_ADC_${phase}`;
    const bypass = `C_CURRENT_${phase}`;
    // pcbPath coordinates are local to the shunt footprint (not board coordinates).
    // Phase A bends between the AVDD filter and enable/bypass pads.
    const wire = (name: string, from: string, to: string, label?:string, thickness="0.15mm") =>
      <trace name={`CURRENT_${phase}_${name}`} from={from} to={to} schDisplayLabel={label} thickness={thickness} pcbStraightLine={phase === "B" && (name === "SENSE_POS" || name === "SENSE_NEG")} pcbPath={phase === "A" && name === "SENSE_POS" ? [{x:-2.25,y:1.15},{x:-2.25,y:2.95}] : phase === "A" && name === "SENSE_NEG" ? [{x:0.1,y:1.05},{x:0.1,y:2.95}] : undefined} maxViaCount={name === "SENSE_POS" || name === "SENSE_NEG" ? 0 : undefined} />;
    return <Fragment key={phase}>
      <FRM121WFR100TM name={shunt} {...p(shunt)} {...sch} schX={x} schY={5} />
      <INA241A1IDDFR name={amp} {...p(amp)} {...sch} schX={x} schY={0} schWidth={2} schHeight={1.71}
        schPinStyle={{pin1:{marginTop:0.65},pin4:{marginTop:0.65},pin7:{marginLeft:0.3},pin3:{marginLeft:0.3}}}
        schPinArrangement={{leftSide:{pins:[8,1],direction:"top-to-bottom"},rightSide:{pins:[5,4],direction:"top-to-bottom"},topSide:{pins:[6,7,3],direction:"left-to-right"},bottomSide:{pins:[2],direction:"left-to-right"}}} />
      <capacitor layer="bottom" name={bypass} capacitance="100nF" footprint="0402" supplierPartNumbers={{jlcpcb:["C1525"]}}
        {...p(bypass)} {...sch} schSectionName="current_supply" schX={index*2.5-2} schY={-5} schOrientation="vertical" maxDecouplingTraceLength={5}/>
      <resistor name={r} resistance="1k" footprint="0402" supplierPartNumbers={{jlcpcb:["C11702"]}}
        {...p(r)} {...sch} schX={x+4} schY={0}/>
      <capacitor name={c} capacitance="10nF" footprint="0402" supplierPartNumbers={{jlcpcb:["C15195"]}}
        {...p(c)} {...sch} schX={x+6} schY={-2} schOrientation="vertical"/>
      {wire("WINDING", `.${shunt} > .pin2`, `.J1 > .pin${index*2+1}`, `${phase}+`, "1mm")}
      {/* Independent sense branches must meet the power path at the shunt pads. */}
      {wire("SENSE_POS", `.${shunt} > .pin1`, `.${amp} > .IN_POS`, `${phase}_DRIVE`)}
      {wire("SENSE_NEG", `.${shunt} > .pin2`, `.${amp} > .IN_NEG`, `${phase}+`)}
      {wire("VCC", supply, `.${amp} > .VS`, "V3V3", "0.3mm")}
      {wire("REF1", supply, `.${amp} > .REF1`, "V3V3")}
      {wire("REF2", `.${amp} > .REF2`, "net.GND")}
      {wire("GND", `.${amp} > .GND`, "net.GND", undefined, "0.3mm")}
      {/* TI requires reserved pin 4 to be grounded, despite its NC label. */}
      {wire("RESERVED", `.${amp} > .NC`, "net.GND")}
      {wire("BYPASS", `.${bypass} > .pin1`, `.${amp} > .VS`, "V3V3", "0.3mm")}
      {wire("BYPASS_GND", `.${bypass} > .pin2`, "net.GND", undefined, "0.3mm")}
      {wire("OUT", `.${amp} > .OUT`, `.${r} > .pin1`)}
      {wire("ADC", `.${r} > .pin2`, `.MCU > .U1 > .GPIO${28+index}_ADC${2+index}`, `CURRENT_${phase}`)}
      {wire("FILTER", `.${r} > .pin2`, `.${c} > .pin1`, `CURRENT_${phase}`)}
      {wire("FILTER_GND", `.${c} > .pin2`, "net.GND")}
    </Fragment>;
  })}
</>;