From 11cc41f7427447efed81b85b2f4d214d6466a19a Mon Sep 17 00:00:00 2001 From: Wastl Kraus Date: Wed, 30 Jul 2025 14:44:01 +0200 Subject: [PATCH] ...DShot Mode rework --- DShotRMT.cpp | 78 +++++----------------------------- DShotRMT.h | 40 ++++++++++++----- README.md | 2 +- examples/dshot300/dshot300.ino | 9 ++-- 4 files changed, 47 insertions(+), 82 deletions(-) diff --git a/DShotRMT.cpp b/DShotRMT.cpp index 1acc3ec..4fcaa1f 100644 --- a/DShotRMT.cpp +++ b/DShotRMT.cpp @@ -15,37 +15,14 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool isBidirectional) : _gpio(gpio), _mode(mode), _isBidirectional(isBidirectional) { + // Fixed Timings for compatibility + _frame_time = dshot_times.frameLength + DSHOT_SWITCH_TIME; - // Setting up fixed DShot Frame length - switch (_mode) - { - case DSHOT_OFF: - _frameLength = 0; - break; - case DSHOT150: - _frameLength = 128; - break; - case DSHOT300: - _frameLength = 64; - break; - case DSHOT600: - _frameLength = 32; - break; - case DSHOT1200: - _frameLength = 16; - break; - default: - break; - } - - // DShot Frame length incl. DShot answer duration + // DShot Frame answer padding if (_isBidirectional) { - _frameLength += _frameLength; + _frame_time += _frame_time; } - - // Add frame tolerance - _frameLength = _frameLength + DSHOT_SWITCH_TIME; } // Initializes RMT TX and RX channels and encoder configuration @@ -86,7 +63,7 @@ void DShotRMT::begin() .trans_queue_depth = TX_BUFFER_SIZE}; // Transmission configuration - _transmit_config.loop_count = 0; + _transmit_config.loop_count = NULL; _transmit_config.flags.eot_level = _isBidirectional; if (rmt_new_tx_channel(&_rmt_tx_channel_config, &_rmt_tx_channel) != 0) @@ -131,7 +108,7 @@ void DShotRMT::setThrottle(uint16_t throttle) encodeDShotTX(packet, tx_symbols); // Ensure frame lenght for compatibility - if (micros() - last_time >= _frameLength) + if (micros() - last_time >= _frame_time) { // Transmit the packet if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, DSHOT_SYMBOLS_SIZE, &_transmit_config) != 0) @@ -206,40 +183,7 @@ uint16_t DShotRMT::parseDShotPacket(const dshot_packet_t dshot_packet) // Converts a 16-bit packet into a valid DShot frame for RMT void DShotRMT::encodeDShotTX(dshot_packet_t dshot_packet, rmt_symbol_word_t *symbols) { - uint16_t ticks_per_bit = 0; - uint16_t ticks_zero_high = 0; - uint16_t ticks_one_high = 0; - - // Select timing based on DShot mode - switch (_mode) - { - case DSHOT150: - ticks_per_bit = 64; - ticks_zero_high = 24; - ticks_one_high = 48; - break; - case DSHOT300: - ticks_per_bit = 32; - ticks_zero_high = 12; - ticks_one_high = 24; - break; - case DSHOT600: - ticks_per_bit = 16; - ticks_zero_high = 6; - ticks_one_high = 12; - break; - case DSHOT1200: - ticks_per_bit = 8; - ticks_zero_high = 3; - ticks_one_high = 6; - break; - case DSHOT_OFF: - return; - } - - uint16_t ticks_zero_low = ticks_per_bit - ticks_zero_high; - uint16_t ticks_one_low = ticks_per_bit - ticks_one_high; - + // Encoding to "raw" DShot Packet uint16_t frame_bits = parseDShotPacket(dshot_packet); // Always start with the "first" bit @@ -252,16 +196,16 @@ void DShotRMT::encodeDShotTX(dshot_packet_t dshot_packet, rmt_symbol_word_t *sym if (_isBidirectional) { symbols[count].level0 = 0; - symbols[count].duration0 = bit ? ticks_one_high : ticks_zero_high; + symbols[count].duration0 = bit ? dshot_times.ticks_one_high : dshot_times.ticks_zero_high; symbols[count].level1 = 1; - symbols[count].duration1 = bit ? ticks_one_low : ticks_zero_low; + symbols[count].duration1 = bit ? dshot_times.ticks_one_low : dshot_times.ticks_zero_low; } else { symbols[count].level0 = 1; - symbols[count].duration0 = bit ? ticks_one_high : ticks_zero_high; + symbols[count].duration0 = bit ? dshot_times.ticks_one_high : dshot_times.ticks_zero_high; symbols[count].level1 = 0; - symbols[count].duration1 = bit ? ticks_one_low : ticks_zero_low; + symbols[count].duration1 = bit ? dshot_times.ticks_one_low : dshot_times.ticks_zero_low; } count++; } diff --git a/DShotRMT.h b/DShotRMT.h index aff4be9..6cc0ece 100644 --- a/DShotRMT.h +++ b/DShotRMT.h @@ -37,10 +37,30 @@ typedef enum dshot_mode_s DSHOT150, DSHOT300, DSHOT600, - DSHOT1200, - COUNTER + DSHOT1200 } dshot_mode_t; +// --- DShot Timings --- +typedef struct dshot_timing_s +{ + uint16_t frameLength; + uint16_t ticks_per_bit; + uint16_t ticks_one_high; + uint16_t ticks_zero_high; + uint16_t ticks_zero_low; + uint16_t ticks_one_low; +} dshot_timing_t; + +// DShot Pulse Length Settings +const dshot_timing_t dshot_timings[] = { + {0, 0, 0, 0, 0, 0}, // DSHOT_OFF + {128, 64, 48, 24, 40, 16}, // DSHOT150 + {64, 32, 24, 12, 20, 8}, // DSHOT300 + {32, 16, 12, 6, 10, 4}, // DSHOT600 + {16, 8, 6, 3, 5, 2} // DSHOT1200 +}; + +// // --- DShotRMT Class --- class DShotRMT { @@ -61,11 +81,17 @@ public: // Accessors for GPIO and DShot settings gpio_num_t getGPIO() const { return _gpio; } dshot_mode_t getDShotMode() const { return _mode; } - uint16_t getFrameLenght() const { return _frameLength; } + + // --- Configuration Parameters --- + gpio_num_t _gpio = GPIO_NUM_NC; + dshot_mode_t _mode = DSHOT_OFF; + bool _isBidirectional = false; + uint16_t _frame_time; + const dshot_timing_t &dshot_times = dshot_timings[_mode]; private: static constexpr uint8_t DSHOT_BITS_PER_FRAME = 16; - static constexpr uint8_t DSHOT_SWITCH_TIME = 21; + static constexpr uint8_t DSHOT_SWITCH_TIME = 42; static constexpr uint16_t DSHOT_NULL_PACKET = 0b000000000000000; static constexpr uint16_t DSHOT_FULL_PACKET = 0b111111111111111; @@ -91,12 +117,6 @@ private: // Decodes the ESC answer uint16_t decodeDShotRX(const rmt_symbol_word_t *symbols, uint32_t count); - // --- Configuration Parameters --- - gpio_num_t _gpio = GPIO_NUM_NC; - dshot_mode_t _mode = DSHOT_OFF; - bool _isBidirectional = false; - uint16_t _frameLength = NULL; - // --- DShot Packets Container --- uint16_t _rx_packet = DSHOT_NULL_PACKET; diff --git a/README.md b/README.md index a35443c..1fd1186 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ Perfect for DShot: ## 📝 API Reference -- `DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool isBidirectional, uint8_t pauseDuration = 120)` +- `DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool isBidirectional)` - `void begin()` - `void setThrottle(uint16_t throttle)` - `uint32_t getERPM()` diff --git a/examples/dshot300/dshot300.ino b/examples/dshot300/dshot300.ino index 79b5d2a..281fd63 100644 --- a/examples/dshot300/dshot300.ino +++ b/examples/dshot300/dshot300.ino @@ -32,6 +32,7 @@ void printRPMPeriodically(uint16_t throttle); // Reads throttle value from serial input uint16_t readSerialThrottle(); +// void setup() { // Start the USB Serial Port @@ -48,6 +49,7 @@ void setup() USB_SERIAL.println("Enter a throttle value (48–2047):"); } +// void loop() { // Read value input from Serial @@ -96,17 +98,16 @@ uint16_t readSerialThrottle() void printRPMPeriodically(uint16_t throttle) { static unsigned long last_print_time = 0; - unsigned long now = millis(); - if (now - last_print_time >= 2000) + if (millis() - last_print_time >= 2000) { - last_print_time = now; - uint32_t rpm = motor01.getMotorRPM(MOTOR01_MAGNET_COUNT); USB_SERIAL.print("Throttle: "); USB_SERIAL.print(throttle); USB_SERIAL.print(" | RPM: "); USB_SERIAL.println(rpm); + + last_print_time = millis(); } }