release 0.9.0

This commit is contained in:
Wastl Kraus 2025-10-09 19:41:03 +02:00
parent 6e3006c4c8
commit 4a2d3f0b9a
7 changed files with 126 additions and 105 deletions

View File

@ -46,7 +46,7 @@ jobs:
~/.arduino15/packages ~/.arduino15/packages
~/.arduino15/cache ~/.arduino15/cache
~/Arduino/libraries ~/Arduino/libraries
key: linux-arduino-esp32-v2-${{ hashFiles('**/library.properties') }} key: linux-arduino-esp32-v2-v3
- name: Install Dependencies - name: Install Dependencies
if: steps.cache-arduino.outputs.cache-hit != 'true' if: steps.cache-arduino.outputs.cache-hit != 'true'
@ -83,7 +83,7 @@ jobs:
~/.arduino15/packages ~/.arduino15/packages
~/.arduino15/cache ~/.arduino15/cache
~/Arduino/libraries ~/Arduino/libraries
key: linux-arduino-esp32-v2-${{ hashFiles('**/library.properties') }} key: linux-arduino-esp32-v2-v3
- name: Run Arduino Lint - name: Run Arduino Lint
uses: arduino/arduino-lint-action@v2 uses: arduino/arduino-lint-action@v2
@ -125,7 +125,7 @@ jobs:
~/.arduino15/packages ~/.arduino15/packages
~/.arduino15/cache ~/.arduino15/cache
~/Arduino/libraries ~/Arduino/libraries
key: linux-arduino-esp32-v2-${{ hashFiles('**/library.properties') }} key: linux-arduino-esp32-v2-v3
- name: Compile Sketch - name: Compile Sketch
run: arduino-cli compile --fqbn esp32:esp32:esp32 --library ${{ github.workspace }} "${{ matrix.sketch }}" run: arduino-cli compile --fqbn esp32:esp32:esp32 --library ${{ github.workspace }} "${{ matrix.sketch }}"

View File

@ -114,9 +114,9 @@ The main class is `DShotRMT`. Here are the most important methods:
- `begin()`: Initializes the DShot RMT channels and encoder. - `begin()`: Initializes the DShot RMT channels and encoder.
- `sendThrottlePercent(float percent)`: Sends a throttle value as a percentage (0.0-100.0) to the ESC. - `sendThrottlePercent(float percent)`: Sends a throttle value as a percentage (0.0-100.0) to the ESC.
- `sendThrottle(uint16_t throttle)`: Sends a raw throttle value (48-2047) to the ESC. A value of 0 sends a motor stop command. - `sendThrottle(uint16_t throttle)`: Sends a raw throttle value (48-2047) to the ESC. A value of 0 sends a motor stop command.
- `sendCommand(dshotCommands_e command)`: Sends a DShot command (0-47) to the ESC. Automatically handles repetitions and delays for specific commands (e.g., `DSHOT_CMD_SAVE_SETTINGS`). - `sendCommand(dshotCommands_e command)`: Sends a DShot command to the ESC. Automatically handles repetitions and delays for specific commands (e.g., `DSHOT_CMD_SAVE_SETTINGS`).
- `sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us)`: Sends a DShot command (0-47) to the ESC with a specified repeat count and delay. This is a blocking function. - `sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us)`: Sends a DShot command to the ESC with a specified repeat count and delay. This is a blocking function.
- `sendCommand(uint16_t command_value)`: Sends a DShot command (0-47) to the ESC by accepting an integer value. It validates the input and then calls `sendCommand(dshotCommands_e command)`. - `sendCommand(uint16_t command_value)`: Sends a DShot command to the ESC by accepting an integer value. It validates the input and then calls `sendCommand(dshotCommands_e command)`.
- `getTelemetry(uint16_t magnet_count = 0)`: Retrieves telemetry data from the ESC. If `magnet_count` is 0, uses the stored motor magnet count. - `getTelemetry(uint16_t magnet_count = 0)`: Retrieves telemetry data from the ESC. If `magnet_count` is 0, uses the stored motor magnet count.
- `getESCInfo()`: Sends a command to the ESC to request ESC information. - `getESCInfo()`: Sends a command to the ESC to request ESC information.
- `setMotorSpinDirection(bool reversed)`: Sets the motor spin direction. `true` for reversed, `false` for normal. - `setMotorSpinDirection(bool reversed)`: Sets the motor spin direction. `true` for reversed, `false` for normal.

