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/tests/test_pd_voltage.c

#include "pd_voltage.h"
#include <assert.h>
#include <stdio.h>

typedef struct { uint16_t config, adc, raw, id, status; bool fail, ready; unsigned triggers; } fake_t;
static bool read_reg(void *p, uint8_t reg, uint16_t *v) {
  fake_t *f=p; if(f->fail) return false;
  switch(reg) {
    case 0:*v=f->config;break; case 1:*v=f->adc;break;
    case 0x05:*v=f->raw;break; case 0x3E:*v=f->id;break;
    case 0x0B:*v=f->status|(f->ready?2u:0u); f->ready=false;break;
    default:assert(0);return false;
  } return true;
}
static bool write_reg(void *p,uint8_t reg,uint16_t v) {
  fake_t *f=p;if(f->fail)return false;
  if(reg==0)f->config=v;
  else if(reg==1) {f->adc=v; f->ready=false; ++f->triggers;}
  else assert(0);
  return true;
}
int main(void) {
  fake_t f={.raw=15360,.id=0x5449,.status=1};
  pd1180_voltage_bus_t bus={read_reg,write_reg,&f};
  pd1180_pd_voltage_t s={0};
  assert(!pd1180_pd_voltage_fresh(&s,0));
  pd1180_pd_voltage_poll(&s,&bus,0); assert(s.pending && !s.valid && f.triggers==1);
  pd1180_pd_voltage_poll(&s,&bus,10); assert(!s.valid); // Old readable raw is insufficient.
  f.ready=true;pd1180_pd_voltage_poll(&s,&bus,20);
  assert(s.valid && s.millivolts==48000 && pd1180_pd_voltage_in_range(&s,20));
  assert(pd1180_pd_voltage_fresh(&s,120) && !pd1180_pd_voltage_fresh(&s,121));
  pd1180_pd_voltage_poll(&s,&bus,40); assert(f.triggers==2);
  pd1180_pd_voltage_poll(&s,&bus,60); assert(s.sampled_at==20);
  pd1180_pd_voltage_poll(&s,&bus,61); assert(!s.valid && !s.configured); // Stalled converter.
  pd1180_pd_voltage_poll(&s,&bus,70);f.adc=0xFB68;
  pd1180_pd_voltage_poll(&s,&bus,80);assert(!s.valid); // Sensor reset/configuration drift.
  pd1180_pd_voltage_poll(&s,&bus,90);f.ready=true; f.status=0;
  pd1180_pd_voltage_poll(&s,&bus,100);assert(!s.valid); // Trim checksum failure.
  f.status=1;f.id=0xFFFF;pd1180_pd_voltage_poll(&s,&bus,110);assert(!s.configured);
  f.id=0x5449;
  const uint16_t raw[]={1600,6400,8960,14080,16320,17600,27200,65535};
  const uint32_t mv[]={5000,20000,28000,44000,51000,55000,85000,0};
  for(unsigned i=0;i<sizeof(raw)/sizeof(*raw);++i) {
    s=(pd1180_pd_voltage_t){0};f.raw=raw[i];
    pd1180_pd_voltage_poll(&s,&bus,UINT32_MAX-4u); f.ready=true;
    pd1180_pd_voltage_poll(&s,&bus,5);
    assert(s.millivolts==mv[i]);
    assert(s.valid==(i!=7));
    assert(pd1180_pd_voltage_in_range(&s,5)==(i==3||i==4));
    assert(!pd1180_pd_voltage_fresh(&s,106));
  }
  s=(pd1180_pd_voltage_t){.valid=true,.millivolts=48000}; f.fail=true;
  pd1180_pd_voltage_poll(&s,&bus,1);assert(!s.valid && s.millivolts==0);
  puts("PASS: INA237 conversion freshness, I2C loss, reset, trim failure, scaling, range and timer wrap");
}