diff --git a/DShotRMT.cpp b/DShotRMT.cpp index 33cd41c..f64edf6 100644 --- a/DShotRMT.cpp +++ b/DShotRMT.cpp @@ -18,7 +18,7 @@ constexpr dshot_timing_t DSHOT_TIMINGS[] = { {16, 8, 6, 2, 3, 5} // DSHOT1200 }; -// --- DShot Config --- +// --- DShot Config Constructor --- DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional): _gpio(gpio), _mode(mode), @@ -32,21 +32,24 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional): _packet{0}, _last_transmission_time(0) { - // Double up frame time for bidirectional mode + // Calculates frame time and adds switch/pause time + _frame_timer_us = _timing_config.frame_length_us + DSHOT_SWITCH_TIME; + + // Doubles up frame time for bidirectional mode if (_is_bidirectional) { - _frame_timer_us = (_timing_config.frame_length_us << 1) + DSHOT_SWITCH_TIME; + // DSHOT_SWITCH_TIME also needed two times + _frame_timer_us = (_frame_timer_us << 1); } - - // Calculate frame time including switch time - _frame_timer_us = _timing_config.frame_length_us + DSHOT_SWITCH_TIME; } // Easy Constructor -DShotRMT::DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional): - DShotRMT((gpio_num_t)pin_nr, - mode, - is_bidirectional) +DShotRMT::DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional): + DShotRMT( + (gpio_num_t)pin_nr, + mode, + is_bidirectional + ) { // ...just to accept pin numbers and GPIO_NUMs } @@ -54,24 +57,24 @@ DShotRMT::DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional): // Setup and configure DShotRMT bool DShotRMT::begin() { - // Init TX Channel + // Inits TX Channel if (!_initTXChannel()) { Serial.println(DSHOT_MSG_01); return DSHOT_ERROR; } - // Init RX Channel + // Inits RX Channel if (!_initRXChannel() && _is_bidirectional) { Serial.println(DSHOT_MSG_02); return DSHOT_ERROR; } - // Init DShot Decoder + // Inits DShot Decoder if (!_initDShotEncoder()) { - Serial.println(DSHOT_MSG_03); + // Serial.println(DSHOT_MSG_03); return DSHOT_ERROR; } @@ -109,7 +112,7 @@ bool DShotRMT::sendCommand(uint16_t command) // Check for valid command if (command < DSHOT_CMD_MOTOR_STOP || command > DSHOT_CMD_MAX) { - Serial.println(DSHOT_MSG_07); + Serial.println(DSHOT_MSG_06); return DSHOT_ERROR; } @@ -123,7 +126,7 @@ uint16_t DShotRMT::getERPM() { if (!_is_bidirectional || !_rmt_rx_channel) { - Serial.println(DSHOT_MSG_08); + Serial.println(DSHOT_MSG_07); return _last_erpm; } @@ -131,7 +134,7 @@ uint16_t DShotRMT::getERPM() rmt_symbol_word_t _rx_symbols[RX_BUFFER_SIZE]; if (!rmt_receive(_rmt_rx_channel, _rx_symbols, DSHOT_SYMBOLS_SIZE, &_receive_config)) { - Serial.println(DSHOT_MSG_09); + Serial.println(DSHOT_MSG_08); return _last_erpm; } @@ -152,10 +155,9 @@ uint32_t DShotRMT::getMotorRPM(uint8_t magnet_count) return getERPM() / pole_pairs; } -// +// --- RMT TX Config --- bool DShotRMT::_initTXChannel() { - // --- RMT TX Config --- _tx_channel_config.gpio_num = _gpio; _tx_channel_config.clk_src = DSHOT_CLOCK_SRC_DEFAULT; _tx_channel_config.resolution_hz = DSHOT_RMT_RESOLUTION; @@ -171,46 +173,55 @@ bool DShotRMT::_initTXChannel() // Creates and activates RMT TX Channel if (rmt_new_tx_channel(&_tx_channel_config, &_rmt_tx_channel) != DSHOT_OK) { + Serial.println(DSHOT_MSG_01); return DSHOT_ERROR; } - return (rmt_enable(_rmt_tx_channel) == 0); + return (rmt_enable(_rmt_tx_channel) == DSHOT_OK); } -// +// --- RMT RX Config --- bool DShotRMT::_initRXChannel() { - // --- RMT RX Config --- _rx_channel_config.gpio_num = _gpio; _rx_channel_config.clk_src = DSHOT_CLOCK_SRC_DEFAULT; _rx_channel_config.resolution_hz = DSHOT_RMT_RESOLUTION; _rx_channel_config.mem_block_symbols = DSHOT_SYMBOLS_SIZE; - // TODO: need to figure out + // TODO: figure out ranges _receive_config.signal_range_min_ns = 2; _receive_config.signal_range_max_ns = 128; // Creates and activates RMT TX Channel if (rmt_new_rx_channel(&_rx_channel_config, &_rmt_rx_channel) != DSHOT_OK) { + Serial.println(DSHOT_MSG_02); return DSHOT_ERROR; } - return (rmt_enable(_rmt_rx_channel) == 0); + return (rmt_enable(_rmt_rx_channel) == DSHOT_OK); } -// +// --- RMT Encoder Config --- bool DShotRMT::_initDShotEncoder() { - // Creates a dummy encoder + // Encoder "config" rmt_copy_encoder_config_t encoder_config = {}; - return rmt_new_copy_encoder(&encoder_config, &_dshot_encoder) == 0; + + // Creates a dummy encoder + if (rmt_new_copy_encoder(&encoder_config, &_dshot_encoder) != DSHOT_OK) + { + Serial.println(DSHOT_MSG_03); + return DSHOT_ERROR; + } + + return DSHOT_OK; } -// Use RMT to transmit a prepared DShot packet and returns it +// Uses RMT to transmit a prepared DShot packet and returns it bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet) { - // Excludes calculation from timing is more stable + // Excluding calculation from timing is more timing stable rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME]; _encodeDShotFrame(packet, tx_symbols); @@ -257,15 +268,15 @@ dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value) // Creates DShot packet packet.throttle_value = value; - packet.telemetric_request = 1; // needed to get the motor spinning + packet.telemetric_request = 1; // needed to get the motor spinning packet.checksum = _calculateCRC(packet); // return packet; } -// Encodes DShot packet into RMT buffer -bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols) +// Encodes DShot packet into RMT buffer and places code into IRAM instead of flash +bool DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols) { // Parse actual packet into buffer _current_packet = _parseDShotPacket(packet); @@ -330,7 +341,7 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols) // Timer triggered bool DShotRMT::_timer_signal() { - return (micros() - _last_transmission_time) >= _frame_timer_us; + return (micros() - _last_transmission_time >= _frame_timer_us); } // Updates timestamp diff --git a/DShotRMT.h b/DShotRMT.h index 7e8dd25..6eab82f 100644 --- a/DShotRMT.h +++ b/DShotRMT.h @@ -15,20 +15,20 @@ #include // --- DShot Protocol Constants --- -static constexpr uint16_t DSHOT_THROTTLE_FAILSAFE = 0; -static constexpr uint16_t DSHOT_THROTTLE_MIN = 48; -static constexpr uint16_t DSHOT_THROTTLE_MAX = 2047; +static constexpr auto DSHOT_THROTTLE_FAILSAFE = 0; +static constexpr auto DSHOT_THROTTLE_MIN = 48; +static constexpr auto DSHOT_THROTTLE_MAX = 2047; -static constexpr uint8_t DSHOT_BITS_PER_FRAME = 16; -static constexpr uint8_t DSHOT_SWITCH_TIME = 300; // 30us -static constexpr uint16_t DSHOT_NULL_PACKET = 0b0000000000000000; +static constexpr auto DSHOT_BITS_PER_FRAME = 16; +static constexpr auto DSHOT_SWITCH_TIME = 30; // 30us +static constexpr auto DSHOT_NULL_PACKET = 0b0000000000000000; // --- RMT Config Constants --- -static constexpr rmt_clock_source_t DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT; -static constexpr uint32_t DSHOT_RMT_RESOLUTION = 10 * 1000 * 1000; // 10 MHz -static constexpr size_t TX_BUFFER_SIZE = DSHOT_BITS_PER_FRAME; -static constexpr size_t RX_BUFFER_SIZE = 64; // debug -static constexpr size_t DSHOT_SYMBOLS_SIZE = 64; +static constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT; +static constexpr auto DSHOT_RMT_RESOLUTION = 10 * 1000 * 1000; // 10 MHz +static constexpr auto TX_BUFFER_SIZE = DSHOT_BITS_PER_FRAME; +static constexpr auto RX_BUFFER_SIZE = 64; // debug +static constexpr auto DSHOT_SYMBOLS_SIZE = 64; // --- DShot Mode Select --- typedef enum dshot_mode_e @@ -59,6 +59,7 @@ typedef struct dshot_timing_s uint16_t ticks_zero_low; } dshot_timing_t; +// Some typedef magic for DShot timing config extern const dshot_timing_t DSHOT_TIMINGS[]; // --- DShotRMT Class --- @@ -73,11 +74,11 @@ public: bool begin(); // Sets the throttle value and transmits - bool setThrottle(uint16_t throttle); // deprecated + bool setThrottle(uint16_t throttle); // deprecated bool sendThrottle(uint16_t throttle); // Sends a DShot Command - bool sendDShotCommand(uint16_t command); // deprecated + bool sendDShotCommand(uint16_t command); // deprecated bool sendCommand(uint16_t command); // Gets eRPM from ESC telemetry @@ -86,10 +87,10 @@ public: // Converts eRPM to motor RPM uint32_t getMotorRPM(uint8_t magnet_count); - // Returns GPIO Pin + // Returns pin number uint16_t getGPIO() const { return _gpio; } - // Returns "raw" Dshot packet sent by RMT + // Debug: returns "raw" Dshot packet sent by RMT uint16_t getDShotPacket() const { return _current_packet; } // @@ -120,7 +121,7 @@ private: uint16_t _last_erpm; uint16_t _current_packet; dshot_packet_t _packet; - unsigned long _last_transmission_time; + uint32_t _last_transmission_time; // ---Helpers --- bool _initTXChannel(); @@ -131,7 +132,7 @@ private: uint16_t _calculateCRC(const dshot_packet_t &packet); dshot_packet_t _buildDShotPacket(const uint16_t value); uint16_t _parseDShotPacket(const dshot_packet_t &packet); - bool IRAM_ATTR _encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols); + bool _encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols); uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols); // --- Simple Timer --- @@ -139,14 +140,14 @@ private: bool _timer_reset(); // --- Error Handling --- - static constexpr bool DSHOT_OK = 0; - static constexpr bool DSHOT_ERROR = 1; - static constexpr char *DSHOT_MSG_01 = "Failed to initialize TX channel!"; - static constexpr char *DSHOT_MSG_02 = "Failed to initialize RX channe!l"; - static constexpr char *DSHOT_MSG_03 = "Failed to initialize encoder!"; - static constexpr char *DSHOT_MSG_04 = "RX CRC Check failed!"; - static constexpr char *DSHOT_MSG_06 = "Throttle value not in range (48 - 2047)!"; - static constexpr char *DSHOT_MSG_07 = "Not a valid DShot Command (0 - 47)!"; - static constexpr char *DSHOT_MSG_08 = "Bidirectional DShot support not enabled!"; - static constexpr char *DSHOT_MSG_09 = "RX RMT module failure!"; + static constexpr auto DSHOT_OK = 0; + static constexpr auto DSHOT_ERROR = 1; + static constexpr auto *DSHOT_MSG_01 = "Failed to initialize TX channel!"; + static constexpr auto *DSHOT_MSG_02 = "Failed to initialize RX channe!l"; + static constexpr auto *DSHOT_MSG_03 = "Failed to initialize DShot encoder!"; + static constexpr auto *DSHOT_MSG_04 = "RX CRC Check failed!"; + static constexpr auto *DSHOT_MSG_05 = "Throttle value not in range (48 - 2047)!"; + static constexpr auto *DSHOT_MSG_06 = "Not a valid DShot Command (0 - 47)!"; + static constexpr auto *DSHOT_MSG_07 = "Bidirectional DShot support not enabled!"; + static constexpr auto *DSHOT_MSG_08 = "RX RMT module failure!"; }; diff --git a/examples/dshot300/dshot300.ino b/examples/dshot300/dshot300.ino index 4ab2212..1556632 100644 --- a/examples/dshot300/dshot300.ino +++ b/examples/dshot300/dshot300.ino @@ -13,8 +13,7 @@ static constexpr auto &USB_SERIAL = Serial0; static constexpr auto USB_SERIAL_BAUD = 115200; -// Motor configuration -// Pin number or GPIO_PIN +// Motor configuration - Pin number or GPIO_PIN // static constexpr gpio_num_t MOTOR01_PIN = GPIO_NUM_17; static constexpr auto MOTOR01_PIN = 17; @@ -22,27 +21,24 @@ static constexpr auto MOTOR01_PIN = 17; static constexpr dshot_mode_t DSHOT_MODE = DSHOT300; // BiDirectional DShot Support (default: false) -static constexpr bool IS_BIDIRECTIONAL = false; +static constexpr auto IS_BIDIRECTIONAL = false; // Motor magnet count for RPM calculation static constexpr auto MOTOR01_MAGNET_COUNT = 14; // -// Create the motor instance +// Creates the motor instance DShotRMT motor01(MOTOR01_PIN, DSHOT_MODE, IS_BIDIRECTIONAL); // void setup() { - // Start the USB Serial Port + // Starts the USB Serial Port USB_SERIAL.begin(USB_SERIAL_BAUD); - // Initialize DShot Signal + // Initializes DShot Signal motor01.begin(); - // Arm ESC with minimum throttle - // motor01.sendThrottle(DSHOT_THROTTLE_MIN); - USB_SERIAL.println("***********************************"); USB_SERIAL.println(" === DShotRMT Demo started. === "); USB_SERIAL.println("Enter a throttle value (48 – 2047):"); @@ -51,18 +47,17 @@ void setup() // void loop() { + // Safety first: start with DSHOT_MIN_THROTTLE static auto throttle = DSHOT_THROTTLE_MIN; + // Takes "every" throttle value if (USB_SERIAL.available() > NULL) { - auto new_throttle = (USB_SERIAL.readStringUntil('\n').toInt()); + throttle = (USB_SERIAL.readStringUntil('\n').toInt()); USB_SERIAL.println("*********************"); USB_SERIAL.print("Throttle set to: "); - USB_SERIAL.println(new_throttle); - - // - throttle = new_throttle; + USB_SERIAL.println(throttle); } // Sends the value to the ESC @@ -75,12 +70,12 @@ void loop() print_RMT_packet(2000); } -// Prints RPM every ms +// Prints RPM every X_ms void printRPMPeriodically(auto timer_ms) { if (IS_BIDIRECTIONAL) { - static unsigned long last_print_time = 0; + static auto last_print_time = 0; if (millis() - last_print_time >= timer_ms) { @@ -97,14 +92,14 @@ void printRPMPeriodically(auto timer_ms) // Prints "raw" packet every ms void print_RMT_packet(auto timer_ms) { - static unsigned long last_print_time = 0; + static auto last_print_time = 0; if (millis() - last_print_time >= timer_ms) { auto packet = motor01.getDShotPacket(); // Print bit by bit - for (int i = 15; i >= 0; --i) + for (auto i = 15; i >= 0; --i) { if ((packet >> i) & 1) {