DShotRMT/src/DShotRMT.h

147 lines
5.3 KiB
C
Raw Normal View History

/**
* @file DShotRMT.h
2025-09-18 10:23:39 +01:00
* @brief Optimized DShot signal generation using ESP32 RMT with bidirectional support
* @author Wastl Kraus
2025-09-18 10:23:39 +01:00
* @date 2025-09-18
* @license MIT
*/
#pragma once
#include <Arduino.h>
#include <driver/rmt_tx.h>
#include <driver/rmt_rx.h>
#include <atomic>
2025-10-01 08:48:26 +01:00
#include "dshot_definitions.h"
#include <driver/rmt_encoder.h>
// DShotRMT Class Definition
class DShotRMT
{
public:
2025-09-27 13:59:23 +01:00
// Constructor for DShotRMT with GPIO number.
2025-10-01 08:48:26 +01:00
explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16, dshot_mode_t mode = DSHOT300, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT);
2025-09-25 13:03:55 +01:00
2025-09-27 13:59:23 +01:00
// Constructor for DShotRMT with Arduino pin number.
DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT);
2025-09-18 10:23:39 +01:00
2025-10-01 08:48:26 +01:00
// Destructor
~DShotRMT();
// Public Core Functions
2025-09-27 13:59:23 +01:00
// Initializes the DShot RMT channels and encoder.
dshot_result_t begin();
2025-09-25 13:03:55 +01:00
2025-10-01 08:48:26 +01:00
// Sends a throttle value as a percentage (0.0-100.0) to the ESC.
dshot_result_t sendThrottlePercent(float percent);
2025-09-25 13:03:55 +01:00
2025-10-01 08:48:26 +01:00
// Sends a raw throttle value (48-2047) to the ESC. A value of 0 sends a motor stop command.
dshot_result_t sendThrottle(uint16_t throttle);
2025-09-25 13:03:55 +01:00
2025-10-01 08:48:26 +01:00
// Sends a DShot command (0-47) to the ESC.
dshot_result_t sendCommand(dshotCommands_e command);
2025-09-25 13:03:55 +01:00
2025-09-27 13:59:23 +01:00
// Retrieves telemetry data from the ESC.
2025-10-01 08:48:26 +01:00
dshot_result_t getTelemetry();
2025-09-25 13:03:55 +01:00
2025-10-01 08:48:26 +01:00
// Sets the motor spin direction. 'true' for reversed, 'false' for normal.
2025-09-18 15:10:59 +01:00
dshot_result_t setMotorSpinDirection(bool reversed);
2025-09-25 13:03:55 +01:00
2025-10-01 08:48:26 +01:00
// Sends a command to the ESC to save its current settings. Use with caution as this writes to ESC's non-volatile memory.
2025-09-18 15:10:59 +01:00
dshot_result_t saveESCSettings();
2025-09-18 10:23:39 +01:00
2025-09-18 15:10:59 +01:00
// Public Utility & Info Functions
2025-09-27 13:59:23 +01:00
// Sets the motor magnet count for RPM calculation.
void setMotorMagnetCount(uint16_t magnet_count);
2025-09-25 13:03:55 +01:00
2025-09-27 13:59:23 +01:00
// Gets the current DShot mode.
2025-09-25 13:03:55 +01:00
dshot_mode_t getMode() const { return _mode; }
2025-09-27 13:59:23 +01:00
// Checks if bidirectional DShot is enabled.
2025-09-25 13:03:55 +01:00
bool isBidirectional() const { return _is_bidirectional; }
2025-10-01 08:48:26 +01:00
// Gets the encoded frame value.
2025-09-25 13:03:55 +01:00
uint16_t getEncodedFrameValue() const { return _encoded_frame_value; }
2025-09-27 13:59:23 +01:00
// Gets the last transmitted throttle value.
2025-09-25 13:03:55 +01:00
uint16_t getThrottleValue() const { return _packet.throttle_value; }
2025-09-18 10:23:39 +01:00
2025-10-01 08:48:26 +01:00
// Testing return "verbose" messages
const char *getDShotMsg(dshot_result_t &result) const { return (_get_result_code_str(result.result_code)); }
// Deprecated Methods
2025-09-27 13:59:23 +01:00
// Deprecated. Use sendThrottle() instead.
[[deprecated("Use sendThrottle() instead")]]
2025-10-01 08:48:26 +01:00
dshot_result_t sendValue(uint16_t value) { return sendThrottle(value); }
2025-09-27 13:59:23 +01:00
// Deprecated. Use sendCommand() instead.
[[deprecated("Use sendCommand() instead")]]
2025-10-01 08:48:26 +01:00
dshot_result_t sendCommand(uint16_t command) { return sendCommand(static_cast<dshotCommands_e>(command)); }
private:
2025-09-18 15:10:59 +01:00
// --- UTILITY METHODS ---
2025-10-01 08:48:26 +01:00
bool _isValidCommand(dshotCommands_e command) const;
2025-09-25 13:03:55 +01:00
dshot_result_t _executeCommand(dshotCommands_e command);
2025-10-01 08:48:26 +01:00
dshot_result_t _sendCommandInternal(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us);
2025-09-17 20:41:20 +01:00
// Core Configuration Variables
gpio_num_t _gpio;
dshot_mode_t _mode;
bool _is_bidirectional;
uint16_t _motor_magnet_count;
const dshot_timing_us_t &_dshot_timing;
2025-10-01 08:48:26 +01:00
uint64_t _frame_timer_us = 0;
// Timing & Packet Variables
2025-10-01 08:48:26 +01:00
rmt_ticks_t _rmt_ticks{};
uint16_t _last_throttle = dshotCommands_e::DSHOT_CMD_MOTOR_STOP;
uint64_t _last_transmission_time_us = 0;
uint64_t _last_command_timestamp = 0;
uint16_t _encoded_frame_value = 0;
dshot_packet_t _packet{};
uint16_t _pulse_level = 1; // DShot protocol: Signal is idle-low, so pulses start by going HIGH.
uint16_t _idle_level = 0; // DShot protocol: Signal returns to LOW after the high pulse.
2025-09-18 10:23:39 +01:00
// RMT Hardware Handles
2025-10-01 08:48:26 +01:00
rmt_channel_handle_t _rmt_tx_channel = nullptr;
rmt_channel_handle_t _rmt_rx_channel = nullptr;
rmt_encoder_handle_t _dshot_encoder = nullptr;
// RMT Configuration Structures
2025-10-01 08:48:26 +01:00
rmt_tx_channel_config_t _tx_channel_config{};
rmt_rx_channel_config_t _rx_channel_config{};
rmt_transmit_config_t _rmt_tx_config{};
rmt_receive_config_t _rmt_rx_config{};
// Bidirectional / Telemetry Variables
2025-10-01 08:48:26 +01:00
rmt_rx_event_callbacks_t _rx_event_callbacks{};
std::atomic<uint16_t> _last_erpm_atomic{0};
std::atomic<bool> _telemetry_ready_flag_atomic{false};
// Private Initialization Functions
dshot_result_t _initTXChannel();
dshot_result_t _initRXChannel();
dshot_result_t _initDShotEncoder();
// Private Packet Management Functions
2025-10-01 08:48:26 +01:00
dshot_packet_t _buildDShotPacket(const uint16_t &value) const;
uint16_t _buildDShotFrameValue(const dshot_packet_t &packet) const;
uint16_t _calculateCRC(const uint16_t &data) const;
2025-09-15 14:56:04 +01:00
void _preCalculateRMTTicks();
// Private Frame Processing Functions
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet);
2025-10-01 08:48:26 +01:00
uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols) const;
2025-09-18 10:23:39 +01:00
// Private Timing Control Functions
2025-10-01 08:48:26 +01:00
bool _isFrameIntervalElapsed() const;
2025-09-26 18:24:50 +01:00
void _recordFrameTransmissionTime();
2025-09-18 10:23:39 +01:00
// Static Callback Functions
2025-09-15 10:58:56 +01:00
static bool _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
2025-09-25 15:15:36 +01:00
};
2025-10-01 08:48:26 +01:00
2025-10-01 08:48:26 +01:00
// Include utility functions after class definition
#include "dshot_utils.h"