RMT timing rewritten
This commit is contained in:
parent
034bd59b64
commit
8d07812548
|
|
@ -8,14 +8,28 @@
|
|||
|
||||
#include "DShotRMT.h"
|
||||
|
||||
// --- HELPERS ---
|
||||
void printDShotResult(dshot_result_t &result, Stream &output)
|
||||
{
|
||||
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", result.msg);
|
||||
|
||||
// Print telemetry data if available
|
||||
if (result.success && (result.erpm > 0 || result.motor_rpm > 0))
|
||||
{
|
||||
output.printf(" | eRPM: %u, Motor RPM: %u", result.erpm, result.motor_rpm);
|
||||
}
|
||||
|
||||
output.println();
|
||||
}
|
||||
|
||||
// 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}
|
||||
static constexpr dshot_timing_t DSHOT_TIMINGS[] = {
|
||||
{0, 0, 0, 0, 0, 0}, // DSHOT_OFF
|
||||
{128, 64, 48, 16, 24, 40}, // DSHOT150
|
||||
{64, 32, 24, 8, 12, 20}, // DSHOT300
|
||||
{32, 16, 12, 4, 6, 10}, // DSHOT600
|
||||
{16, 8, 6, 2, 3, 5} // DSHOT1200
|
||||
// Format: {frame_length_ticks, ticks_per_bit, t1h_ticks, t1l_ticks, t0h_ticks, t0l_ticks}
|
||||
static constexpr dshot_timing_us_t DSHOT_TIMING_US[] = {
|
||||
{0.00, 0.00},
|
||||
{6.67, 5.00},
|
||||
{3.33, 2.50},
|
||||
{1.67, 1.25},
|
||||
{0.83, 0.67}
|
||||
};
|
||||
|
||||
// Constructor with GPIO number
|
||||
|
|
@ -26,9 +40,10 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional)
|
|||
_last_erpm_atomic(0),
|
||||
_telemetry_ready_flag(false),
|
||||
_frame_timer_us(0),
|
||||
_timing_config(DSHOT_TIMINGS[mode]),
|
||||
_dshot_timing(DSHOT_TIMING_US[mode]),
|
||||
_rmt_ticks{0},
|
||||
_last_throttle(DSHOT_CMD_MOTOR_STOP),
|
||||
_last_transmission_time(0),
|
||||
_last_transmission_time_us(0),
|
||||
_parsed_packet(0),
|
||||
_packet{0},
|
||||
_bitPositions{0},
|
||||
|
|
@ -42,8 +57,15 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional)
|
|||
_transmit_config{},
|
||||
_receive_config{}
|
||||
{
|
||||
// Calculate frame timing including switch/pause time
|
||||
_frame_timer_us = _timing_config.frame_length_us + DSHOT_PAUSE_US;
|
||||
// Convert DShot timings (us) to RMT ticks
|
||||
_rmt_ticks.ticks_per_bit = static_cast<uint16_t>(_dshot_timing.bit_length_us * RMT_TICKS_PER_US);
|
||||
_rmt_ticks.t1h_ticks = static_cast<uint16_t>(_dshot_timing.t1h_lenght_us * RMT_TICKS_PER_US);
|
||||
_rmt_ticks.t0h_ticks = _rmt_ticks.t1h_ticks >> 1; // High time for a 1 is always double that of a 0
|
||||
_rmt_ticks.t1l_ticks = _rmt_ticks.ticks_per_bit - _rmt_ticks.t1h_ticks;
|
||||
_rmt_ticks.t0l_ticks = _rmt_ticks.ticks_per_bit - _rmt_ticks.t0h_ticks;
|
||||
|
||||
// Pause between frames is frame time in us, some padding and about 30 us is added by hardware
|
||||
_frame_timer_us = (static_cast<uint32_t>(_dshot_timing.bit_length_us * DSHOT_BITS_PER_FRAME) << 1) + DSHOT_PADDING_US;
|
||||
|
||||
// Double frame time for bidirectional mode (includes response time)
|
||||
if (_is_bidirectional)
|
||||
|
|
@ -54,7 +76,7 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional)
|
|||
|
||||
// Constructor using pin number
|
||||
DShotRMT::DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional)
|
||||
: DShotRMT((gpio_num_t)pin_nr, mode, is_bidirectional)
|
||||
: DShotRMT(static_cast<gpio_num_t>(pin_nr), mode, is_bidirectional)
|
||||
{
|
||||
// Delegates to primary constructor with type cast
|
||||
}
|
||||
|
|
@ -152,7 +174,6 @@ dshot_result_t DShotRMT::_initTXChannel()
|
|||
// Init RMT RX channel
|
||||
dshot_result_t DShotRMT::_initRXChannel()
|
||||
{
|
||||
|
||||
// Direct RMT symbol processing - Performance optimized
|
||||
_rx_event_callbacks.on_recv_done = _rmt_rx_done_callback;
|
||||
|
||||
|
|
@ -258,7 +279,7 @@ dshot_result_t DShotRMT::sendCommand(uint16_t command)
|
|||
dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count)
|
||||
{
|
||||
// Result container with unified structure
|
||||
dshot_result_t result = {false, TELEMETRY_FAILED, NO_DSHOT_ERPM, NO_DSHOT_RPM};
|
||||
dshot_result_t result = {false, TELEMETRY_FAILED, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
|
||||
|
||||
// Check if bidirectional mode is enabled
|
||||
if (!_is_bidirectional)
|
||||
|
|
@ -277,7 +298,7 @@ dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count)
|
|||
//
|
||||
if (erpm != DSHOT_NULL_PACKET && magnet_count >= 1)
|
||||
{
|
||||
uint8_t pole_pairs = max(MIN_POLE_PAIRS, (magnet_count / MAGNETS_PER_POLE_PAIR));
|
||||
uint8_t pole_pairs = max(POLE_PAIRS_MIN, (magnet_count / MAGNETS_PER_POLE_PAIR));
|
||||
uint32_t motor_rpm = (erpm / pole_pairs);
|
||||
|
||||
result.success = true;
|
||||
|
|
@ -426,9 +447,9 @@ bool DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t
|
|||
|
||||
bool bit = (_parsed_packet >> bit_position) & 0b0000000000000001;
|
||||
symbols[i].level0 = _level0;
|
||||
symbols[i].duration0 = bit ? _timing_config.ticks_one_high : _timing_config.ticks_zero_high;
|
||||
symbols[i].duration0 = bit ? _rmt_ticks.t1h_ticks : _rmt_ticks.t0h_ticks;
|
||||
symbols[i].level1 = _level1;
|
||||
symbols[i].duration1 = bit ? _timing_config.ticks_one_low : _timing_config.ticks_zero_low;
|
||||
symbols[i].duration1 = bit ? _rmt_ticks.t1l_ticks : _rmt_ticks.t0l_ticks;
|
||||
}
|
||||
|
||||
return DSHOT_OK;
|
||||
|
|
@ -487,7 +508,7 @@ bool DShotRMT::_timer_signal()
|
|||
uint64_t current_time = esp_timer_get_time();
|
||||
|
||||
// Handle potential overflow
|
||||
uint64_t elapsed = current_time - _last_transmission_time;
|
||||
uint64_t elapsed = current_time - _last_transmission_time_us;
|
||||
|
||||
return elapsed >= _frame_timer_us;
|
||||
}
|
||||
|
|
@ -495,7 +516,7 @@ bool DShotRMT::_timer_signal()
|
|||
// Reset transmission timer to current time
|
||||
bool DShotRMT::_timer_reset()
|
||||
{
|
||||
_last_transmission_time = esp_timer_get_time();
|
||||
_last_transmission_time_us = esp_timer_get_time();
|
||||
|
||||
return DSHOT_OK;
|
||||
}
|
||||
|
|
@ -546,17 +567,3 @@ void DShotRMT::printCpuInfo(Stream &output) const
|
|||
output.printf("XTAL Freq = %lu MHz\n", getXtalFrequencyMhz());
|
||||
output.printf("APB Freq = %lu Hz\n", getApbFrequency());
|
||||
}
|
||||
|
||||
// --- HELPERS ---
|
||||
void printDShotResult(dshot_result_t &result, Stream &output)
|
||||
{
|
||||
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", result.msg);
|
||||
|
||||
// Print telemetry data if available
|
||||
if (result.success && (result.erpm > 0 || result.motor_rpm > 0))
|
||||
{
|
||||
output.printf(" | eRPM: %u, Motor RPM: %u", result.erpm, result.motor_rpm);
|
||||
}
|
||||
|
||||
output.println();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,29 +20,7 @@ static constexpr auto DSHOT_THROTTLE_FAILSAFE = 0;
|
|||
static constexpr auto DSHOT_THROTTLE_MIN = 48;
|
||||
static constexpr auto DSHOT_THROTTLE_MAX = 2047;
|
||||
static constexpr auto DSHOT_BITS_PER_FRAME = 16;
|
||||
static constexpr auto DSHOT_PAUSE_US = 30; // Additional frame pause time
|
||||
static constexpr auto DSHOT_NULL_PACKET = 0b0000000000000000;
|
||||
static constexpr auto DSHOT_FULL_PACKET = 0b1111111111111111;
|
||||
static constexpr auto DSHOT_CRC_MASK = 0b0000000000001111;
|
||||
static constexpr auto DSHOT_RX_TIMEOUT_MS = 2; // Never reached, just a timeeout
|
||||
static constexpr auto GCR_BITS_PER_FRAME = 21; // Number of GCR bits in a DShot answer frame (1 start + 16 data + 4 CRC)
|
||||
static constexpr auto DEFAULT_MOTOR_MAGNET_COUNT = 14;
|
||||
static constexpr auto MAGNETS_PER_POLE_PAIR = 2;
|
||||
static constexpr auto MIN_POLE_PAIRS = 1;
|
||||
static constexpr auto NO_DSHOT_ERPM = 0;
|
||||
static constexpr auto NO_DSHOT_RPM = 0;
|
||||
|
||||
// RMT Configuration Constants
|
||||
constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT;
|
||||
constexpr auto DSHOT_RMT_RESOLUTION = 10 * 1000 * 1000; // 10 MHz resolution
|
||||
constexpr auto RMT_BUFFER_SIZE = DSHOT_BITS_PER_FRAME;
|
||||
constexpr auto RMT_BUFFER_SYMBOLS = 64;
|
||||
constexpr auto RMT_QUEUE_DEPTH = 1;
|
||||
|
||||
// Smallest pulse for DShot1200 is 2us. Largest for DShot150 is 40us.
|
||||
// The range is set from 3us (3000ns) to 60us (60000ns) to be safe across all modes.
|
||||
constexpr uint32_t DSHOT_PULSE_MIN = 3000;
|
||||
constexpr uint32_t DSHOT_PULSE_MAX = 60000;
|
||||
|
||||
// DShot Modes
|
||||
typedef enum
|
||||
|
|
@ -62,16 +40,22 @@ typedef struct
|
|||
uint16_t checksum : 4;
|
||||
} dshot_packet_t;
|
||||
|
||||
// DShot Timing Configuration
|
||||
// DShot Timings
|
||||
typedef struct
|
||||
{
|
||||
double bit_length_us;
|
||||
double t1h_lenght_us;
|
||||
} dshot_timing_us_t;
|
||||
|
||||
// RMT Ticks Configuration
|
||||
typedef struct
|
||||
{
|
||||
uint32_t frame_length_us;
|
||||
uint16_t ticks_per_bit;
|
||||
uint16_t ticks_one_high;
|
||||
uint16_t ticks_one_low;
|
||||
uint16_t ticks_zero_high;
|
||||
uint16_t ticks_zero_low;
|
||||
} dshot_timing_t;
|
||||
uint16_t t1h_ticks;
|
||||
uint16_t t1l_ticks;
|
||||
uint16_t t0h_ticks;
|
||||
uint16_t t0l_ticks;
|
||||
} rmt_ticks_t;
|
||||
|
||||
// Unified DShot result structure
|
||||
typedef struct
|
||||
|
|
@ -149,11 +133,12 @@ private:
|
|||
dshot_mode_t _mode;
|
||||
bool _is_bidirectional;
|
||||
uint32_t _frame_timer_us;
|
||||
const dshot_timing_t &_timing_config;
|
||||
rmt_ticks_t _rmt_ticks;
|
||||
const dshot_timing_us_t &_dshot_timing;
|
||||
uint16_t _last_throttle;
|
||||
|
||||
// --- TIMING & PACKET VARIABLES ---
|
||||
uint64_t _last_transmission_time;
|
||||
uint64_t _last_transmission_time_us;
|
||||
uint16_t _parsed_packet;
|
||||
dshot_packet_t _packet;
|
||||
uint8_t _bitPositions[DSHOT_BITS_PER_FRAME];
|
||||
|
|
@ -193,13 +178,12 @@ private:
|
|||
|
||||
// -- CALLBACKS ---
|
||||
rmt_rx_event_callbacks_t _rx_event_callbacks;
|
||||
volatile rmt_symbol_word_t _rx_symbols_direct[GCR_BITS_PER_FRAME];
|
||||
volatile uint16_t _last_erpm_atomic;
|
||||
volatile bool _telemetry_ready_flag;
|
||||
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);
|
||||
|
||||
// --- DSHOT DEFAULTS ---
|
||||
static constexpr auto const DSHOT_TELEMETRY_INVALID = (0xffff);
|
||||
static constexpr auto const DSHOT_TELEMETRY_INVALID = 0b1111111111111111;
|
||||
|
||||
// --- CONSTANTS & ERROR MESSAGES ---
|
||||
static constexpr bool DSHOT_OK = 0;
|
||||
|
|
@ -226,4 +210,26 @@ 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!";
|
||||
|
||||
// Configuration Constants
|
||||
static constexpr auto const DSHOT_NULL_PACKET = 0b0000000000000000;
|
||||
static constexpr auto const DSHOT_FULL_PACKET = 0b1111111111111111;
|
||||
static constexpr auto const DSHOT_CRC_MASK = 0b0000000000001111;
|
||||
static constexpr auto const DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT;
|
||||
static constexpr auto const DSHOT_RMT_RESOLUTION = 8 * 1000 * 1000; // 8 MHz resolution
|
||||
static constexpr auto const RMT_TICKS_PER_US = DSHOT_RMT_RESOLUTION / (1 * 1000 * 1000); // RMT Ticks per microsecond, based on the RMT resolution in MHz
|
||||
static constexpr auto const RMT_BUFFER_SIZE = DSHOT_BITS_PER_FRAME;
|
||||
static constexpr auto const DSHOT_RX_TIMEOUT_MS = 2; // Never reached
|
||||
static constexpr auto const DSHOT_PADDING_US = 3;
|
||||
static constexpr auto const RMT_BUFFER_SYMBOLS = 64;
|
||||
static constexpr auto const RMT_QUEUE_DEPTH = 1;
|
||||
static constexpr auto const GCR_BITS_PER_FRAME = 21; // Number of GCR bits in a DShot answer frame (1 start + 16 data + 4 CRC)
|
||||
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;
|
||||
|
||||
// Smallest pulse for DShot1200 is 2us. Largest for DShot150 is 40us.
|
||||
// The range is set from 3us (3000ns) to 60us (60000ns) to be safe across all modes.
|
||||
static constexpr auto const DSHOT_PULSE_MIN = 3000;
|
||||
static constexpr auto const DSHOT_PULSE_MAX = 60000;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue