more clean up
This commit is contained in:
parent
51c1d345e8
commit
a763786fbf
|
|
@ -108,8 +108,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(uint16_t command)`: Sends a single DShot command (0-47) to the ESC.
|
- `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 dshot_command, uint16_t repeat_count = DEFAULT_CMD_REPEAT_COUNT, uint16_t delay_us = DEFAULT_CMD_DELAY_US)`: Sends a DShot command multiple times with a delay between repetitions. This is a blocking function.
|
- `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(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)`.
|
||||||
- `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.
|
||||||
|
|
|
||||||
169
src/DShotRMT.cpp
169
src/DShotRMT.cpp
|
|
@ -14,7 +14,7 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional, ui
|
||||||
_mode(mode),
|
_mode(mode),
|
||||||
_is_bidirectional(is_bidirectional),
|
_is_bidirectional(is_bidirectional),
|
||||||
_motor_magnet_count(magnet_count),
|
_motor_magnet_count(magnet_count),
|
||||||
_dshot_timing(DSHOT_TIMING_US[static_cast<int>(mode)])
|
_dshot_timing(DSHOT_TIMING_US[_mode])
|
||||||
{
|
{
|
||||||
// Pre-calculate timing and bit positions for performance
|
// Pre-calculate timing and bit positions for performance
|
||||||
_preCalculateRMTTicks();
|
_preCalculateRMTTicks();
|
||||||
|
|
@ -61,24 +61,27 @@ DShotRMT::~DShotRMT()
|
||||||
// Initialize DShotRMT
|
// Initialize DShotRMT
|
||||||
dshot_result_t DShotRMT::begin()
|
dshot_result_t DShotRMT::begin()
|
||||||
{
|
{
|
||||||
if (!_initTXChannel().success)
|
dshot_result_t result = init_rmt_tx_channel(_gpio, &_rmt_tx_channel, _is_bidirectional);
|
||||||
|
if (!result.success)
|
||||||
{
|
{
|
||||||
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_is_bidirectional)
|
if (_is_bidirectional)
|
||||||
{
|
{
|
||||||
if (!_initRXChannel().success)
|
result = init_rmt_rx_channel(_gpio, &_rmt_rx_channel, &_rx_event_callbacks, this);
|
||||||
|
if (!result.success)
|
||||||
{
|
{
|
||||||
// Cleanup previously allocated TX channel on failure
|
// Cleanup previously allocated TX channel on failure
|
||||||
rmt_disable(_rmt_tx_channel);
|
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;
|
||||||
return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_initDShotEncoder().success)
|
result = init_dshot_encoder(&_dshot_encoder, _rmt_ticks, _pulse_level, _idle_level);
|
||||||
|
if (!result.success)
|
||||||
{
|
{
|
||||||
// Cleanup previously allocated channels on failure
|
// Cleanup previously allocated channels on failure
|
||||||
rmt_disable(_rmt_tx_channel);
|
rmt_disable(_rmt_tx_channel);
|
||||||
|
|
@ -91,8 +94,7 @@ dshot_result_t DShotRMT::begin()
|
||||||
rmt_del_channel(_rmt_rx_channel);
|
rmt_del_channel(_rmt_rx_channel);
|
||||||
_rmt_rx_channel = nullptr;
|
_rmt_rx_channel = nullptr;
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
return {false, dshot_msg_code_t::DSHOT_ENCODER_INIT_FAILED};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {true, dshot_msg_code_t::DSHOT_INIT_SUCCESS};
|
return {true, dshot_msg_code_t::DSHOT_INIT_SUCCESS};
|
||||||
|
|
@ -127,21 +129,45 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
|
||||||
return sendThrottle(throttle);
|
return sendThrottle(throttle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send DShot command to ESC
|
// Sends a DShot command (0-47) to the ESC by accepting an integer value.
|
||||||
dshot_result_t DShotRMT::sendCommand(dshotCommands_e command)
|
dshot_result_t DShotRMT::sendCommand(uint16_t command_value)
|
||||||
{
|
{
|
||||||
_packet = _buildDShotPacket(static_cast<uint16_t>(command));
|
// Validate the integer command value before casting
|
||||||
return _sendDShotFrame(_packet);
|
if (command_value < DSHOT_CMD_MOTOR_STOP || command_value > DSHOT_CMD_MAX)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_COMMAND_NOT_VALID};
|
||||||
|
}
|
||||||
|
return sendCommand(static_cast<dshotCommands_e>(command_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sends a DShot command (0-47) to the ESC.
|
||||||
|
dshot_result_t DShotRMT::sendCommand(dshotCommands_e command)
|
||||||
|
{
|
||||||
|
uint16_t repeat_count = DEFAULT_CMD_REPEAT_COUNT;
|
||||||
|
uint16_t delay_us = DEFAULT_CMD_DELAY_US;
|
||||||
|
|
||||||
// Send full DShot commands for setup etc
|
switch (command)
|
||||||
// This is a blocking function that uses delayMicroseconds for repetitions.
|
{
|
||||||
dshot_result_t DShotRMT::_sendCommandInternal(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us)
|
case DSHOT_CMD_SAVE_SETTINGS:
|
||||||
|
case DSHOT_CMD_SPIN_DIRECTION_NORMAL:
|
||||||
|
case DSHOT_CMD_SPIN_DIRECTION_REVERSED:
|
||||||
|
repeat_count = SETTINGS_COMMAND_REPEATS;
|
||||||
|
delay_us = SETTINGS_COMMAND_DELAY_US;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// For other commands, use default repeat and delay
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendCommand(command, repeat_count, delay_us);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a DShot command (0-47) to the ESC with a specified repeat count and delay.
|
||||||
|
dshot_result_t DShotRMT::sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us)
|
||||||
{
|
{
|
||||||
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_UNKNOWN, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
|
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_UNKNOWN, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
|
||||||
|
|
||||||
if (!_isValidCommand(dshot_command))
|
if (!_isValidCommand(command))
|
||||||
{
|
{
|
||||||
result.result_code = dshot_msg_code_t::DSHOT_INVALID_COMMAND;
|
result.result_code = dshot_msg_code_t::DSHOT_INVALID_COMMAND;
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -152,7 +178,7 @@ dshot_result_t DShotRMT::_sendCommandInternal(dshotCommands_e dshot_command, uin
|
||||||
// Send command multiple times with delay
|
// Send command multiple times with delay
|
||||||
for (uint16_t i = 0; i < repeat_count; i++)
|
for (uint16_t i = 0; i < repeat_count; i++)
|
||||||
{
|
{
|
||||||
dshot_result_t single_result = _executeCommand(dshot_command);
|
dshot_result_t single_result = _executeCommand(command);
|
||||||
|
|
||||||
if (!single_result.success)
|
if (!single_result.success)
|
||||||
{
|
{
|
||||||
|
|
@ -168,7 +194,6 @@ dshot_result_t DShotRMT::_sendCommandInternal(dshotCommands_e dshot_command, uin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
result.success = all_successful;
|
result.success = all_successful;
|
||||||
|
|
||||||
if (result.success)
|
if (result.success)
|
||||||
|
|
@ -221,15 +246,13 @@ dshot_result_t DShotRMT::setMotorSpinDirection(bool reversed)
|
||||||
// Use command as a yes / no switch
|
// Use command as a yes / no switch
|
||||||
dshotCommands_e command = reversed ? dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_REVERSED : dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_NORMAL;
|
dshotCommands_e command = reversed ? dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_REVERSED : dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_NORMAL;
|
||||||
|
|
||||||
return _sendCommandInternal(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
return sendCommand(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Use with caution
|
// Use with caution
|
||||||
dshot_result_t DShotRMT::saveESCSettings()
|
dshot_result_t DShotRMT::saveESCSettings()
|
||||||
{
|
{
|
||||||
return _sendCommandInternal(dshotCommands_e::DSHOT_CMD_SAVE_SETTINGS, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
return sendCommand(dshotCommands_e::DSHOT_CMD_SAVE_SETTINGS, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple check
|
// Simple check
|
||||||
|
|
@ -252,103 +275,7 @@ dshot_result_t DShotRMT::_executeCommand(dshotCommands_e command)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private Initialization Functions
|
|
||||||
dshot_result_t DShotRMT::_initTXChannel()
|
|
||||||
{
|
|
||||||
_tx_channel_config.gpio_num = _gpio;
|
|
||||||
_tx_channel_config.clk_src = DSHOT_CLOCK_SRC_DEFAULT;
|
|
||||||
_tx_channel_config.resolution_hz = DSHOT_RMT_RESOLUTION;
|
|
||||||
_tx_channel_config.mem_block_symbols = RMT_BUFFER_SYMBOLS;
|
|
||||||
_tx_channel_config.trans_queue_depth = RMT_QUEUE_DEPTH;
|
|
||||||
|
|
||||||
_rmt_tx_config.loop_count = 0; // No automatic loops - real-time calculation
|
|
||||||
_rmt_tx_config.flags.eot_level = _is_bidirectional ? 1 : 0;
|
|
||||||
|
|
||||||
if (rmt_new_tx_channel(&_tx_channel_config, &_rmt_tx_channel) != DSHOT_OK)
|
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rmt_enable(_rmt_tx_channel) != DSHOT_OK)
|
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {true, dshot_msg_code_t::DSHOT_TX_INIT_SUCCESS};
|
|
||||||
}
|
|
||||||
|
|
||||||
dshot_result_t DShotRMT::_initRXChannel()
|
|
||||||
{
|
|
||||||
// Double check if bidirectional mode is enabled
|
|
||||||
if (!_is_bidirectional)
|
|
||||||
{
|
|
||||||
return {true, dshot_msg_code_t::DSHOT_NONE};
|
|
||||||
}
|
|
||||||
|
|
||||||
_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 = RMT_BUFFER_SYMBOLS;
|
|
||||||
|
|
||||||
// Filter for pulses that are within a reasonable range for DShot telemetry
|
|
||||||
_rmt_rx_config.signal_range_min_ns = DSHOT_PULSE_MIN_NS;
|
|
||||||
_rmt_rx_config.signal_range_max_ns = DSHOT_PULSE_MAX_NS;
|
|
||||||
|
|
||||||
if (rmt_new_rx_channel(&_rx_channel_config, &_rmt_rx_channel) != DSHOT_OK)
|
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the callback function that will be triggered when a frame is received
|
|
||||||
_rx_event_callbacks.on_recv_done = _on_rx_done;
|
|
||||||
if (rmt_rx_register_event_callbacks(_rmt_rx_channel, &_rx_event_callbacks, this) != DSHOT_OK)
|
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_CALLBACK_REGISTERING_FAILED};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
|
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the receiver to wait for incoming telemetry data
|
|
||||||
rmt_symbol_word_t rx_symbols[GCR_BITS_PER_FRAME];
|
|
||||||
size_t rx_size_bytes = GCR_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
|
|
||||||
if (rmt_receive(_rmt_rx_channel, rx_symbols, rx_size_bytes, &_rmt_rx_config) != DSHOT_OK)
|
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_RECEIVER_FAILED};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {true, dshot_msg_code_t::DSHOT_RX_INIT_SUCCESS};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
dshot_result_t DShotRMT::_initDShotEncoder()
|
|
||||||
{
|
|
||||||
rmt_bytes_encoder_config_t encoder_config = {
|
|
||||||
.bit0 = {
|
|
||||||
.duration0 = _rmt_ticks.t0h_ticks,
|
|
||||||
.level0 = _pulse_level,
|
|
||||||
.duration1 = _rmt_ticks.t0l_ticks,
|
|
||||||
.level1 = _idle_level,
|
|
||||||
},
|
|
||||||
.bit1 = {
|
|
||||||
.duration0 = _rmt_ticks.t1h_ticks,
|
|
||||||
.level0 = _pulse_level,
|
|
||||||
.duration1 = _rmt_ticks.t1l_ticks,
|
|
||||||
.level1 = _idle_level,
|
|
||||||
},
|
|
||||||
.flags = {
|
|
||||||
.msb_first = 1 // DShot is MSB first
|
|
||||||
}};
|
|
||||||
|
|
||||||
if (rmt_new_bytes_encoder(&encoder_config, &_dshot_encoder) != DSHOT_OK)
|
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_ENCODER_INIT_FAILED};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {true, dshot_msg_code_t::DSHOT_ENCODER_INIT_SUCCESS};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private Packet Management Functions
|
// Private Packet Management Functions
|
||||||
dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t &value) const
|
dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t &value) const
|
||||||
|
|
@ -422,7 +349,11 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||||
// The DShot frame is 16 bits, which is 2 bytes
|
// The DShot frame is 16 bits, which is 2 bytes
|
||||||
size_t tx_size_bytes = sizeof(swapped_value);
|
size_t tx_size_bytes = sizeof(swapped_value);
|
||||||
|
|
||||||
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, &swapped_value, tx_size_bytes, &_rmt_tx_config) != DSHOT_OK)
|
rmt_transmit_config_t tx_config = {}; // Initialize all members to zero
|
||||||
|
tx_config.loop_count = 0; // No automatic loops - real-time calculation
|
||||||
|
tx_config.flags.eot_level = _is_bidirectional ? 1 : 0;
|
||||||
|
|
||||||
|
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, &swapped_value, tx_size_bytes, &tx_config) != DSHOT_OK)
|
||||||
{
|
{
|
||||||
return {false, dshot_msg_code_t::DSHOT_TRANSMISSION_FAILED};
|
return {false, dshot_msg_code_t::DSHOT_TRANSMISSION_FAILED};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "dshot_definitions.h"
|
#include "dshot_definitions.h"
|
||||||
#include <driver/rmt_encoder.h>
|
#include <driver/rmt_encoder.h>
|
||||||
|
#include "dshot_config.h"
|
||||||
|
|
||||||
// DShotRMT Class Definition
|
// DShotRMT Class Definition
|
||||||
class DShotRMT
|
class DShotRMT
|
||||||
|
|
@ -41,6 +42,10 @@ public:
|
||||||
|
|
||||||
// Sends a DShot command (0-47) to the ESC.
|
// Sends a DShot command (0-47) 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.
|
||||||
|
dshot_result_t sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us);
|
||||||
|
// Sends a DShot command (0-47) to the ESC by accepting an integer value.
|
||||||
|
dshot_result_t sendCommand(uint16_t command_value);
|
||||||
|
|
||||||
// Retrieves telemetry data from the ESC.
|
// Retrieves telemetry data from the ESC.
|
||||||
dshot_result_t getTelemetry();
|
dshot_result_t getTelemetry();
|
||||||
|
|
@ -71,19 +76,11 @@ public:
|
||||||
const char *getDShotMsg(dshot_result_t &result) const { return (_get_result_code_str(result.result_code)); }
|
const char *getDShotMsg(dshot_result_t &result) const { return (_get_result_code_str(result.result_code)); }
|
||||||
|
|
||||||
// Deprecated Methods
|
// Deprecated Methods
|
||||||
// Deprecated. Use sendThrottle() instead.
|
|
||||||
[[deprecated("Use sendThrottle() instead")]]
|
|
||||||
dshot_result_t sendValue(uint16_t value) { return sendThrottle(value); }
|
|
||||||
|
|
||||||
// Deprecated. Use sendCommand() instead.
|
|
||||||
[[deprecated("Use sendCommand() instead")]]
|
|
||||||
dshot_result_t sendCommand(uint16_t command) { return sendCommand(static_cast<dshotCommands_e>(command)); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- UTILITY METHODS ---
|
// --- UTILITY METHODS ---
|
||||||
bool _isValidCommand(dshotCommands_e command) const;
|
bool _isValidCommand(dshotCommands_e command) const;
|
||||||
dshot_result_t _executeCommand(dshotCommands_e command);
|
dshot_result_t _executeCommand(dshotCommands_e command);
|
||||||
dshot_result_t _sendCommandInternal(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us);
|
|
||||||
|
|
||||||
// Core Configuration Variables
|
// Core Configuration Variables
|
||||||
gpio_num_t _gpio;
|
gpio_num_t _gpio;
|
||||||
|
|
@ -108,22 +105,13 @@ private:
|
||||||
rmt_channel_handle_t _rmt_rx_channel = nullptr;
|
rmt_channel_handle_t _rmt_rx_channel = nullptr;
|
||||||
rmt_encoder_handle_t _dshot_encoder = nullptr;
|
rmt_encoder_handle_t _dshot_encoder = nullptr;
|
||||||
|
|
||||||
// RMT Configuration Structures
|
|
||||||
rmt_tx_channel_config_t _tx_channel_config{};
|
|
||||||
rmt_rx_channel_config_t _rx_channel_config{};
|
|
||||||
rmt_transmit_config_t _rmt_tx_config{};
|
|
||||||
rmt_receive_config_t _rmt_rx_config{};
|
|
||||||
|
|
||||||
// Bidirectional / Telemetry Variables
|
// Bidirectional / Telemetry Variables
|
||||||
rmt_rx_event_callbacks_t _rx_event_callbacks{};
|
rmt_rx_event_callbacks_t _rx_event_callbacks{};
|
||||||
std::atomic<uint16_t> _last_erpm_atomic{0};
|
std::atomic<uint16_t> _last_erpm_atomic{0};
|
||||||
std::atomic<bool> _telemetry_ready_flag_atomic{false};
|
std::atomic<bool> _telemetry_ready_flag_atomic{false};
|
||||||
|
|
||||||
// Private Initialization Functions
|
|
||||||
dshot_result_t _initTXChannel();
|
|
||||||
dshot_result_t _initRXChannel();
|
|
||||||
dshot_result_t _initDShotEncoder();
|
|
||||||
|
|
||||||
// Private Packet Management Functions
|
// Private Packet Management Functions
|
||||||
dshot_packet_t _buildDShotPacket(const uint16_t &value) const;
|
dshot_packet_t _buildDShotPacket(const uint16_t &value) const;
|
||||||
uint16_t _buildDShotFrameValue(const dshot_packet_t &packet) const;
|
uint16_t _buildDShotFrameValue(const dshot_packet_t &packet) const;
|
||||||
|
|
@ -143,4 +131,4 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Include utility functions after class definition
|
// Include utility functions after class definition
|
||||||
#include "dshot_utils.h"
|
#include "dshot_utils.h"
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
#include "dshot_config.h"
|
||||||
|
|
||||||
|
// Function to initialize the RMT TX channel
|
||||||
|
dshot_result_t init_rmt_tx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_channel, bool is_bidirectional)
|
||||||
|
{
|
||||||
|
rmt_tx_channel_config_t tx_channel_config = {
|
||||||
|
.gpio_num = gpio,
|
||||||
|
.clk_src = DSHOT_CLOCK_SRC_DEFAULT,
|
||||||
|
.resolution_hz = DSHOT_RMT_RESOLUTION,
|
||||||
|
.mem_block_symbols = RMT_BUFFER_SYMBOLS,
|
||||||
|
.trans_queue_depth = RMT_QUEUE_DEPTH,
|
||||||
|
};
|
||||||
|
|
||||||
|
rmt_transmit_config_t rmt_tx_config = {}; // Initialize all members to zero
|
||||||
|
rmt_tx_config.loop_count = 0; // No automatic loops - real-time calculation
|
||||||
|
rmt_tx_config.flags.eot_level = is_bidirectional ? 1 : 0;
|
||||||
|
|
||||||
|
if (rmt_new_tx_channel(&tx_channel_config, out_channel) != DSHOT_OK)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmt_enable(*out_channel) != DSHOT_OK)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_TX_INIT_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {true, dshot_msg_code_t::DSHOT_TX_INIT_SUCCESS};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to initialize the RMT RX channel
|
||||||
|
dshot_result_t init_rmt_rx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_channel, rmt_rx_event_callbacks_t *rx_event_callbacks, void *user_data)
|
||||||
|
{
|
||||||
|
rmt_rx_channel_config_t rx_channel_config = {
|
||||||
|
.gpio_num = gpio,
|
||||||
|
.clk_src = DSHOT_CLOCK_SRC_DEFAULT,
|
||||||
|
.resolution_hz = DSHOT_RMT_RESOLUTION,
|
||||||
|
.mem_block_symbols = RMT_BUFFER_SYMBOLS,
|
||||||
|
};
|
||||||
|
|
||||||
|
rmt_receive_config_t rmt_rx_config = {
|
||||||
|
.signal_range_min_ns = DSHOT_PULSE_MIN_NS,
|
||||||
|
.signal_range_max_ns = DSHOT_PULSE_MAX_NS,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (rmt_new_rx_channel(&rx_channel_config, out_channel) != DSHOT_OK)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmt_rx_register_event_callbacks(*out_channel, rx_event_callbacks, user_data) != DSHOT_OK)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_CALLBACK_REGISTERING_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmt_enable(*out_channel) != DSHOT_OK)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_RX_INIT_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the receiver to wait for incoming telemetry data
|
||||||
|
rmt_symbol_word_t rx_symbols[GCR_BITS_PER_FRAME];
|
||||||
|
size_t rx_size_bytes = GCR_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
|
||||||
|
if (rmt_receive(*out_channel, rx_symbols, rx_size_bytes, &rmt_rx_config) != DSHOT_OK)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_RECEIVER_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {true, dshot_msg_code_t::DSHOT_RX_INIT_SUCCESS};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to initialize the DShot RMT encoder
|
||||||
|
dshot_result_t init_dshot_encoder(rmt_encoder_handle_t *out_encoder, const rmt_ticks_t &rmt_ticks, uint16_t pulse_level, uint16_t idle_level)
|
||||||
|
{
|
||||||
|
rmt_bytes_encoder_config_t encoder_config = {
|
||||||
|
.bit0 = {
|
||||||
|
.duration0 = rmt_ticks.t0h_ticks,
|
||||||
|
.level0 = pulse_level,
|
||||||
|
.duration1 = rmt_ticks.t0l_ticks,
|
||||||
|
.level1 = idle_level,
|
||||||
|
},
|
||||||
|
.bit1 = {
|
||||||
|
.duration0 = rmt_ticks.t1h_ticks,
|
||||||
|
.level0 = pulse_level,
|
||||||
|
.duration1 = rmt_ticks.t1l_ticks,
|
||||||
|
.level1 = idle_level,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.msb_first = 1 // DShot is MSB first
|
||||||
|
}};
|
||||||
|
|
||||||
|
if (rmt_new_bytes_encoder(&encoder_config, out_encoder) != DSHOT_OK)
|
||||||
|
{
|
||||||
|
return {false, dshot_msg_code_t::DSHOT_ENCODER_INIT_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {true, dshot_msg_code_t::DSHOT_ENCODER_INIT_SUCCESS};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <driver/rmt_tx.h>
|
||||||
|
#include <driver/rmt_rx.h>
|
||||||
|
|
||||||
|
#include "dshot_definitions.h"
|
||||||
|
|
||||||
|
// Function to initialize the RMT TX channel
|
||||||
|
dshot_result_t init_rmt_tx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_channel, bool is_bidirectional);
|
||||||
|
|
||||||
|
// Function to initialize the RMT RX channel
|
||||||
|
dshot_result_t init_rmt_rx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_channel, rmt_rx_event_callbacks_t *rx_event_callbacks, void *user_data);
|
||||||
|
|
||||||
|
// Function to initialize the DShot RMT encoder
|
||||||
|
dshot_result_t init_dshot_encoder(rmt_encoder_handle_t *out_encoder, const rmt_ticks_t &rmt_ticks, uint16_t pulse_level, uint16_t idle_level);
|
||||||
Loading…
Reference in New Issue