TMC2209的UART/PDN引脚使用
在TODO(TMC2209驱动文章链接)中,已经可以通过串口控制电机的启动、停止、正反转以及速度的控制,为什么还在写一章TMC2209串口通讯呢?因为这个模块自带了一个串口通信,就是这个引脚(UART),本章节就来研究下如何使用该引脚

该串口通讯和PDN(省电低功耗,低电平有效)是共用的,这个设计就很巧妙,如果MCU配置了串口功能,那么引脚在空闲状态都是高电平的,就不会让TMC2209进入到省电模式,就是正常的串口通讯。
但是有一个问题随着而来,串口通讯一般都是有两个引脚:TX和RX。为啥这只用到一个引脚呢?难道只用发送数据不接受数据吗?
确实也可以,只发相关的控制命令,不需要接收。如果需要接收数据,那么TX和RX之间串连一个1K的电阻,然后RX在连接到模块的UART引脚,这样就可以接收和发送数据了,官方的连接示意图如下:


那么可以参考这种连接方式,恰巧模块上的UART/PDN通过焊盘跳线对外引脚出了两个引脚,那么可以取巧一下,这样连接,将PAD2和PAD3短接,然后PDN和短接的地方串联一个1K的电阻,这样就将PDN作为TX,UART作为RX了。


串口协议格式
写寄存器:帧总长8个字节
Byte0 sync/reserved = 0x05 Byte1 node address, 0..3,由 MS1/MS2 决定 Byte2 register address | 0x80 Byte3 data[31:24] Byte4 data[23:16] Byte5 data[15:8] Byte6 data[7:0] Byte7 CRC
读寄存器:帧总长4个字节:
Byte0 sync/reserved = 0x05 Byte1 node address, 0..3 Byte2 register address & 0x7F Byte3 CRC
UART 读访问回复数据报结构:
Byte0 sync/reserved = 0x05 Byte1 master address = 0xFF Byte2 register address & 0x7F Byte3 data[31:24] Byte4 data[23:16] Byte5 data[15:8] Byte6 data[7:0] Byte7 CRC
CRC
读写都使用8-bit CRC,算法是CRC8-ATM,初始值为0x00,多项式:x^8 + x^2 + x + 1,文档中也给出来了C语言计算函数

