568 字
3 分钟
[onstep] OnStep项目SPI通信实现总结
引言
OnStep 系统在 ESP32 平台上与 TMC 驱动器交互时,未直接使用硬件 SPI,而是采用了软件模拟(Bit-Banging)方案。本文通过分析源码记录其底层实现细节及设计原因。
1. 核心机制:软件模拟 SPI
TIPOnStep 通过
bbspi类手动控制 GPIO 电平翻转,模拟标准的串行移位过程。
1.1 实现逻辑
核心逻辑位于 src/lib/SoftSPI.h 中。除了单字节传输,它还提供了高效的 32 位传输函数:
// 摘自 src/lib/SoftSPI.huint32_t bbspi::transfer32(uint32_t data_out) { uint32_t data_in = 0; for(int i=31; i >= 0; i--) { digitalWrite(_sck, LOW); digitalWrite(_mosi, bitRead(data_out, i)); delaySPI; digitalWrite(_sck, HIGH); if (_miso >= 0) bitWrite(data_in, i, digitalRead(_miso)); delaySPI; } return data_in;}2. 协议参数与时序
- SPI 模式: 源码注释明确为 Mode 3 (CPOL=1, CPHA=1)。
- 时钟空闲:
digitalWrite(_sck, HIGH)。 - 通信频率: 由
delaySPI宏控制。在src/HAL/ESP32/ESP32.h中:
#define delaySPI delayNanoseconds(500)NOTE单次位翻转包含两次
delaySPI,实际 SPI 频率约为 1MHz。这在保障长线缆抗干扰性的同时,满足了驱动器配置的需求。
3. 数据封包:TMC 40-bit 结构
针对 TMC 驱动器,单次读写由 1 字节地址和 4 字节数据组成。src/lib/TMC_SPI.h 实现了具体的封包逻辑:
3.1 写操作实现
// 摘自 src/lib/TMC_SPI.huint8_t tmcSpiDriver::write(byte Address, uint32_t data_out) { Address = Address | 0x80; // 第 1 位设为 1 表示写操作 uint8_t status_byte = BBSpi.transfer(Address); // 发送地址,获取状态字节 BBSpi.transfer32(data_out); // 发送 32 位配置数据 return status_byte;}3.2 读操作实现
uint8_t tmcSpiDriver::read(byte Address, uint32_t* data_out) { Address = Address & ~0x80; // 第 1 位设为 0 表示读操作 uint8_t status_byte = BBSpi.transfer(Address); *data_out = BBSpi.transfer32(*data_out); return status_byte;}4. 工程设计考量
IMPORTANT
- 确定性定时: 软件模拟 SPI 避免了硬件 SPI 中断或 DMA 可能对电机脉冲生成(ISR)造成的抖动干扰。
- 引脚灵活性: 允许在
Config.h中映射至任意可用 GPIO,不依赖硬件 SPI 专用引脚。- 一致性:
bbspi类可无缝跨平台(AVR, STM32, ESP32)运行,降低了维护成本。
总结
OnStep 的 SPI 实现体现了工程上的资源取舍:通过放弃极高的传输速度,换取了系统的实时确定性与极强的硬件适配性。这种设计对于需要精确定时和支持多样化 DIY 硬件的天文跟踪系统至关重要。
[onstep] OnStep项目SPI通信实现总结
https://www.eustia-astraea.top/posts/onstep/onstep-spi-analysis/