TMC2660驱动及调试记录

TMC2660驱动及调试记录文章介绍了 TMC2660 作为步进电机驱动芯片 如何通过 SPI 通信配置参数并驱动电机

大家好,欢迎来到IT知识分享网。

TMC2660

一款优秀的电机驱动芯片,驱动简单。
理论就看这篇:TMC260/TMC2660/TMC262步进电机驱动
或者直接看手册,手册也不复杂。

  • 使用SPI通信,通过SPI配置参数。
  • 支持直接使用SPI和Step/Dir方式控制两种控制步进电机的方式。

TMC2660驱动

1、原理图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
需要驱动两个步进电机,两个步进电机连接一样,使用同一个SPI接口通信 —— SPI2

2、编写驱动

2.1 SPI驱动

SPI驱动直接STM32CubeMX配置即可,容易得很。
需要注意的是查看手册SPI通信时序就知道,时钟极性选择SPI_POLARITY_HIGH,时钟相位选择SPI_PHASE_2EDGE

void MX_SPI2_Init(void) { 
    ... hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH; hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; ... } 

2.2 TMC2660驱动代码

bsp_tmc2660.h:

#ifndef _BSP_TMC2660_H_ #define _BSP_TMC2660_H_ // #include <stdint.h> typedef unsigned char uint8_t; #define TMC2660_M1 0 #define TMC2660_M2 1 typedef uint8_t enTCM2660Def; #define TMC2660_Disable 1 #define TMC2660_Enable 0 typedef uint8_t enTCM2660EnDisableDef; #define TMC2660_CW 0 #define TMC2660_CCW 1 typedef uint8_t enTMC2660DirDef; /* 细分步数 register value 用于Step/DIR模式 */ #define TMC2660_MICROSTEP_256 0x00 #define TMC2660_MICROSTEP_128 0x01 #define TMC2660_MICROSTEP_64 0x02 #define TMC2660_MICROSTEP_32 0x03 #define TMC2660_MICROSTEP_16 0x04 #define TMC2660_MICROSTEP_8 0x05 #define TMC2660_MICROSTEP_4 0x06 #define TMC2660_MICROSTEP_2 0x07 /* Half Step */ #define TMC2660_MICROSTEP_1 0x08 /* Full Step */ typedef uint8_t microstep_t; #define TMC2660_SG2_THRESHOLD_VAL (val) (val << 8) void BSP_TMC2660_Init(void); void BSP_TMC2660_DirectSet(enTCM2660Def t, enTMC2660DirDef dir); void BSP_TMC2660_Enable(enTCM2660Def t, enTCM2660EnDisableDef state); microstep_t BSP_TMC2660_MicrostepSet(enTCM2660Def t, microstep_t microstep); uint8_t BSP_TMC2660_TorqueSet(enTCM2660Def t, uint8_t torque); #endif /* _BSP_TMC2660_H_ */ 

bsp_tmc2660.c:

