Use automatic tx / rx switching
This commit is contained in:
parent
206a19ac41
commit
8c309d648c
|
|
@ -12,3 +12,4 @@ examples/dshot300/debug.cfg
|
|||
examples/dshot300/esp32.svd
|
||||
examples/dshot300/debug_custom.json
|
||||
examples/dshot300/debug.svd
|
||||
.vscode
|
||||
|
|
|
|||
100
src/DShotRMT.cpp
100
src/DShotRMT.cpp
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue