CGcontroller/tmc5160_driver/tmc5160.c

835 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file tmc5160.c
* @brief TMC5160 步进电机驱动芯片驱动实现
* @note 支持 SPI 和 UART 双接口,完整运动控制 + StallGuard4
* 适用于 STM32F103C8T6 + HAL 库 (CubeMX 生成框架)
*/
#include "tmc5160.h"
#include <string.h>
/* ======================== 内部宏定义 ======================== */
#define TMC5160_WRITE_BIT 0x80 /* 寄存器写标志位 */
#define TMC5160_UART_SYNC 0x05 /* UART 同步字节 */
#define TMC5160_SPI_TIMEOUT 100 /* SPI 超时 (ms) */
#define TMC5160_UART_TIMEOUT 10 /* UART 超时 (ms) */
/* ======================== SPI 片选控制 ======================== */
static inline void TMC5160_CS_Low(TMC5160_HandleTypeDef *htmc)
{
HAL_GPIO_WritePin(htmc->cs_port, htmc->cs_pin, GPIO_PIN_RESET);
}
static inline void TMC5160_CS_High(TMC5160_HandleTypeDef *htmc)
{
HAL_GPIO_WritePin(htmc->cs_port, htmc->cs_pin, GPIO_PIN_SET);
}
/* ================================================================
* UART CRC8 计算
* TMC5160 UART 协议使用 CRC8多项式 0x07初始值 0
* ================================================================ */
static uint8_t TMC5160_CalcCRC(uint8_t *data, uint8_t len)
{
uint8_t crc = 0;
for (uint8_t i = 0; i < len; i++) {
uint8_t byte = data[i];
for (uint8_t j = 0; j < 8; j++) {
if ((crc >> 7) ^ (byte >> 7)) {
crc = (crc << 1) ^ 0x07;
} else {
crc = crc << 1;
}
byte <<= 1;
}
}
return crc;
}
/* ================================================================
* SPI 寄存器读写
* 40-bit 数据帧: [地址(8bit)] + [数据(32bit)]
* 写: 地址 bit7=1; 读: 地址 bit7=0
* 返回上一次读取的数据,因此读操作需要发送两次
* ================================================================ */
static void TMC5160_SPI_ReadWrite(TMC5160_HandleTypeDef *htmc,
uint8_t *tx, uint8_t *rx, uint8_t len)
{
TMC5160_CS_Low(htmc);
HAL_SPI_TransmitReceive(htmc->hspi, tx, rx, len, TMC5160_SPI_TIMEOUT);
TMC5160_CS_High(htmc);
}
static void TMC5160_SPI_WriteRegister(TMC5160_HandleTypeDef *htmc,
uint8_t reg, uint32_t value)
{
uint8_t tx[5], rx[5];
tx[0] = reg | TMC5160_WRITE_BIT;
tx[1] = (value >> 24) & 0xFF;
tx[2] = (value >> 16) & 0xFF;
tx[3] = (value >> 8) & 0xFF;
tx[4] = value & 0xFF;
TMC5160_SPI_ReadWrite(htmc, tx, rx, 5);
htmc->spi_status = rx[0]; /* 保存状态字节 */
}
static uint32_t TMC5160_SPI_ReadRegister(TMC5160_HandleTypeDef *htmc, uint8_t reg)
{
uint8_t tx[5] = {0}, rx[5] = {0};
/* 第一次传输:发送读请求 */
tx[0] = reg & 0x7F;
TMC5160_SPI_ReadWrite(htmc, tx, rx, 5);
/* 第二次传输:获取实际数据 */
memset(tx, 0, 5);
tx[0] = reg & 0x7F;
TMC5160_SPI_ReadWrite(htmc, tx, rx, 5);
htmc->spi_status = rx[0];
return ((uint32_t)rx[1] << 24) | ((uint32_t)rx[2] << 16) |
((uint32_t)rx[3] << 8) | (uint32_t)rx[4];
}
/* ================================================================
* UART 寄存器读写
* 写帧: [SYNC(0x05)] [SLAVE_ADDR] [REG|0x80] [DATA x4] [CRC] 共8字节
* 读请求: [SYNC] [SLAVE_ADDR] [REG] [CRC] 共4字节
* 读响应: [SYNC] [0xFF] [REG] [DATA x4] [CRC] 共8字节
* ================================================================ */
static void TMC5160_UART_WriteRegister(TMC5160_HandleTypeDef *htmc,
uint8_t reg, uint32_t value)
{
uint8_t tx[8];
tx[0] = TMC5160_UART_SYNC;
tx[1] = htmc->slave_addr;
tx[2] = reg | TMC5160_WRITE_BIT;
tx[3] = (value >> 24) & 0xFF;
tx[4] = (value >> 16) & 0xFF;
tx[5] = (value >> 8) & 0xFF;
tx[6] = value & 0xFF;
tx[7] = TMC5160_CalcCRC(tx, 7);
HAL_UART_Transmit(htmc->huart, tx, 8, TMC5160_UART_TIMEOUT);
/* 等待总线释放(单线半双工需要等回显消失) */
HAL_Delay(1);
}
static uint32_t TMC5160_UART_ReadRegister(TMC5160_HandleTypeDef *htmc, uint8_t reg)
{
uint8_t tx[4], rx[8];
/* 构造读请求帧 */
tx[0] = TMC5160_UART_SYNC;
tx[1] = htmc->slave_addr;
tx[2] = reg & 0x7F;
tx[3] = TMC5160_CalcCRC(tx, 3);
/* 发送读请求 */
HAL_UART_Transmit(htmc->huart, tx, 4, TMC5160_UART_TIMEOUT);
/* 接收响应 (8字节: sync + master_addr + reg + data[4] + crc) */
memset(rx, 0, 8);
HAL_UART_Receive(htmc->huart, rx, 8, TMC5160_UART_TIMEOUT);
/* 校验 CRC */
uint8_t crc = TMC5160_CalcCRC(rx, 7);
if (crc != rx[7]) {
return 0xFFFFFFFF; /* CRC 错误返回全1 */
}
return ((uint32_t)rx[3] << 24) | ((uint32_t)rx[4] << 16) |
((uint32_t)rx[5] << 8) | (uint32_t)rx[6];
}
/* ================================================================
* 统一寄存器读写接口
* 根据句柄中的 interface 字段自动选择 SPI 或 UART
* ================================================================ */
void TMC5160_WriteRegister(TMC5160_HandleTypeDef *htmc, uint8_t reg, uint32_t value)
{
if (htmc->interface == TMC5160_INTERFACE_SPI) {
TMC5160_SPI_WriteRegister(htmc, reg, value);
} else {
TMC5160_UART_WriteRegister(htmc, reg, value);
}
}
uint32_t TMC5160_ReadRegister(TMC5160_HandleTypeDef *htmc, uint8_t reg)
{
if (htmc->interface == TMC5160_INTERFACE_SPI) {
return TMC5160_SPI_ReadRegister(htmc, reg);
} else {
return TMC5160_UART_ReadRegister(htmc, reg);
}
}
/* ================================================================
* 初始化与复位
* ================================================================ */
/**
* @brief 初始化 TMC5160
* @param htmc TMC5160 句柄(需预先填充接口类型和外设指针)
* @param config 初始化配置参数
* @retval HAL_OK 成功, HAL_ERROR 芯片通信失败
*/
HAL_StatusTypeDef TMC5160_Init(TMC5160_HandleTypeDef *htmc, TMC5160_InitTypeDef *config)
{
/* 如果是 SPI 接口,先拉高片选 */
if (htmc->interface == TMC5160_INTERFACE_SPI) {
TMC5160_CS_High(htmc);
HAL_Delay(10);
}
/* 读取 IOIN 寄存器验证通信高8位包含芯片版本号TMC5160 = 0x30 */
uint32_t ioin = TMC5160_ReadRegister(htmc, TMC5160_IOIN);
uint8_t version = (ioin >> 24) & 0xFF;
if (version != 0x30) {
return HAL_ERROR; /* 芯片版本不匹配,通信可能有问题 */
}
/* 清除全局状态标志 */
TMC5160_WriteRegister(htmc, TMC5160_GSTAT, 0x07);
/* 全局电流缩放 */
if (config->global_scaler > 0) {
TMC5160_WriteRegister(htmc, TMC5160_GLOBAL_SCALER, config->global_scaler);
}
/* 设置运行/保持电流 */
TMC5160_SetIHoldIRun(htmc, config->hold_current, config->run_current, config->hold_delay);
/* 停止后降功率延迟 */
TMC5160_WriteRegister(htmc, TMC5160_TPOWERDOWN, 10);
/* 配置斩波器: TOFF + HSTRT + HEND + TBL + 细分 + 插值 */
uint32_t chopconf = 0;
chopconf |= (config->toff & 0x0F);
chopconf |= ((uint32_t)(config->hstrt & 0x07) << TMC5160_CHOPCONF_HSTRT_SHIFT);
chopconf |= ((uint32_t)(config->hend & 0x0F) << TMC5160_CHOPCONF_HEND_SHIFT);
chopconf |= ((uint32_t)(config->tbl & 0x03) << TMC5160_CHOPCONF_TBL_SHIFT);
chopconf |= ((uint32_t)config->microstep_res << TMC5160_CHOPCONF_MRES_SHIFT);
if (config->interpolation) {
chopconf |= TMC5160_CHOPCONF_INTPOL;
}
TMC5160_WriteRegister(htmc, TMC5160_CHOPCONF, chopconf);
/* 配置 GCONF: StealthChop 使能 + 方向 + 多步滤波 */
uint32_t gconf = TMC5160_GCONF_MULTISTEP_FILT;
if (config->en_pwm_mode) {
gconf |= TMC5160_GCONF_EN_PWM_MODE;
}
if (config->shaft) {
gconf |= TMC5160_GCONF_SHAFT;
}
TMC5160_WriteRegister(htmc, TMC5160_GCONF, gconf);
/* StealthChop PWM 默认配置 (自动调节) */
/* PWM_AUTOSCALE=1, PWM_AUTOGRAD=1, PWM_FREQ=01, PWM_OFS=36 */
TMC5160_WriteRegister(htmc, TMC5160_PWMCONF, 0xC40C001E);
/* 短路保护默认配置 */
TMC5160_WriteRegister(htmc, TMC5160_SHORT_CONF, 0x00010606);
TMC5160_WriteRegister(htmc, TMC5160_DRV_CONF, 0x00080400);
/* 初始化斜坡参数为安全默认值 */
TMC5160_WriteRegister(htmc, TMC5160_VSTART, 0);
TMC5160_WriteRegister(htmc, TMC5160_VSTOP, 10);
TMC5160_WriteRegister(htmc, TMC5160_AMAX, 1000);
TMC5160_WriteRegister(htmc, TMC5160_DMAX, 1000);
TMC5160_WriteRegister(htmc, TMC5160_A1, 500);
TMC5160_WriteRegister(htmc, TMC5160_D1, 500);
TMC5160_WriteRegister(htmc, TMC5160_V1, 50000);
TMC5160_WriteRegister(htmc, TMC5160_VMAX, 100000);
TMC5160_WriteRegister(htmc, TMC5160_RAMPMODE, TMC5160_MODE_POSITION);
return HAL_OK;
}
/**
* @brief 反初始化 TMC5160停止电机并关闭驱动
*/
void TMC5160_DeInit(TMC5160_HandleTypeDef *htmc)
{
TMC5160_Stop(htmc);
HAL_Delay(10);
/* TOFF=0 关闭驱动桥 */
uint32_t chopconf = TMC5160_ReadRegister(htmc, TMC5160_CHOPCONF);
chopconf &= ~TMC5160_CHOPCONF_TOFF_MASK;
TMC5160_WriteRegister(htmc, TMC5160_CHOPCONF, chopconf);
}
/**
* @brief 获取芯片版本号
* @retval 版本号 (TMC5160 应返回 0x30)
*/
uint32_t TMC5160_GetVersion(TMC5160_HandleTypeDef *htmc)
{
uint32_t ioin = TMC5160_ReadRegister(htmc, TMC5160_IOIN);
return (ioin >> 24) & 0xFF;
}
/* ================================================================
* 运动控制
* ================================================================ */
/** @brief 设置斜坡模式 */
void TMC5160_SetRampMode(TMC5160_HandleTypeDef *htmc, TMC5160_RampMode mode)
{
TMC5160_WriteRegister(htmc, TMC5160_RAMPMODE, (uint32_t)mode);
}
/**
* @brief 绝对定位运动
* @param position 目标位置(微步单位)
*/
void TMC5160_MoveTo(TMC5160_HandleTypeDef *htmc, int32_t position)
{
TMC5160_WriteRegister(htmc, TMC5160_RAMPMODE, TMC5160_MODE_POSITION);
TMC5160_WriteRegister(htmc, TMC5160_XTARGET, (uint32_t)position);
}
/**
* @brief 相对定位运动
* @param offset 相对偏移量(微步单位,正/负)
*/
void TMC5160_MoveBy(TMC5160_HandleTypeDef *htmc, int32_t offset)
{
int32_t current = TMC5160_GetActualPosition(htmc);
TMC5160_MoveTo(htmc, current + offset);
}
/**
* @brief 速度模式旋转
* @param velocity 目标速度正值正转负值反转0停止
*/
void TMC5160_Rotate(TMC5160_HandleTypeDef *htmc, int32_t velocity)
{
if (velocity >= 0) {
TMC5160_WriteRegister(htmc, TMC5160_RAMPMODE, TMC5160_MODE_VEL_POS);
TMC5160_WriteRegister(htmc, TMC5160_VMAX, (uint32_t)velocity);
} else {
TMC5160_WriteRegister(htmc, TMC5160_RAMPMODE, TMC5160_MODE_VEL_NEG);
TMC5160_WriteRegister(htmc, TMC5160_VMAX, (uint32_t)(-velocity));
}
}
/** @brief 减速停止电机 */
void TMC5160_Stop(TMC5160_HandleTypeDef *htmc)
{
TMC5160_WriteRegister(htmc, TMC5160_VMAX, 0);
TMC5160_WriteRegister(htmc, TMC5160_RAMPMODE, TMC5160_MODE_VEL_POS);
}
/** @brief 检查是否到达目标位置 (定位模式) */
uint8_t TMC5160_IsPositionReached(TMC5160_HandleTypeDef *htmc)
{
uint32_t stat = TMC5160_ReadRegister(htmc, TMC5160_RAMP_STAT);
return (stat & TMC5160_RS_POS_REACHED) ? 1 : 0;
}
/** @brief 检查是否到达目标速度 (速度模式) */
uint8_t TMC5160_IsVelocityReached(TMC5160_HandleTypeDef *htmc)
{
uint32_t stat = TMC5160_ReadRegister(htmc, TMC5160_RAMP_STAT);
return (stat & TMC5160_RS_VEL_REACHED) ? 1 : 0;
}
/* ================================================================
* 位置与速度读写
* ================================================================ */
void TMC5160_SetTargetPosition(TMC5160_HandleTypeDef *htmc, int32_t position)
{
TMC5160_WriteRegister(htmc, TMC5160_XTARGET, (uint32_t)position);
}
int32_t TMC5160_GetTargetPosition(TMC5160_HandleTypeDef *htmc)
{
return (int32_t)TMC5160_ReadRegister(htmc, TMC5160_XTARGET);
}
void TMC5160_SetActualPosition(TMC5160_HandleTypeDef *htmc, int32_t position)
{
TMC5160_WriteRegister(htmc, TMC5160_XACTUAL, (uint32_t)position);
}
int32_t TMC5160_GetActualPosition(TMC5160_HandleTypeDef *htmc)
{
return (int32_t)TMC5160_ReadRegister(htmc, TMC5160_XACTUAL);
}
int32_t TMC5160_GetActualVelocity(TMC5160_HandleTypeDef *htmc)
{
return (int32_t)TMC5160_ReadRegister(htmc, TMC5160_VACTUAL);
}
/* ================================================================
* 斜坡参数设置
* 六点斜坡: VSTART -> A1 -> V1 -> AMAX -> VMAX (加速)
* VMAX -> DMAX -> V1 -> D1 -> VSTOP (减速)
* ================================================================ */
void TMC5160_SetVMAX(TMC5160_HandleTypeDef *htmc, uint32_t vmax)
{
TMC5160_WriteRegister(htmc, TMC5160_VMAX, vmax & 0x7FFFFF);
}
void TMC5160_SetAMAX(TMC5160_HandleTypeDef *htmc, uint32_t amax)
{
TMC5160_WriteRegister(htmc, TMC5160_AMAX, amax & 0xFFFF);
}
void TMC5160_SetDMAX(TMC5160_HandleTypeDef *htmc, uint32_t dmax)
{
TMC5160_WriteRegister(htmc, TMC5160_DMAX, dmax & 0xFFFF);
}
void TMC5160_SetV1(TMC5160_HandleTypeDef *htmc, uint32_t v1)
{
TMC5160_WriteRegister(htmc, TMC5160_V1, v1 & 0xFFFFF);
}
void TMC5160_SetA1(TMC5160_HandleTypeDef *htmc, uint32_t a1)
{
TMC5160_WriteRegister(htmc, TMC5160_A1, a1 & 0xFFFF);
}
void TMC5160_SetD1(TMC5160_HandleTypeDef *htmc, uint32_t d1)
{
TMC5160_WriteRegister(htmc, TMC5160_D1, d1 & 0xFFFF);
}
void TMC5160_SetVSTART(TMC5160_HandleTypeDef *htmc, uint32_t vstart)
{
TMC5160_WriteRegister(htmc, TMC5160_VSTART, vstart & 0x3FFFF);
}
void TMC5160_SetVSTOP(TMC5160_HandleTypeDef *htmc, uint32_t vstop)
{
TMC5160_WriteRegister(htmc, TMC5160_VSTOP, vstop & 0x3FFFF);
}
void TMC5160_SetTZEROWAIT(TMC5160_HandleTypeDef *htmc, uint32_t tzerowait)
{
TMC5160_WriteRegister(htmc, TMC5160_TZEROWAIT, tzerowait & 0xFFFF);
}
/* ================================================================
* 电流控制
* IHOLD_IRUN 寄存器: [IHOLDDELAY(19:16)] [IRUN(12:8)] [IHOLD(4:0)]
* 电流值 0-31实际电流 = (value+1)/32 * GLOBAL_SCALER/256 * V_REF/R_SENSE
* ================================================================ */
void TMC5160_SetIHoldIRun(TMC5160_HandleTypeDef *htmc,
uint8_t ihold, uint8_t irun, uint8_t iholddelay)
{
uint32_t val = ((uint32_t)(iholddelay & 0x0F) << 16) |
((uint32_t)(irun & 0x1F) << 8) |
(uint32_t)(ihold & 0x1F);
TMC5160_WriteRegister(htmc, TMC5160_IHOLD_IRUN, val);
}
void TMC5160_SetRunCurrent(TMC5160_HandleTypeDef *htmc, uint8_t current)
{
uint32_t val = TMC5160_ReadRegister(htmc, TMC5160_IHOLD_IRUN);
val &= ~(0x1FUL << 8);
val |= ((uint32_t)(current & 0x1F) << 8);
TMC5160_WriteRegister(htmc, TMC5160_IHOLD_IRUN, val);
}
void TMC5160_SetHoldCurrent(TMC5160_HandleTypeDef *htmc, uint8_t current)
{
uint32_t val = TMC5160_ReadRegister(htmc, TMC5160_IHOLD_IRUN);
val &= ~0x1FUL;
val |= (uint32_t)(current & 0x1F);
TMC5160_WriteRegister(htmc, TMC5160_IHOLD_IRUN, val);
}
void TMC5160_SetGlobalScaler(TMC5160_HandleTypeDef *htmc, uint8_t scaler)
{
TMC5160_WriteRegister(htmc, TMC5160_GLOBAL_SCALER, scaler);
}
/* ================================================================
* 斩波器配置
* ================================================================ */
/**
* @brief 设置斩波器参数
* @param toff 关断时间 (3-15, 推荐3-5, 0=驱动关闭)
* @param hstrt 迟滞起始值 (0-7)
* @param hend 迟滞结束值 (0-15, 实际值 = hend - 3)
* @param tbl 比较器空白时间 (0-3, 推荐2)
*/
void TMC5160_SetChopConf(TMC5160_HandleTypeDef *htmc,
uint8_t toff, uint8_t hstrt, uint8_t hend, uint8_t tbl)
{
uint32_t val = TMC5160_ReadRegister(htmc, TMC5160_CHOPCONF);
/* 清除相关位 */
val &= ~(0x0FUL | (0x07UL << 4) | (0x0FUL << 7) | (0x03UL << 15));
/* 写入新值 */
val |= (toff & 0x0F);
val |= ((uint32_t)(hstrt & 0x07) << TMC5160_CHOPCONF_HSTRT_SHIFT);
val |= ((uint32_t)(hend & 0x0F) << TMC5160_CHOPCONF_HEND_SHIFT);
val |= ((uint32_t)(tbl & 0x03) << TMC5160_CHOPCONF_TBL_SHIFT);
TMC5160_WriteRegister(htmc, TMC5160_CHOPCONF, val);
}
/** @brief 设置细分 */
void TMC5160_SetMicrostepResolution(TMC5160_HandleTypeDef *htmc, TMC5160_MicrostepRes mres)
{
uint32_t val = TMC5160_ReadRegister(htmc, TMC5160_CHOPCONF);
val &= ~(0x0FUL << TMC5160_CHOPCONF_MRES_SHIFT);
val |= ((uint32_t)mres << TMC5160_CHOPCONF_MRES_SHIFT);
TMC5160_WriteRegister(htmc, TMC5160_CHOPCONF, val);
}
/** @brief 启用/禁用 256 细分插值 */
void TMC5160_EnableInterpolation(TMC5160_HandleTypeDef *htmc, uint8_t enable)
{
uint32_t val = TMC5160_ReadRegister(htmc, TMC5160_CHOPCONF);
if (enable) {
val |= TMC5160_CHOPCONF_INTPOL;
} else {
val &= ~TMC5160_CHOPCONF_INTPOL;
}
TMC5160_WriteRegister(htmc, TMC5160_CHOPCONF, val);
}
/* ================================================================
* StealthChop / SpreadCycle
* StealthChop: 低速静音模式 (GCONF.en_pwm_mode=1)
* SpreadCycle: 高速高精度模式
* TPWMTHRS: 速度低于此阈值时使用 StealthChop高于时切换 SpreadCycle
* ================================================================ */
void TMC5160_EnableStealthChop(TMC5160_HandleTypeDef *htmc, uint8_t enable)
{
uint32_t gconf = TMC5160_ReadRegister(htmc, TMC5160_GCONF);
if (enable) {
gconf |= TMC5160_GCONF_EN_PWM_MODE;
} else {
gconf &= ~TMC5160_GCONF_EN_PWM_MODE;
}
TMC5160_WriteRegister(htmc, TMC5160_GCONF, gconf);
}
void TMC5160_SetPWMConf(TMC5160_HandleTypeDef *htmc, uint32_t pwmconf)
{
TMC5160_WriteRegister(htmc, TMC5160_PWMCONF, pwmconf);
}
void TMC5160_SetTPWMTHRS(TMC5160_HandleTypeDef *htmc, uint32_t tpwmthrs)
{
TMC5160_WriteRegister(htmc, TMC5160_TPWMTHRS, tpwmthrs & 0xFFFFF);
}
/* ================================================================
* StallGuard4 堵转检测
*
* 工作原理: 通过检测电机反电动势来判断负载情况
* SG_RESULT: 0=高负载/堵转, 值越大负载越轻
* SGT: StallGuard 阈值 (-64 ~ +63),值越大越不敏感
*
* 使用条件:
* 1. 必须设置 TCOOLTHRS速度高于此阈值时 StallGuard 才工作
* 2. 建议在 SpreadCycle 模式下使用(更准确)
* 3. StealthChop 模式下也可用,但需速度高于 TPWMTHRS
* ================================================================ */
/**
* @brief 设置 StallGuard 灵敏度阈值
* @param sgt 阈值 (-64 ~ +63),值越小越敏感
* 推荐从 0 开始调试,堵转时降低,误触发时升高
*/
void TMC5160_SetStallGuardThreshold(TMC5160_HandleTypeDef *htmc, int8_t sgt)
{
uint32_t val = TMC5160_ReadRegister(htmc, TMC5160_COOLCONF);
val &= ~(0x7FUL << 16); /* 清除 SGT 位 [22:16] */
val |= ((uint32_t)(sgt & 0x7F) << 16);
TMC5160_WriteRegister(htmc, TMC5160_COOLCONF, val);
}
/**
* @brief 设置 CoolStep/StallGuard 速度下限阈值
* @note 只有当 TSTEP < TCOOLTHRS 时 StallGuard 才激活
* TSTEP 与速度成反比,所以 TCOOLTHRS 越大,激活速度越低
*/
void TMC5160_SetTCOOLTHRS(TMC5160_HandleTypeDef *htmc, uint32_t tcoolthrs)
{
TMC5160_WriteRegister(htmc, TMC5160_TCOOLTHRS, tcoolthrs & 0xFFFFF);
}
/**
* @brief 设置高速模式切换阈值
* @note TSTEP < THIGH 时切换到全步模式(如果 VHIGHFS 使能)
*/
void TMC5160_SetTHIGH(TMC5160_HandleTypeDef *htmc, uint32_t thigh)
{
TMC5160_WriteRegister(htmc, TMC5160_THIGH, thigh & 0xFFFFF);
}
/**
* @brief 获取 StallGuard 结果值
* @retval SG_RESULT (0-1023)0=堵转,值越大负载越轻
*/
uint16_t TMC5160_GetStallGuardResult(TMC5160_HandleTypeDef *htmc)
{
uint32_t status = TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS);
return (uint16_t)(status & TMC5160_DRV_SG_RESULT_MASK);
}
/**
* @brief 检查电机是否堵转
* @retval 1=堵转, 0=正常
*/
uint8_t TMC5160_IsStalled(TMC5160_HandleTypeDef *htmc)
{
uint32_t status = TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS);
return (status & TMC5160_DRV_STALLGUARD) ? 1 : 0;
}
/**
* @brief 启用/禁用 StallGuard 自动停止功能
* @note 启用后堵转时电机自动停止RAMP_STAT.event_stop_sg 置位
* 通过 SW_MODE 寄存器的 sg_stop 位控制
*/
void TMC5160_EnableStallGuardStop(TMC5160_HandleTypeDef *htmc, uint8_t enable)
{
uint32_t sw_mode = TMC5160_ReadRegister(htmc, TMC5160_SW_MODE);
if (enable) {
sw_mode |= (1UL << 10); /* sg_stop 位 */
} else {
sw_mode &= ~(1UL << 10);
}
TMC5160_WriteRegister(htmc, TMC5160_SW_MODE, sw_mode);
}
/** @brief 注册堵转回调函数 */
void TMC5160_SetStallCallback(TMC5160_HandleTypeDef *htmc, TMC5160_StallCallback cb)
{
htmc->stall_callback = cb;
}
/**
* @brief StallGuard 轮询检测(在主循环中调用)
* @note 检测到堵转时自动调用回调函数
*/
void TMC5160_StallGuardPoll(TMC5160_HandleTypeDef *htmc)
{
if (TMC5160_IsStalled(htmc)) {
if (htmc->stall_callback != NULL) {
htmc->stall_callback();
}
}
}
/* ================================================================
* CoolStep 自适应电流控制
* 根据负载自动调节电流,降低功耗和发热
* 依赖 StallGuard 结果,需要 TCOOLTHRS 配置
* ================================================================ */
void TMC5160_SetCoolConf(TMC5160_HandleTypeDef *htmc, uint32_t coolconf)
{
TMC5160_WriteRegister(htmc, TMC5160_COOLCONF, coolconf);
}
/**
* @brief 配置 CoolStep 参数
* @param semin CoolStep 下限 (0=关闭, 1-15: SG_RESULT < semin*32 时增加电流)
* @param semax CoolStep 上限 (0-15: SG_RESULT > (semin+semax+1)*32 时降低电流)
* @param seup 电流增加步长 (0-3: 1/2/4/8)
* @param sedn 电流降低速度 (0-3: 每32/8/2/1次降低)
* @param seimin 最小电流 (0=IRUN/2, 1=IRUN/4)
*/
void TMC5160_ConfigCoolStep(TMC5160_HandleTypeDef *htmc,
uint8_t semin, uint8_t semax,
uint8_t seup, uint8_t sedn, uint8_t seimin)
{
uint32_t val = TMC5160_ReadRegister(htmc, TMC5160_COOLCONF);
/* 保留 SGT 位 [22:16],清除 CoolStep 位 */
val &= (0x7FUL << 16);
val |= (uint32_t)(semin & 0x0F);
val |= ((uint32_t)(seup & 0x03) << 5);
val |= ((uint32_t)(semax & 0x0F) << 8);
val |= ((uint32_t)(sedn & 0x03) << 13);
val |= ((uint32_t)(seimin & 0x01) << 15);
TMC5160_WriteRegister(htmc, TMC5160_COOLCONF, val);
}
/* ================================================================
* 状态查询
* ================================================================ */
uint32_t TMC5160_GetDrvStatus(TMC5160_HandleTypeDef *htmc)
{
return TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS);
}
uint32_t TMC5160_GetRampStat(TMC5160_HandleTypeDef *htmc)
{
return TMC5160_ReadRegister(htmc, TMC5160_RAMP_STAT);
}
uint32_t TMC5160_GetGStat(TMC5160_HandleTypeDef *htmc)
{
return TMC5160_ReadRegister(htmc, TMC5160_GSTAT);
}
/** @brief 清除全局状态标志 (写1清除) */
void TMC5160_ClearGStat(TMC5160_HandleTypeDef *htmc)
{
TMC5160_WriteRegister(htmc, TMC5160_GSTAT, 0x07);
}
/** @brief 获取实际驱动电流 CS (0-31) */
uint8_t TMC5160_GetCurrentCS(TMC5160_HandleTypeDef *htmc)
{
uint32_t status = TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS);
return (uint8_t)((status & TMC5160_DRV_CS_ACTUAL_MASK) >> TMC5160_DRV_CS_ACTUAL_SHIFT);
}
/** @brief 过温关断检测 */
uint8_t TMC5160_IsOverTemp(TMC5160_HandleTypeDef *htmc)
{
return (TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS) & TMC5160_DRV_OT) ? 1 : 0;
}
/** @brief 过温预警检测 */
uint8_t TMC5160_IsOverTempWarning(TMC5160_HandleTypeDef *htmc)
{
return (TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS) & TMC5160_DRV_OTPW) ? 1 : 0;
}
/** @brief 对地短路检测 (A相或B相) */
uint8_t TMC5160_IsShortToGround(TMC5160_HandleTypeDef *htmc)
{
uint32_t s = TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS);
return (s & (TMC5160_DRV_S2GA | TMC5160_DRV_S2GB)) ? 1 : 0;
}
/** @brief 开路检测 (A相或B相) */
uint8_t TMC5160_IsOpenLoad(TMC5160_HandleTypeDef *htmc)
{
uint32_t s = TMC5160_ReadRegister(htmc, TMC5160_DRV_STATUS);
return (s & (TMC5160_DRV_OLA | TMC5160_DRV_OLB)) ? 1 : 0;
}
/** @brief 获取当前步进间隔时间 */
uint32_t TMC5160_GetTStep(TMC5160_HandleTypeDef *htmc)
{
return TMC5160_ReadRegister(htmc, TMC5160_TSTEP);
}
/* ================================================================
* 电机方向
* ================================================================ */
/** @brief 设置电机旋转方向 (0=正常, 1=反转) */
void TMC5160_SetDirection(TMC5160_HandleTypeDef *htmc, uint8_t shaft)
{
uint32_t gconf = TMC5160_ReadRegister(htmc, TMC5160_GCONF);
if (shaft) {
gconf |= TMC5160_GCONF_SHAFT;
} else {
gconf &= ~TMC5160_GCONF_SHAFT;
}
TMC5160_WriteRegister(htmc, TMC5160_GCONF, gconf);
}
/* ================================================================
* 编码器接口
* ================================================================ */
void TMC5160_SetEncMode(TMC5160_HandleTypeDef *htmc, uint32_t encmode)
{
TMC5160_WriteRegister(htmc, TMC5160_ENCMODE, encmode);
}
int32_t TMC5160_GetEncPosition(TMC5160_HandleTypeDef *htmc)
{
return (int32_t)TMC5160_ReadRegister(htmc, TMC5160_X_ENC);
}
void TMC5160_SetEncPosition(TMC5160_HandleTypeDef *htmc, int32_t position)
{
TMC5160_WriteRegister(htmc, TMC5160_X_ENC, (uint32_t)position);
}
void TMC5160_SetEncConst(TMC5160_HandleTypeDef *htmc, uint32_t enc_const)
{
TMC5160_WriteRegister(htmc, TMC5160_ENC_CONST, enc_const);
}
/* ================================================================
* 限位开关配置
* ================================================================ */
void TMC5160_SetSWMode(TMC5160_HandleTypeDef *htmc, uint32_t sw_mode)
{
TMC5160_WriteRegister(htmc, TMC5160_SW_MODE, sw_mode);
}
uint32_t TMC5160_GetSWMode(TMC5160_HandleTypeDef *htmc)
{
return TMC5160_ReadRegister(htmc, TMC5160_SW_MODE);
}
/* ================================================================
* 功率管理
* ================================================================ */
/**
* @brief 设置停止后降低电流的延迟
* @param tpowerdown 延迟值 (0-255),单位约 2^18 个时钟周期
*/
void TMC5160_SetTPOWERDOWN(TMC5160_HandleTypeDef *htmc, uint8_t tpowerdown)
{
TMC5160_WriteRegister(htmc, TMC5160_TPOWERDOWN, tpowerdown);
}
/* ================================================================
* DIAG 诊断引脚配置
* DIAG0/DIAG1 可配置为输出堵转、错误、过温等信号
* 可连接到 MCU 外部中断引脚实现硬件级堵转检测
* ================================================================ */
/**
* @brief 配置 DIAG0 引脚输出
* @param stall 1=输出堵转信号
* @param error 1=输出错误信号
* @param otpw 1=输出过温预警信号
*/
void TMC5160_ConfigDiag0(TMC5160_HandleTypeDef *htmc,
uint8_t stall, uint8_t error, uint8_t otpw)
{
uint32_t gconf = TMC5160_ReadRegister(htmc, TMC5160_GCONF);
gconf &= ~(TMC5160_GCONF_DIAG0_STALL | TMC5160_GCONF_DIAG0_ERROR |
TMC5160_GCONF_DIAG0_OTPW);
if (stall) gconf |= TMC5160_GCONF_DIAG0_STALL;
if (error) gconf |= TMC5160_GCONF_DIAG0_ERROR;
if (otpw) gconf |= TMC5160_GCONF_DIAG0_OTPW;
TMC5160_WriteRegister(htmc, TMC5160_GCONF, gconf);
}
/**
* @brief 配置 DIAG1 引脚输出
* @param stall 1=输出堵转信号
* @param index 1=输出编码器索引信号
* @param onstate 1=输出 chopper on 状态
*/
void TMC5160_ConfigDiag1(TMC5160_HandleTypeDef *htmc,
uint8_t stall, uint8_t index, uint8_t onstate)
{
uint32_t gconf = TMC5160_ReadRegister(htmc, TMC5160_GCONF);
gconf &= ~(TMC5160_GCONF_DIAG1_STALL | TMC5160_GCONF_DIAG1_INDEX |
TMC5160_GCONF_DIAG1_ONSTATE);
if (stall) gconf |= TMC5160_GCONF_DIAG1_STALL;
if (index) gconf |= TMC5160_GCONF_DIAG1_INDEX;
if (onstate) gconf |= TMC5160_GCONF_DIAG1_ONSTATE;
TMC5160_WriteRegister(htmc, TMC5160_GCONF, gconf);
}