View File

@ -29,7 +29,7 @@ static constexpr auto IS_BIDIRECTIONAL = false;
// static constexpr auto MOTOR01_MAGNET_COUNT = 14; // static constexpr auto MOTOR01_MAGNET_COUNT = 14;
// Creates the motor instance // Creates the motor instance
DShotRMT motor01(MOTOR01_PIN, DSHOT_MODE, IS_BIDIRECTIONAL, DEFAULT_MOTOR_MAGNET_COUNT); DShotRMT motor01(MOTOR01_PIN, DSHOT_MODE, IS_BIDIRECTIONAL);
// //
void setup() void setup()

View File

@ -33,22 +33,18 @@ DShotRMT::~DShotRMT()
// Cleanup TX channel // Cleanup TX channel
if (_rmt_tx_channel) if (_rmt_tx_channel)
{ {
if (rmt_disable(_rmt_tx_channel) == DSHOT_OK) rmt_disable(_rmt_tx_channel);
{
rmt_del_channel(_rmt_tx_channel); rmt_del_channel(_rmt_tx_channel);
_rmt_tx_channel = nullptr; _rmt_tx_channel = nullptr;
} }
}
// Cleanup RX channel // Cleanup RX channel
if (_rmt_rx_channel) if (_rmt_rx_channel)
{ {
if (rmt_disable(_rmt_rx_channel) == DSHOT_OK) rmt_disable(_rmt_rx_channel);
{
rmt_del_channel(_rmt_rx_channel); rmt_del_channel(_rmt_rx_channel);
_rmt_rx_channel = nullptr; _rmt_rx_channel = nullptr;
} }
}
// Cleanup encoder // Cleanup encoder
if (_dshot_encoder) if (_dshot_encoder)
@ -65,6 +61,7 @@ dshot_result_t DShotRMT::begin()
if (!result.success) if (!result.success)
{ {
_cleanupRmtResources(); // Clean up any allocated resources on failure
return result; return result;
} }
@ -73,10 +70,7 @@ dshot_result_t DShotRMT::begin()
result = init_rmt_rx_channel(_gpio, &_rmt_rx_channel, &_rx_event_callbacks, this); result = init_rmt_rx_channel(_gpio, &_rmt_rx_channel, &_rx_event_callbacks, this);
if (!result.success) if (!result.success)
{ {
// Cleanup previously allocated TX channel on failure _cleanupRmtResources(); // Clean up any allocated resources on failure
rmt_disable(_rmt_tx_channel);
rmt_del_channel(_rmt_tx_channel);
_rmt_tx_channel = nullptr;
return result; return result;
} }
} }
@ -85,17 +79,7 @@ dshot_result_t DShotRMT::begin()
if (!result.success) if (!result.success)
{ {
// Cleanup previously allocated channels on failure _cleanupRmtResources(); // Clean up any allocated resources on failure
rmt_disable(_rmt_tx_channel);
rmt_del_channel(_rmt_tx_channel);
_rmt_tx_channel = nullptr;
if (_rmt_rx_channel)
{
rmt_disable(_rmt_rx_channel);
rmt_del_channel(_rmt_rx_channel);
_rmt_rx_channel = nullptr;
}
return result; return result;
} }
@ -260,10 +244,10 @@ dshot_result_t DShotRMT::saveESCSettings()
// Simple check // Simple check
bool DShotRMT::_isValidCommand(dshotCommands_e command) const bool DShotRMT::_isValidCommand(dshotCommands_e command) const
{ {
return (command >= dshotCommands_e::DSHOT_CMD_MOTOR_STOP && command <= dshotCommands_e::DSHOT_CMD_MAX); return (command >= dshotCommands_e::DSHOT_CMD_MOTOR_STOP && command <= DSHOT_CMD_MAX);
} }
// // Executes a single DShot command by building and sending a DShot frame.
dshot_result_t DShotRMT::_executeCommand(dshotCommands_e command) dshot_result_t DShotRMT::_executeCommand(dshotCommands_e command)
{ {
uint64_t start_time = esp_timer_get_time(); uint64_t start_time = esp_timer_get_time();
@ -314,18 +298,18 @@ uint16_t DShotRMT::_calculateCRC(const uint16_t &data) const
void DShotRMT::_preCalculateRMTTicks() void DShotRMT::_preCalculateRMTTicks()
{ {
// Pre-calculate all timing values in RMT ticks to save CPU cycles later // Pre-calculate all timing values in RMT ticks to save CPU cycles later.
_rmt_ticks.bit_length_ticks = static_cast<uint16_t>(_dshot_timing.bit_length_us * RMT_TICKS_PER_US); _rmt_ticks.bit_length_ticks = static_cast<uint16_t>(_dshot_timing.bit_length_us * RMT_TICKS_PER_US);
_rmt_ticks.t1h_ticks = static_cast<uint16_t>(_dshot_timing.t1h_lenght_us * RMT_TICKS_PER_US); _rmt_ticks.t1h_ticks = static_cast<uint16_t>(_dshot_timing.t1h_lenght_us * RMT_TICKS_PER_US);
_rmt_ticks.t0h_ticks = _rmt_ticks.t1h_ticks >> 1; // High time for a 1 is always double of 0 _rmt_ticks.t0h_ticks = _rmt_ticks.t1h_ticks >> 1; // High time for a '0' bit is half of a '1' bit.
_rmt_ticks.t1l_ticks = _rmt_ticks.bit_length_ticks - _rmt_ticks.t1h_ticks; _rmt_ticks.t1l_ticks = _rmt_ticks.bit_length_ticks - _rmt_ticks.t1h_ticks;
_rmt_ticks.t0l_ticks = _rmt_ticks.bit_length_ticks - _rmt_ticks.t0h_ticks; _rmt_ticks.t0l_ticks = _rmt_ticks.bit_length_ticks - _rmt_ticks.t0h_ticks;
// Calculate the minimum time required between frames // Calculate the minimum time required between frames.
// Pause between frames is frame time in us, some padding and about 30 us is added by hardware // Pause between frames is frame time in us, some padding and about 30 us is added by hardware.
_frame_timer_us = (static_cast<uint64_t>(_dshot_timing.bit_length_us * DSHOT_BITS_PER_FRAME) << 1) + DSHOT_PADDING_US; _frame_timer_us = (static_cast<uint64_t>(_dshot_timing.bit_length_us * DSHOT_BITS_PER_FRAME) << 1) + DSHOT_PADDING_US;
// For bidirectional, double up // For bidirectional, double up.
if (_is_bidirectional) if (_is_bidirectional)
{ {
_frame_timer_us = (_frame_timer_us << 1); _frame_timer_us = (_frame_timer_us << 1);
@ -365,12 +349,12 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
// This function needs to be fast, as it generates the RMT symbols just before sending // This function needs to be fast, as it generates the RMT symbols just before sending
// Placed in IRAM for high performance, as it's called from an ISR context // Placed in IRAM for high performance, as it's called from an ISR context.
uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols) const uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols) const
{ {
uint32_t gcr_value = 0; uint32_t gcr_value = 0;
// Step 1: Decode RMT symbols into a 21-bit GCR (Group Code Recording) value. // Decode RMT symbols into a 21-bit GCR (Group Code Recording) value.
// The ESC sends back a signal where the duration determines the bit value. // The ESC sends back a signal where the duration determines the bit value.
for (size_t i = 0; i < GCR_BITS_PER_FRAME; ++i) for (size_t i = 0; i < GCR_BITS_PER_FRAME; ++i)
{ {
@ -378,23 +362,23 @@ uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
gcr_value = (gcr_value << 1) | bit_is_one; gcr_value = (gcr_value << 1) | bit_is_one;
} }
// Step 2: Perform GCR decoding (GCR = Value ^ (Value >> 1)) // Perform GCR decoding (GCR = Value ^ (Value >> 1)).
uint32_t decoded_frame = gcr_value ^ (gcr_value >> 1); uint32_t decoded_frame = gcr_value ^ (gcr_value >> 1);
// Step 3: Extract the 16-bit DShot frame from the decoded data // Extract the 16-bit DShot frame from the decoded data.
uint16_t data_and_crc = (decoded_frame & DSHOT_FULL_PACKET); uint16_t data_and_crc = (decoded_frame & DSHOT_FULL_PACKET);
// Step 4: Extract data and CRC from the 16-bit frame // Extract data and CRC from the 16-bit frame.
uint16_t received_data = data_and_crc >> DSHOT_CRC_BIT_SHIFT; uint16_t received_data = data_and_crc >> DSHOT_CRC_BIT_SHIFT;
uint16_t received_crc = data_and_crc & DSHOT_CRC_MASK; uint16_t received_crc = data_and_crc & DSHOT_CRC_MASK;
// Step 5: A valid response must have the telemetry request bit set to 1. This is a sanity check. // A valid response must have the telemetry request bit set to 1. This is a sanity check.
if (!((received_data >> DSHOT_TELEMETRY_BIT_POSITION) & 1)) if (!((received_data >> DSHOT_TELEMETRY_BIT_POSITION) & 1))
{ {
return DSHOT_NULL_PACKET; return DSHOT_NULL_PACKET;
} }
// Step 6: Calculate and validate CRC // Calculate and validate CRC.
uint16_t calculated_crc = _calculateCRC(received_data); uint16_t calculated_crc = _calculateCRC(received_data);
if (received_crc != calculated_crc) if (received_crc != calculated_crc)
{ {
@ -440,3 +424,26 @@ bool IRAM_ATTR DShotRMT::_on_rx_done(rmt_channel_handle_t rmt_rx_channel, const
return false; return false;
} }
void DShotRMT::_cleanupRmtResources()
{
if (_rmt_tx_channel)
{
rmt_disable(_rmt_tx_channel);
rmt_del_channel(_rmt_tx_channel);
_rmt_tx_channel = nullptr;
}
if (_rmt_rx_channel)
{
rmt_disable(_rmt_rx_channel);
rmt_del_channel(_rmt_rx_channel);
_rmt_rx_channel = nullptr;
}
if (_dshot_encoder)
{
rmt_del_encoder(_dshot_encoder);
_dshot_encoder = nullptr;
}
}

View File

@ -18,18 +18,19 @@
#include "dshot_definitions.h" #include "dshot_definitions.h"
#include "dshot_init.h" #include "dshot_init.h"
// Forward declaration for the RMT receive callback
class DShotRMT;
void IRAM_ATTR rmt_rx_done_callback(rmt_channel_handle_t rx_chan, const rmt_rx_done_event_data_t *edata, void *user_data);
// DShot Protocol Constants // DShot Protocol Constants
static constexpr auto DSHOT_THROTTLE_FAILSAFE = 0; static constexpr auto DSHOT_THROTTLE_FAILSAFE = 0;
static constexpr auto DSHOT_THROTTLE_MIN = 48;
static constexpr auto DSHOT_BITS_PER_FRAME = 16;
static constexpr auto DEFAULT_MOTOR_MAGNET_COUNT = 14;
// // DShotRMT class for generating DShot signals and receiving telemetry.
class DShotRMT class DShotRMT
{ {
public: public:
// Constructor with GPIO number // Constructor for DShotRMT.
DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT); DShotRMT(gpio_num_t gpio, dshot_mode_t mode = DSHOT300, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT);
// Constructor using pin number // Constructor using pin number
DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT); DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT);
@ -40,28 +41,28 @@ public:
// Initialize DShotRMT // Initialize DShotRMT
dshot_result_t begin(); dshot_result_t begin();
// Send throttle value // Sends a raw throttle value to the ESC.
dshot_result_t sendThrottle(uint16_t throttle); dshot_result_t sendThrottle(uint16_t throttle);
// Send throttle value as a percentage // Sends a throttle value as a percentage to the ESC.
dshot_result_t sendThrottlePercent(float percent); dshot_result_t sendThrottlePercent(float percent);
// Sends a DShot command (0-47) to the ESC by accepting an integer value. // Sends a DShot command to the ESC by accepting an integer value.
dshot_result_t sendCommand(uint16_t command_value); dshot_result_t sendCommand(uint16_t command_value);
// Sends a DShot command (0-47) to the ESC. // Sends a DShot command to the ESC.
dshot_result_t sendCommand(dshotCommands_e command); dshot_result_t sendCommand(dshotCommands_e command);
// Sends a DShot command (0-47) to the ESC with a specified repeat count and delay. // Sends a DShot command to the ESC with a specified repeat count and delay.
dshot_result_t sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us); dshot_result_t sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us);
// Get telemetry data // Retrieves telemetry data from the ESC.
dshot_result_t getTelemetry(); dshot_result_t getTelemetry();
// Reverse motor direction directly // Sets the motor spin direction.
dshot_result_t setMotorSpinDirection(bool reversed); dshot_result_t setMotorSpinDirection(bool reversed);
// Use with caution // Sends a command to the ESC to save its current settings.
dshot_result_t saveESCSettings(); dshot_result_t saveESCSettings();
// Getters for DShot info // Getters for DShot info
@ -71,50 +72,53 @@ public:
uint16_t getEncodedFrameValue() const { return _encoded_frame_value; } uint16_t getEncodedFrameValue() const { return _encoded_frame_value; }
private: private:
// Configuration static bool IRAM_ATTR _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
gpio_num_t _gpio;
dshot_mode_t _mode;
bool _is_bidirectional;
uint16_t _motor_magnet_count;
dshot_timing_us_t _dshot_timing;
// RMT Handles & Config // DShot Configuration Parameters
rmt_channel_handle_t _rmt_tx_channel = nullptr; gpio_num_t _gpio; // GPIO pin used for DShot communication
rmt_channel_handle_t _rmt_rx_channel = nullptr; dshot_mode_t _mode; // DShot mode (e.g., DSHOT300, DSHOT600)
rmt_encoder_handle_t _dshot_encoder = nullptr; bool _is_bidirectional; // True if bidirectional DShot is enabled
rmt_ticks_t _rmt_ticks; uint16_t _motor_magnet_count; // Number of magnets in the motor for RPM calculation
uint16_t _pulse_level = 1; // Default to high dshot_timing_us_t _dshot_timing; // DShot timing parameters in microseconds
uint16_t _idle_level = 0; // Default to low
// Timing & State // RMT Hardware Handles and Configuration
uint64_t _last_transmission_time_us = 0; rmt_channel_handle_t _rmt_tx_channel = nullptr; // RMT transmit channel handle
uint64_t _frame_timer_us = 0; rmt_channel_handle_t _rmt_rx_channel = nullptr; // RMT receive channel handle
uint16_t _last_throttle = 0; rmt_encoder_handle_t _dshot_encoder = nullptr; // DShot RMT encoder handle
dshot_packet_t _packet; rmt_ticks_t _rmt_ticks; // Pre-calculated RMT timing ticks
uint16_t _encoded_frame_value = 0; uint16_t _pulse_level = 1; // Output level for a pulse (typically high)
uint64_t _last_command_timestamp = 0; uint16_t _idle_level = 0; // Output level for idle (typically low)
// Telemetry // DShot Frame Timing and State Variables
std::atomic<uint16_t> _last_erpm_atomic = 0; uint64_t _last_transmission_time_us = 0; // Timestamp of the last DShot frame transmission
std::atomic<bool> _telemetry_ready_flag_atomic = false; uint64_t _frame_timer_us = 0; // Minimum time required between DShot frames
uint16_t _last_throttle = 0; // Last transmitted throttle value
dshot_packet_t _packet; // Current DShot packet being processed
uint16_t _encoded_frame_value = 0; // Last encoded 16-bit DShot frame value
uint64_t _last_command_timestamp = 0; // Timestamp of the last command sent
// Telemetry Related Variables
std::atomic<uint16_t> _last_erpm_atomic = 0; // Atomically stored last received eRPM value
std::atomic<bool> _telemetry_ready_flag_atomic = false; // Atomically stored flag indicating new telemetry data
rmt_rx_event_callbacks_t _rx_event_callbacks = { rmt_rx_event_callbacks_t _rx_event_callbacks = {
// RMT receive event callbacks
.on_recv_done = _on_rx_done, .on_recv_done = _on_rx_done,
}; };
// Private helper functions // Private Helper Functions for DShot Protocol Logic
bool _isValidCommand(dshotCommands_e command) const; bool _isValidCommand(dshotCommands_e command) const; // Checks if a given DShot command is valid
dshot_result_t _executeCommand(dshotCommands_e command); dshot_result_t _executeCommand(dshotCommands_e command); // Executes a single DShot command
dshot_packet_t _buildDShotPacket(const uint16_t &value) const; dshot_packet_t _buildDShotPacket(const uint16_t &value) const; // Builds a DShot packet from a value (throttle or command)
uint16_t _buildDShotFrameValue(const dshot_packet_t &packet) const; uint16_t _buildDShotFrameValue(const dshot_packet_t &packet) const; // Combines packet data into a 16-bit DShot frame value
uint16_t _calculateCRC(const uint16_t &data) const; uint16_t _calculateCRC(const uint16_t &data) const; // Calculates the 4-bit CRC for a DShot frame
void _preCalculateRMTTicks(); void _preCalculateRMTTicks(); // Pre-calculates RMT timing ticks for the selected DShot mode
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet); dshot_result_t _sendDShotFrame(const dshot_packet_t &packet); // Sends a DShot frame via RMT TX channel
uint16_t IRAM_ATTR _decodeDShotFrame(const rmt_symbol_word_t *symbols) const; uint16_t IRAM_ATTR _decodeDShotFrame(const rmt_symbol_word_t *symbols) const; // Decodes a received RMT symbol array into an eRPM value
bool IRAM_ATTR _isFrameIntervalElapsed() const; bool IRAM_ATTR _isFrameIntervalElapsed() const; // Checks if enough time has passed since the last frame transmission
void _recordFrameTransmissionTime(); void _recordFrameTransmissionTime(); // Records the current time as the last frame transmission time
// Static Callback Functions // Static Callback Function for RMT RX Events
static bool IRAM_ATTR _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data); void _cleanupRmtResources();
}; };
#include "dshot_utils.h" // Include for helper functions #include "dshot_utils.h" // Include for helper functions

