You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
437 lines
15 KiB
437 lines
15 KiB
#include "tmc51x0.hpp"
|
|
|
|
#include "reg/TMC5130_Constants.h"
|
|
#include "reg/TMC5130_Fields.h"
|
|
#include "reg/TMC5130_Register.h"
|
|
//
|
|
|
|
using namespace iflytop;
|
|
|
|
#if 0
|
|
// Register access permissions:
|
|
// 0x00: none (reserved)
|
|
// 0x01: read
|
|
// 0x02: write
|
|
// 0x03: read/write
|
|
// 0x13: read/write, separate functions/values for reading or writing
|
|
// 0x21: read, flag register (read to clear)
|
|
// 0x42: write, has hardware presets on reset
|
|
static const uint8_t tmc5130_defaultRegisterAccess[TMC5130_REGISTER_COUNT] = {
|
|
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
|
0x03, 0x21, 0x01, 0x02, 0x13, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x00 - 0x0F
|
|
0x02, 0x02, 0x01, 0x02, 0x02, 0x02, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x10 - 0x1F
|
|
0x03, 0x03, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, ____, 0x02, 0x02, 0x02, 0x03, ____, ____, // 0x20 - 0x2F
|
|
____, ____, ____, 0x02, 0x03, 0x21, 0x01, ____, 0x03, 0x03, 0x02, 0x21, 0x01, ____, ____, ____, // 0x30 - 0x3F
|
|
____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x40 - 0x4F
|
|
____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, // 0x50 - 0x5F
|
|
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x01, 0x01, 0x03, 0x02, 0x02, 0x01, // 0x60 - 0x6F
|
|
0x42, 0x01, 0x02, 0x01, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____, ____ // 0x70 - 0x7F
|
|
};
|
|
#endif
|
|
|
|
/***********************************************************************************************************************
|
|
* 工具宏 *
|
|
***********************************************************************************************************************/
|
|
|
|
#define FIELD_SET(data, mask, shift, value) (data = (((data) & (~(mask))) | (((value) << (shift)) & (mask))))
|
|
#define FIELD_GET(data, mask, shift) (((data) & (mask)) >> (shift))
|
|
#define BYTE(value, n) (((value) >> ((n) << 3)) & 0xFF)
|
|
#define NIBBLE(value, n) (((value) >> ((n) << 2)) & 0x0F)
|
|
#define SHORT(value, n) (((value) >> ((n) << 4)) & 0xFFFF)
|
|
#define WORD(value, n) (((value) >> ((n) << 5)) & 0xFFFFFFFF)
|
|
|
|
#define TMC51x0_ADDRESS(x) ((x) & (TMC5130_ADDRESS_MASK))
|
|
#define TAG "TMC51X0"
|
|
void TMC51X0::initialize(TMC51X0Cfg cfg) {
|
|
m_cfg = cfg;
|
|
m_hspi = cfg.hspi;
|
|
|
|
ZLOGI(TAG, "SPI:%p CSPin:%s,enPIn:%s", cfg.hspi, pinname(cfg.csnpin), pinname(cfg.ennpin));
|
|
m_mutex.init();
|
|
|
|
m_csnpin.initAsOutput(m_cfg.csnpin, kxs_gpio_nopull, false, true);
|
|
m_ennpin.initAsOutput(m_cfg.ennpin, kxs_gpio_nopull, false, true);
|
|
|
|
enable(false);
|
|
|
|
stop();
|
|
|
|
writeInt(TMC5130_PWMCONF, 0x000500C8);
|
|
writeInt(TMC5130_CHOPCONF, 0x000100c3);
|
|
writeInt(TMC5130_IHOLD_IRUN, 0x00051A00);
|
|
writeInt(TMC5130_PWMCONF, 0x000401c8);
|
|
writeInt(TMC5130_XTARGET, 0);
|
|
writeInt(TMC5130_XACTUAL, 0x00000000);
|
|
writeInt(TMC5130_VACTUAL, 0x00000000);
|
|
writeInt(TMC5130_TZEROWAIT, 0);
|
|
|
|
setVstart(100);
|
|
setA1(30);
|
|
setAmax(50);
|
|
setV1(500);
|
|
setDmax(50);
|
|
setD1(30);
|
|
setVstop(100);
|
|
setTzerowait(100);
|
|
|
|
setIHOLD_IRUN(0, 30, 100);
|
|
enable(false);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* 驱动器寄存器读写方法 *
|
|
*******************************************************************************/
|
|
|
|
void TMC51X0::readWriteArray(uint8_t *data, size_t length) {
|
|
portENTER_CRITICAL();
|
|
m_csnpin.write(false);
|
|
HAL_SPI_TransmitReceive(m_hspi, data, data, length, 100);
|
|
m_csnpin.write(true);
|
|
portEXIT_CRITICAL();
|
|
}
|
|
void TMC51X0::writeDatagram(uint8_t address, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4) {
|
|
uint8_t data[5] = {static_cast<uint8_t>(address | static_cast<uint8_t>(TMC5130_WRITE_BIT)), x1, x2, x3, x4};
|
|
readWriteArray(&data[0], 5);
|
|
}
|
|
void TMC51X0::writeInt(uint8_t address, int32_t value) { //
|
|
writeDatagram(address, BYTE(value, 3), BYTE(value, 2), BYTE(value, 1), BYTE(value, 0));
|
|
}
|
|
|
|
void TMC51X0::writeField(uint8_t add, uint32_t mask, uint32_t shift, uint32_t value) {
|
|
uint32_t regval = readUInt(add);
|
|
regval = (regval & ~mask) | ((value << shift) & mask);
|
|
writeInt(add, regval);
|
|
}
|
|
|
|
int32_t TMC51X0::readInt(uint8_t address) {
|
|
/**
|
|
* @WARNING:
|
|
* 这里没有判断寄存器是否可读,有些寄存器是不可读所以,所以可能读回来的数值和写入数值是不相等的
|
|
*/
|
|
address = TMC51x0_ADDRESS(address);
|
|
|
|
uint8_t data[5] = {0, 0, 0, 0, 0};
|
|
|
|
data[0] = address;
|
|
readWriteArray(&data[0], 5);
|
|
|
|
data[0] = address;
|
|
readWriteArray(&data[0], 5);
|
|
|
|
return ((uint32_t)data[1] << 24) | ((uint32_t)data[2] << 16) | (data[3] << 8) | data[4];
|
|
}
|
|
|
|
uint32_t TMC51X0::readUInt(uint8_t address) {
|
|
int32_t val = readInt(address);
|
|
uint32_t ret;
|
|
memcpy(&ret, &val, sizeof(uint32_t));
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************************************************************
|
|
* BASIC *
|
|
***********************************************************************************************************************/
|
|
|
|
bool TMC51X0::ping() {
|
|
zlock_guard lkg(m_mutex);
|
|
uint32_t regval = readUInt(TMC5130_IOIN);
|
|
uint32_t chipId = FIELD_GET(regval, TMC5130_VERSION_MASK, TMC5130_VERSION_SHIFT);
|
|
return chipId != 0;
|
|
}
|
|
void TMC51X0::enable(bool enable) {
|
|
zlock_guard lkg(m_mutex);
|
|
|
|
m_ennpin.write(!enable);
|
|
}
|
|
|
|
int32_t TMC51X0::to_motor_acc(int32_t acc) { //
|
|
int32_t val = acc / 60.0 * m_onecirclepulse; // 65535
|
|
if (val > 65535) val = 65535;
|
|
return val;
|
|
}
|
|
int32_t TMC51X0::to_motor_vel(int32_t vel) { //
|
|
int32_t val = vel / 60.0 * m_onecirclepulse;
|
|
if (val > 8388095 /*2^23-512*/) {
|
|
val = 8388095;
|
|
}
|
|
return val;
|
|
} // rpm
|
|
int32_t TMC51X0::to_motor_pos(int32_t pos) { //
|
|
int32_t val = pos * 1.0 / m_scale * m_scale_deceleration * m_onecirclepulse + 0.5;
|
|
return val;
|
|
} //
|
|
|
|
int32_t TMC51X0::to_user_pos(int32_t pos) { //
|
|
int32_t val = pos / m_onecirclepulse * m_scale / m_scale_deceleration + 0.5;
|
|
// ZLOGI("TMC5130", "to_user_pos %d,%d", pos, val);
|
|
return val;
|
|
} //
|
|
int32_t TMC51X0::to_user_vel(int32_t vel) { //
|
|
int32_t val = vel * 60.0 / m_onecirclepulse;
|
|
return val;
|
|
}
|
|
/***********************************************************************************************************************
|
|
* CTRL *
|
|
***********************************************************************************************************************/
|
|
void TMC51X0::stop() {
|
|
zlock_guard lkg(m_mutex);
|
|
|
|
rotate(0);
|
|
}
|
|
void TMC51X0::rotate(int32_t velocity) {
|
|
zlock_guard lkg(m_mutex);
|
|
|
|
velocity = to_motor_vel(velocity);
|
|
writeInt(TMC5130_VMAX, abs(velocity));
|
|
writeInt(TMC5130_RAMPMODE, (velocity >= 0) ? TMC5130_MODE_VELPOS : TMC5130_MODE_VELNEG);
|
|
}
|
|
void TMC51X0::moveTo(int32_t position, uint32_t velocityMax) {
|
|
zlock_guard lkg(m_mutex);
|
|
|
|
position = to_motor_pos(position);
|
|
velocityMax = to_motor_vel(velocityMax);
|
|
writeInt(TMC5130_RAMPMODE, TMC5130_MODE_POSITION);
|
|
writeInt(TMC5130_VMAX, velocityMax);
|
|
writeInt(TMC5130_XTARGET, position);
|
|
}
|
|
void TMC51X0::moveToEnd(int32_t direction, uint32_t velocityMax) {
|
|
zlock_guard lkg(m_mutex);
|
|
|
|
if (direction >= 0) {
|
|
writeInt(TMC5130_RAMPMODE, TMC5130_MODE_POSITION);
|
|
writeInt(TMC5130_VMAX, to_motor_vel(velocityMax));
|
|
writeInt(TMC5130_XTARGET, INT32_MAX / 1.5 - 1000);
|
|
} else {
|
|
writeInt(TMC5130_RAMPMODE, TMC5130_MODE_POSITION);
|
|
writeInt(TMC5130_VMAX, to_motor_vel(velocityMax));
|
|
writeInt(TMC5130_XTARGET, INT32_MIN / 1.5 + 1000);
|
|
}
|
|
}
|
|
|
|
void TMC51X0::moveBy(int32_t relativePosition, uint32_t velocityMax) { // determine actual position and add numbers of ticks to move
|
|
zlock_guard lkg(m_mutex);
|
|
|
|
int32_t pos = getXACTUAL();
|
|
int32_t target = pos + relativePosition;
|
|
moveTo(target, velocityMax);
|
|
}
|
|
|
|
/***********************************************************************************************************************
|
|
* GET STATE *
|
|
***********************************************************************************************************************/
|
|
|
|
int32_t TMC51X0::getXACTUAL() {
|
|
zlock_guard lkg(m_mutex);
|
|
|
|
return to_user_pos(readInt(TMC5130_XACTUAL));
|
|
}
|
|
int32_t TMC51X0::getVACTUAL() {
|
|
zlock_guard lkg(m_mutex);
|
|
return to_user_pos(readInt(TMC5130_VACTUAL));
|
|
}
|
|
int32_t TMC51X0::getEncVal() {
|
|
zlock_guard lkg(m_mutex);
|
|
int32_t enc_val = to_user_pos(readInt(TMC5130_XENC));
|
|
if (m_enc_resolution < 0) {
|
|
enc_val = -enc_val;
|
|
}
|
|
return enc_val;
|
|
}
|
|
TMC5130RampStat TMC51X0::getRampStat() {
|
|
zlock_guard lkg(m_mutex);
|
|
int32_t val = readInt(TMC5130_RAMPSTAT);
|
|
return TMC5130RampStat(val);
|
|
}
|
|
|
|
bool TMC51X0::isReachTarget(TMC5130RampStat *state) {
|
|
zlock_guard lkg(m_mutex);
|
|
int mode = readInt(TMC5130_RAMPMODE);
|
|
if (mode == TMC5130_MODE_POSITION) {
|
|
return state->isSetted(TMC5130RampStat::ktmc5130_rs_posreached);
|
|
} else {
|
|
return state->isSetted(TMC5130RampStat::ktmc5130_rs_vzero) && state->isSetted(TMC5130RampStat::ktmc5130_rs_velreached);
|
|
}
|
|
}
|
|
bool TMC51X0::isTMC5130() {
|
|
zlock_guard lkg(m_mutex);
|
|
uint32_t regval = readUInt(TMC5130_IOIN);
|
|
uint32_t chipId = FIELD_GET(regval, TMC5130_VERSION_MASK, TMC5130_VERSION_SHIFT);
|
|
return chipId == kTMC5130;
|
|
}
|
|
|
|
TMC5130DevStatusReg_t TMC51X0::getDevStatus() { // R 读后不清
|
|
zlock_guard lkg(m_mutex);
|
|
static_assert(sizeof(TMC5130DevStatusReg_t) == 4);
|
|
uint32_t value = readInt(TMC5130_DRVSTATUS);
|
|
TMC5130DevStatusReg_t val;
|
|
memcpy(&val, &value, sizeof(TMC5130DevStatusReg_t));
|
|
return val;
|
|
}
|
|
TMC5130GState_t TMC51X0::getGState() { // R+C 读后自动清除
|
|
zlock_guard lkg(m_mutex);
|
|
static_assert(sizeof(TMC5130GState_t) == 4);
|
|
uint32_t value = readInt(TMC5130_GSTAT);
|
|
TMC5130GState_t val;
|
|
memcpy(&val, &value, sizeof(TMC5130GState_t));
|
|
return val;
|
|
}
|
|
int32_t TMC51X0::readICVersion() {
|
|
zlock_guard lkg(m_mutex);
|
|
uint32_t regval = readUInt(TMC5130_IOIN);
|
|
uint32_t chipId = FIELD_GET(regval, TMC5130_VERSION_MASK, TMC5130_VERSION_SHIFT);
|
|
return chipId;
|
|
}
|
|
|
|
/***********************************************************************************************************************
|
|
* set state *
|
|
***********************************************************************************************************************/
|
|
|
|
void TMC51X0::setXACTUAL(int32_t value) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_XACTUAL, to_motor_pos(value));
|
|
}
|
|
void TMC51X0::setMotorShaft(bool reverse) {
|
|
zlock_guard lkg(m_mutex);
|
|
uint32_t regval = readUInt(TMC5130_GCONF);
|
|
FIELD_SET(regval, TMC5130_SHAFT_MASK, TMC5130_SHAFT_SHIFT, reverse ? 1 : 0);
|
|
writeInt(TMC5130_GCONF, regval);
|
|
// uint32_t readbak = readUInt(TMC5130_GCONF);
|
|
// ZLOGI(TAG, "%x,%x", regval, readbak);
|
|
}
|
|
void TMC51X0::setIHOLD_IRUN(uint8_t ihold, uint8_t irun, uint16_t iholddelay) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_IHOLD_IRUN, (iholddelay << TMC5130_IHOLDDELAY_SHIFT) | (irun << TMC5130_IRUN_SHIFT) | (ihold << TMC5130_IHOLD_SHIFT));
|
|
}
|
|
void TMC51X0::setGlobalScale(uint8_t globalscale) {
|
|
#define TMC5160_GLOBAL_SCALER 0x0B
|
|
#define TMC5160_GLOBAL_SCALER_MASK 0xFF
|
|
#define TMC5160_GLOBAL_SCALER_SHIFT 0
|
|
zlock_guard lkg(m_mutex);
|
|
if (isTMC5130()) {
|
|
return;
|
|
}
|
|
|
|
if (globalscale == 0) {
|
|
globalscale = 0;
|
|
} else if (globalscale <= 31 && globalscale >= 1) {
|
|
globalscale = 32;
|
|
} else {
|
|
globalscale = globalscale;
|
|
}
|
|
writeInt(TMC5160_GLOBAL_SCALER, (readInt(TMC5160_GLOBAL_SCALER) & ~TMC5160_GLOBAL_SCALER_MASK) | (globalscale << TMC5160_GLOBAL_SCALER_SHIFT));
|
|
}
|
|
void TMC51X0::setScale(int32_t scale) {
|
|
zlock_guard lkg(m_mutex);
|
|
m_scale = scale;
|
|
}
|
|
void TMC51X0::setScaleDenominator(int32_t scale) {
|
|
zlock_guard lkg(m_mutex);
|
|
m_scale_deceleration = scale;
|
|
}
|
|
void TMC51X0::setVstart(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_VSTART, to_motor_vel(val));
|
|
}
|
|
void TMC51X0::setA1(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_A1, to_motor_acc(val));
|
|
}
|
|
void TMC51X0::setAmax(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_AMAX, to_motor_acc(val));
|
|
}
|
|
void TMC51X0::setV1(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_V1, to_motor_vel(val));
|
|
}
|
|
void TMC51X0::setDmax(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_DMAX, to_motor_acc(val));
|
|
}
|
|
void TMC51X0::setD1(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_D1, to_motor_acc(val));
|
|
}
|
|
void TMC51X0::setVstop(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_VSTOP, to_motor_vel(val));
|
|
}
|
|
void TMC51X0::setTzerowait(int32_t val) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(TMC5130_TZEROWAIT, val);
|
|
}
|
|
bool TMC51X0::setEncResolution(int32_t enc_resolution) {
|
|
zlock_guard lkg(m_mutex);
|
|
/**
|
|
* @brief
|
|
*
|
|
* 1.假设电机是256细分
|
|
* 2.假设TMC5130_ENC_CONST是十进制模式
|
|
* 3.只支持指定分辨率的编码器
|
|
*/
|
|
|
|
int32_t enc_resolution_tmp = enc_resolution * 4;
|
|
int16_t enc_const_integral = 0;
|
|
int16_t enc_const_fractional = 0;
|
|
|
|
switch (abs(enc_resolution_tmp)) {
|
|
case 1000:
|
|
enc_const_integral = 51;
|
|
enc_const_fractional = 0.2 * 10000;
|
|
break;
|
|
case 1024:
|
|
enc_const_integral = 50;
|
|
enc_const_fractional = 0 * 10000;
|
|
break;
|
|
case 4000:
|
|
enc_const_integral = 12;
|
|
enc_const_fractional = 0.8 * 10000;
|
|
break;
|
|
case 4096:
|
|
enc_const_integral = 12;
|
|
enc_const_fractional = 0.5 * 10000;
|
|
break;
|
|
case 16384:
|
|
enc_const_integral = 3;
|
|
enc_const_fractional = 0.125 * 10000;
|
|
break;
|
|
case 0:
|
|
m_enc_resolution = 0;
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
m_enc_resolution = enc_resolution;
|
|
uint32_t setval = 0;
|
|
uint8_t *psetval = (uint8_t *)&setval;
|
|
|
|
memcpy(psetval + 2, &enc_const_integral, 2);
|
|
memcpy(psetval, &enc_const_fractional, 2);
|
|
|
|
writeInt(TMC5130_ENCMODE, 0x1 << 10);
|
|
writeInt(TMC5130_ENC_CONST, setval);
|
|
return true;
|
|
}
|
|
void TMC51X0::setEncVal(int32_t enc_val) {
|
|
zlock_guard lkg(m_mutex);
|
|
int32_t enc_set_val = to_motor_pos(enc_val);
|
|
if (m_enc_resolution < 0) {
|
|
enc_set_val = -enc_set_val;
|
|
}
|
|
writeInt(TMC5130_XENC, enc_set_val);
|
|
}
|
|
|
|
/***********************************************************************************************************************
|
|
* reg operation *
|
|
***********************************************************************************************************************/
|
|
void TMC51X0::writeIntExt(uint8_t address, int32_t value) {
|
|
zlock_guard lkg(m_mutex);
|
|
writeInt(address, value);
|
|
}
|
|
int32_t TMC51X0::readIntExt(uint8_t address) {
|
|
zlock_guard lkg(m_mutex);
|
|
return readInt(address);
|
|
}
|