diff --git a/.gitignore b/.gitignore index e43b0f98..3786e617 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +*.sublime-workspace diff --git a/src/source/TMC2208Stepper.cpp b/src/source/TMC2208Stepper.cpp index a5dd227f..6e0aa006 100644 --- a/src/source/TMC2208Stepper.cpp +++ b/src/source/TMC2208Stepper.cpp @@ -7,6 +7,10 @@ #include "TMC_MACROS.h" #include "SERIAL_SWITCH.h" +#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN) + #include +#endif + // Protected // addr needed for TMC2209 TMC2208Stepper::TMC2208Stepper(Stream * SerialPort, float RS, uint8_t addr) : @@ -225,7 +229,7 @@ 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(); @@ -233,8 +237,42 @@ void TMC2208Stepper::write(uint8_t addr, uint32_t regVal) { delay(replyDelay); } +#if defined(ARDUINO_ARCH_RP2040) && defined(RP2040_SINGLE_WIRE_UART_PIN) + + #include + + // 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) { @@ -243,7 +281,14 @@ 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) { @@ -251,21 +296,18 @@ uint64_t TMC2208Stepper::_sendDatagram(uint8_t datagram[], const uint8_t len, ui } #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(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; @@ -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