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/esp32.svd
|
||||||
examples/dshot300/debug_custom.json
|
examples/dshot300/debug_custom.json
|
||||||
examples/dshot300/debug.svd
|
examples/dshot300/debug.svd
|
||||||
|
.vscode
|
||||||
|
|
|
||||||
100
src/DShotRMT.cpp
100
src/DShotRMT.cpp
|
|
@ -6,7 +6,7 @@
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "DShotRMT.h"
|
#include <DShotRMT.h>
|
||||||
|
|
||||||
// Static Data & Helper Functions
|
// Static Data & Helper Functions
|
||||||
// Timing parameters for each DShot mode
|
// 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
|
// Configure RMT ticks for DShot timings
|
||||||
_preCalculateRMTTicks();
|
_preCalculateRMTTicks();
|
||||||
|
|
||||||
|
// Bit positions precalculation
|
||||||
|
_preCalculateBitPositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor using pin number
|
// Constructor using pin number
|
||||||
|
|
@ -106,6 +109,12 @@ DShotRMT::~DShotRMT()
|
||||||
// Initialize DShotRMT
|
// Initialize DShotRMT
|
||||||
dshot_result_t DShotRMT::begin()
|
dshot_result_t DShotRMT::begin()
|
||||||
{
|
{
|
||||||
|
// Init TX channel
|
||||||
|
if (!_initTXChannel().success)
|
||||||
|
{
|
||||||
|
return {false, TX_INIT_FAILED};
|
||||||
|
}
|
||||||
|
|
||||||
// Init RX channel first (for bidirectional mode)
|
// Init RX channel first (for bidirectional mode)
|
||||||
if (_is_bidirectional)
|
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
|
// Init DShot encoder
|
||||||
if (!_initDShotEncoder().success)
|
if (!_initDShotEncoder().success)
|
||||||
{
|
{
|
||||||
return {false, ENCODER_INIT_FAILED};
|
return {false, ENCODER_INIT_FAILED};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bit positions precalculation
|
|
||||||
_preCalculateBitPositions();
|
|
||||||
|
|
||||||
return {true, INIT_SUCCESS};
|
return {true, INIT_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,8 +285,11 @@ dshot_result_t DShotRMT::_initTXChannel()
|
||||||
// Initialize RMT RX channel
|
// Initialize RMT RX channel
|
||||||
dshot_result_t DShotRMT::_initRXChannel()
|
dshot_result_t DShotRMT::_initRXChannel()
|
||||||
{
|
{
|
||||||
// Direct RMT symbol processing - Performance optimized
|
// Check if the bidirectional mode is enabled to be sure
|
||||||
_rx_event_callbacks.on_recv_done = _on_rx_done;
|
if (!_is_bidirectional)
|
||||||
|
{
|
||||||
|
return {true, NONE};
|
||||||
|
}
|
||||||
|
|
||||||
// Config RMT RX
|
// Config RMT RX
|
||||||
_rx_channel_config.gpio_num = _gpio;
|
_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.resolution_hz = DSHOT_RMT_RESOLUTION;
|
||||||
_rx_channel_config.mem_block_symbols = RMT_BUFFER_SYMBOLS;
|
_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_min_ns = DSHOT_PULSE_MIN;
|
||||||
_rmt_rx_config.signal_range_max_ns = DSHOT_PULSE_MAX;
|
_rmt_rx_config.signal_range_max_ns = DSHOT_PULSE_MAX;
|
||||||
|
|
||||||
|
|
@ -304,12 +307,28 @@ dshot_result_t DShotRMT::_initRXChannel()
|
||||||
return {false, RX_INIT_FAILED};
|
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
|
// Enable RX channel
|
||||||
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
|
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
|
||||||
{
|
{
|
||||||
return {false, RX_INIT_FAILED};
|
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};
|
return {true, RX_INIT_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,55 +435,25 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||||
return {false, TIMING_CORRECTION};
|
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
|
// Local for performance
|
||||||
rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME];
|
rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME];
|
||||||
|
|
||||||
// Encode DShot packet into RMT symbols
|
// 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
|
// Calculate transmission data size
|
||||||
size_t tx_size_bytes = DSHOT_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
|
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
|
// Perform RMT transmission
|
||||||
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, tx_size_bytes, &_rmt_tx_config) != DSHOT_OK)
|
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, tx_size_bytes, &_rmt_tx_config) != DSHOT_OK)
|
||||||
{
|
{
|
||||||
return {false, TRANSMISSION_FAILED};
|
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
|
// Update timestamp and calculate execution time
|
||||||
_timer_reset();
|
_timer_reset();
|
||||||
|
|
||||||
|
|
@ -537,7 +526,7 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
||||||
return received_data & DSHOT_THROTTLE_MAX;
|
return received_data & DSHOT_THROTTLE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private Timing Control Functions
|
// Timing Control Functions
|
||||||
// Check if enough time has passed for next transmission
|
// Check if enough time has passed for next transmission
|
||||||
bool IRAM_ATTR DShotRMT::_timer_signal()
|
bool IRAM_ATTR DShotRMT::_timer_signal()
|
||||||
{
|
{
|
||||||
|
|
@ -557,23 +546,22 @@ bool DShotRMT::_timer_reset()
|
||||||
return DSHOT_OK;
|
return DSHOT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static Callback Functions
|
|
||||||
// Callback for RMT RX
|
// 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)
|
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);
|
DShotRMT *instance = static_cast<DShotRMT *>(user_data);
|
||||||
|
|
||||||
// ISR check for valid data
|
// Process received symbols only if the frame size is correct
|
||||||
if (edata && edata->num_symbols >= GCR_BITS_PER_FRAME && edata->num_symbols <= GCR_BITS_PER_FRAME)
|
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);
|
uint16_t erpm = instance->_decodeDShotFrame(edata->received_symbols);
|
||||||
|
|
||||||
if (erpm != DSHOT_NULL_PACKET)
|
if (erpm != DSHOT_NULL_PACKET)
|
||||||
{
|
{
|
||||||
// Atomic writes - thread-safe
|
// Atomic writes - thread-safe
|
||||||
instance->_last_erpm_atomic = erpm;
|
instance->_last_erpm_atomic.store(erpm);
|
||||||
instance->_telemetry_ready_flag_atomic = true;
|
instance->_telemetry_ready_flag_atomic.store(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,8 @@ private:
|
||||||
static constexpr auto const POLE_PAIRS_MIN = 1;
|
static constexpr auto const POLE_PAIRS_MIN = 1;
|
||||||
static constexpr auto const MAGNETS_PER_POLE_PAIR = 2;
|
static constexpr auto const MAGNETS_PER_POLE_PAIR = 2;
|
||||||
static constexpr auto const NO_DSHOT_TELEMETRY = 0;
|
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_MIN = 1000; // 1.0us minimum pulse
|
||||||
static constexpr auto const DSHOT_PULSE_MAX = 10000; // 10us maximum pulse
|
static constexpr auto const DSHOT_PULSE_MAX = 8000; // 10.0us maximum pulse
|
||||||
static constexpr auto const DSHOT_TELEMETRY_INVALID = DSHOT_THROTTLE_MAX;
|
static constexpr auto const DSHOT_TELEMETRY_INVALID = DSHOT_THROTTLE_MAX;
|
||||||
|
|
||||||
// Error Messages
|
// Error Messages
|
||||||
|
|
@ -167,7 +167,8 @@ private:
|
||||||
static constexpr char const *TELEMETRY_FAILED = "No valid Telemetric Frame received!";
|
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 *INVALID_MAGNET_COUNT = "Invalid motor magnet count!";
|
||||||
static constexpr char const *TIMING_CORRECTION = "Timing correction!";
|
static constexpr char const *TIMING_CORRECTION = "Timing correction!";
|
||||||
|
static constexpr char const *CALLBACK_REGISTERING_FAILED = "RMT RX Callback registering failed!";
|
||||||
|
|
||||||
// Core Configuration Variables
|
// Core Configuration Variables
|
||||||
gpio_num_t _gpio;
|
gpio_num_t _gpio;
|
||||||
dshot_mode_t _mode;
|
dshot_mode_t _mode;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue