system/driver/tmc2240.c

455 lines
13 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.

#include "tmc2240.h"
tmc2240_t _tmc2240[TMC2240_MAX];
static void tmc2240_write(tmc2240_index_e index, uint8_t *data)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
for (uint16_t i = 0; i < 5; i++)
{
tmc->spi->interface.u.normal.spi_send(tmc->spi, data[i]);
}
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
}
static void tmc2240_read(tmc2240_index_e index, uint8_t *wdata, uint8_t *rdata)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
for (uint16_t i = 0; i < 5; i++)
{
rdata[i] = tmc->spi->interface.u.normal.spi_send(tmc->spi, wdata[i]);
}
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
__NOP();
__NOP();
__NOP();
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
for (uint16_t i = 0; i < 5; i++)
{
rdata[i] = tmc->spi->interface.u.normal.spi_send(tmc->spi, wdata[i]);
}
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
}
/**
* @brief 向TMC2240寄存器写入数据
*
* 向指定TMC2240的指定寄存器写入32位数据。
*
* @param index TMC2240索引
* @param reg 寄存器地址
* @param data 要写入的数据
*/
static void tmc2240_reg_write(tmc2240_index_e index, uint8_t reg, uint32_t data)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
uint8_t wdata[5] = {0};
wdata[0] = TMC2240_HIGHT_BIT | reg;
wdata[1] = (data >> 24) & 0xFF;
wdata[2] = (data >> 16) & 0xFF;
wdata[3] = (data >> 8) & 0xFF;
wdata[4] = data & 0xFF;
tmc2240_write(index, wdata);
}
/**
* @brief 从TMC2240寄存器中读取数据
*
* 从指定的TMC2240驱动器的指定寄存器中读取数据。
*
* @param index TMC2240驱动器的索引
* @param reg 要读取的寄存器地址
*
* @return 读取到的32位数据
*/
static uint32_t tmc2240_reg_read(tmc2240_index_e index, uint8_t reg)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
uint8_t wdata[5] = {0};
uint8_t rdata[5] = {0};
wdata[0] = reg;
tmc2240_read(index, wdata, rdata);
return (rdata[1] << 24) | (rdata[2] << 16) | (rdata[3] << 8) | rdata[4];
}
/**
* @brief 配置TMC2240步进电机驱动器
*
* 该函数用于配置TMC2240步进电机驱动器的各种参数包括步进电机的工作模式、加减速曲线等。
*
* @param index TMC2240步进电机驱动器的索引用于指定要配置的驱动器。
*/
static void tmc2240_config_write(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
tmc->config.gconf.data = 0x00000000;
tmc->config.chopconf.data = 0x00410153;
tmc->config.chopconf.bits.mres = TMC2240_MRES_8;
tmc->config.drvconf.data = 0x00000021;
tmc->config.global_scaler.data = 0x00000000;
tmc->config.ihold_irun.bits.ihold = 31;
tmc->config.ihold_irun.bits.irun = 31;
tmc->config.ihold_irun.bits.iholddelay = 0;
tmc->config.ihold_irun.bits.irundelay = 0;
tmc->config.pwmconf.data = 0xC44C261E;
tmc->config.gstat.data = 0x00000007;
tmc2240_reg_write(index, TMC2240_GCONF, tmc->config.gconf.data);
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
tmc2240_reg_write(index, TMC2240_DRV_CONF, tmc->config.drvconf.data);
tmc2240_reg_write(index, TMC2240_GLOBAL_SCALER, tmc->config.global_scaler.data);
tmc2240_reg_write(index, TMC2240_IHOLD_IRUN, tmc->config.ihold_irun.data);
tmc2240_reg_write(index, TMC2240_PWMCONF, tmc->config.pwmconf.data);
tmc2240_reg_write(index, TMC2240_GSTAT, tmc->config.gstat.data);
}
/**
* @brief 更新TMC2240步进电机的步进角度和每圈脉冲数
*
* 根据TMC2240的配置更新步进电机的步进角度和每圈脉冲数。
*
* @param index TMC2240步进电机的索引
*/
static void _tmc2240_motor_update(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
switch (tmc->config.chopconf.bits.mres)
{
case TMC2240_MRES_256:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 256;
break;
case TMC2240_MRES_128:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 128;
break;
case TMC2240_MRES_64:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 64;
break;
case TMC2240_MRES_32:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 32;
break;
case TMC2240_MRES_16:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 16;
break;
case TMC2240_MRES_8:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 8;
break;
case TMC2240_MRES_4:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 4;
break;
case TMC2240_MRES_2:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 2;
break;
case TMC2240_MRES_1:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE;
break;
default:
break;
}
tmc->motor.circle_pulse = 360 / tmc->motor.step_angle;
}
/**
* @brief 启用或禁用TMC2240电机驱动器
*
* 根据传入的索引和启用标志启用或禁用TMC2240电机驱动器。
*
* @param index TMC2240驱动器的索引
* @param enable 启用标志TRUE表示启用FALSE表示禁用
*/
static void _tmc2240_enable(tmc2240_index_e index, BOOL enable)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
BOOL state = tmc->en->read(*tmc->en) == 0 ? TRUE : FALSE;
if (state == enable)
{
return;
}
if (enable == TRUE)
{
PWM_START(tmc->timer, tmc->time_ch);
tmc->en->reset(*tmc->en);
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
}
else
{
PWM_STOP(tmc->timer, tmc->time_ch);
tmc->en->set(*tmc->en);
chopconf_u chopconf;
osel_memset((uint8_t *)&chopconf, 0, sizeof(chopconf_u));
chopconf.bits.mres = TMC2240_MRES_1;
tmc2240_reg_write(index, TMC2240_CHOPCONF, chopconf.data);
}
}
/**
* @brief 设置TMC2240驱动器的方向
*
* 该函数用于设置TMC2240驱动器的方向。
*
* @param index TMC2240驱动器的索引
* @param dir 方向设置TMC2240_FORWARD表示正向TMC2240_BACKWARD表示反向
*/
static void _tmc2240_direction(tmc2240_index_e index, tmc2240_direction_e dir)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
if (dir == TMC2240_FORWARD)
{
tmc->dir->reset(*tmc->dir);
}
else
{
tmc->dir->set(*tmc->dir);
}
}
/**
* @brief 初始化TMC2240电机驱动器
*
* 初始化TMC2240电机驱动器配置相关硬件资源包括SPI通信、定时器以及GPIO引脚。
*
* @param index TMC2240的索引号
* @param SPIx SPI外设指针
* @param timer 定时器外设指针
* @param time_ch 定时器通道号
* @param gpios SPI通信相关的GPIO引脚组
*/
void tmc2240_init(tmc2240_index_e index, SPI_TypeDef *SPIx, TIM_TypeDef *timer, uint32_t time_ch, spi_gpio_group_t *gpios)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
osel_memset((uint8_t *)tmc, 0, sizeof(tmc2240_t));
tmc->timer = timer;
tmc->time_ch = time_ch;
tmc->spi = spi_create(SPI_TYPE_NORMAL, *gpios, 0);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
tmc->spi->interface.hardware_enable(tmc->spi, SPIx);
{
tmc->default_tm.sysclk = SystemCoreClock / 1000;
tmc->default_tm.psc = PWM_GET_PSC(tmc->timer);
tmc->default_tm.arr = PWM_GET_ARR(tmc->timer);
tmc->default_tm.freq = PWM_GET_FREQ(tmc->timer);
}
tmc->params.percent = TMC2240_PWM_DUTY_DEFAULT;
tmc->params.arr = 0;
tmc->params.freq = 0;
tmc->params.enable = FALSE;
tmc->params.direction = TMC2240_FORWARD;
tmc2240_config_write(index);
_tmc2240_motor_update(index);
}
tmc2240_t *tmc2240_get(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
return &_tmc2240[index];
}
/**
* @brief 设置TMC2240的占空比
*
* 根据给定的索引和百分比设置TMC2240的占空比。
*
* @param index TMC2240的索引
* @param percent 占空比的百分比,范围为-100到100
*/
void tmc2240_percent(tmc2240_index_e index, float32 percent)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
PWM_SET_DUTY(tmc->timer, tmc->time_ch, ABS(percent));
}
/**
* @brief 读取TMC2240的配置参数
*
* 从TMC2240电机驱动器的寄存器中读取多个配置参数并将其存储在相应的结构体中。
*
* @param index TMC2240电机驱动器的索引
*/
void tmc2240_config_read(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
tmc->read_config.gconf.data = tmc2240_reg_read(index, TMC2240_GCONF);
tmc->read_config.chopconf.data = tmc2240_reg_read(index, TMC2240_CHOPCONF);
tmc->read_config.drvconf.data = tmc2240_reg_read(index, TMC2240_DRV_CONF);
tmc->read_config.global_scaler.data = tmc2240_reg_read(index, TMC2240_GLOBAL_SCALER);
tmc->read_config.ihold_irun.data = tmc2240_reg_read(index, TMC2240_IHOLD_IRUN);
tmc->read_config.pwmconf.data = tmc2240_reg_read(index, TMC2240_PWMCONF);
tmc->read_config.gstat.data = tmc2240_reg_read(index, TMC2240_GSTAT);
tmc->data.tmc2240_adc_temp = tmc2240_reg_read(index, TMC2240_ADC_TEMP);
tmc->data.tmc2240_temperature = (float32)(tmc->data.tmc2240_adc_temp - 2038) / 7.7;
}
/**
* @brief 测试TMC2240电机驱动器
*
* 该函数用于测试TMC2240电机驱动器并设置相关参数。
*
* @param index TMC2240电机驱动器的索引
*/
void tmc2240_test(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
_tmc2240_enable(index, tmc->params.enable);
if (tmc->params.enable == TRUE)
{
_tmc2240_direction(index, tmc->params.direction);
if (PWM_GET_ARR(tmc->timer) != tmc->params.arr)
{
if (tmc->params.arr == 0)
{
tmc->params.arr = tmc->default_tm.arr;
}
PWM_SET_ARR(tmc->timer, tmc->params.arr);
tmc->params.freq = PWM_GET_FREQ(tmc->timer);
}
tmc2240_percent(index, tmc->params.percent);
if (tmc->config.chopconf.bits.mres != tmc->read_config.chopconf.bits.mres)
{
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
_tmc2240_motor_update(index);
}
}
}
/**
* @brief 设置TMC2240电机的角度
*
* 设置指定TMC2240电机的目标角度。
*
* @param index 电机索引
* @param angle 目标角度,正值表示正向旋转,负值表示反向旋转
*/
void tmc2240_motor_set_angle(tmc2240_index_e index, int32_t angle)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
if (angle == 0)
{
return;
}
if (angle > 0)
{
tmc->params.direction = TMC2240_FORWARD;
}
else
{
tmc->params.direction = TMC2240_BACKWARD;
}
tmc->motor.pulse_count = ABS(angle) / tmc->motor.step_angle;
tmc->motor.step_angle_count = 0;
tmc->params.enable = TRUE;
_tmc2240_direction(index, tmc->params.direction);
if (PWM_GET_ARR(tmc->timer) != tmc->params.arr)
{
if (tmc->params.arr == 0)
{
tmc->params.arr = tmc->default_tm.arr;
}
PWM_SET_ARR(tmc->timer, tmc->params.arr);
tmc->params.freq = PWM_GET_FREQ(tmc->timer);
}
tmc2240_percent(index, tmc->params.percent);
if (tmc->config.chopconf.bits.mres != tmc->read_config.chopconf.bits.mres)
{
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
_tmc2240_motor_update(index);
}
_tmc2240_enable(index, tmc->params.enable);
}
/**
* @brief 更新TMC2240步进电机的状态
*
* 该函数用于更新TMC2240步进电机的状态包括脉冲计数、步距计数和绝对位置等。
*
* @param index TMC2240步进电机的索引
*/
void tmc2240_motor_update(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
if (tmc->motor.pulse_count > 0)
{
tmc->motor.pulse_count--; // 脉冲数
tmc->motor.step_angle_count++; // 步距个数
if (tmc->params.direction == TMC2240_FORWARD)
{
tmc->motor.add_pulse_count++; /* 绝对位置++ */
}
else
{
tmc->motor.add_pulse_count--; /* 绝对位置-- */
}
}
/* 当脉冲数等于0的时候 代表需要发送的脉冲个数已完成,停止输出 */
if (tmc->motor.pulse_count <= 0)
{
tmc->params.enable = FALSE;
_tmc2240_enable(index, tmc->params.enable);
}
}