techmannih/nema34-mounted-stepper-controller
A 48 V USB‑C PD 3.1 EPR NEMA‑34 stepper controller PCB combining STM32/TMC5160 control, external MOSFET motor bridges, protected power and regenerative braking, USB data, telemetry, diagnostics, status LEDs, and buzzer alarms.
- Version
- 0.3.92
- License
- unset
- Stars
- 1
firmware/src/tmc5160.c
#include "tmc5160.h"
#include "tmc5160_config.h"
#include <string.h>
#define IOIN 0x04u
#define GSTAT 0x01u
#define CHOPCONF 0x6Cu
#define DRIVER_FAULT_MASK 0x1E003000u /* OT, OTPW, S2GA/B, S2VSA/B; not open-load */
static uint32_t payload(const uint8_t rx[5]) {
return ((uint32_t)rx[1]<<24)|((uint32_t)rx[2]<<16)|((uint32_t)rx[3]<<8)|rx[4];
}
static bool frame(pd1180_tmc_t *d, uint8_t address, uint32_t value, uint8_t rx[5]) {
const uint8_t tx[5]={address,(uint8_t)(value>>24),(uint8_t)(value>>16),(uint8_t)(value>>8),(uint8_t)value};
memset(rx,0,5);
return d && d->frame && d->frame(d->context,tx,rx);
}
bool pd1180_tmc_read(pd1180_tmc_t *d, uint8_t address, uint32_t *value) {
uint8_t rx[5];
if (!value || address>0x7Fu || !frame(d,address,0,rx) || !frame(d,address,0,rx)) return false;
*value=payload(rx);
return true;
}
bool pd1180_tmc_write(pd1180_tmc_t *d, uint8_t address, uint32_t value) {
uint8_t rx[5];
if (address>0x7Fu || !frame(d,address|0x80u,value,rx) || !frame(d,IOIN,0,rx)) return false;
// The next datagram echoes the prior write, including write-only registers.
// IFCNT is UART-only; it must not be used as an SPI acknowledgement.
return payload(rx)==value;
}
void pd1180_tmc_invalidate(pd1180_tmc_t *d) { d->configured=false; d->chopconf=0; d->irun=0; }
bool pd1180_tmc_status(pd1180_tmc_t *d, pd1180_tmc_status_t *s) {
*s=(pd1180_tmc_status_t){0};
s->valid=pd1180_tmc_read(d,IOIN,&s->ioin) && (s->ioin>>24)==0x30u &&
pd1180_tmc_read(d,GSTAT,&s->gstat) && pd1180_tmc_read(d,0x6Fu,&s->drv_status);
s->fault=!s->valid || (s->gstat&7u) || (s->drv_status&DRIVER_FAULT_MASK);
if (s->fault) pd1180_tmc_invalidate(d);
return s->valid && !s->fault;
}
bool pd1180_tmc_set_current(pd1180_tmc_t *d, uint16_t permille) {
if (!d->configured || !permille || permille>PD1180_BENCH_CURRENT_MAX_PERMILLE) return false;
const uint32_t scale=(32u*permille)/1000u;
if (!scale) return false;
const uint8_t irun=(uint8_t)(scale-1u), ihold=irun<PD1180_IHOLD?irun:PD1180_IHOLD;
if (!pd1180_tmc_write(d,0x10u,(6u<<16)|((uint32_t)irun<<8)|ihold)) {
pd1180_tmc_invalidate(d); return false;
}
d->irun=irun;
return true;
}
bool pd1180_tmc_set_chopper(pd1180_tmc_t *d, bool enabled) {
if (enabled && !d->configured) return false;
const uint32_t value=enabled?PD1180_TMC_RAMP_CHOPCONF:(PD1180_TMC_RAMP_CHOPCONF&~15u);
uint32_t actual;
if (!pd1180_tmc_write(d,CHOPCONF,value) || !pd1180_tmc_read(d,CHOPCONF,&actual) || actual!=value) {
pd1180_tmc_invalidate(d); return false;
}
d->chopconf=value;
return true;
}
bool pd1180_tmc_configure_ramp(pd1180_tmc_t *d, uint16_t permille) {
pd1180_tmc_invalidate(d);
uint32_t ioin, actual;
if (!permille || permille>PD1180_BENCH_CURRENT_MAX_PERMILLE || !pd1180_tmc_read(d,IOIN,&ioin) ||
(ioin>>24)!=0x30u || (ioin&0x50u)!=0x10u || (ioin&0x0Cu)) return false;
for (size_t i=0;i<pd1180_tmc5160_boot_config_count;++i) {
const tmc5160_register_t reg=pd1180_tmc5160_boot_config[i];
if (!pd1180_tmc_write(d,reg.address,reg.value)) return false;
}
if (!pd1180_tmc_read(d,CHOPCONF,&actual) || actual!=(PD1180_TMC_RAMP_CHOPCONF&~15u) ||
!pd1180_tmc_read(d,0x00u,&actual) || actual!=PD1180_TMC_RAMP_GCONF ||
!pd1180_tmc_read(d,0x22u,&actual) || (actual&0xFFFFFFu)!=0u ||
!pd1180_tmc_write(d,GSTAT,7u)) return false;
d->chopconf=PD1180_TMC_RAMP_CHOPCONF&~15u;
pd1180_tmc_status_t status;
if (!pd1180_tmc_status(d,&status)) return false;
d->configured=true;
return pd1180_tmc_set_current(d,permille);
}
bool pd1180_tmc_velocity(pd1180_tmc_t *d, uint32_t target) {
if (!d->configured || target>PD1180_BENCH_VMAX) return false;
if (!pd1180_tmc_write(d,0x27u,target)) { pd1180_tmc_invalidate(d); return false; }
return true;
}
bool pd1180_tmc_actual_velocity(pd1180_tmc_t *d, int32_t *velocity) {
uint32_t raw;
if (!velocity || !d->configured || !pd1180_tmc_read(d,0x22u,&raw)) return false;
raw &= 0xFFFFFFu;
*velocity = (raw&0x800000u) ? (int32_t)(raw|0xFF000000u) : (int32_t)raw;
return true;
}