任务介绍
本项目实现了Funpack第4-3期活动板卡二的任务一,基于MicroPython控制Teensy 4.1开发板实现了对TMC4361A+TMC2160步进电机控制,并在此软硬件基础上控制42步进电机,实现了一个精密运动控制系统,支持通过串口命令进行速度、位置控制,同时实时反馈电机运行状态信息。
硬件平台
本次使用Teensy 4.1开发板,是一款面向嵌入式开发的高性能评估平台。该开发板搭载了基于ARM Cortex-M7内核的IMXRT1062 MCU,具备丰富的外设资源,包括多个SPI接口、UART接口、I2C接口等,非常适合用于实时步进电机控制系统的开发。开发板集成了调试器接口、USB接口、用户可编程LED与GPIO,便于快速搭建电机控制原型系统。
在软件方面,本项目采用MicroPython实时编程环境作为底层运行环境。MicroPython以其轻量级、高可扩展性和良好的硬件抽象层支持而著称,适用于资源受限的嵌入式设备。通过将TMC4361驱动程序移植至Teensy平台,实现了精确的位置控制、速度调节以及实时状态监控等功能。
核心部件:TMC4361A-BOB & TMC2160-BOB步进电机控制评估套件
TMC4361A运动控制器
TMC4361A是ADI公司的一款高性能步进电机驱动芯片,支持SPI和Step/Dir接口,还具备编码器接口,能实现闭环控制。它集成了ChopSync和dcStep技术,支持S形或六点式斜坡发生器,可实时调整速度曲线。但它只是控制器,无法直接控制步进电机,我们还需要一个驱动器。

TMC2160栅极驱动器
TMC2160是ADI推出的一款高性能两相步进电机驱动芯片,专为高动态、高扭矩应用设计,支持外部MOSFET,具备静音、高效和紧凑等优势。它有以下几个关键特性:
- 工作电压:8V 至 60V(支持外部N沟道MOSFET)
- 电流能力:高达4.6A RMS(6.5A峰值)
- 接口:SPI + Step/Direction,支持高达256微步细分
- 优势功能:
- StealthChop:实现超静音运行
- SpreadCycle:智能混合衰减模式,优化能效和扭矩
- CoolStep:动态电流调节,节能高效
- StallGuard2:负载检测,无需传感器

主控设备:TEENSY 4.1开发板
- 搭载IMXRT1062 MCU(ARM Cortex-M7内核)
- 集成USB接口与调试器
- 板载用户可编程LED指示灯
- 支持MicroPython实时编程环境

被控对象:42步进电机

任务分析与实现
本系统实现了基于MicroPython的TMC4361A+TMC2160步进电机控制平台,主要功能包括:
三通道数据交互:
- 电机控制指令
- 串口命令解析频率:20Hz
- 支持RPM转速、角度、圈数控制
- SPI通信控制
- 通信波特率:4MHz
- 高可靠性数据传输
- MicroPython任务调度
- 实时反馈电机状态
- 精确位置与速度控制
方案框图:
驱动编写
本项目基于 TEENSY 4.1 开发板完成了 TMC4361A+TMC2160 电机控制系统的成功移植,并在此基础上实现了对42步进电机的精密控制与运动监测功能。以下详细描述了MicroPython移植的关键流程和核心要点。
一、驱动编写前的准备
1. 硬件环境
- 主控芯片:NXP IMXRT1062(ARM Cortex-M7 内核)
- 开发板:TEENSY 4.1
- 外设资源:
- SPI 接口用于驱动 TMC4361A 运动控制器
- PWM 输出提供系统时钟信号
- UART 串口用于命令控制与状态反馈
2. 软件环境
- IDE:Thonny
- MicroPython 版本:MicroPython 最新版
- 构建工具:mpy-cross 编译器
二、驱动模块编写的核心步骤
1. 驱动模块创建 (tmc4361.py)
驱动模块是MicroPython针对TMC4361A运动控制器的支持包,主要包括寄存器定义、通信协议、控制接口以及运动参数配置。
a. 寄存器地址定义
- 定义TMC4361A全部寄存器地址映射
- 包含运动控制、速度设定、加速度配置等功能寄存器
- 提供事件检测和状态反馈寄存器
# TMC4361 register addresses
TMC4361_GENERAL_CONFIG_REGISTER = 0x0
TMC4361_REFERENCE_CONFIG_REGISTER = 0x01
TMC4361_START_CONFIG_REGISTER = 0x2
TMC4361_INPUT_FILTER_REGISTER = 0x3
b. 功能枚举定义
- 定义运动模式(速度模式、定位模式)
- 定义斜坡类型(矩形、梯形、S型斜坡)
- 定义事件类型和标志位
class RampMode:
VELOCITY_MODE = 0x00
POSITIONING_MODE = (0x01 << 2)
class RampType:
HOLD_RAMP = 0x00 # Follow max speed (rectangle shape)
TRAPEZOIDAL_RAMP = 0x01
S_SHAPED_RAMP = 0x02
2. SPI通信实现 (_spi_transfer函数)
完成SPI协议的底层实现:
def _spi_transfer(self, address, data):
"""Perform SPI transfer"""
return_buffer = 0
self._cs.value(0)
time.sleep_us(10)
if (address & 0x80) != 0: # Write operation
# For write operations, send the address + data (5 bytes)
data_bytes = struct.pack('>BI', address, data)
self._spi.write(data_bytes)
else: # Read operation
# Send address as one byte sequence for read
address_byte = struct.pack('>B', address)
self._spi.write(address_byte)
# Read response - first byte is dummy, next 4 bytes contain the actual data
response = self._spi.read(4)
# Unpack the 4 bytes of actual data (ignore first dummy byte)
return_buffer = struct.unpack('>I', response)[0]
self._cs.value(1)
time.sleep_ms(10)
return return_buffer
3. 运动控制接口实现
a. 位置与速度控制接口 (set_target_position, set_max_speed)
- 实现目标位置设定功能
- 提供最大速度限制控制
- 支持当前实际位置查询
def set_target_position(self, position):
"""Set the target position
/!\ Set all other motion profile parameters before
"""
self.write_register(TMC4361_X_TARGET_REGISTER, position)
def set_max_speed(self, speed):
"""Set the max speed VMAX (steps/second)
/!\ Don't exceed clockFreq / 2 in velocity mode and clockFreq / 4 in positioning mode
"""
self.write_register(TMC4361_V_MAX_REGISTER, self._float_to_fixed_point(speed, 8))
b. 加速度控制接口 (set_accelerations)
- 封装加速度、减速度参数设置
- 实现起始加速度和最终减速度控制
- 支持S型斜坡控制参数设定
def set_accelerations(self, max_accel, max_decel, start_accel, final_decel):
"""Set the ramp accelerations (in steps / second^2). See datasheet §6.3.6"""
self.write_register(TMC4361_A_MAX_REGISTER, self._float_to_fixed_point(abs(max_accel), 2) & 0xFFFFFFFF)
self.write_register(TMC4361_D_MAX_REGISTER, self._float_to_fixed_point(abs(max_decel), 2) & 0xFFFFFFFF)
self.write_register(TMC4361_A_START_REGISTER, self._float_to_fixed_point(abs(start_accel), 2) & 0xFFFFFFFF)
self.write_register(TMC4361_D_FINAL_REGISTER, self._float_to_fixed_point(abs(final_decel), 2) & 0xFFFFFFFF)
4. 应用层控制实现
使用MicroPython提供的高级接口,实现便捷的控制功能:
def set_speed_in_rpm(rpm):
"""Set motor speed in RPM"""
# Convert RPM to steps per second
# 1 RPM = 1 revolution per minute = STEPS_PER_REVOLUTION steps per minute
# So RPM * STEPS_PER_REVOLUTION / 60 = steps per second
steps_per_second = rpm * STEPS_PER_REVOLUTION // 60
tmc.set_ramp_mode(tmc4361.TMC4361.RampMode.VELOCITY_MODE, tmc4361.TMC4361.RampType.HOLD_RAMP)
tmc.set_max_speed(steps_per_second)
代码详解
整体软件流程图:
一、硬件初始化与电机配置
系统启动后首先完成TMC4361A控制器初始化序列,关键流程如下:
- 配置SPI接口为模式1(CPOL=1, CPHA=1),设置通信波特率为4MHz
- 初始化PWM输出提供TMC4361A系统时钟(16MHz)
- 启动TMC4361A并配置基本运动参数
def setup():
print("Starting TMC4361 controller test...")
# Init TMC4361 clock using PWM
clk_pin = Pin(TMC4361_CLK_PIN, Pin.OUT)
clk_pwm = PWM(clk_pin)
clk_pwm.freq(TMC4361_CLK_FREQ)
clk_pwm.duty_u16(65535//2) # 50% duty cycle (65535 is max for default resolution)
# Initialize TMC4361
tmc.begin()
# Configuration sequence from original Arduino code
# SPI_OUT_CONF
tmc.write_register(tmc4361.TMC4361_SPIOUT_CONF_REGISTER, 0x4440128D)
time.sleep_ms(5)
在PWM代码编写完后,可以接示波器测量一下,是否有实际波形输出。如图:

二、串口命令解析与执行
def handle_serial_command(cmd):
"""Process a serial command"""
# Handle S command for setting speed in RPM
if len(cmd) >= 2 and cmd[0] == 'S':
try:
rpm_str = cmd[1:]
rpm = int(rpm_str)
print(f"Setting speed to {rpm} RPM")
set_speed_in_rpm(rpm)
except ValueError:
print("Error: Invalid RPM value.")
# Handle A command for rotation by degrees
elif len(cmd) >= 2 and cmd[0] == 'A':
try:
angle_str = cmd[1:]
angle = int(angle_str)
print(f"Rotating by {angle} degrees")
rotate_by_degrees(angle)
except ValueError:
print("Error: Invalid angle value.")
# Handle C command for rotation by number of turns
elif len(cmd) >= 2 and cmd[0] == 'C':
try:
turns_str = cmd[1:]
turns = int(turns_str)
print(f"Rotating by {turns} turns")
rotate_by_turns(turns)
except ValueError:
print("Error: Invalid turns value.")
elif len(cmd) > 0:
print("Invalid command. Use format: Sxxx (RPM), Axxx (degrees), Cxxx (turns)")
效果展示

遇到的难题与解决办法
问题:MicroPython驱动编写过程中遇到SPI通信没效果的问题
解法
整个移植过程中,有几个要注意的地方:
- SPI通信时序与TMC4361A时序要求的精确匹配
- 固定点数值转换算法的准确性,确保速度和位置控制精度
- 连接逻辑分析仪,即时抓取波形观察是否符合预期
活动感想
通过本项目实践,我深入掌握了基于TMC4361A+TMC2160的步进电机控制方法。这个过程中TEENSY 4.1开发板良好的硬件兼容性与MicroPython强大的实时编程能力极大提升了开发效率,相比于C编程体验要更丝滑。果然还得是那句话:人生苦短,我用Python!
感谢硬禾学堂和得捷电子联合举办的Funpack活动,祝硬禾的活动越办越好!