diff --git a/DShotRMT.cpp b/DShotRMT.cpp index 86b7fa7..dea73cd 100644 --- a/DShotRMT.cpp +++ b/DShotRMT.cpp @@ -46,21 +46,21 @@ bool DShotRMT::begin() // Init TX Channel if (!_initTXChannel()) { - Serial.println("Failed to initialize TX channel"); + Serial.println(DSHOT_MSG_01); return DSHOT_ERROR; } // Init RX Channel if (!_initRXChannel() && _is_bidirectional) { - Serial.println("Failed to initialize RX channel"); + Serial.println(DSHOT_MSG_02); return DSHOT_ERROR; } // Init DShot Decoder if (!_initDShotEncoder()) { - Serial.println("Failed to initialize encoder"); + Serial.println(DSHOT_MSG_02); return DSHOT_ERROR; } @@ -74,6 +74,7 @@ bool DShotRMT::setThrottle(uint16_t throttle) // Precheck throttle value if (throttle < DSHOT_THROTTLE_MIN || throttle > DSHOT_THROTTLE_MAX) { + Serial.println(DSHOT_MSG_06); return DSHOT_ERROR; } @@ -86,9 +87,10 @@ bool DShotRMT::setThrottle(uint16_t throttle) // bool DShotRMT::sendDShotCommand(uint16_t command) { - // Precheck throttle value + // Precheck command value if (command < DSHOT_CMD_MOTOR_STOP || command > DSHOT_CMD_MAX) { + Serial.println(DSHOT_MSG_07); return DSHOT_ERROR; } @@ -99,21 +101,24 @@ bool DShotRMT::sendDShotCommand(uint16_t command) } // -uint32_t DShotRMT::getERPM() +uint16_t DShotRMT::getERPM() { if (!_is_bidirectional || !_rmt_rx_channel) { + Serial.println(DSHOT_MSG_08); return _last_erpm; } // Try to receive telemetry data + 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); return _last_erpm; } // Decode the response - uint16_t new_erpm = _decodeDShotFrame(_rx_symbols, DSHOT_BITS_PER_FRAME); + uint16_t new_erpm = _decodeDShotFrame(_rx_symbols); if (new_erpm != 0) { _last_erpm = new_erpm; @@ -139,12 +144,13 @@ bool DShotRMT::_initTXChannel() _tx_channel_config.mem_block_symbols = DSHOT_SYMBOLS_SIZE; _tx_channel_config.trans_queue_depth = TX_BUFFER_SIZE; + // _transmit_config.loop_count = 0; // ...it's a trap _transmit_config.flags.eot_level = _is_bidirectional ? 1 : 0; - // Creates and activate RMT TX Channel + // Creates and activates RMT TX Channel if (rmt_new_tx_channel(&_tx_channel_config, &_rmt_tx_channel) != DSHOT_OK) { return DSHOT_ERROR; @@ -165,7 +171,7 @@ bool DShotRMT::_initRXChannel() _receive_config.signal_range_min_ns = 300; _receive_config.signal_range_max_ns = 5000; - // Create and activate RMT TX Channel + // Creates and activates RMT TX Channel if (rmt_new_rx_channel(&_rx_channel_config, &_rmt_rx_channel) != DSHOT_OK) { return DSHOT_ERROR; @@ -185,16 +191,16 @@ bool DShotRMT::_initDShotEncoder() // Use RMT to transmit a prepared DShot packet and returns it bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet) { - // + // Exclude calculation from timing is more stable + rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME]; + _encodeDShotFrame(packet, tx_symbols); + + // Checking timer signal if (_timer_signal()) { - // Encodes packet directly into RMT Buffer - rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME]; - _encodeDShotFrame(packet, tx_symbols); - // Trigger RMT Transmit rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, DSHOT_SYMBOLS_SIZE, &_transmit_config); - + // Time Stamp return _timer_reset(); } @@ -217,14 +223,14 @@ uint16_t DShotRMT::_calculateCRC(const dshot_packet_t &packet) return crc; } -// +// Returns bitwise parsed DShot packet uint16_t DShotRMT::_parseDShotPacket(const dshot_packet_t &packet) { - // Parses DShot Frame uint16_t data = (packet.throttle_value << 1) | packet.telemetric_request; return (data << 4) | _calculateCRC(packet); } +// Returns a "true" DShot Packet ready to roll dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value) { // DShot Frame Container @@ -239,10 +245,10 @@ dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value) return packet; } -// +// Encodes DShot packet into RMT buffer bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols) { - // Decoding "raw" DShot Packet + // Parse actual packet into buffer _current_packet = _parseDShotPacket(packet); // Convert the parsed dshot frame to rmt_tx data @@ -269,7 +275,7 @@ bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_sym } // -uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t symbol_count) +uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols) { uint16_t received_frame = 0; @@ -282,10 +288,10 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t sy // Extract payload and CRC uint16_t data = received_frame >> 4; - uint8_t received_crc = received_frame & 0b0000000000001111; + uint16_t received_crc = received_frame & 0b0000000000001111; // Calculate CRC for received frame - uint8_t calculated_crc = (data ^ (data >> 4) ^ (data >> 8)) & 0b0000000000001111; + uint16_t calculated_crc = (data ^ (data >> 4) ^ (data >> 8)) & 0b0000000000001111; if (_is_bidirectional) { calculated_crc = (~calculated_crc) & 0b0000000000001111; @@ -294,25 +300,23 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t sy // Compare CRC if (received_crc != calculated_crc) { - Serial.println("RX CRC Check failed"); + Serial.println(DSHOT_MSG_04); return 0b0000000000000000; } - // Remove telemetry bit and return eRPM + // Removes telemetry bit and returns 10bit value return data >> 1; } -// +// Timer triggered bool DShotRMT::_timer_signal() { - // Timer triggered return (micros() - _last_transmission_time) >= _frame_time_us; } -// +// Updates timestamp bool DShotRMT::_timer_reset() { - // Timestamp update _last_transmission_time = micros(); return DSHOT_OK; } diff --git a/DShotRMT.h b/DShotRMT.h index 1bac776..0b14631 100644 --- a/DShotRMT.h +++ b/DShotRMT.h @@ -13,10 +13,6 @@ #include #include #include -#include - -static constexpr bool DSHOT_OK = 0; -static constexpr bool DSHOT_ERROR = 1; // --- DShot Protocol Constants --- static constexpr uint16_t DSHOT_THROTTLE_FAILSAFE = 0; @@ -35,7 +31,7 @@ static constexpr size_t RX_BUFFER_SIZE = 32; static constexpr size_t DSHOT_SYMBOLS_SIZE = 64; // --- DShot Mode Select --- -typedef enum +typedef enum dshot_mode_e { DSHOT_OFF, DSHOT150, @@ -45,7 +41,7 @@ typedef enum } dshot_mode_t; // --- DShot Packet Structure --- -typedef struct +typedef struct dshot_packet_s { uint16_t throttle_value : 11; bool telemetric_request : 1; @@ -53,7 +49,7 @@ typedef struct } dshot_packet_t; // --- DShot Timing Config --- -typedef struct +typedef struct dshot_timing_s { uint16_t frame_length_us; uint16_t ticks_per_bit; @@ -83,14 +79,18 @@ public: bool sendDShotCommand(uint16_t command); // Gets eRPM from ESC telemetry - uint32_t getERPM(); + uint16_t getERPM(); // Converts eRPM to motor RPM uint32_t getMotorRPM(uint8_t magnet_count); - // - gpio_num_t getGPIO() const { return _gpio; } + // Returns GPIO Pin + uint16_t getGPIO() const { return _gpio; } + + // Returns "raw" Dshot packet sent by RMT uint16_t getDShotPacket() { return _current_packet; } + + // bool is_bidirectional() const { return _is_bidirectional; } private: @@ -98,7 +98,7 @@ private: gpio_num_t _gpio; dshot_mode_t _mode; bool _is_bidirectional; - uint32_t _frame_time_us; + uint16_t _frame_time_us; // --- DShot Timings --- const dshot_timing_t &_timing_config; @@ -115,10 +115,9 @@ private: rmt_receive_config_t _receive_config; // --- Buffers --- - rmt_symbol_word_t _rx_symbols[RX_BUFFER_SIZE]; uint16_t _last_erpm; - unsigned long _last_transmission_time; uint16_t _current_packet; + unsigned long _last_transmission_time; // bool _initTXChannel(); @@ -130,10 +129,20 @@ private: 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); - uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t symbol_count); + uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols); bool _timer_signal(); 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!"; }; diff --git a/hw_defaults.h b/hw_defaults.h deleted file mode 100644 index 02457bb..0000000 --- a/hw_defaults.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file hw_defaults.h - * @brief Some Shortcuts - * @author Wastl Kraus - * @date 2025-08-02 - * @license MIT - */ - -#ifdef ESP32 -// USB-Serial (UART0): GPIO1/3 in use by default - -// Serial1 -constexpr auto PIN_UART1_TX = GPIO_NUM_13; -constexpr auto PIN_UART1_RX = GPIO_NUM_14; - -// Serial2 -constexpr auto PIN_UART2_TX = GPIO_NUM_16; -constexpr auto PIN_UART2_RX = GPIO_NUM_17; - -// SPI (VSPI) -constexpr auto PIN_SPI_SCLK = GPIO_NUM_18; -constexpr auto PIN_SPI_MISO = GPIO_NUM_19; -constexpr auto PIN_SPI_MOSI = GPIO_NUM_23; -constexpr auto PIN_SPI_SS = GPIO_NUM_5; - -// I2C (Wire) -constexpr auto PIN_I2C_SDA = GPIO_NUM_21; -constexpr auto PIN_I2C_SCL = GPIO_NUM_22; - -// RMT (5 Channels) -constexpr auto PIN_RMT_CH0 = GPIO_NUM_25; -constexpr auto PIN_RMT_CH1 = GPIO_NUM_26; -constexpr auto PIN_RMT_CH2 = GPIO_NUM_27; -constexpr auto PIN_RMT_CH3 = GPIO_NUM_32; -constexpr auto PIN_RMT_CH4 = GPIO_NUM_33; -#endif // ESP32