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_rp2040_driver.c
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "drv8262.h"
#include "as5600.h"
#include "step_motion.h"
typedef struct {drv8262_output_t last; bool fail; unsigned calls;} fake_t;
static bool apply(void *ctx,const drv8262_output_t *out) {
fake_t *f=ctx;f->calls++;f->last=*out;return !f->fail;
}
static void drivers(void) {
fake_t f={0};drv8262_t d={.apply=apply,.context=&f};
assert(!drv8262_configure(&d,800,false) && f.calls==0);
assert(!drv8262_configure(&d,801,true) && f.calls==0);
assert(drv8262_configure(&d,800,true) && d.configured && !d.enabled);
assert(!f.last.enable_a && !f.last.enable_b && f.last.word_a==0x1000 && f.last.word_b==0x9000);
assert(drv8262_enable(&d,true));
// 800mA RMS => 1131mA peak => 359mV nominal. B is zero at phase 0.
assert((f.last.word_a&4095)==359 && (f.last.word_b&4095)==0);
assert(f.last.enable_a && !f.last.enable_b && f.last.phase_a);
for(unsigned k=1;k<=64;k++) {
assert(drv8262_step(&d,false));
const unsigned a=f.last.word_a&4095,b=f.last.word_b&4095;
assert(a<=359 && b<=359);
assert(f.last.enable_a==(a>=50) && f.last.enable_b==(b>=50));
// Constant current-vector magnitude, allowing DAC quantization and the
// specified <50mV zero-crossing blanking, not a mirror of the sine table.
const unsigned square=a*a+b*b;
assert(square>126000 && square<=130000);
if(k==16) assert(!f.last.enable_a && f.last.phase_b && b==359);
if(k==32) assert(!f.last.phase_a && a==359 && !f.last.enable_b);
if(k==48) assert(!f.last.enable_a && !f.last.phase_b && b==359);
}
assert(d.microstep==0);assert(drv8262_step(&d,true) && d.microstep==63);
assert(drv8262_set_current(&d,400));assert((f.last.word_a&4095)<300);
assert(drv8262_enable(&d,false));assert(!f.last.enable_a && !f.last.enable_b);
assert(!drv8262_step(&d,false));
f.fail=true;assert(!drv8262_enable(&d,true) && !d.configured && !d.enabled);
assert(!drv8262_configure(&d,800,true));
f.fail=false;assert(drv8262_configure(&d,800,true));
assert(!drv8262_set_current(&d,801) && !d.configured);
assert(!drv8262_output(0,0,true,&f.last));
}
static bool encoder(void *ctx,uint8_t reg,uint8_t *data,uint8_t count) {
assert(reg==0x0b && count==3);memcpy(data,ctx,3);return true;
}
static void encoders(void) {
as5600_sample_t s;uint8_t bytes[]={0x20,0x0a,0xbc};
assert(as5600_sample(encoder,bytes,&s) && s.angle==0xabc);
for(unsigned n=0;n<3;n++) {bytes[0]=(uint8_t[]){0,0x30,0x28}[n];assert(!as5600_sample(encoder,bytes,&s) && !s.valid);}
bytes[0]=0x20;bytes[1]=0xfa;assert(!as5600_sample(encoder,bytes,&s));
assert(!as5600_sample(NULL,NULL,&s));
}
static void steps(void) {
step_motion_t s={0};uint32_t now=0xfffffff0u;unsigned pulses=0;
step_motion_renew(&s,now,true);
for(unsigned n=0;n<100000;n++) {
now+=20;
if(n%500==0)step_motion_renew(&s,now,true);
if(step_motion_tick(&s,now,true)) pulses++;
}
assert(s.speed_millihz==STEP_MOTION_MAX_MILLIHZ);assert(pulses>790 && pulses<810);
step_motion_renew(&s,now,false);
for(unsigned n=0;n<51000;n++){now+=20;if(n%500==0)step_motion_renew(&s,now,false);step_motion_tick(&s,now,true);}
assert(!s.active && !s.high && !s.speed_millihz);
step_motion_renew(&s,now,true);assert(!step_motion_tick(&s,now+20,false));assert(!s.active);
step_motion_renew(&s,now,true);
for(unsigned n=1;n<=1250;n++)step_motion_tick(&s,now+n*20,true);
assert(!s.active); // expired 25 ms main-loop lease
step_motion_renew(&s,now,true);assert(!step_motion_tick(&s,now+101,true) && !s.active);
}
int main(void){drivers();encoders();steps();puts("DRV8262 current vector/limits/transport failures, AS5600 validity, timed STEP/stop/lease/wraparound: PASS");}