常用的协议
UART 帧格式
操作发送方向字节数帧格式
| 写寄存器 | MCU -> TMC2209 | 8 | 0x05, NODE, ADDR |
| 读请求 | MCU -> TMC2209 | 4 | 0x05, NODE, ADDR&0x7F, CRC |
| 读响应 | TMC2209 -> MCU | 8 | 0x05, 0xFF, ADDR&0x7F, D3, D2, D1, D0, CRC |
NODE:节点地址,范围是:0..3,由 MS1/MS2 决定。
D3..D0:32位数据,高字节先发。
功能分类寄存器地址读命令字写命令字用途
| 全局配置 | GCONF | 0x00 | 0x00 | 0x80 | 使能 UART 模式、方向反转、StealthChop/SpreadCycle、微步来源等 |
| 状态清除 | GSTAT | 0x01 | 0x01 | 0x81 | 读取/清除复位、驱动错误、欠压标志 |
| 通信检测 | IFCNT | 0x02 | 0x02 | - | 成功写帧计数器,用来确认 UART 写入是否生效 |
| 节点配置 | NODECONF | 0x03 | - | 0x83 | 设置读响应延迟 SENDDELAY |
| IO 状态 | IOIN | 0x06 | 0x06 | - | 读取 ENN/MS1/MS2/DIAG/PDN_UART/STEP/DIR 等引脚状态和版本号 |
| 工厂配置 | FACTORY_CONF | 0x07 | 0x07 | 0x87 | 时钟微调、过温阈值配置,通常不建议随意改 |
| 电流控制 | IHOLD_IRUN | 0x10 | - | 0x90 | 设置保持电流 IHOLD、运行电流 IRUN、电流下降延迟 |
| 掉电延迟 | TPOWERDOWN | 0x11 | - | 0x91 | 静止后多久进入低保持电流 |
| 速度测量 | TSTEP | 0x12 | 0x12 | - | 读取 STEP 输入对应的速度周期 |
| 静音阈值 | TPWMTHRS | 0x13 | - | 0x93 | 设置 StealthChop 与 SpreadCycle 切换阈值 |
| StallGuard 阈值 | TCOOLTHRS | 0x14 | - | 0x94 | 设置 CoolStep/StallGuard 生效的速度下限 |
| UART 运动 | VACTUAL | 0x22 | - | 0xA2 | 通过 UART 直接给速度,不用 STEP 脉冲 |
| 堵转阈值 | SGTHRS | 0x40 | - | 0xC0 | 设置 StallGuard 堵转检测阈值 |
| 堵转结果 | SG_RESULT | 0x41 | 0x41 | - | 读取 StallGuard 负载结果,值越低负载越大 |
| CoolStep | COOLCONF | 0x42 | - | 0xC2 | 配置 CoolStep 自动电流调节 |
| 微步位置 | MSCNT | 0x6A | 0x6A | - | 读取当前微步计数位置 |
| 相电流表值 | MSCURACT | 0x6B | 0x6B | - | 读取内部正弦表当前 A/B 相电流值 |
| 斩波配置 | CHOPCONF | 0x6C | 0x6C | 0xEC | 设置微步、插值、TOFF、blank time、SpreadCycle 参数等 |
| 驱动状态 | DRV_STATUS | 0x6F | 0x6F | - | 读取过温、短路、开路、实际电流、静止状态等 |
| PWM 配置 | PWMCONF | 0x70 | 0x70 | 0xF0 | 配置 StealthChop PWM 自动调节、频率、freewheel 等 |
| PWM 运行值 | PWM_SCALE | 0x71 | 0x71 | - | 读取 StealthChop 当前 PWM 调节结果 |
| PWM 自动值 | PWM_AUTO | 0x72 | 0x72 | - | 读取自动整定得到的 PWM_OFS_AUTO/PWM_GRAD_AUTO |
根据这个总览表,可以计算出来实际需要发送的数据:
功能写入值直接发送 HEX
| 启用 UART 控制,使用寄存器微步,保留外部 VREF 模式 | GCONF=0x000001C1 | 05 00 80 00 00 01 C1 7F |
| 启用 UART 控制,使用寄存器微步,内部参考模式 | GCONF=0x000001C0 | 05 00 80 00 00 01 C0 F6 |
| 清除 GSTAT 的 reset / drv_err / uv_cp 标志 | GSTAT=0x00000007 | 05 00 81 00 00 00 07 70 |
| 设置读响应延迟,适合多节点 | NODECONF=0x00000200 | 05 00 83 00 00 02 00 4D |
| 设置电流:IHOLD=8, IRUN=31, IHOLDDELAY=8 | IHOLD_IRUN=0x00081F08 | 05 00 90 00 08 1F 08 3E |
| 设置电流:IHOLD=16, IRUN=31, IHOLDDELAY=8 | IHOLD_IRUN=0x00081F10 | 05 00 90 00 08 1F 10 76 |
| 设置电流:IHOLD=8, IRUN=20, IHOLDDELAY=8 | IHOLD_IRUN=0x00081408 | 05 00 90 00 08 14 08 84 |
| 静止降流延迟,默认常用值 | TPOWERDOWN=20 | 05 00 91 00 00 00 14 1F |
| 关闭 StealthChop 速度阈值限制 | TPWMTHRS=0 | 05 00 93 00 00 00 00 0F |
| 关闭 CoolStep/StallGuard 速度阈值 | TCOOLTHRS=0 | 05 00 94 00 00 00 00 34 |
| 设置 StallGuard 阈值 80 | SGTHRS=80 | 05 00 C0 00 00 00 50 BB |
| 关闭 CoolStep 自动电流调节 | COOLCONF=0 | 05 00 C2 00 00 00 00 45 |
CHOPCONF 微步设置
这些命令会设置 intpol=1、TOFF=3,驱动器开启。
微步CHOPCONF 值直接发送 HEX
| 256 | 0x10000053 | 05 00 EC 10 00 00 53 9C |
| 128 | 0x11000053 | 05 00 EC 11 00 00 53 AD |
| 64 | 0x12000053 | 05 00 EC 12 00 00 53 07 |
| 32 | 0x13000053 | 05 00 EC 13 00 00 53 36 |
| 16 | 0x14000053 | 05 00 EC 14 00 00 53 52 |
| 8 | 0x15000053 | 05 00 EC 15 00 00 53 63 |
| 4 | 0x16000053 | 05 00 EC 16 00 00 53 C9 |
| 2 | 0x17000053 | 05 00 EC 17 00 00 53 F8 |
| 全步 | 0x18000053 | 05 00 EC 18 00 00 53 FB |
关闭驱动输出:
功能写入值直接发送 HEX
| 关闭 driver,TOFF=0 | CHOPCONF=0x10000050 | 05 00 EC 10 00 00 50 D2 |
UART 直接转动命令
这些会让电机通过 VACTUAL 直接运动,不需要 STEP 脉冲
功能写入值直接发送 HEX
| 停止UART速度模式 | VACTUAL=0 | 05 00 A2 00 00 00 00 0E |
| 正向低速转动 | VACTUAL=10000 | 05 00 A2 00 00 27 10 21 |
| 反向低速转动 | VACTUAL=-10000 | 05 00 A2 00 FF D8 F0 C8 |
发送几个读取命令看看:
发现接收部分的前几个字节和发送的是一样的,这是因为TX和RX是通过1K的电阻相连接的,相当于自发自收了,后面那部分的数据才是模块回复的

发送几个写入命令看看:
写入命令不会有任何的返回,看到的接收数据是自发自收的。

我要赚赏金