View File

@ -11,6 +11,19 @@
#include <cstdint> #include <cstdint>
#include <driver/rmt_common.h> #include <driver/rmt_common.h>
// DShot protocol definitions
static constexpr uint16_t DSHOT_FRAME_LENGTH = 16; // 11 throttle bits + 1 telemetry bit + 4 CRC bits
static constexpr uint16_t DSHOT_BITS_PER_FRAME = 16;
static constexpr uint16_t DSHOT_THROTTLE_MAX = 2047; // Maximum throttle value (0-2047)
static constexpr uint16_t DSHOT_THROTTLE_MIN = 48; // Minimum throttle value for motor spin
static constexpr uint16_t DSHOT_CMD_MIN = 0; // Minimum command value
static constexpr uint16_t DSHOT_CMD_MAX = 47; // Maximum command value
static constexpr uint16_t DSHOT_TELEMETRY_BIT_MASK = 0x0800; // Bit mask for telemetry request bit (11th bit)
static constexpr uint16_t DSHOT_CRC_MASK = 0x000F; // Bit mask for CRC bits
// Default motor magnet count for RPM calculation
static constexpr uint16_t DEFAULT_MOTOR_MAGNET_COUNT = 14;
// Defines the available DShot communication speeds. // Defines the available DShot communication speeds.
enum dshot_mode_t enum dshot_mode_t
{ {
@ -114,8 +127,7 @@ enum dshotCommands_e
DSHOT_CMD_LED2_OFF, DSHOT_CMD_LED2_OFF,
DSHOT_CMD_LED3_OFF, DSHOT_CMD_LED3_OFF,
DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF = 30, DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF = 30,
DSHOT_CMD_SILENT_MODE_ON_OFF = 31, DSHOT_CMD_SILENT_MODE_ON_OFF = 31
DSHOT_CMD_MAX = 47
}; };
// Custom status codes // Custom status codes
@ -125,7 +137,6 @@ static constexpr int DSHOT_ERROR = 1;
// Configuration Constants // Configuration Constants
static constexpr auto DSHOT_NULL_PACKET = 0b0000000000000000; static constexpr auto DSHOT_NULL_PACKET = 0b0000000000000000;
static constexpr auto DSHOT_FULL_PACKET = 0b1111111111111111; static constexpr auto DSHOT_FULL_PACKET = 0b1111111111111111;
static constexpr auto DSHOT_CRC_MASK = 0b0000000000001111;
static constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT; static constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT;
static constexpr auto DSHOT_RMT_RESOLUTION = 8000000; // 8 MHz resolution static constexpr auto DSHOT_RMT_RESOLUTION = 8000000; // 8 MHz resolution
static constexpr auto RMT_TICKS_PER_US = DSHOT_RMT_RESOLUTION / 1000000; // RMT Ticks per microsecond static constexpr auto RMT_TICKS_PER_US = DSHOT_RMT_RESOLUTION / 1000000; // RMT Ticks per microsecond
@ -137,7 +148,6 @@ static constexpr auto GCR_BITS_PER_FRAME = 21; // GCR bits in a DShot answer fra
static constexpr auto POLE_PAIRS_MIN = 1; static constexpr auto POLE_PAIRS_MIN = 1;
static constexpr auto MAGNETS_PER_POLE_PAIR = 2; static constexpr auto MAGNETS_PER_POLE_PAIR = 2;
static constexpr auto NO_DSHOT_TELEMETRY = 0; static constexpr auto NO_DSHOT_TELEMETRY = 0;
static constexpr auto DSHOT_THROTTLE_MAX = 2047;
static constexpr auto DSHOT_PULSE_MIN_NS = 800; // 0.8us minimum pulse static constexpr auto DSHOT_PULSE_MIN_NS = 800; // 0.8us minimum pulse
static constexpr auto DSHOT_PULSE_MAX_NS = 8000; // 8.0us maximum pulse static constexpr auto DSHOT_PULSE_MAX_NS = 8000; // 8.0us maximum pulse
static constexpr auto DSHOT_TELEMETRY_INVALID = DSHOT_THROTTLE_MAX; static constexpr auto DSHOT_TELEMETRY_INVALID = DSHOT_THROTTLE_MAX;

View File

@ -41,7 +41,7 @@ static constexpr char INVALID_COMMAND[] = "Invalid command!";
static constexpr char COMMAND_SUCCESS[] = "DShot command sent successfully"; static constexpr char COMMAND_SUCCESS[] = "DShot command sent successfully";
// Helper to get result code string // Helper to get result code string
inline const char *_get_result_code_str(dshot_msg_code_t code) inline const char *get_result_code_str(dshot_msg_code_t code)
{ {
switch (code) switch (code)
{ {
@ -103,7 +103,7 @@ inline const char *_get_result_code_str(dshot_msg_code_t code)
// Helper to quick print DShot result codes // Helper to quick print DShot result codes
inline void printDShotResult(dshot_result_t &result, Stream &output = Serial) inline void printDShotResult(dshot_result_t &result, Stream &output = Serial)
{ {
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", _get_result_code_str(result.result_code)); output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", get_result_code_str(result.result_code));
// Print telemetry data if available // Print telemetry data if available
if (result.success && (result.erpm > 0 || result.motor_rpm > 0)) if (result.success && (result.erpm > 0 || result.motor_rpm > 0))