Skip to content
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.DS_Store
*.sublime-workspace
79 changes: 58 additions & 21 deletions src/source/TMC2208Stepper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,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 @@ -225,16 +229,50 @@ void TMC2208Stepper::write(uint8_t addr, uint32_t regVal) {

preWriteCommunication();

for(uint8_t i=0; i<=len; i++) {
for (uint8_t i = 0; i<= len; i++) {
bytesWritten += serial_write(datagram[i]);
}
postWriteCommunication();

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 // ARDUINO_ARCH_RP2040 && RP2040_SINGLE_WIRE_UART_PIN

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 ===
const uint32_t _flush_t0 = micros();
while (available() > 0) {
serial_read();
if ((micros() - _flush_t0) > (uint32_t)timeout * 1000UL) break;
}

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

for(int i=0; i<=len; i++) serial_write(datagram[i]);
// === 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 HAS_HALF_DUPLEX_MODE
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 @@ -276,26 +318,21 @@ 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--;
for (uint8_t i = 0; i < 5; i++) {
if ((micros() - _body_t0) > (uint32_t)timeout * 1000UL) {
return 0;
}
if (!timeout) return 0;

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

out <<= 8;
out |= res & 0xFF;

i++;
}

#if HAS_HALF_DUPLEX_MODE
Expand Down