...hotfix: memory consumption
...update callback ...performance optimizations ... fix memory consumption ...update timers ...clean up ...update GCR logic ...some more memory testing ...optimize encoder logic
This commit is contained in:
parent
ff673e475e
commit
d9d8dce251
122
DShotRMT.cpp
122
DShotRMT.cpp
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "DShotRMT.h"
|
#include "DShotRMT.h"
|
||||||
#include <driver/rmt_tx.h>
|
|
||||||
|
|
||||||
// Timing parameters for each DShot mode
|
// Timing parameters for each DShot mode
|
||||||
// Format: {frame_length_us, ticks_per_bit, ticks_one_high, ticks_one_low, ticks_zero_high, ticks_zero_low}
|
// Format: {frame_length_us, ticks_per_bit, ticks_one_high, ticks_one_low, ticks_zero_high, ticks_zero_low}
|
||||||
|
|
@ -19,19 +18,24 @@ static constexpr dshot_timing_t DSHOT_TIMINGS[] = {
|
||||||
{16, 8, 6, 2, 3, 5} // DSHOT1200
|
{16, 8, 6, 2, 3, 5} // DSHOT1200
|
||||||
};
|
};
|
||||||
|
|
||||||
// Primary constructor with GPIO number
|
// Constructor with GPIO number
|
||||||
DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional)
|
DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional)
|
||||||
: _gpio(gpio),
|
: _gpio(gpio),
|
||||||
_mode(mode),
|
_mode(mode),
|
||||||
_is_bidirectional(is_bidirectional),
|
_is_bidirectional(is_bidirectional),
|
||||||
|
_frame_timer_us(0),
|
||||||
_timing_config(DSHOT_TIMINGS[mode]),
|
_timing_config(DSHOT_TIMINGS[mode]),
|
||||||
_rmt_tx_channel(nullptr),
|
_last_transmission_time(0),
|
||||||
_rmt_rx_channel(nullptr),
|
|
||||||
_dshot_encoder(nullptr),
|
|
||||||
_last_erpm(0),
|
_last_erpm(0),
|
||||||
_parsed_packet(0),
|
_parsed_packet(0),
|
||||||
_packet{0},
|
_packet{0},
|
||||||
_last_transmission_time(0),
|
_rmt_tx_channel(nullptr),
|
||||||
|
_rmt_rx_channel(nullptr),
|
||||||
|
_dshot_encoder(nullptr),
|
||||||
|
_tx_channel_config{},
|
||||||
|
_rx_channel_config{},
|
||||||
|
_transmit_config{},
|
||||||
|
_receive_config{},
|
||||||
_rx_queue(nullptr)
|
_rx_queue(nullptr)
|
||||||
{
|
{
|
||||||
// Calculate frame timing including switch/pause time
|
// Calculate frame timing including switch/pause time
|
||||||
|
|
@ -84,14 +88,14 @@ DShotRMT::~DShotRMT()
|
||||||
// Initialize DShotRMT
|
// Initialize DShotRMT
|
||||||
uint16_t DShotRMT::begin()
|
uint16_t DShotRMT::begin()
|
||||||
{
|
{
|
||||||
// Initialize TX channel
|
// Init TX channel
|
||||||
if (!_initTXChannel())
|
if (!_initTXChannel())
|
||||||
{
|
{
|
||||||
_dshot_log(TX_INIT_FAILED);
|
_dshot_log(TX_INIT_FAILED);
|
||||||
return DSHOT_ERROR;
|
return DSHOT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize RX channel only if bidirectional mode is enabled
|
// Init RX channel
|
||||||
if (_is_bidirectional)
|
if (_is_bidirectional)
|
||||||
{
|
{
|
||||||
if (!_initRXChannel())
|
if (!_initRXChannel())
|
||||||
|
|
@ -101,7 +105,7 @@ uint16_t DShotRMT::begin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize DShot encoder
|
// Init DShot encoder
|
||||||
if (_initDShotEncoder() != DSHOT_OK)
|
if (_initDShotEncoder() != DSHOT_OK)
|
||||||
{
|
{
|
||||||
_dshot_log(ENCODER_INIT_FAILED);
|
_dshot_log(ENCODER_INIT_FAILED);
|
||||||
|
|
@ -111,7 +115,7 @@ uint16_t DShotRMT::begin()
|
||||||
return DSHOT_OK;
|
return DSHOT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize RMT TX channel
|
// Init RMT TX channel
|
||||||
bool DShotRMT::_initTXChannel()
|
bool DShotRMT::_initTXChannel()
|
||||||
{
|
{
|
||||||
// Configure TX channel
|
// Configure TX channel
|
||||||
|
|
@ -121,7 +125,7 @@ bool DShotRMT::_initTXChannel()
|
||||||
_tx_channel_config.mem_block_symbols = RMT_BUFFER_SYMBOLS;
|
_tx_channel_config.mem_block_symbols = RMT_BUFFER_SYMBOLS;
|
||||||
_tx_channel_config.trans_queue_depth = RMT_QUEUE_DEPTH;
|
_tx_channel_config.trans_queue_depth = RMT_QUEUE_DEPTH;
|
||||||
|
|
||||||
// Configure transmission
|
// Config RMT TX
|
||||||
_transmit_config.loop_count = 0; // No automatic loops - real-time calculation
|
_transmit_config.loop_count = 0; // No automatic loops - real-time calculation
|
||||||
_transmit_config.flags.eot_level = _is_bidirectional ? 1 : 0; // Telemetric Bit used as bidir flag
|
_transmit_config.flags.eot_level = _is_bidirectional ? 1 : 0; // Telemetric Bit used as bidir flag
|
||||||
|
|
||||||
|
|
@ -135,23 +139,23 @@ bool DShotRMT::_initTXChannel()
|
||||||
return (rmt_enable(_rmt_tx_channel) == DSHOT_OK);
|
return (rmt_enable(_rmt_tx_channel) == DSHOT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize RMT RX channel
|
// Init RMT RX channel
|
||||||
bool DShotRMT::_initRXChannel()
|
bool DShotRMT::_initRXChannel()
|
||||||
{
|
{
|
||||||
// Create a queue to receive data from the RX callback
|
// Create a queue for RX callback data
|
||||||
_rx_queue = xQueueCreate(RMT_QUEUE_DEPTH, sizeof(rmt_rx_done_event_data_t));
|
_rx_queue = xQueueCreate(RMT_QUEUE_DEPTH, sizeof(rmt_rx_done_event_data_t));
|
||||||
if (_rx_queue == nullptr)
|
if (_rx_queue == nullptr)
|
||||||
{
|
{
|
||||||
return DSHOT_ERROR;
|
return DSHOT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure RX channel parameters
|
// Config RMT RX
|
||||||
_rx_channel_config.gpio_num = _gpio;
|
_rx_channel_config.gpio_num = _gpio;
|
||||||
_rx_channel_config.clk_src = DSHOT_CLOCK_SRC_DEFAULT;
|
_rx_channel_config.clk_src = DSHOT_CLOCK_SRC_DEFAULT;
|
||||||
_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;
|
||||||
|
|
||||||
// Configure reception parameters
|
// Config RMT RX parameters
|
||||||
_receive_config.signal_range_min_ns = DSHOT_PULSE_MIN;
|
_receive_config.signal_range_min_ns = DSHOT_PULSE_MIN;
|
||||||
_receive_config.signal_range_max_ns = DSHOT_PULSE_MAX;
|
_receive_config.signal_range_max_ns = DSHOT_PULSE_MAX;
|
||||||
|
|
||||||
|
|
@ -162,9 +166,10 @@ bool DShotRMT::_initRXChannel()
|
||||||
return DSHOT_ERROR;
|
return DSHOT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register callback for reception
|
// Register RX callback
|
||||||
_rx_event_cbs.on_recv_done = _rmt_rx_done_callback;
|
_rx_event_callbacks.on_recv_done = _rmt_rx_done_callback;
|
||||||
if (rmt_rx_register_event_callbacks(_rmt_rx_channel, &_rx_event_cbs, _rx_queue) != DSHOT_OK)
|
|
||||||
|
if (rmt_rx_register_event_callbacks(_rmt_rx_channel, &_rx_event_callbacks, _rx_queue) != DSHOT_OK)
|
||||||
{
|
{
|
||||||
_dshot_log(RX_INIT_FAILED);
|
_dshot_log(RX_INIT_FAILED);
|
||||||
return DSHOT_ERROR;
|
return DSHOT_ERROR;
|
||||||
|
|
@ -174,14 +179,14 @@ bool DShotRMT::_initRXChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback for RMT RX
|
// Callback for RMT RX
|
||||||
bool IRAM_ATTR DShotRMT::_rmt_rx_done_callback(rmt_channel_handle_t rx_chan, const rmt_rx_done_event_data_t *edata, void *user_data)
|
bool IRAM_ATTR DShotRMT::_rmt_rx_done_callback(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data)
|
||||||
{
|
{
|
||||||
// Get the queue handle
|
// Init RX buffer
|
||||||
QueueHandle_t rx_queue = (QueueHandle_t)user_data;
|
QueueHandle_t rx_queue = (QueueHandle_t)user_data;
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
// Send the event data to the queue
|
// Copy callback data into RX buffer
|
||||||
xQueueSendFromISR(rx_queue, edata, &xHigherPriorityTaskWoken);
|
xQueueGenericSendFromISR(rx_queue, edata, &xHigherPriorityTaskWoken, queueSEND_TO_BACK);
|
||||||
|
|
||||||
return (xHigherPriorityTaskWoken == pdTRUE);
|
return (xHigherPriorityTaskWoken == pdTRUE);
|
||||||
}
|
}
|
||||||
|
|
@ -340,20 +345,26 @@ uint16_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||||
// Enable RMT RX before RMT TX
|
// Enable RMT RX before RMT TX
|
||||||
if (_is_bidirectional)
|
if (_is_bidirectional)
|
||||||
{
|
{
|
||||||
rmt_receive(_rmt_rx_channel, _rx_symbols, sizeof(_rx_symbols), &_receive_config);
|
// Performance reasons
|
||||||
|
rmt_symbol_word_t rx_symbols[DSHOT_BITS_PER_FRAME];
|
||||||
|
|
||||||
|
rmt_receive(_rmt_rx_channel, rx_symbols, sizeof(rx_symbols), &_receive_config);
|
||||||
|
|
||||||
// Disable RMT RX for sending
|
// Disable RMT RX for sending
|
||||||
rmt_disable(_rmt_rx_channel);
|
rmt_disable(_rmt_rx_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Local for performance
|
||||||
|
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);
|
_encodeDShotFrame(packet, tx_symbols);
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
// Perform RMT transmission
|
// Perform RMT transmission
|
||||||
uint16_t result = rmt_transmit(_rmt_tx_channel, _dshot_encoder, _tx_symbols, tx_size_bytes, &_transmit_config);
|
uint16_t result = rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, tx_size_bytes, &_transmit_config);
|
||||||
|
|
||||||
if (result != DSHOT_OK)
|
if (result != DSHOT_OK)
|
||||||
{
|
{
|
||||||
|
|
@ -377,32 +388,20 @@ uint16_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||||
// Encode DShot packet into RMT symbol format (placed in IRAM for performance)
|
// Encode DShot packet into RMT symbol format (placed in IRAM for performance)
|
||||||
bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols)
|
bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols)
|
||||||
{
|
{
|
||||||
// Parse packet to 16-bit format
|
|
||||||
_parsed_packet = _parseDShotPacket(packet);
|
_parsed_packet = _parseDShotPacket(packet);
|
||||||
|
|
||||||
// Convert each bit to RMT symbol
|
const uint16_t level0 = _is_bidirectional ? 0 : 1;
|
||||||
|
const uint16_t level1 = _is_bidirectional ? 1 : 0;
|
||||||
|
|
||||||
for (int i = 0; i < DSHOT_BITS_PER_FRAME; i++)
|
for (int i = 0; i < DSHOT_BITS_PER_FRAME; i++)
|
||||||
{
|
{
|
||||||
// Extract bit from packet
|
// Decode MSB
|
||||||
bool bit = (_parsed_packet >> (DSHOT_BITS_PER_FRAME - 1 - i)) & 0b0000000000000001;
|
bool bit = (_parsed_packet >> (DSHOT_BITS_PER_FRAME - 1 - i)) & 0b0000000000000001;
|
||||||
|
symbols[i].level0 = level0;
|
||||||
if (_is_bidirectional)
|
|
||||||
{
|
|
||||||
// Bidirectional DShot uses inverted levels - Idle HIGH
|
|
||||||
symbols[i].level0 = 0;
|
|
||||||
symbols[i].duration0 = bit ? _timing_config.ticks_one_high : _timing_config.ticks_zero_high;
|
symbols[i].duration0 = bit ? _timing_config.ticks_one_high : _timing_config.ticks_zero_high;
|
||||||
symbols[i].level1 = 1;
|
symbols[i].level1 = level1;
|
||||||
symbols[i].duration1 = bit ? _timing_config.ticks_one_low : _timing_config.ticks_zero_low;
|
symbols[i].duration1 = bit ? _timing_config.ticks_one_low : _timing_config.ticks_zero_low;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Standard DShot levels - Idle LOW
|
|
||||||
symbols[i].level0 = 1;
|
|
||||||
symbols[i].duration0 = bit ? _timing_config.ticks_one_high : _timing_config.ticks_zero_high;
|
|
||||||
symbols[i].level1 = 0;
|
|
||||||
symbols[i].duration1 = bit ? _timing_config.ticks_one_low : _timing_config.ticks_zero_low;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return DSHOT_OK;
|
return DSHOT_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -410,30 +409,33 @@ bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_sym
|
||||||
// Decode received RMT symbols
|
// Decode received RMT symbols
|
||||||
uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
||||||
{
|
{
|
||||||
// DShot answer is GCR encoded?
|
// DShot answer is GCR encoded.
|
||||||
// GCR decoding: bit_N = gcr_bit_N ^ gcr_bit_(N-1)
|
// GCR decoding: bit_N = gcr_bit_N ^ gcr_bit_(N-1)
|
||||||
uint32_t raw_gcr_data = 0;
|
uint32_t raw_gcr_data = 0;
|
||||||
|
|
||||||
// Reconstruct the raw GCR frame from RMT symbols
|
// Based on DShot bidirectional protocol, idle state is high,
|
||||||
for (size_t i = 0; i < DSHOT_BITS_PER_FRAME; ++i)
|
// so the first duration is a low pulse.
|
||||||
{
|
|
||||||
// Based on DShot bidirectional protocol, idle state is high, so first duration is low pulse.
|
|
||||||
// Bit 1: long low pulse, short high pulse
|
// Bit 1: long low pulse, short high pulse
|
||||||
// Bit 0: short low pulse, long high pulse
|
// Bit 0: short low pulse, long high pulse
|
||||||
|
for (size_t i = 0; i < GCR_BITS_PER_FRAME; ++i)
|
||||||
|
{
|
||||||
|
// Check which duration is longer to determine if it's a '1' bit
|
||||||
bool bit_is_one = symbols[i].duration0 > symbols[i].duration1;
|
bool bit_is_one = symbols[i].duration0 > symbols[i].duration1;
|
||||||
raw_gcr_data = (raw_gcr_data << 1) | bit_is_one;
|
raw_gcr_data = (raw_gcr_data << 1) | bit_is_one;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract the 10-bit data from the GCR frame
|
||||||
|
uint16_t gcr_data = (raw_gcr_data >> 5) & 0b0000001111111111; // Mask for 10 bits
|
||||||
|
|
||||||
// GCR decoding over the "throttle" bits
|
// GCR decoding over the "throttle" bits
|
||||||
// GCR encoding rule is: bit_n = gcr_bit_n ^ gcr_bit_(n-1)
|
|
||||||
uint16_t gcr_data = (raw_gcr_data >> 5) & 0b000000001111111111;
|
|
||||||
uint16_t received_data = gcr_data ^ (gcr_data >> 1);
|
uint16_t received_data = gcr_data ^ (gcr_data >> 1);
|
||||||
|
|
||||||
// Extract CRC from gcr answer
|
// Extract CRC from gcr answer (4 bits)
|
||||||
uint16_t received_crc = raw_gcr_data & 0b0000000000001111;
|
uint16_t received_crc = raw_gcr_data & 0b0000000000001111; // Mask for 4 bits
|
||||||
|
|
||||||
// Calculate expected CRC using the new, centralized function
|
// Calculate expected CRC using the new, centralized function
|
||||||
uint16_t data_for_crc = (received_data << 1) | 1; // Telemetry request bit is always 1 for bidirectional
|
// Telemetry request bit is always 1 for bidirectional
|
||||||
|
uint16_t data_for_crc = (received_data << 1) | 1;
|
||||||
uint16_t calculated_crc = _calculateCRC(data_for_crc);
|
uint16_t calculated_crc = _calculateCRC(data_for_crc);
|
||||||
|
|
||||||
// Validate CRC
|
// Validate CRC
|
||||||
|
|
@ -450,10 +452,10 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
||||||
// 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()
|
||||||
{
|
{
|
||||||
uint32_t current_time = micros();
|
uint64_t current_time = esp_timer_get_time();
|
||||||
|
|
||||||
// Handle potential overflow
|
// Handle potential overflow
|
||||||
uint32_t elapsed = current_time - _last_transmission_time;
|
uint64_t elapsed = current_time - _last_transmission_time;
|
||||||
|
|
||||||
return elapsed >= _frame_timer_us;
|
return elapsed >= _frame_timer_us;
|
||||||
}
|
}
|
||||||
|
|
@ -461,7 +463,7 @@ bool IRAM_ATTR DShotRMT::_timer_signal()
|
||||||
// Reset transmission timer to current time
|
// Reset transmission timer to current time
|
||||||
bool DShotRMT::_timer_reset()
|
bool DShotRMT::_timer_reset()
|
||||||
{
|
{
|
||||||
_last_transmission_time = micros();
|
_last_transmission_time = esp_timer_get_time();
|
||||||
return DSHOT_OK;
|
return DSHOT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -473,10 +475,10 @@ void DShotRMT::printDshotInfo(Stream &output) const
|
||||||
|
|
||||||
// Current DShot mode
|
// Current DShot mode
|
||||||
output.printf("Current Mode: DSHOT%d\n",
|
output.printf("Current Mode: DSHOT%d\n",
|
||||||
_mode == DSHOT150 ? 150 : _mode == DSHOT300 ? 300
|
_mode == DSHOT150 ? 150 :
|
||||||
: _mode == DSHOT600 ? 600
|
_mode == DSHOT300 ? 300 :
|
||||||
: _mode == DSHOT1200 ? 1200
|
_mode == DSHOT600 ? 600 :
|
||||||
: 0);
|
_mode == DSHOT1200 ? 1200 : 0);
|
||||||
|
|
||||||
output.printf("Bidirectional: %s\n", _is_bidirectional ? "YES" : "NO");
|
output.printf("Bidirectional: %s\n", _is_bidirectional ? "YES" : "NO");
|
||||||
|
|
||||||
|
|
|
||||||
37
DShotRMT.h
37
DShotRMT.h
|
|
@ -13,8 +13,6 @@
|
||||||
#include <driver/gpio.h>
|
#include <driver/gpio.h>
|
||||||
#include <driver/rmt_tx.h>
|
#include <driver/rmt_tx.h>
|
||||||
#include <driver/rmt_rx.h>
|
#include <driver/rmt_rx.h>
|
||||||
#include <iostream>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
// DShot Protocol Constants
|
// DShot Protocol Constants
|
||||||
constexpr auto DSHOT_THROTTLE_FAILSAFE = 0;
|
constexpr auto DSHOT_THROTTLE_FAILSAFE = 0;
|
||||||
|
|
@ -29,6 +27,7 @@ constexpr auto DSHOT_RX_TIMEOUT_MS = 2;
|
||||||
constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT;
|
constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT;
|
||||||
constexpr auto DSHOT_RMT_RESOLUTION = 10 * 1000 * 1000; // 10 MHz resolution
|
constexpr auto DSHOT_RMT_RESOLUTION = 10 * 1000 * 1000; // 10 MHz resolution
|
||||||
constexpr auto RMT_BUFFER_SIZE = DSHOT_BITS_PER_FRAME;
|
constexpr auto RMT_BUFFER_SIZE = DSHOT_BITS_PER_FRAME;
|
||||||
|
constexpr auto GCR_BITS_PER_FRAME = 20;
|
||||||
constexpr auto RMT_BUFFER_SYMBOLS = 64;
|
constexpr auto RMT_BUFFER_SYMBOLS = 64;
|
||||||
constexpr auto RMT_QUEUE_DEPTH = 1;
|
constexpr auto RMT_QUEUE_DEPTH = 1;
|
||||||
|
|
||||||
|
|
@ -70,7 +69,7 @@ typedef struct
|
||||||
class DShotRMT
|
class DShotRMT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Primary constructor with GPIO enum
|
// Constructor with GPIO enum
|
||||||
explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16,
|
explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16,
|
||||||
dshot_mode_t mode = DSHOT300,
|
dshot_mode_t mode = DSHOT300,
|
||||||
bool is_bidirectional = false);
|
bool is_bidirectional = false);
|
||||||
|
|
@ -121,7 +120,7 @@ private:
|
||||||
const dshot_timing_t &_timing_config;
|
const dshot_timing_t &_timing_config;
|
||||||
|
|
||||||
// --- TIMING & STATE VARIABLES ---
|
// --- TIMING & STATE VARIABLES ---
|
||||||
uint32_t _last_transmission_time;
|
uint64_t _last_transmission_time;
|
||||||
uint16_t _last_erpm;
|
uint16_t _last_erpm;
|
||||||
uint16_t _parsed_packet;
|
uint16_t _parsed_packet;
|
||||||
dshot_packet_t _packet;
|
dshot_packet_t _packet;
|
||||||
|
|
@ -137,10 +136,6 @@ private:
|
||||||
rmt_transmit_config_t _transmit_config;
|
rmt_transmit_config_t _transmit_config;
|
||||||
rmt_receive_config_t _receive_config;
|
rmt_receive_config_t _receive_config;
|
||||||
|
|
||||||
// --- RMT DATA BUFFERS ---
|
|
||||||
rmt_symbol_word_t _tx_symbols[RMT_BUFFER_SYMBOLS];
|
|
||||||
rmt_symbol_word_t _rx_symbols[RMT_BUFFER_SYMBOLS];
|
|
||||||
|
|
||||||
// --- INITS ---
|
// --- INITS ---
|
||||||
bool _initTXChannel();
|
bool _initTXChannel();
|
||||||
bool _initRXChannel();
|
bool _initRXChannel();
|
||||||
|
|
@ -162,24 +157,24 @@ private:
|
||||||
|
|
||||||
// -- CALLBACKS ---
|
// -- CALLBACKS ---
|
||||||
QueueHandle_t _rx_queue;
|
QueueHandle_t _rx_queue;
|
||||||
rmt_rx_event_callbacks_t _rx_event_cbs;
|
rmt_rx_event_callbacks_t _rx_event_callbacks;
|
||||||
static bool IRAM_ATTR _rmt_rx_done_callback(rmt_channel_handle_t rx_chan, const rmt_rx_done_event_data_t *edata, void *user_data);
|
static bool IRAM_ATTR _rmt_rx_done_callback(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
||||||
|
|
||||||
// --- ERROR HANDLING & LOGGING ---
|
// --- ERROR HANDLING & LOGGING ---
|
||||||
void _dshot_log(std::string_view msg) { std::cerr << msg << '\n'; }
|
void _dshot_log(const char *msg, Stream &output = Serial) { output.println(msg); }
|
||||||
|
|
||||||
// --- CONSTANTS & ERROR MESSAGES ---
|
// --- CONSTANTS & ERROR MESSAGES ---
|
||||||
static constexpr uint16_t DSHOT_OK = 0;
|
static constexpr uint16_t DSHOT_OK = 0;
|
||||||
static constexpr uint16_t DSHOT_ERROR = 1;
|
static constexpr uint16_t DSHOT_ERROR = 1;
|
||||||
|
|
||||||
static constexpr std::string_view NEW_LINE = " ";
|
static constexpr char *NEW_LINE = " ";
|
||||||
static constexpr std::string_view TX_INIT_FAILED = "Failed to initialize TX channel!";
|
static constexpr char *TX_INIT_FAILED = "Failed to initialize TX channel!";
|
||||||
static constexpr std::string_view RX_INIT_FAILED = "Failed to initialize RX channel!";
|
static constexpr char *RX_INIT_FAILED = "Failed to initialize RX channel!";
|
||||||
static constexpr std::string_view ENCODER_INIT_FAILED = "Failed to initialize DShot encoder!";
|
static constexpr char *ENCODER_INIT_FAILED = "Failed to initialize DShot encoder!";
|
||||||
static constexpr std::string_view CRC_CHECK_FAILED = "RX CRC Check failed!";
|
static constexpr char *CRC_CHECK_FAILED = "RX CRC Check failed!";
|
||||||
static constexpr std::string_view THROTTLE_NOT_IN_RANGE = "Throttle value not in range (48 - 2047)!";
|
static constexpr char *THROTTLE_NOT_IN_RANGE = "Throttle value not in range (48 - 2047)!";
|
||||||
static constexpr std::string_view COMMAND_NOT_VALID = "Not a valid DShot Command (0 - 47)!";
|
static constexpr char *COMMAND_NOT_VALID = "Not a valid DShot Command (0 - 47)!";
|
||||||
static constexpr std::string_view BIDIR_NOT_ENABLED = "Bidirectional DShot support not enabled!";
|
static constexpr char *BIDIR_NOT_ENABLED = "Bidirectional DShot support not enabled!";
|
||||||
static constexpr std::string_view RX_RMT_RECEIVER_ERROR = "RX RMT receiver error!";
|
static constexpr char *RX_RMT_RECEIVER_ERROR = "RX RMT receiver error!";
|
||||||
static constexpr std::string_view PACKET_BUILD_ERROR = "Value too big for DShot Packet!";
|
static constexpr char *PACKET_BUILD_ERROR = "Value too big for DShot Packet!";
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue