大家好,欢迎来到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 |
对比这里双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