哈喽,各位工程师、技术小伙伴们~
上一篇我们系统拆解了 TMC2240 芯片工作原理概述,吃透了芯片的整体运行逻辑、核心技术与控制链路。本篇作为系列第五篇,严格对标官方数据手册的「SPI Interface」章节,结合时序图、数据结构、读写示例,从数据帧结构、读写规则、时序参数、状态位、工程实现等维度,完整拆解 TMC2240 的 SPI 接口,直接给出可落地的代码实现与避坑指南,帮大家彻底搞定 SPI 通信配置。
一、SPI接口核心定位与基础特性
TMC2240 采用 40位SPI数据帧 实现与微控制器的通信,是芯片寄存器配置、状态读取、参数整定的核心接口,核心特性如下:
- 通信模式:标准 SPI Mode 3(CPOL=1,CPHA=1),SCK 空闲为高,数据在 SCK 下降沿采样、上升沿输出
- 最大时钟频率:10MHz,兼容主流 MCU 硬件 SPI 外设
- 数据位序:MSB 先行(最高位先发送/接收)
- 片选逻辑:CSN 低电平有效,整个数据帧传输期间必须保持低电平
- 数据对齐:所有寄存器数据右对齐,支持无符号/有符号(补码)数值
- 内置滤波:所有 SPI 输入内置 10ns 尖峰滤波,避免短脉冲误触发
二、SPI数据帧结构(SPI Datagram Structure)
1. 40位数据帧总览
TMC2240 的每一次 SPI 通信都基于 40位固定长度数据帧,结构如下表:
| 位范围(MSB→LSB) | 39(最高位) | 38~32 | 31~0 |
|---|---|---|---|
| 写操作 | W=1(写标志) | 7位寄存器地址 | 32位待写入数据 |
| 读操作 | W=0(读标志) | 7位寄存器地址 | 32位待读取数据(上一次读操作的结果) |
关键规则:
- 读写标志位W(bit39):W=1 表示写操作,W=0 表示读操作,写操作需给地址加上 0x80(即最高位置1)
- 地址字节:每个寄存器对应唯一的 8位地址(bit39~bit32),其中 bit39 为读写标志,bit38~bit32 为7位寄存器地址
- 数据域:固定32位,即使寄存器实际使用位数不足32位,也按32位传输
- 读操作回传特性:SPI 接口在发送当前数据帧时,回传的是上一次读操作的数据;写操作时回传的是本次写入的数据(镜像)
2. 字节拆分结构
40位数据帧可拆分为 5个字节,结构更清晰:
| 字节序号 | 位范围 | 写操作内容 | 读操作内容 |
|---|---|---|---|
| 字节0(首字节) | 39~32 | W(1) + 7位寄存器地址 | W(0) + 7位寄存器地址 |
| 字节1 | 31~24 | 数据字节3(最高位数据字节) | 数据字节3(最高位数据字节) |
| 字节2 | 23~16 | 数据字节2 | 数据字节2 |
| 字节3 | 15~8 | 数据字节1 | 数据字节1 |
| 字节4(末字节) | 7~0 | 数据字节0(最低位数据字节) | 数据字节0(最低位数据字节) |
三、读写操作规则与示例
1. 读写操作核心规则
-
写操作:
- 地址字节最高位 W=1(地址 = 寄存器地址 | 0x80)
- 32位数据域为待写入寄存器的值
- 回传数据为本次写入的数据(镜像),无实际状态意义
- 所有寄存器可写,部分寄存器为「写1清零」(如 GSTAT 状态寄存器)
-
读操作:
- 地址字节最高位 W=0(地址 = 寄存器地址 & 0x7F)
- 发送当前读命令时,回传的是上一次读操作的寄存器数据
- 若上一次为写操作,回传的是上一次写入的数据(镜像)
- 所有寄存器可读,部分寄存器为只读
-
流水线读操作:连续读多个寄存器时,可采用流水线方式,前一次读命令的回传即为后一次的有效数据
2. 读写流程示例(对照官方 Table 2)
以寄存器 XACTUAL(地址 0x21)和 VMAX(地址 0x27)为例,完整读写流程如下:
| 操作动作 | 发送给TMC2240的数据(40位) | 从TMC2240接收的数据(40位) | 说明 |
|---|---|---|---|
| 第一次读 XACTUAL | 0x2100000000 | 0xSS & 无用数据* | 首次读无有效历史数据 |
| 第二次读 XACTUAL | 0x2100000000 | 0xSS & XACTUAL 实际值 | 回传第一次读的有效数据 |
| 写 VMAX=0x00ABCDEF | 0xA700ABCDEF | 0xSS & XACTUAL 实际值 | 回传上一次读的 XACTUAL 值 |
| 写 VMAX=0x00123456 | 0xA700123456 | 0xSS00ABCDEF | 回传上一次写的 VMAX 值 |
*SS 为 SPI_STATUS 状态位,固定占据回传数据的最高8位(bit39~bit32)
四、SPI_STATUS状态位详解
每一次 SPI 访问的回传数据中,最高8位(bit39~bit32)为 SPI_STATUS 状态标志,实时反映芯片状态,结构如下表:
| 位号 | 名称 | 功能说明 |
|---|---|---|
| 7:4 | don’t care | TMC2240 未使用,可忽略 |
| 3 | STST (standstill) | DRV_STATUS[31],1 表示电机处于静止状态 |
| 2 | SG2_RESULT | DRV_STATUS[24],1 表示 StallGuard2 标志激活(负载达到阈值) |
| 1 | OLA (driver_error) | GSTAT[1],1 表示驱动器1错误(通过读取 GSTAT 清零) |
| 0 | RESET (reset_flag) | GSTAT[0],1 表示发生复位(通过读取 GSTAT 清零,上电后默认置1) |
关键应用:
reset_flag:上电后必须读取 GSTAT 寄存器清零,否则一直置1driver_error:检测到驱动错误时置1,需排查过流、过温等故障standstill:用于判断电机是否静止,配合自动降压功能使用sg2:用于 CoolStep 负载检测、堵转判断
五、SPI时序参数与时序图
1. SPI时序图(Figure 4 官方时序)

