Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 54 additions & 16 deletions src/source/TMC2208Stepper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#include "TMC_MACROS.h"
#include "SERIAL_SWITCH.h"

#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN)
#include <hardware/gpio.h>
#endif

// Protected
// addr needed for TMC2209
TMC2208Stepper::TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr) :
Expand Down Expand Up @@ -201,8 +205,41 @@ void TMC2208Stepper::write(uint8_t addr, uint32_t regVal) {
delay(replyDelay);
}

#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN)
#include <hardware/gpio.h>
// Bit-bang one 8N1 UART byte on the single-wire PDN_UART pin.
// Temporarily switches GPIO to SIO output for TX, then restores UART RX mode.
// 9 µs/bit ≈ 111 kbaud (-3.7% vs 115200) — within the ±6.25% 8N1 tolerance.
static void _rp2040_sw_uart_write_byte(uint8_t byte) {
constexpr uint32_t T = 9; // µs per bit
gpio_set_function(RP2040_SINGLE_WIRE_UART_PIN, GPIO_FUNC_SIO);
gpio_set_dir(RP2040_SINGLE_WIRE_UART_PIN, GPIO_OUT);
gpio_put(RP2040_SINGLE_WIRE_UART_PIN, 1); // idle HIGH before start bit
// Start bit
gpio_put(RP2040_SINGLE_WIRE_UART_PIN, 0);
delayMicroseconds(T);
// 8 data bits, LSB first
for (int i = 0; i < 8; i++) {
gpio_put(RP2040_SINGLE_WIRE_UART_PIN, (byte >> i) & 1);
delayMicroseconds(T);
}
// Stop bit
gpio_put(RP2040_SINGLE_WIRE_UART_PIN, 1);
delayMicroseconds(T);
// Restore UART1 RX function on GPIO9
gpio_set_function(RP2040_SINGLE_WIRE_UART_PIN, GPIO_FUNC_UART);
}
#endif

uint64_t TMC2208Stepper::_sendDatagram(uint8_t datagram[], const uint8_t len, uint16_t timeout) {
while (available() > 0) serial_read(); // Flush
// === STEP 0: flush stale RX bytes ===
{
uint32_t _flush_t0 = micros();
while (available() > 0) {
serial_read();
if ((micros() - _flush_t0) > (uint32_t)timeout * 1000UL) break;
}
}

#if defined(ARDUINO_ARCH_AVR)
if (RXTX_pin > 0) {
Expand All @@ -211,29 +248,33 @@ uint64_t TMC2208Stepper::_sendDatagram(uint8_t datagram[], const uint8_t len, ui
}
#endif

// === STEP 1: write request ===
#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN)
noInterrupts();
for(int i=0; i<=len; i++) _rp2040_sw_uart_write_byte(datagram[i]);
interrupts();
#else
for(int i=0; i<=len; i++) serial_write(datagram[i]);
#endif

#if defined(ARDUINO_ARCH_AVR)
if (RXTX_pin > 0) {
pinMode(RXTX_pin, INPUT_PULLUP);
}
#endif

// === STEP 2: reply delay ===
delay(this->replyDelay);

// scan for the rx frame and read it
uint32_t ms = millis();
// === STEP 3: sync scan with micros() timeout ===
uint32_t _sync_t0 = micros();
uint32_t sync_target = (static_cast<uint32_t>(datagram[0])<<16) | 0xFF00 | datagram[2];
uint32_t sync = 0;

do {
uint32_t ms2 = millis();
if (ms2 != ms) {
// 1ms tick
ms = ms2;
timeout--;
if ((micros() - _sync_t0) > (uint32_t)timeout * 1000UL) {
return 0;
}
if (!timeout) return 0;

int16_t res = serial_read();
if (res < 0) continue;
Expand All @@ -244,18 +285,15 @@ uint64_t TMC2208Stepper::_sendDatagram(uint8_t datagram[], const uint8_t len, ui

} while (sync != sync_target);

// === STEP 4: body read ===
uint64_t out = sync;
ms = millis();
uint32_t _body_t0 = micros();
timeout = this->abort_window;

for(uint8_t i=0; i<5;) {
uint32_t ms2 = millis();
if (ms2 != ms) {
// 1ms tick
ms = ms2;
timeout--;
if ((micros() - _body_t0) > (uint32_t)timeout * 1000UL) {
return 0;
}
if (!timeout) return 0;

int16_t res = serial_read();
if (res < 0) continue;
Expand Down