#include <stdio.h> #include "spi.h" #include "bsp_tmc2660.h" #include "bsp_cfg.h" /* tmc2660 register */ #define REG_DRVCTRL 0x00000000 #define REG_CHOPCONF 0x00080000 #define REG_SMARTEN 0x000A0000 #define REG_SGCSCONF 0x000C0000 #define REG_DRVCONF 0x000E0000 #define DRVCTRL_SPI_PHA (1 << 17) /* * 使用SPI模式需要设置DRVCONF寄存器的SDOFF位(bit7), * 0: Enable STEP and DIR interface. * 1: Disable STEP and DIR interface. SPI interface is used * to move motor. */ /* 默认配置 */ #define SCG_DEFAULT 0x10000 /* spi chip select */ #define TMC2660_M1_PORT_CS GPIOB #define TMC2660_M1_GPIO_CS GPIO_PIN_12  /* Step motor enable */ #define TMC2660_M1_PORT_EN GPIOA  #define TMC2660_M1_GPIO_EN GPIO_PIN_8 /* step pulse */ #define TMC2660_M1_PORT_STEP GPIOC  #define TMC2660_M1_GPIO_STEP GPIO_PIN_8 /* direction */ #define TMC2660_M1_PORT_DIR GPIOC  #define TMC2660_M1_GPIO_DIR GPIO_PIN_7  /* spi chip select */ #define TMC2660_M2_PORT_CS GPIOC #define TMC2660_M2_GPIO_CS GPIO_PIN_6  /* Step motor enable */ #define TMC2660_M2_PORT_EN GPIOD  #define TMC2660_M2_GPIO_EN GPIO_PIN_2 /* step pulse */ #define TMC2660_M2_PORT_STEP GPIOB  #define TMC2660_M2_GPIO_STEP GPIO_PIN_9 /* direction */ #define TMC2660_M2_PORT_DIR GPIOC  #define TMC2660_M2_GPIO_DIR GPIO_PIN_10  static uint32_t tmc2660_SPI_Xfer(uint32_t wdata) { 
    uint8_t wbuf[3] = { 
   0}; uint8_t rbuf[3] = { 
   0}; wbuf[0] = (wdata>>16) & 0xff; wbuf[1] = (wdata>>8) & 0xff; wbuf[2] = (wdata&0xff); HAL_SPI_TransmitReceive(&hspi2, (uint8_t *)&wbuf, rbuf, 3, HAL_MAX_DELAY); uint32_t ret = (rbuf[0]<<16 | rbuf[1]<<8 | rbuf[2]); return ret; } #define LEVEL_SW(level) ((level) > 0 ? GPIO_PIN_SET : GPIO_PIN_RESET) static void tmc2660_SPI_CS(enTCM2660Def t, uint8_t level) { 
    if (t == TMC2660_M1) { 
    HAL_GPIO_WritePin(TMC2660_M2_PORT_CS, TMC2660_M2_GPIO_CS, LEVEL_SW(1)); /* cancel M2 chip select */ HAL_GPIO_WritePin(TMC2660_M1_PORT_CS, TMC2660_M1_GPIO_CS, LEVEL_SW(level)); } else if (t == TMC2660_M2) { 
    HAL_GPIO_WritePin(TMC2660_M1_PORT_CS, TMC2660_M1_GPIO_CS, LEVEL_SW(1)); /* cancel M1 chip select */ HAL_GPIO_WritePin(TMC2660_M2_PORT_CS, TMC2660_M2_GPIO_CS, LEVEL_SW(level)); } } static void tmc2660Enable(enTCM2660Def t, uint8_t level) { 
    if (t == TMC2660_M1) { 
    HAL_GPIO_WritePin(TMC2660_M1_PORT_EN, TMC2660_M1_GPIO_EN, LEVEL_SW(level)); } else { 
    HAL_GPIO_WritePin(TMC2660_M2_PORT_EN, TMC2660_M2_GPIO_EN, LEVEL_SW(level)); } } static void tmc2660GPIOConfig(void) { 
    GPIO_InitTypeDef GPIO_InitStruct = { 
   0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin : TMC2660_M1 */ GPIO_InitStruct.Pin = TMC2660_M1_GPIO_CS; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(TMC2660_M1_PORT_CS, &GPIO_InitStruct); GPIO_InitStruct.Pin = TMC2660_M1_GPIO_EN; HAL_GPIO_Init(TMC2660_M1_PORT_EN, &GPIO_InitStruct); GPIO_InitStruct.Pin = TMC2660_M1_GPIO_DIR; HAL_GPIO_Init(TMC2660_M1_PORT_DIR, &GPIO_InitStruct); /*Configure GPIO pin : TMC2660_M2 */ GPIO_InitStruct.Pin = TMC2660_M2_GPIO_CS; HAL_GPIO_Init(TMC2660_M2_PORT_CS, &GPIO_InitStruct); GPIO_InitStruct.Pin = TMC2660_M2_GPIO_EN; HAL_GPIO_Init(TMC2660_M2_PORT_EN, &GPIO_InitStruct); GPIO_InitStruct.Pin = TMC2660_M2_GPIO_DIR; HAL_GPIO_Init(TMC2660_M2_PORT_DIR, &GPIO_InitStruct); HAL_GPIO_WritePin(TMC2660_M1_PORT_CS, TMC2660_M1_GPIO_CS, LEVEL_SW(1)); HAL_GPIO_WritePin(TMC2660_M1_PORT_EN, TMC2660_M1_GPIO_EN, LEVEL_SW(1)); HAL_GPIO_WritePin(TMC2660_M1_PORT_DIR, TMC2660_M1_GPIO_DIR, LEVEL_SW(0)); HAL_GPIO_WritePin(TMC2660_M2_PORT_CS, TMC2660_M2_GPIO_CS, LEVEL_SW(1)); HAL_GPIO_WritePin(TMC2660_M2_PORT_EN, TMC2660_M2_GPIO_EN, LEVEL_SW(1)); HAL_GPIO_WritePin(TMC2660_M2_PORT_DIR, TMC2660_M2_GPIO_DIR, LEVEL_SW(0)); } #define BSP_TMC2660_MODE_SPI 1 #define BSP_TMC2660_MODE_STEP_DIR 0 #define BSP_TMC2660_MODE BSP_TMC2660_MODE_SPI static void tmc2660ParamInit(void) { 
    uint32_t ret; //Device Initialization from Datasheet /* 1- spi, 0 - step/dir */ #if BSP_TMC2660_MODE == BSP_TMC2660_MODE_SPI /* SPI Mode */ #define INIT_DRVCTRL 0x00000000 #define INIT_CHOPCONF 0x000901B4 #define INIT_SMARTEN 0x000A8202 #define INIT_SGCSCONF 0x000D0010 #define INIT_DRVCONF 0x000E0090 #elif BSP_TMC2660_MODE == BSP_TMC2660_MODE_STEP_DIR /* Step/DIR Mode*/ #define INIT_DRVCTRL 0x00000000 #define INIT_CHOPCONF 0x000901B4 #define INIT_SMARTEN 0x000A8202 #define INIT_SGCSCONF 0x000D0010//0x000D001F #define INIT_DRVCONF 0x000EF010 #endif  tmc2660_SPI_CS(TMC2660_M2, 0); ret = tmc2660_SPI_Xfer(REG_DRVCTRL | INIT_DRVCTRL | TMC2660_MICROSTEP_32); tmc2660_SPI_CS(TMC2660_M2, 1); printf("reg %08lx\r\n", ret); tmc2660_SPI_CS(TMC2660_M2, 0); ret = tmc2660_SPI_Xfer(REG_CHOPCONF | INIT_CHOPCONF); tmc2660_SPI_CS(TMC2660_M2, 1); printf("reg %08lx\r\n", ret); tmc2660_SPI_CS(TMC2660_M2, 0); ret = tmc2660_SPI_Xfer(REG_SMARTEN | INIT_SMARTEN); tmc2660_SPI_CS(TMC2660_M2, 1); printf("reg %08lx\r\n", ret); tmc2660_SPI_CS(TMC2660_M2, 0); ret = tmc2660_SPI_Xfer(REG_SGCSCONF | INIT_SGCSCONF); tmc2660_SPI_CS(TMC2660_M2, 1); printf("reg %08lx\r\n", ret); tmc2660_SPI_CS(TMC2660_M2, 0); ret = tmc2660_SPI_Xfer(REG_DRVCONF | INIT_DRVCONF); tmc2660_SPI_CS(TMC2660_M2, 1); printf("reg %08lx\r\n", ret); } void BSP_TMC2660_Init(void) { 
    MX_SPI2_Init(); tmc2660GPIOConfig(); tmc2660ParamInit(); BSP_TMC2660_Enable(TMC2660_M1, TMC2660_Disable); BSP_TMC2660_Enable(TMC2660_M2, TMC2660_Enable); } / * @brief: Set Motor direction(设置电机方向) * @retval: * @note: */ void BSP_TMC2660_DirectSet(enTCM2660Def t, enTCM2660EnDisableDef dir) { 
    if (t == TMC2660_M1) { 
    HAL_GPIO_WritePin(TMC2660_M1_PORT_DIR, TMC2660_M1_GPIO_DIR, LEVEL_SW(dir)); } else if (t == TMC2660_M2) { 
    HAL_GPIO_WritePin(TMC2660_M2_PORT_DIR, TMC2660_M2_GPIO_DIR, LEVEL_SW(dir)); } } void BSP_TMC2660_Enable(enTCM2660Def t, enTCM2660EnDisableDef state) { 
    if (t == TMC2660_M1) { 
    HAL_GPIO_WritePin(TMC2660_M1_PORT_EN, TMC2660_M1_GPIO_EN, LEVEL_SW(state)); } else if (t == TMC2660_M2) { 
    HAL_GPIO_WritePin(TMC2660_M2_PORT_EN, TMC2660_M2_GPIO_EN, LEVEL_SW(state)); } } / * @brief: Set Motor microstep (设置tmc2660细分步数) * @retval: return microstep * @note: */ microstep_t BSP_TMC2660_MicrostepSet(enTCM2660Def t, microstep_t microstep) { 
    uint32_t cmd = 0; if (microstep > TMC2660_MICROSTEP_1 || microstep < TMC2660_MICROSTEP_256) { 
    microstep = TMC2660_MICROSTEP_16; } cmd = REG_DRVCTRL | INIT_DRVCTRL | microstep; tmc2660_SPI_CS(t, 0); uint32_t ret = tmc2660_SPI_Xfer(cmd); tmc2660_SPI_CS(t, 1); return microstep; } / * @brief: Set Motor microstep (设置tmc2660电流缩放) * @retval: return scale * @note: scaleCurrent = scale / 32 * Current */ uint8_t BSP_TMC2660_CurrentScaleSet(enTCM2660Def t, uint8_t scale) { 
    uint32_t cmd = 0; if (scale > 31 || scale < 0) { 
    scale = 16; } cmd = REG_SGCSCONF | INIT_SGCSCONF | scale; tmc2660_SPI_CS(t, 0); uint32_t ret = tmc2660_SPI_Xfer(cmd); tmc2660_SPI_CS(t, 1); return scale; } 
  • BSP_TMC2660_MODE通过宏选择SPI模式还是STEP/DIR模式控制,通过设置REG_DRVCONF寄存器bit7来选择,但bit7为0时使用STEP/DIR模式为1时使用SPI模式
2.2.3 使用STEP/DIR方式驱动

STEP/DIR方式驱动很简单,给STEP引脚输入PWM信号即可,可以使用定时器输出PWM。
当使用PWM方式驱动时,由芯片产生驱动步进电机的时序。
这里使用定时器比较输出翻转模式输出PWM进行控制。输出固定频率时候步进电机就匀速转动,频率越快步进电机转速就越快。

2.2.4 使用SPI驱动

查看手册可以知道DRVCTRL寄存器在SPI模式时用于控制步进电机。
在这里插入图片描述
在这里插入图片描述

  • 寄存器的bit17和bit8分别用于控制OA1-OA2、OB1-OB2的电流方向
  • bit16 – bit9用于控制通过OA1-OA2电流的大小。
  • bit7 – bit0 用于控制通过OB1-OB2电流的大小。

在这里插入图片描述

  • A ~ OA1
  • A ‾ \overline{A} A ~ OA2
  • B ~ OB1
  • B ‾ \overline{B} B ~ OB2

具体如何控制还需要了解步进电机控制原理:两相步进电机的控制及其实现
查看步进电机规格书里面也写了驱动时序 : 只要按照这个时序输出脉冲就可以控制。如果用STEP/DIR模式控制则由芯片把我们输出这种脉冲时序。
在这里插入图片描述

