techmannih/nema34-mounted-stepper-controller

A USB-C PD-powered RP2040 motor controller with protected 48 V power, DRV8262 dual-bridge drive for a NEMA34 motor, regenerative-braking resistor, isolated sensing, hardware interlocks, and telemetry/status interfaces.

Version
0.3.113
License
unset
Stars
1

firmware/src/pd_voltage.c

#include "pd_voltage.h"

/* TI SBOSA20A: bus-only single shot, 1052 us, one sample. INA237 has
 * MANUFACTURER_ID but no documented DEVICE_ID register; do not probe 0x3F.
 * 16-bit VBUS at 0x05 is unsigned, with a 3.125 mV LSB. */
#define BUS_SINGLE_SHOT 0x1A00u

void pd1180_pd_voltage_poll(pd1180_pd_voltage_t *s, const pd1180_voltage_bus_t *bus, uint32_t now) {
  uint16_t config, status, raw;
  if (!s || !bus || !bus->read || !bus->write) { if (s) *s=(pd1180_pd_voltage_t){0}; return; }
  if (!s->configured) {
    if (!bus->read(bus->context,0x3E,&raw) || raw!=0x5449u ||
        !bus->write(bus->context,0x00,0) || !bus->read(bus->context,0x00,&config) || config!=0)
      goto failed;
    s->configured=true;
  }
  if (!s->pending) {
    if (s->valid && now-s->sampled_at<20u) return;
    /* Starting a new conversion clears CNVRF. A readable old VBUS register
     * cannot renew freshness without a newly completed conversion. */
    if (!bus->write(bus->context,0x01,BUS_SINGLE_SHOT)) goto failed;
    s->pending=true; s->triggered_at=now;
    return;
  }
  if (now-s->triggered_at>20u) goto failed;
  if (now-s->triggered_at<2u) return;
  if (!bus->read(bus->context,0x00,&config) || config!=0 ||
      !bus->read(bus->context,0x01,&config) || config!=BUS_SINGLE_SHOT ||
      !bus->read(bus->context,0x0B,&status) || !(status&1u)) goto failed;
  if (!(status&2u)) return;
  if (!bus->read(bus->context,0x05,&raw)) goto failed;
  s->millivolts=(uint32_t)raw*25u/8u;
  if (s->millivolts>85000u) goto failed;
  s->sampled_at=now; s->valid=true; s->pending=false;
  return;
failed:
  *s=(pd1180_pd_voltage_t){0};
}

bool pd1180_pd_voltage_fresh(const pd1180_pd_voltage_t *s, uint32_t now) {
  return s && s->valid && now-s->sampled_at<=100u;
}
bool pd1180_pd_voltage_in_range(const pd1180_pd_voltage_t *s, uint32_t now) {
  /* Engineering operating window, matching the existing VMOTOR interlock.
   * This does not certify USB-PD accuracy or replace the hardware OVP. */
  return pd1180_pd_voltage_fresh(s,now) && s->millivolts>=44000u && s->millivolts<=51000u;
}