Use automatic tx / rx switching

This commit is contained in:
Wastl Kraus 2025-09-17 21:41:20 +02:00
parent 206a19ac41
commit 8c309d648c
3 changed files with 49 additions and 59 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ examples/dshot300/debug.cfg
examples/dshot300/esp32.svd
examples/dshot300/debug_custom.json
examples/dshot300/debug.svd
.vscode

View File

@ -6,7 +6,7 @@
* @license MIT
*/
#include "DShotRMT.h"
#include <DShotRMT.h>
// Static Data & Helper Functions
// Timing parameters for each DShot mode
@ -61,6 +61,9 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional)
{
// Configure RMT ticks for DShot timings
_preCalculateRMTTicks();
// Bit positions precalculation
_preCalculateBitPositions();
}
// Constructor using pin number
@ -106,6 +109,12 @@ DShotRMT::~DShotRMT()
// Initialize DShotRMT
dshot_result_t DShotRMT::begin()
{
// Init TX channel
if (!_initTXChannel().success)
{
return {false, TX_INIT_FAILED};
}
// Init RX channel first (for bidirectional mode)
if (_is_bidirectional)
{
@ -115,21 +124,12 @@ dshot_result_t DShotRMT::begin()
}
}
// Init TX channel
if (!_initTXChannel().success)
{
return {false, TX_INIT_FAILED};
}
// Init DShot encoder
if (!_initDShotEncoder().success)
{
return {false, ENCODER_INIT_FAILED};
}
// Bit positions precalculation
_preCalculateBitPositions();
return {true, INIT_SUCCESS};
}
@ -285,8 +285,11 @@ dshot_result_t DShotRMT::_initTXChannel()
// Initialize RMT RX channel
dshot_result_t DShotRMT::_initRXChannel()
{
// Direct RMT symbol processing - Performance optimized
_rx_event_callbacks.on_recv_done = _on_rx_done;
// Check if the bidirectional mode is enabled to be sure
if (!_is_bidirectional)
{
return {true, NONE};
}
// Config RMT RX
_rx_channel_config.gpio_num = _gpio;
@ -294,7 +297,7 @@ dshot_result_t DShotRMT::_initRXChannel()
_rx_channel_config.resolution_hz = DSHOT_RMT_RESOLUTION;
_rx_channel_config.mem_block_symbols = RMT_BUFFER_SYMBOLS;
// Config RMT RX parameters
// Config RMT RX parameters
_rmt_rx_config.signal_range_min_ns = DSHOT_PULSE_MIN;
_rmt_rx_config.signal_range_max_ns = DSHOT_PULSE_MAX;
@ -304,12 +307,28 @@ dshot_result_t DShotRMT::_initRXChannel()
return {false, RX_INIT_FAILED};
}
// Register RX event callback
_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, CALLBACK_REGISTERING_FAILED};
}
// Enable RX channel
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
{
return {false, RX_INIT_FAILED};
}
// Calculate transmission data size
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, RECEIVER_FAILED};
}
return {true, RX_INIT_SUCCESS};
}
@ -416,55 +435,25 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
return {false, TIMING_CORRECTION};
}
// Enable RMT RX before RMT TX (bidirectional mode)
if (_is_bidirectional)
{
// Calculate transmission data size
size_t rx_size_bytes = GCR_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
// Performance reasons
rmt_symbol_word_t rx_symbols[GCR_BITS_PER_FRAME];
if (rmt_receive(_rmt_rx_channel, rx_symbols, rx_size_bytes, &_rmt_rx_config) != DSHOT_OK)
{
return {false, RECEIVER_FAILED};
}
}
// Local for performance
rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME];
// Encode DShot packet into RMT symbols
_encodeDShotFrame(packet, tx_symbols);
dshot_result_t result = _encodeDShotFrame(packet, tx_symbols);
if (!result.success)
{
return result;
}
// Calculate transmission data size
size_t tx_size_bytes = DSHOT_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
// TODO: Find out, why this is needed
if (_is_bidirectional)
{
// Disable RMT RX for sending
if (rmt_disable(_rmt_rx_channel) != DSHOT_OK)
{
return {false, RECEIVER_FAILED};
}
}
// Perform RMT transmission
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, tx_size_bytes, &_rmt_tx_config) != DSHOT_OK)
{
return {false, TRANSMISSION_FAILED};
}
// Re-enable RMT RX
if (_is_bidirectional)
{
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
{
return {false, RECEIVER_FAILED};
}
}
// Update timestamp and calculate execution time
_timer_reset();
@ -537,7 +526,7 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
return received_data & DSHOT_THROTTLE_MAX;
}
// Private Timing Control Functions
// Timing Control Functions
// Check if enough time has passed for next transmission
bool IRAM_ATTR DShotRMT::_timer_signal()
{
@ -557,23 +546,22 @@ bool DShotRMT::_timer_reset()
return DSHOT_OK;
}
// Static Callback Functions
// Callback for RMT RX
bool IRAM_ATTR DShotRMT::_on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data)
{
// Casts the user data back to class instance
DShotRMT *instance = static_cast<DShotRMT *>(user_data);
// ISR check for valid data
if (edata && edata->num_symbols >= GCR_BITS_PER_FRAME && edata->num_symbols <= GCR_BITS_PER_FRAME)
// Process received symbols only if the frame size is correct
if (edata && edata->num_symbols == GCR_BITS_PER_FRAME)
{
// Direct decoding
// Parse the GCR frame and store the result
uint16_t erpm = instance->_decodeDShotFrame(edata->received_symbols);
if (erpm != DSHOT_NULL_PACKET)
{
// Atomic writes - thread-safe
instance->_last_erpm_atomic = erpm;
instance->_telemetry_ready_flag_atomic = true;
instance->_last_erpm_atomic.store(erpm);
instance->_telemetry_ready_flag_atomic.store(true);
}
}

View File

@ -141,8 +141,8 @@ private:
static constexpr auto const POLE_PAIRS_MIN = 1;
static constexpr auto const MAGNETS_PER_POLE_PAIR = 2;
static constexpr auto const NO_DSHOT_TELEMETRY = 0;
static constexpr auto const DSHOT_PULSE_MIN = 800; // 0.8us minimum pulse
static constexpr auto const DSHOT_PULSE_MAX = 10000; // 10us maximum pulse
static constexpr auto const DSHOT_PULSE_MIN = 1000; // 1.0us minimum pulse
static constexpr auto const DSHOT_PULSE_MAX = 8000; // 10.0us maximum pulse
static constexpr auto const DSHOT_TELEMETRY_INVALID = DSHOT_THROTTLE_MAX;
// Error Messages
@ -167,6 +167,7 @@ private:
static constexpr char const *TELEMETRY_FAILED = "No valid Telemetric Frame received!";
static constexpr char const *INVALID_MAGNET_COUNT = "Invalid motor magnet count!";
static constexpr char const *TIMING_CORRECTION = "Timing correction!";
static constexpr char const *CALLBACK_REGISTERING_FAILED = "RMT RX Callback registering failed!";
// Core Configuration Variables
gpio_num_t _gpio;