STEP A B A ‾ \overline{A} A B ‾ \overline{B} B
1 1 1 0 0
2 0 1 1 0
3 0 0 1 1
4 1 0 0 1
5 1 1 0 0

* 第1节拍,OA 1 OB1 通电,也就是输出高电平;OA2、OB2输出低电平
对比这里双4拍可知步进电机的时序和这个是一样的。

使用SPI模式控制

/ * @brief: SPI Mode To ctrl stepper motor * @retval: * @note: 0 */ void BSP_TMC2660_SPIMoveStep(enTCM2660Def t) { 
    static uint8_t index = 0; uint32_t beats[4] = { 
   0x01f0f8, 0x03f0f8, 0x03f1f8, 0x01f1f8}; // uint32_t beats[4] = {0x00f87c, 0x002f87c, 0x002f97c, 0x00f97c}; uint32_t cmd; tmc2660Enable(t, 0); cmd = REG_DRVCTRL | beats[index]; tmc2660_SPI_CS(t, 0); tmc2660_SPI_Xfer(cmd); tmc2660_SPI_CS(t, 1); index = (++index) % 4; } 
  • 第1节拍,向寄存器写入0x01f0f8,bit17和bit8是0,电流方向OA1 —> OA2、OB1 —>OB2,也就是X+Y+,对应规格书 时序 1 1 0 0
  • 第2节拍,向寄存器写入0x03f0f8,bit17为1,bit8为0,电流方向OA2 —> OA1、OB1 —>OB2,也就是X-Y+,对应规格书 时序 0 1 1 0
  • 第3节拍,向寄存器写入0x03f1f8,bit17为1,bit8为1,所以电流方向OA2 —> OA1、OB2 —>OB1,也就是X-Y-,对应规格书 时序 0 0 1 1,
  • 第4节拍,向寄存器写入0x01f1f8,bit17为0,bit8为1,所以电流方向OA1 —> OA2、OB2 —>OB1,也就是X+Y-,对应规格书 时序 1 0 0 1,

测试是可以运行的,说明SPI模式驱动步进电机完成。

问题

驱动很简单,然而按照上面驱动调试了好久电机都驱动不了。
问题就出在了电机连接线是6线,相比一般的4线驱动电机还多了ACOM线和BCOM线。
没有接电机的时候,示波器测试脉冲信号输出都是正常的,一旦接上这6线电机,再次测量脉冲信号就异常了,
在这里插入图片描述
正常波形应该是这样的:
在这里插入图片描述
更换了一个4线的电机,测试发现可以驱动,这证明驱动是没问题了。
对比两个电机就是多了ACOM和BCOM线,猜测可能是ACOM和BCOM影响的所以驱动不了,去掉ACOM和BCOM连接后,测试果然电机成功驱动。

推测原因:电机连接了ACOM和BCOM线,属于单极性步进电机?TMC2660芯片不支持驱动单极性步进电机?

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/155880.html

(0)
上一篇 2025-02-16 16:26
下一篇 2025-02-16 16:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信