DShotRMT/src/DShotRMT.h

125 lines
5.9 KiB
C
Raw Normal View History

/**
* @file DShotRMT.h
2025-10-01 23:31:24 +01:00
* @brief DShot signal generation using ESP32 RMT with bidirectional support
* @author Wastl Kraus
2025-10-01 23:31:24 +01:00
* @date 2025-06-11
* @license MIT
*/
#pragma once
2025-10-01 23:31:24 +01:00
#include <atomic>
2025-10-04 20:41:25 +01:00
#include <Arduino.h>
2025-10-01 23:31:24 +01:00
#include <driver/gpio.h>
#include <driver/rmt_rx.h>
2025-10-04 20:41:25 +01:00
#include <driver/rmt_tx.h>
2025-10-01 08:48:26 +01:00
#include "dshot_definitions.h"
2025-10-04 20:41:25 +01:00
#include "dshot_init.h"
2025-10-01 08:48:26 +01:00
2025-10-09 18:41:03 +01:00
// Forward declaration for the RMT receive callback
class DShotRMT;
void IRAM_ATTR rmt_rx_done_callback(rmt_channel_handle_t rx_chan, const rmt_rx_done_event_data_t *edata, void *user_data);
2025-10-02 13:45:03 +01:00
// DShot Protocol Constants
static constexpr auto DSHOT_THROTTLE_FAILSAFE = 0;
2025-10-09 18:41:03 +01:00
// DShotRMT class for generating DShot signals and receiving telemetry.
class DShotRMT
{
public:
2025-10-09 18:41:03 +01:00
// Constructor for DShotRMT.
DShotRMT(gpio_num_t gpio, 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-10-01 23:31:24 +01:00
// Constructor using pin number
2025-10-02 13:45:03 +01:00
DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional = false, 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();
2025-10-01 23:31:24 +01:00
// Initialize DShotRMT
dshot_result_t begin();
2025-09-25 13:03:55 +01:00
2025-10-09 18:41:03 +01:00
// Sends a raw throttle value to the ESC.
2025-10-01 23:31:24 +01:00
dshot_result_t sendThrottle(uint16_t throttle);
2025-10-09 18:41:03 +01:00
// Sends a throttle value as a percentage to the ESC.
dshot_result_t sendThrottlePercent(float percent);
2025-09-25 13:03:55 +01:00
2025-10-09 18:41:03 +01:00
// Sends a DShot command to the ESC by accepting an integer value.
2025-10-01 23:31:24 +01:00
dshot_result_t sendCommand(uint16_t command_value);
2025-09-25 13:03:55 +01:00
2025-10-09 18:41:03 +01:00
// Sends a DShot command to the ESC.
2025-10-01 08:48:26 +01:00
dshot_result_t sendCommand(dshotCommands_e command);
2025-10-01 23:31:24 +01:00
2025-10-09 18:41:03 +01:00
// Sends a DShot command to the ESC with a specified repeat count and delay.
2025-10-01 15:50:24 +01:00
dshot_result_t sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us);
2025-09-25 13:03:55 +01:00
2025-10-09 18:41:03 +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-09 18:41:03 +01:00
// Sets the motor spin direction.
2025-09-18 15:10:59 +01:00
dshot_result_t setMotorSpinDirection(bool reversed);
2025-09-25 13:03:55 +01:00
2025-10-09 18:41:03 +01:00
// Sends a command to the ESC to save its current settings.
2025-09-18 15:10:59 +01:00
dshot_result_t saveESCSettings();
2025-09-18 10:23:39 +01:00
2025-10-01 23:31:24 +01:00
// Getters for DShot info
2025-09-25 13:03:55 +01:00
dshot_mode_t getMode() const { return _mode; }
bool isBidirectional() const { return _is_bidirectional; }
2025-10-01 23:31:24 +01:00
uint16_t getThrottleValue() const { return _last_throttle; }
2025-09-25 13:03:55 +01:00
uint16_t getEncodedFrameValue() const { return _encoded_frame_value; }
private:
2025-10-09 18:41:03 +01:00
static bool IRAM_ATTR _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
// DShot Configuration Parameters
gpio_num_t _gpio; // GPIO pin used for DShot communication
dshot_mode_t _mode; // DShot mode (e.g., DSHOT300, DSHOT600)
bool _is_bidirectional; // True if bidirectional DShot is enabled
uint16_t _motor_magnet_count; // Number of magnets in the motor for RPM calculation
dshot_timing_us_t _dshot_timing; // DShot timing parameters in microseconds
// RMT Hardware Handles and Configuration
rmt_channel_handle_t _rmt_tx_channel = nullptr; // RMT transmit channel handle
rmt_channel_handle_t _rmt_rx_channel = nullptr; // RMT receive channel handle
rmt_encoder_handle_t _dshot_encoder = nullptr; // DShot RMT encoder handle
rmt_ticks_t _rmt_ticks; // Pre-calculated RMT timing ticks
uint16_t _pulse_level = 1; // Output level for a pulse (typically high)
uint16_t _idle_level = 0; // Output level for idle (typically low)
// DShot Frame Timing and State Variables
uint64_t _last_transmission_time_us = 0; // Timestamp of the last DShot frame transmission
uint64_t _frame_timer_us = 0; // Minimum time required between DShot frames
uint16_t _last_throttle = 0; // Last transmitted throttle value
dshot_packet_t _packet; // Current DShot packet being processed
uint16_t _encoded_frame_value = 0; // Last encoded 16-bit DShot frame value
uint64_t _last_command_timestamp = 0; // Timestamp of the last command sent
// Telemetry Related Variables
std::atomic<uint16_t> _last_erpm_atomic = 0; // Atomically stored last received eRPM value
std::atomic<bool> _telemetry_ready_flag_atomic = false; // Atomically stored flag indicating new telemetry data
2025-10-01 23:31:24 +01:00
rmt_rx_event_callbacks_t _rx_event_callbacks = {
2025-10-09 18:41:03 +01:00
// RMT receive event callbacks
2025-10-01 23:31:24 +01:00
.on_recv_done = _on_rx_done,
};
2025-10-01 15:50:24 +01:00
2025-10-09 18:41:03 +01:00
// Private Helper Functions for DShot Protocol Logic
bool _isValidCommand(dshotCommands_e command) const; // Checks if a given DShot command is valid
dshot_result_t _executeCommand(dshotCommands_e command); // Executes a single DShot command
dshot_packet_t _buildDShotPacket(const uint16_t &value) const; // Builds a DShot packet from a value (throttle or command)
uint16_t _buildDShotFrameValue(const dshot_packet_t &packet) const; // Combines packet data into a 16-bit DShot frame value
uint16_t _calculateCRC(const uint16_t &data) const; // Calculates the 4-bit CRC for a DShot frame
void _preCalculateRMTTicks(); // Pre-calculates RMT timing ticks for the selected DShot mode
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet); // Sends a DShot frame via RMT TX channel
uint16_t IRAM_ATTR _decodeDShotFrame(const rmt_symbol_word_t *symbols) const; // Decodes a received RMT symbol array into an eRPM value
bool IRAM_ATTR _isFrameIntervalElapsed() const; // Checks if enough time has passed since the last frame transmission
void _recordFrameTransmissionTime(); // Records the current time as the last frame transmission time
// Static Callback Function for RMT RX Events
void _cleanupRmtResources();
2025-09-25 15:15:36 +01:00
};
2025-10-01 08:48:26 +01:00
2025-10-09 18:41:03 +01:00
#include "dshot_utils.h" // Include for helper functions