TMC2240 SPI 接口时序如下,严格遵循 SPI Mode 3 规范:
- CSN 拉低启动通信,整个传输期间保持低电平
- SCK 空闲为高电平,数据在 SCK 下降沿采样(SDI)、上升沿输出(SDO)
- MSB 先行,40位数据依次传输
- CSN 拉高后,内部移位寄存器锁存命令,完成本次通信
2. 关键时序参数(电气规格表)
| 参数符号 | 参数名称 | 最小值 | 典型值 | 最大值 | 单位 | 说明 |
|---|---|---|---|---|---|---|
| fSCK | SCK 时钟频率 | - | - | 10 | MHz | 最大通信时钟 |
| tCC | CSN 高电平时间 | 50 | - | - | ns | 两次通信间 CSN 最小高电平 |
| tCL | SCK 低电平时间 | 20 | - | - | ns | SCK 低电平最小宽度 |
| tCH | SCK 高电平时间 | 20 | - | - | ns | SCK 高电平最小宽度 |
| tDU | SDI 建立时间(SCK 上升沿前) | 10 | - | - | ns | 数据输入建立时间 |
| tDH | SDI 保持时间(SCK 上升沿后) | 10 | - | - | ns | 数据输入保持时间 |
| tDO | SDO 输出有效时间(SCK 下降沿后) | 27 | - | 40 | ns | 数据输出延迟时间 |
| tZC | SDO 高阻时间(CSN 上升沿后) | - | - | - | ns | 总线释放时间 |
| tFILT | 输入滤波时间 | - | 10 | - | ns | 尖峰滤波宽度 |
工程注意:
- MCU SPI 配置必须严格匹配时序参数,避免通信错误
- 若 SCK 频率超过 10MHz,会导致通信异常,芯片不响应
- 超过40位的冗余数据会被内部移位寄存器延迟40个时钟后输出,可用于多芯片级联
六、SPI接口引脚定义与硬件设计
1. 引脚对应关系(两种封装)
| 引脚功能 | TQFN32 引脚号 | TSSOP38 引脚号 | 类型 | 说明 |
|---|---|---|---|---|
| SCK/AD1 | 27 | 38 | 数字输入 | SPI 串行时钟,UART 模式为地址位1 |
| SDI/AD0 | 28 | 1 | 数字输入 | SPI 数据输入,UART 模式为地址位0 |
| SDO/NAO | 29 | 2 | 数字输出 | SPI 数据输出,UART 模式为开漏输出 |
| CSN/AD2 | 26 | 36 | 数字输入 | SPI 片选(低有效),UART 模式为地址位2 |
2. 硬件设计注意事项
- 走线规范:SPI 信号线(SCK/SDI/SDO/CSN)远离电机功率线、大电流走线,做包地屏蔽,减少 EMI 干扰
- 上拉/下拉:CSN 需外接 10kΩ 上拉电阻,防止悬空误触发;SDI/SCK 内置上拉,无需额外上拉
- 时序匹配:MCU SPI 波特率不超过 10MHz,严格配置 SPI Mode 3,避免模式错误导致通信失败
- 多芯片级联:可通过冗余位实现多芯片 Daisy Chain 级联,共享 SCK/SDI/SDO,独立 CSN 控制。Daisy Chain 连接时,将所有芯片的 SCK、SDI 并联,MCU 的 SDO 仅连接第一片芯片的 SDI,每片芯片的 CSN 独立控制;发送 N×40 位数据即可将命令依次移位到各芯片。
七、工程实现:SPI读写代码示例(STM32 HAL库)
1. SPI初始化配置(SPI Mode 3)
// SPI1 初始化,配置为 SPI Mode 3,波特率 5MHz(≤10MHz)
SPI_HandleTypeDef hspi1;
void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH; // CPOL=1,空闲为高
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE; // CPHA=1,第二个沿采样
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件控制CSN
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB先行
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
}
2. TMC2240 SPI写操作函数
// TMC2240 SPI写寄存器函数
// addr: 寄存器7位地址
// data: 32位待写入数据
void TMC2240_SPI_Write(uint8_t addr, uint32_t data)
{
uint8_t tx_buf[5];
uint8_t rx_buf[5];
// 构造40位数据帧:addr最高位置1(写标志)
tx_buf[0] = addr | 0x80; // bit39~bit32:W=1 + 7位地址
tx_buf[1] = (data >> 24) & 0xFF; // bit31~bit24
tx_buf[2] = (data >> 16) & 0xFF; // bit23~bit16
tx_buf[3] = (data >> 8) & 0xFF; // bit15~bit8
tx_buf[4] = data & 0xFF; // bit7~bit0
// 拉低CSN,启动通信
HAL_GPIO_WritePin(TMC2240_CSN_GPIO_Port, TMC2240_CSN_Pin, GPIO_PIN_RESET);
// 发送40位数据,同时接收回传数据
HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 5, HAL_MAX_DELAY);
// 拉高CSN,结束通信
HAL_GPIO_WritePin(TMC2240_CSN_GPIO_Port, TMC2240_CSN_Pin, GPIO_PIN_SET);
// 延时满足CSN高电平时间要求(>50ns)
HAL_Delay(1); // 1ms 远大于要求,安全可靠
}
3. TMC2240 SPI读操作函数
// TMC2240 SPI读寄存器函数
// addr: 寄存器7位地址
// 返回值: 32位寄存器数据
uint32_t TMC2240_SPI_Read(uint8_t addr)
{
uint8_t tx_buf[5] = {0};
uint8_t rx_buf[5] = {0};
uint32_t data = 0;
// 构造40位读命令数据帧:addr最高位清0(读标志)
tx_buf[0] = addr & 0x7F; // bit39~bit32:W=0 + 7位地址
tx_buf[1] = 0x00;
tx_buf[2] = 0x00;
tx_buf[3] = 0x00;
tx_buf[4] = 0x00;
// 第一次发送读命令,回传为上一次数据(无效)
HAL_GPIO_WritePin(TMC2240_CSN_GPIO_Port, TMC2240_CSN_Pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 5, HAL_MAX_DELAY);
HAL_GPIO_WritePin(TMC2240_CSN_GPIO_Port, TMC2240_CSN_Pin, GPIO_PIN_SET);
HAL_Delay(1);
// 第二次发送读命令,回传为本次读的有效数据
HAL_GPIO_WritePin(TMC2240_CSN_GPIO_Port, TMC2240_CSN_Pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, tx_buf, rx_buf, 5, HAL_MAX_DELAY);
HAL_GPIO_WritePin(TMC2240_CSN_GPIO_Port, TMC2240_CSN_Pin, GPIO_PIN_SET);
HAL_Delay(1);
// 拼接32位数据(跳过最高8位状态位)
data = ((uint32_t)rx_buf[1] << 24) | ((uint32_t)rx_buf[2] << 16) |
((uint32_t)rx_buf[3] << 8) | rx_buf[4];
return data;
}
八、常见问题与避坑指南
1. 通信失败/无响应
- 排查 SPI 模式是否为 Mode 3,CPOL/CPHA 配置错误会导致完全无响应
- 检查 CSN 是否在整个传输期间保持低电平,CSN 提前拉高会导致命令丢失
- 确认 SCK 频率不超过 10MHz,过高频率会导致采样错误
- 检查硬件接线:SCK/SDI/SDO/CSN 是否接反,SDI/SDO 交叉会导致通信失败
2. 读数据错误/回传异常
- 读操作必须发送两次命令,第一次为预读,第二次才是有效数据
- 写操作后读数据,回传的是上一次写的数据,而非新写入的数据
- 状态位 SS 占据最高8位,读数据时需屏蔽该字节,避免数据错误
3. 上电后通信异常
- 上电后
reset_flag默认为1,必须读取 GSTAT 寄存器清零,否则芯片状态异常 - 上电后需延时至少 1ms,等待芯片稳定后再进行 SPI 通信
- 检查 VCC_IO 电压是否在 2.2V~5.5V 范围内,电压不足会导致逻辑异常
4. 多芯片级联问题
- 多芯片级联时,需保证每片芯片的 CSN 独立控制,避免总线冲突
- 冗余位传输时,需注意40位延迟,避免数据错位
九、系列更新预告
💡 下一篇我们将进入 TMC2240 UART单总线接口详解,拆解UART通信协议、数据帧结构、多节点寻址、时序参数与工程实现,完整覆盖两种串行接口。
有想看的重点内容(比如SPI/UART接口对比、寄存器配置实战、故障排查代码等)欢迎在评论区留言,我会在对应篇章重点补充!
记得关注不迷路,一起吃透 TMC2240!🚀
🎁欢迎关注公众号,获取更多技术干货!
博主准备到这份资料包涵盖了从硬件电路设计到STM32单片机开发,再到Linux系统学习的全链路内容,适合不同阶段的学习者:
- 硬件基础:包含硬件电路合集、硬件设计开发工具包,帮你打牢底层基础。
- STM32专项:从环境搭建、开发工具、传感器模块到项目实战,还有书籍和芯片手册,一站式搞定STM32学习。
- C语言进阶:C语言学习资料包,助你掌握嵌入式开发的核心语言。
- 面试求职:嵌入式面试题合集,提前备战技术面试。
- Linux拓展:Linux相关学习资料包,拓宽技术视野。

📂资料包目录
- 00-STM32单片机环境搭建
- 01-硬件电路合集
- 02-硬件设计开发工具包
- 03-C语言学习资料包
- 04-STM32单片机开发工具包
- 05-STM32传感器模块合集
- 06-STM32项目合集
- 07-STM32单片机书籍&芯片手册
- 08-Linux相关学习资料包

转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/u014411348/article/details/160051808



