fixing reboot loop
This commit is contained in:
parent
51cac2f1ad
commit
145ce88312
10
README.md
10
README.md
|
|
@ -62,7 +62,7 @@ void setup() {
|
||||||
motor.begin();
|
motor.begin();
|
||||||
|
|
||||||
// Print CPU Info
|
// Print CPU Info
|
||||||
DShotRMT::printCpuInfo(Serial);
|
printCpuInfo(Serial);
|
||||||
|
|
||||||
Serial.println("Motor initialized. Ramping up to 25% throttle...");
|
Serial.println("Motor initialized. Ramping up to 25% throttle...");
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ void loop() {
|
||||||
motor.sendThrottlePercent(0);
|
motor.sendThrottlePercent(0);
|
||||||
|
|
||||||
// Print DShot Info
|
// Print DShot Info
|
||||||
DShotRMT::printDShotInfo(motor, Serial);
|
printDShotInfo(motor, Serial);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ The `web_control` and `web_client` examples require the following additional lib
|
||||||
|
|
||||||
The main class is `DShotRMT`. Here are the most important methods:
|
The main class is `DShotRMT`. Here are the most important methods:
|
||||||
|
|
||||||
- `DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT)`: Constructor to create a new DShotRMT instance.
|
- `DShotRMT(gpio_num_t gpio, dshot_mode_t mode = DSHOT300, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT)`: Constructor to create a new DShotRMT instance.
|
||||||
- `begin()`: Initializes the DShot RMT channels and encoder.
|
- `begin()`: Initializes the DShot RMT channels and encoder.
|
||||||
- `sendThrottlePercent(float percent)`: Sends a throttle value as a percentage (0.0-100.0) to the ESC.
|
- `sendThrottlePercent(float percent)`: Sends a throttle value as a percentage (0.0-100.0) to the ESC.
|
||||||
- `sendThrottle(uint16_t throttle)`: Sends a raw throttle value (48-2047) to the ESC. A value of 0 sends a motor stop command.
|
- `sendThrottle(uint16_t throttle)`: Sends a raw throttle value (48-2047) to the ESC. A value of 0 sends a motor stop command.
|
||||||
|
|
@ -115,8 +115,8 @@ The main class is `DShotRMT`. Here are the most important methods:
|
||||||
- `setMotorSpinDirection(bool reversed)`: Sets the motor spin direction. `true` for reversed, `false` for normal.
|
- `setMotorSpinDirection(bool reversed)`: Sets the motor spin direction. `true` for reversed, `false` for normal.
|
||||||
- `saveESCSettings()`: Sends a command to the ESC to save its current settings. Use with caution as this writes to ESC's non-volatile memory.
|
- `saveESCSettings()`: Sends a command to the ESC to save its current settings. Use with caution as this writes to ESC's non-volatile memory.
|
||||||
- `printDShotResult(dshot_result_t &result, Stream &output = Serial)`: Prints the result of a DShot operation to the specified output stream.
|
- `printDShotResult(dshot_result_t &result, Stream &output = Serial)`: Prints the result of a DShot operation to the specified output stream.
|
||||||
- `DShotRMT::printDShotInfo(const DShotRMT &dshot_rmt, Stream &output = Serial)`: Prints detailed DShot signal information for a given DShotRMT instance.
|
- `printDShotInfo(const DShotRMT &dshot_rmt, Stream &output = Serial)`: Prints detailed DShot signal information for a given DShotRMT instance.
|
||||||
- `DShotRMT::printCpuInfo(Stream &output = Serial)`: Prints detailed CPU information.
|
- `printCpuInfo(Stream &output = Serial)`: Prints detailed CPU information.
|
||||||
- `setMotorMagnetCount(uint16_t magnet_count)`: Sets the motor magnet count for RPM calculation.
|
- `setMotorMagnetCount(uint16_t magnet_count)`: Sets the motor magnet count for RPM calculation.
|
||||||
- `getMode()`: Gets the current DShot mode.
|
- `getMode()`: Gets the current DShot mode.
|
||||||
- `isBidirectional()`: Checks if bidirectional DShot is enabled.
|
- `isBidirectional()`: Checks if bidirectional DShot is enabled.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ static constexpr gpio_num_t MOTOR01_PIN = GPIO_NUM_27;
|
||||||
// static constexpr auto MOTOR01_PIN = 17;
|
// static constexpr auto MOTOR01_PIN = 17;
|
||||||
|
|
||||||
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
||||||
static constexpr dshot_mode_t DSHOT_MODE = dshot_mode_t::DSHOT300;
|
static constexpr dshot_mode_t DSHOT_MODE = DSHOT300;
|
||||||
|
|
||||||
// BiDirectional DShot Support (default: false)
|
// BiDirectional DShot Support (default: false)
|
||||||
// Note: Bidirectional DShot is currently not officially supported
|
// Note: Bidirectional DShot is currently not officially supported
|
||||||
|
|
@ -26,7 +26,7 @@ static constexpr dshot_mode_t DSHOT_MODE = dshot_mode_t::DSHOT300;
|
||||||
static constexpr auto IS_BIDIRECTIONAL = false;
|
static constexpr auto IS_BIDIRECTIONAL = false;
|
||||||
|
|
||||||
// Motor magnet count for RPM calculation
|
// Motor magnet count for RPM calculation
|
||||||
static constexpr auto MOTOR01_MAGNET_COUNT = 14;
|
// static constexpr auto MOTOR01_MAGNET_COUNT = 14;
|
||||||
|
|
||||||
// Creates the motor instance
|
// Creates the motor instance
|
||||||
DShotRMT motor01(MOTOR01_PIN, DSHOT_MODE, IS_BIDIRECTIONAL);
|
DShotRMT motor01(MOTOR01_PIN, DSHOT_MODE, IS_BIDIRECTIONAL);
|
||||||
|
|
@ -41,7 +41,7 @@ void setup()
|
||||||
motor01.begin();
|
motor01.begin();
|
||||||
|
|
||||||
// Print CPU Info
|
// Print CPU Info
|
||||||
DShotRMT::printCpuInfo(USB_SERIAL);
|
printCpuInfo(USB_SERIAL);
|
||||||
|
|
||||||
//
|
//
|
||||||
printMenu();
|
printMenu();
|
||||||
|
|
@ -80,7 +80,7 @@ void loop()
|
||||||
// Print motor stats every 3 seconds in continuous mode
|
// Print motor stats every 3 seconds in continuous mode
|
||||||
if (continuous_throttle && (esp_timer_get_time() - last_stats_print >= 3000000))
|
if (continuous_throttle && (esp_timer_get_time() - last_stats_print >= 3000000))
|
||||||
{
|
{
|
||||||
DShotRMT::printDShotInfo(motor01, USB_SERIAL);
|
printDShotInfo(motor01, USB_SERIAL);
|
||||||
|
|
||||||
USB_SERIAL.println(" ");
|
USB_SERIAL.println(" ");
|
||||||
|
|
||||||
|
|
@ -132,7 +132,7 @@ void handleSerialInput(const String &input, uint16_t &throttle, bool &continuous
|
||||||
}
|
}
|
||||||
else if (input == "info")
|
else if (input == "info")
|
||||||
{
|
{
|
||||||
DShotRMT::printDShotInfo(motor01, USB_SERIAL);
|
printDShotInfo(motor01, USB_SERIAL);
|
||||||
}
|
}
|
||||||
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ static constexpr auto USB_SERIAL_BAUD = 115200;
|
||||||
static constexpr gpio_num_t MOTOR01_PIN = GPIO_NUM_27;
|
static constexpr gpio_num_t MOTOR01_PIN = GPIO_NUM_27;
|
||||||
|
|
||||||
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
||||||
static constexpr dshot_mode_t DSHOT_MODE = dshot_mode_t::DSHOT300;
|
static constexpr dshot_mode_t DSHOT_MODE = DSHOT300;
|
||||||
|
|
||||||
// BiDirectional DShot Support (default: false)
|
// BiDirectional DShot Support (default: false)
|
||||||
// Note: Bidirectional DShot is currently not officially supported
|
// Note: Bidirectional DShot is currently not officially supported
|
||||||
|
|
@ -44,7 +44,7 @@ void setup()
|
||||||
motor01.begin();
|
motor01.begin();
|
||||||
|
|
||||||
// Print CPU Info
|
// Print CPU Info
|
||||||
motor01.printCpuInfo();
|
printCpuInfo(USB_SERIAL);
|
||||||
|
|
||||||
//
|
//
|
||||||
printMenu();
|
printMenu();
|
||||||
|
|
@ -98,7 +98,7 @@ void handleSerialInput(const String &input)
|
||||||
}
|
}
|
||||||
else if (input == "info")
|
else if (input == "info")
|
||||||
{
|
{
|
||||||
DShotRMT::printDShotInfo(motor01, USB_SERIAL);
|
printDShotInfo(motor01, USB_SERIAL);
|
||||||
}
|
}
|
||||||
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
else if (input == "rpm" && IS_BIDIRECTIONAL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,10 @@ static constexpr auto &USB_SERIAL = Serial;
|
||||||
static constexpr auto USB_SERIAL_BAUD = 115200;
|
static constexpr auto USB_SERIAL_BAUD = 115200;
|
||||||
|
|
||||||
// Motor configuration - Pin number or GPIO_PIN
|
// Motor configuration - Pin number or GPIO_PIN
|
||||||
static constexpr auto MOTOR01_PIN = 17;
|
static constexpr gpio_num_t MOTOR01_PIN = GPIO_NUM_27;
|
||||||
|
|
||||||
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
||||||
static constexpr dshot_mode_t DSHOT_MODE = dshot_mode_t::DSHOT300;
|
static constexpr dshot_mode_t DSHOT_MODE = DSHOT300;
|
||||||
|
|
||||||
// BiDirectional DShot Support (default: false)
|
// BiDirectional DShot Support (default: false)
|
||||||
static constexpr auto IS_BIDIRECTIONAL = false; // Note: Bidirectional DShot is currently not officially supported due to instability and external hardware requirements.
|
static constexpr auto IS_BIDIRECTIONAL = false; // Note: Bidirectional DShot is currently not officially supported due to instability and external hardware requirements.
|
||||||
|
|
@ -84,7 +84,7 @@ void setup()
|
||||||
USB_SERIAL.println("DShotRMT Web Client Demo Starting...");
|
USB_SERIAL.println("DShotRMT Web Client Demo Starting...");
|
||||||
|
|
||||||
motor01.begin();
|
motor01.begin();
|
||||||
motor01.printCpuInfo();
|
printCpuInfo(USB_SERIAL);
|
||||||
|
|
||||||
// Connect to WiFi network
|
// Connect to WiFi network
|
||||||
USB_SERIAL.println("\nConnecting to WiFi network...");
|
USB_SERIAL.println("\nConnecting to WiFi network...");
|
||||||
|
|
@ -172,7 +172,7 @@ void loop()
|
||||||
// Print motor stats every 3 seconds in continuous mode
|
// Print motor stats every 3 seconds in continuous mode
|
||||||
if ((esp_timer_get_time() - last_serial_update >= 3000000))
|
if ((esp_timer_get_time() - last_serial_update >= 3000000))
|
||||||
{
|
{
|
||||||
DShotRMT::printDShotInfo(motor01, USB_SERIAL);
|
printDShotInfo(motor01, USB_SERIAL);
|
||||||
|
|
||||||
// Get Motor RPM if bidirectional and armed
|
// Get Motor RPM if bidirectional and armed
|
||||||
if (IS_BIDIRECTIONAL && isArmed)
|
if (IS_BIDIRECTIONAL && isArmed)
|
||||||
|
|
@ -447,7 +447,7 @@ void handleSerialInput(const String &input)
|
||||||
|
|
||||||
if (input == "info")
|
if (input == "info")
|
||||||
{
|
{
|
||||||
DShotRMT::printDShotInfo(motor01, USB_SERIAL);
|
printDShotInfo(motor01, USB_SERIAL);
|
||||||
USB_SERIAL.println(" ");
|
USB_SERIAL.println(" ");
|
||||||
USB_SERIAL.printf("Arming Status: %s\n", isArmed ? "ARMED" : "DISARMED");
|
USB_SERIAL.printf("Arming Status: %s\n", isArmed ? "ARMED" : "DISARMED");
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,10 @@ static constexpr auto &USB_SERIAL = Serial;
|
||||||
static constexpr auto USB_SERIAL_BAUD = 115200;
|
static constexpr auto USB_SERIAL_BAUD = 115200;
|
||||||
|
|
||||||
// Motor configuration - Pin number or GPIO_PIN
|
// Motor configuration - Pin number or GPIO_PIN
|
||||||
static constexpr auto MOTOR01_PIN = 17;
|
static constexpr gpio_num_t MOTOR01_PIN = GPIO_NUM_27;
|
||||||
|
|
||||||
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
||||||
static constexpr dshot_mode_t DSHOT_MODE = dshot_mode_t::DSHOT300;
|
static constexpr dshot_mode_t DSHOT_MODE = DSHOT300;
|
||||||
|
|
||||||
// BiDirectional DShot Support (default: false)
|
// BiDirectional DShot Support (default: false)
|
||||||
static constexpr auto IS_BIDIRECTIONAL = false; // Note: Bidirectional DShot is currently not officially supported due to instability and external hardware requirements.
|
static constexpr auto IS_BIDIRECTIONAL = false; // Note: Bidirectional DShot is currently not officially supported due to instability and external hardware requirements.
|
||||||
|
|
@ -74,7 +74,7 @@ void setup()
|
||||||
USB_SERIAL.begin(USB_SERIAL_BAUD);
|
USB_SERIAL.begin(USB_SERIAL_BAUD);
|
||||||
|
|
||||||
motor01.begin();
|
motor01.begin();
|
||||||
motor01.printCpuInfo();
|
printCpuInfo(USB_SERIAL);
|
||||||
|
|
||||||
// Set IP Address
|
// Set IP Address
|
||||||
WiFi.softAPConfig(local_IP, gateway, subnet);
|
WiFi.softAPConfig(local_IP, gateway, subnet);
|
||||||
|
|
@ -138,7 +138,7 @@ void loop()
|
||||||
// Print motor stats every 3 seconds in continuous mode
|
// Print motor stats every 3 seconds in continuous mode
|
||||||
if ((esp_timer_get_time() - last_serial_update >= 3000000))
|
if ((esp_timer_get_time() - last_serial_update >= 3000000))
|
||||||
{
|
{
|
||||||
DShotRMT::printDShotInfo(motor01, USB_SERIAL);
|
printDShotInfo(motor01, USB_SERIAL);
|
||||||
|
|
||||||
USB_SERIAL.println(" ");
|
USB_SERIAL.println(" ");
|
||||||
|
|
||||||
|
|
@ -254,7 +254,7 @@ void handleSerialInput(const String &input)
|
||||||
}
|
}
|
||||||
if (input == "info")
|
if (input == "info")
|
||||||
{
|
{
|
||||||
DShotRMT::printDShotInfo(motor01, USB_SERIAL);
|
printDShotInfo(motor01, USB_SERIAL);
|
||||||
USB_SERIAL.println(" ");
|
USB_SERIAL.println(" ");
|
||||||
USB_SERIAL.printf("Arming Status: %s\n", isArmed ? "ARMED" : "DISARMED");
|
USB_SERIAL.printf("Arming Status: %s\n", isArmed ? "ARMED" : "DISARMED");
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
name=DShotRMT
|
name=DShotRMT
|
||||||
version=0.8.7
|
version=0.8.8
|
||||||
author=Wastl Kraus <wir-sind-die-matrix.de>
|
author=Wastl Kraus <wir-sind-die-matrix.de>
|
||||||
maintainer=Wastl Kraus <wir-sind-die-matrix.de>
|
maintainer=Wastl Kraus <wir-sind-die-matrix.de>
|
||||||
license=MIT
|
license=MIT
|
||||||
|
|
|
||||||
112
src/DShotRMT.cpp
112
src/DShotRMT.cpp
|
|
@ -8,33 +8,13 @@
|
||||||
|
|
||||||
#include <DShotRMT.h>
|
#include <DShotRMT.h>
|
||||||
|
|
||||||
// Constructors & Destructor
|
|
||||||
// Constructor with GPIO number
|
// Constructor with GPIO number
|
||||||
DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional, uint16_t magnet_count)
|
DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional, uint16_t magnet_count)
|
||||||
: _gpio(gpio),
|
: _gpio(gpio),
|
||||||
_mode(mode),
|
_mode(mode),
|
||||||
_is_bidirectional(is_bidirectional),
|
_is_bidirectional(is_bidirectional),
|
||||||
_motor_magnet_count(magnet_count),
|
_motor_magnet_count(magnet_count),
|
||||||
_dshot_timing(DSHOT_TIMING_US[static_cast<int>(mode)]),
|
_dshot_timing(DSHOT_TIMING_US[static_cast<int>(mode)])
|
||||||
_frame_timer_us(0),
|
|
||||||
_rmt_ticks{0},
|
|
||||||
_last_throttle(dshotCommands_e::DSHOT_CMD_MOTOR_STOP),
|
|
||||||
_last_transmission_time_us(0),
|
|
||||||
_last_command_timestamp(0),
|
|
||||||
_encoded_frame_value(0),
|
|
||||||
_packet{0},
|
|
||||||
_pulse_level(1), // DShot standard: signal is idle-low, so pulses start by going HIGH
|
|
||||||
_idle_level(0), // DShot standard: signal returns to LOW after the high pulse
|
|
||||||
_rmt_tx_channel(nullptr),
|
|
||||||
_rmt_rx_channel(nullptr),
|
|
||||||
_dshot_encoder(nullptr),
|
|
||||||
_tx_channel_config{},
|
|
||||||
_rx_channel_config{},
|
|
||||||
_rmt_tx_config{},
|
|
||||||
_rmt_rx_config{},
|
|
||||||
_rx_event_callbacks{},
|
|
||||||
_last_erpm_atomic(0),
|
|
||||||
_telemetry_ready_flag_atomic(false)
|
|
||||||
{
|
{
|
||||||
// Pre-calculate timing and bit positions for performance
|
// Pre-calculate timing and bit positions for performance
|
||||||
_preCalculateRMTTicks();
|
_preCalculateRMTTicks();
|
||||||
|
|
@ -78,7 +58,6 @@ DShotRMT::~DShotRMT()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public Core Functions
|
|
||||||
// Initialize DShotRMT
|
// Initialize DShotRMT
|
||||||
dshot_result_t DShotRMT::begin()
|
dshot_result_t DShotRMT::begin()
|
||||||
{
|
{
|
||||||
|
|
@ -149,20 +128,16 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send DShot command to ESC
|
// Send DShot command to ESC
|
||||||
dshot_result_t DShotRMT::sendCommand(uint16_t command)
|
dshot_result_t DShotRMT::sendCommand(dshotCommands_e command)
|
||||||
{
|
{
|
||||||
if (command > dshotCommands_e::DSHOT_CMD_MAX)
|
_packet = _buildDShotPacket(static_cast<uint16_t>(command));
|
||||||
{
|
|
||||||
return {false, dshot_msg_code_t::DSHOT_COMMAND_NOT_VALID};
|
|
||||||
}
|
|
||||||
|
|
||||||
_packet = _buildDShotPacket(command);
|
|
||||||
return _sendDShotFrame(_packet);
|
return _sendDShotFrame(_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Send full DShot commands for setup etc
|
// Send full DShot commands for setup etc
|
||||||
// This is a blocking function that uses delayMicroseconds for repetitions.
|
// This is a blocking function that uses delayMicroseconds for repetitions.
|
||||||
dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us)
|
dshot_result_t DShotRMT::_sendCommandInternal(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us)
|
||||||
{
|
{
|
||||||
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_UNKNOWN, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
|
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_UNKNOWN, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
|
||||||
|
|
||||||
|
|
@ -205,7 +180,7 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e dshot_command, uint16_t rep
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get telemetry data
|
// Get telemetry data
|
||||||
dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count)
|
dshot_result_t DShotRMT::getTelemetry()
|
||||||
{
|
{
|
||||||
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_TELEMETRY_FAILED, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
|
dshot_result_t result = {false, dshot_msg_code_t::DSHOT_TELEMETRY_FAILED, NO_DSHOT_TELEMETRY, NO_DSHOT_TELEMETRY};
|
||||||
|
|
||||||
|
|
@ -216,7 +191,7 @@ dshot_result_t DShotRMT::getTelemetry(uint16_t magnet_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use stored magnet count if parameter is 0 (default)
|
// Use stored magnet count if parameter is 0 (default)
|
||||||
uint16_t final_magnet_count = (magnet_count == 0) ? _motor_magnet_count : magnet_count;
|
uint16_t final_magnet_count = _motor_magnet_count;
|
||||||
|
|
||||||
// Check if the callback has set the flag for new data
|
// Check if the callback has set the flag for new data
|
||||||
if (_telemetry_ready_flag_atomic)
|
if (_telemetry_ready_flag_atomic)
|
||||||
|
|
@ -246,22 +221,19 @@ dshot_result_t DShotRMT::setMotorSpinDirection(bool reversed)
|
||||||
// Use command as a yes / no switch
|
// Use command as a yes / no switch
|
||||||
dshotCommands_e command = reversed ? dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_REVERSED : dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_NORMAL;
|
dshotCommands_e command = reversed ? dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_REVERSED : dshotCommands_e::DSHOT_CMD_SPIN_DIRECTION_NORMAL;
|
||||||
|
|
||||||
return sendCommand(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
return _sendCommandInternal(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
dshot_result_t DShotRMT::getESCInfo()
|
|
||||||
{
|
|
||||||
return sendCommand(dshotCommands_e::DSHOT_CMD_ESC_INFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use with caution
|
// Use with caution
|
||||||
dshot_result_t DShotRMT::saveESCSettings()
|
dshot_result_t DShotRMT::saveESCSettings()
|
||||||
{
|
{
|
||||||
return sendCommand(dshotCommands_e::DSHOT_CMD_SAVE_SETTINGS, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
return _sendCommandInternal(dshotCommands_e::DSHOT_CMD_SAVE_SETTINGS, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple check
|
// Simple check
|
||||||
bool DShotRMT::_isValidCommand(dshotCommands_e command)
|
bool DShotRMT::_isValidCommand(dshotCommands_e command) const
|
||||||
{
|
{
|
||||||
return (command >= dshotCommands_e::DSHOT_CMD_MOTOR_STOP && command <= dshotCommands_e::DSHOT_CMD_MAX);
|
return (command >= dshotCommands_e::DSHOT_CMD_MOTOR_STOP && command <= dshotCommands_e::DSHOT_CMD_MAX);
|
||||||
}
|
}
|
||||||
|
|
@ -271,8 +243,8 @@ dshot_result_t DShotRMT::_executeCommand(dshotCommands_e command)
|
||||||
{
|
{
|
||||||
uint64_t start_time = esp_timer_get_time();
|
uint64_t start_time = esp_timer_get_time();
|
||||||
|
|
||||||
// Execute the command using the DShotRMT instance
|
_packet = _buildDShotPacket(static_cast<uint16_t>(command));
|
||||||
dshot_result_t result = sendCommand(command);
|
dshot_result_t result = _sendDShotFrame(_packet);
|
||||||
|
|
||||||
uint64_t end_time = esp_timer_get_time();
|
uint64_t end_time = esp_timer_get_time();
|
||||||
_last_command_timestamp = end_time;
|
_last_command_timestamp = end_time;
|
||||||
|
|
@ -350,6 +322,7 @@ dshot_result_t DShotRMT::_initRXChannel()
|
||||||
return {true, dshot_msg_code_t::DSHOT_RX_INIT_SUCCESS};
|
return {true, dshot_msg_code_t::DSHOT_RX_INIT_SUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
dshot_result_t DShotRMT::_initDShotEncoder()
|
dshot_result_t DShotRMT::_initDShotEncoder()
|
||||||
{
|
{
|
||||||
rmt_bytes_encoder_config_t encoder_config = {
|
rmt_bytes_encoder_config_t encoder_config = {
|
||||||
|
|
@ -367,8 +340,7 @@ dshot_result_t DShotRMT::_initDShotEncoder()
|
||||||
},
|
},
|
||||||
.flags = {
|
.flags = {
|
||||||
.msb_first = 1 // DShot is MSB first
|
.msb_first = 1 // DShot is MSB first
|
||||||
}
|
}};
|
||||||
};
|
|
||||||
|
|
||||||
if (rmt_new_bytes_encoder(&encoder_config, &_dshot_encoder) != DSHOT_OK)
|
if (rmt_new_bytes_encoder(&encoder_config, &_dshot_encoder) != DSHOT_OK)
|
||||||
{
|
{
|
||||||
|
|
@ -379,7 +351,7 @@ dshot_result_t DShotRMT::_initDShotEncoder()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private Packet Management Functions
|
// Private Packet Management Functions
|
||||||
dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t &value)
|
dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t &value) const
|
||||||
{
|
{
|
||||||
dshot_packet_t packet = {};
|
dshot_packet_t packet = {};
|
||||||
|
|
||||||
|
|
@ -393,14 +365,14 @@ dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t &value)
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t DShotRMT::_buildDShotFrameValue(const dshot_packet_t &packet)
|
uint16_t DShotRMT::_buildDShotFrameValue(const dshot_packet_t &packet) const
|
||||||
{
|
{
|
||||||
// Combine throttle, telemetry bit, and CRC into a single 16-bit frame
|
// Combine throttle, telemetry bit, and CRC into a single 16-bit frame
|
||||||
uint16_t data_and_telemetry = (packet.throttle_value << 1) | packet.telemetric_request;
|
uint16_t data_and_telemetry = (packet.throttle_value << 1) | packet.telemetric_request;
|
||||||
return (data_and_telemetry << 4) | packet.checksum;
|
return (data_and_telemetry << 4) | packet.checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t DShotRMT::_calculateCRC(const uint16_t &data)
|
uint16_t DShotRMT::_calculateCRC(const uint16_t &data) const
|
||||||
{
|
{
|
||||||
// Standard DShot CRC calculation using XOR
|
// Standard DShot CRC calculation using XOR
|
||||||
uint16_t crc = (data ^ (data >> 4) ^ (data >> 8)) & DSHOT_CRC_MASK;
|
uint16_t crc = (data ^ (data >> 4) ^ (data >> 8)) & DSHOT_CRC_MASK;
|
||||||
|
|
@ -463,7 +435,7 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||||
// This function needs to be fast, as it generates the RMT symbols just before sending
|
// This function needs to be fast, as it generates the RMT symbols just before sending
|
||||||
|
|
||||||
// Placed in IRAM for high performance, as it's called from an ISR context
|
// Placed in IRAM for high performance, as it's called from an ISR context
|
||||||
uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols) const
|
||||||
{
|
{
|
||||||
uint32_t gcr_value = 0;
|
uint32_t gcr_value = 0;
|
||||||
|
|
||||||
|
|
@ -503,7 +475,7 @@ uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timing Control Functions
|
// Timing Control Functions
|
||||||
bool IRAM_ATTR DShotRMT::_isFrameIntervalElapsed()
|
bool IRAM_ATTR DShotRMT::_isFrameIntervalElapsed() const
|
||||||
{
|
{
|
||||||
// Check if the minimum interval between frames has passed
|
// Check if the minimum interval between frames has passed
|
||||||
uint64_t current_time = esp_timer_get_time();
|
uint64_t current_time = esp_timer_get_time();
|
||||||
|
|
@ -537,47 +509,3 @@ bool IRAM_ATTR DShotRMT::_on_rx_done(rmt_channel_handle_t rmt_rx_channel, const
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public Static Utility Functions
|
|
||||||
void DShotRMT::printDShotInfo(const DShotRMT &dshot_rmt, Stream &output)
|
|
||||||
{
|
|
||||||
output.println("\n === DShot Signal Info === ");
|
|
||||||
|
|
||||||
uint16_t dshot_mode_val = 0;
|
|
||||||
switch (dshot_rmt.getMode())
|
|
||||||
{
|
|
||||||
case dshot_mode_t::DSHOT150:
|
|
||||||
dshot_mode_val = 150;
|
|
||||||
break;
|
|
||||||
case dshot_mode_t::DSHOT300:
|
|
||||||
dshot_mode_val = 300;
|
|
||||||
break;
|
|
||||||
case dshot_mode_t::DSHOT600:
|
|
||||||
dshot_mode_val = 600;
|
|
||||||
break;
|
|
||||||
case dshot_mode_t::DSHOT1200:
|
|
||||||
dshot_mode_val = 1200;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
output.printf("Current Mode: DSHOT%d\n", dshot_mode_val);
|
|
||||||
|
|
||||||
output.printf("Bidirectional: %s\n", dshot_rmt.isBidirectional() ? "YES" : "NO");
|
|
||||||
output.printf("Current Packet: ");
|
|
||||||
|
|
||||||
for (int i = DSHOT_BITS_PER_FRAME - 1; i >= 0; --i)
|
|
||||||
{
|
|
||||||
output.print((dshot_rmt.getEncodedFrameValue() >> i) & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.printf("\nCurrent Value: %u\n", dshot_rmt.getThrottleValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
void DShotRMT::printCpuInfo(Stream &output)
|
|
||||||
{
|
|
||||||
output.println("\n === CPU Info === ");
|
|
||||||
output.printf("Chip Model: %s\n", ESP.getChipModel());
|
|
||||||
output.printf("Chip Revision: %d\n", ESP.getChipRevision());
|
|
||||||
output.printf("CPU Freq = %lu MHz\n", ESP.getCpuFreqMHz());
|
|
||||||
output.printf("XTAL Freq = %lu MHz\n", getXtalFrequencyMhz());
|
|
||||||
output.printf("APB Freq = %lu Hz\n", getApbFrequency());
|
|
||||||
}
|
|
||||||
|
|
|
||||||
178
src/DShotRMT.h
178
src/DShotRMT.h
|
|
@ -9,64 +9,49 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <dshot_definitions.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 <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
// Main class for DShot signal generation and reception.
|
#include "dshot_definitions.h"
|
||||||
// This class provides an interface to generate DShot signals for Electronic Speed Controllers (ESCs)
|
#include <driver/rmt_encoder.h>
|
||||||
// and to receive telemetry data using the ESP32's RMT peripheral.
|
|
||||||
|
// DShotRMT Class Definition
|
||||||
class DShotRMT
|
class DShotRMT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Constructor for DShotRMT with GPIO number.
|
// Constructor for DShotRMT with GPIO number.
|
||||||
explicit DShotRMT(gpio_num_t gpio = GPIO_NUM_16, dshot_mode_t mode = dshot_mode_t::DSHOT300, bool is_bidirectional = false, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT);
|
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);
|
||||||
|
|
||||||
// Constructor for DShotRMT with Arduino pin number.
|
// 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);
|
DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional, uint16_t magnet_count = DEFAULT_MOTOR_MAGNET_COUNT);
|
||||||
|
|
||||||
// Destructor for DShotRMT.
|
// Destructor
|
||||||
// Cleans up RMT channels and encoder resources.
|
|
||||||
~DShotRMT();
|
~DShotRMT();
|
||||||
|
|
||||||
// Public Core Functions
|
// Public Core Functions
|
||||||
// Initializes the DShot RMT channels and encoder.
|
// Initializes the DShot RMT channels and encoder.
|
||||||
dshot_result_t begin();
|
dshot_result_t begin();
|
||||||
|
|
||||||
// Sends a DShot throttle value to the ESC.
|
// Sends a throttle value as a percentage (0.0-100.0) to the ESC.
|
||||||
dshot_result_t sendThrottle(uint16_t throttle);
|
|
||||||
|
|
||||||
// Sends a DShot throttle value as a percentage to the ESC.
|
|
||||||
dshot_result_t sendThrottlePercent(float percent);
|
dshot_result_t sendThrottlePercent(float percent);
|
||||||
|
|
||||||
// Sends a single DShot command to the ESC.
|
// Sends a raw throttle value (48-2047) to the ESC. A value of 0 sends a motor stop command.
|
||||||
dshot_result_t sendCommand(uint16_t command);
|
dshot_result_t sendThrottle(uint16_t throttle);
|
||||||
|
|
||||||
// Sends a DShot command multiple times with a delay between repetitions. This is a blocking function.
|
// Sends a DShot command (0-47) to the ESC.
|
||||||
dshot_result_t sendCommand(dshotCommands_e dshot_command, uint16_t repeat_count = DEFAULT_CMD_REPEAT_COUNT, uint16_t delay_us = DEFAULT_CMD_DELAY_US);
|
dshot_result_t sendCommand(dshotCommands_e command);
|
||||||
|
|
||||||
// Retrieves telemetry data from the ESC.
|
// Retrieves telemetry data from the ESC.
|
||||||
dshot_result_t getTelemetry(uint16_t magnet_count = 0);
|
dshot_result_t getTelemetry();
|
||||||
|
|
||||||
// Sends a command to the ESC to request ESC information.
|
// Sets the motor spin direction. 'true' for reversed, 'false' for normal.
|
||||||
dshot_result_t getESCInfo();
|
|
||||||
|
|
||||||
// Sets the motor spin direction.
|
|
||||||
dshot_result_t setMotorSpinDirection(bool reversed);
|
dshot_result_t setMotorSpinDirection(bool reversed);
|
||||||
|
|
||||||
// Sends a command to the ESC to save its current settings.
|
// Sends a command to the ESC to save its current settings. Use with caution as this writes to ESC's non-volatile memory.
|
||||||
// Use with caution as this writes to ESC's non-volatile memory.
|
|
||||||
dshot_result_t saveESCSettings();
|
dshot_result_t saveESCSettings();
|
||||||
|
|
||||||
// Public Utility & Info Functions
|
// Public Utility & Info Functions
|
||||||
// Prints detailed DShot signal information for a given DShotRMT instance.
|
|
||||||
static void printDShotInfo(const DShotRMT &dshot_rmt, Stream &output = Serial);
|
|
||||||
|
|
||||||
// Prints detailed CPU information.
|
|
||||||
static void printCpuInfo(Stream &output = Serial);
|
|
||||||
|
|
||||||
// Sets the motor magnet count for RPM calculation.
|
// Sets the motor magnet count for RPM calculation.
|
||||||
void setMotorMagnetCount(uint16_t magnet_count);
|
void setMotorMagnetCount(uint16_t magnet_count);
|
||||||
|
|
||||||
|
|
@ -76,41 +61,29 @@ public:
|
||||||
// Checks if bidirectional DShot is enabled.
|
// Checks if bidirectional DShot is enabled.
|
||||||
bool isBidirectional() const { return _is_bidirectional; }
|
bool isBidirectional() const { return _is_bidirectional; }
|
||||||
|
|
||||||
// Gets the last encoded DShot frame value.
|
// Gets the encoded frame value.
|
||||||
uint16_t getEncodedFrameValue() const { return _encoded_frame_value; }
|
uint16_t getEncodedFrameValue() const { return _encoded_frame_value; }
|
||||||
|
|
||||||
// Gets the last transmitted throttle value.
|
// Gets the last transmitted throttle value.
|
||||||
uint16_t getThrottleValue() const { return _packet.throttle_value; }
|
uint16_t getThrottleValue() const { return _packet.throttle_value; }
|
||||||
|
|
||||||
|
// Testing return "verbose" messages
|
||||||
|
const char *getDShotMsg(dshot_result_t &result) const { return (_get_result_code_str(result.result_code)); }
|
||||||
|
|
||||||
// Deprecated Methods
|
// Deprecated Methods
|
||||||
// Deprecated. Use sendThrottle() instead.
|
// Deprecated. Use sendThrottle() instead.
|
||||||
[[deprecated("Use sendThrottle() instead")]]
|
[[deprecated("Use sendThrottle() instead")]]
|
||||||
bool setThrottle(uint16_t throttle)
|
dshot_result_t sendValue(uint16_t value) { return sendThrottle(value); }
|
||||||
{
|
|
||||||
auto result = sendThrottle(throttle);
|
|
||||||
return result.success;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated. Use sendCommand() instead.
|
// Deprecated. Use sendCommand() instead.
|
||||||
[[deprecated("Use sendCommand() instead")]]
|
[[deprecated("Use sendCommand() instead")]]
|
||||||
bool sendDShotCommand(uint16_t command)
|
dshot_result_t sendCommand(uint16_t command) { return sendCommand(static_cast<dshotCommands_e>(command)); }
|
||||||
{
|
|
||||||
auto result = sendCommand(command);
|
|
||||||
return result.success;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated. Use getTelemetry() instead.
|
|
||||||
[[deprecated("Use getTelemetry() instead")]]
|
|
||||||
uint32_t getMotorRPM(uint8_t magnet_count)
|
|
||||||
{
|
|
||||||
auto result = getTelemetry(magnet_count);
|
|
||||||
return result.motor_rpm;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- UTILITY METHODS ---
|
// --- UTILITY METHODS ---
|
||||||
bool _isValidCommand(dshotCommands_e command);
|
bool _isValidCommand(dshotCommands_e command) const;
|
||||||
dshot_result_t _executeCommand(dshotCommands_e command);
|
dshot_result_t _executeCommand(dshotCommands_e command);
|
||||||
|
dshot_result_t _sendCommandInternal(dshotCommands_e dshot_command, uint16_t repeat_count, uint16_t delay_us);
|
||||||
|
|
||||||
// Core Configuration Variables
|
// Core Configuration Variables
|
||||||
gpio_num_t _gpio;
|
gpio_num_t _gpio;
|
||||||
|
|
@ -118,33 +91,33 @@ private:
|
||||||
bool _is_bidirectional;
|
bool _is_bidirectional;
|
||||||
uint16_t _motor_magnet_count;
|
uint16_t _motor_magnet_count;
|
||||||
const dshot_timing_us_t &_dshot_timing;
|
const dshot_timing_us_t &_dshot_timing;
|
||||||
uint64_t _frame_timer_us;
|
uint64_t _frame_timer_us = 0;
|
||||||
|
|
||||||
// Timing & Packet Variables
|
// Timing & Packet Variables
|
||||||
rmt_ticks_t _rmt_ticks;
|
rmt_ticks_t _rmt_ticks{};
|
||||||
uint16_t _last_throttle;
|
uint16_t _last_throttle = dshotCommands_e::DSHOT_CMD_MOTOR_STOP;
|
||||||
uint64_t _last_transmission_time_us;
|
uint64_t _last_transmission_time_us = 0;
|
||||||
uint64_t _last_command_timestamp;
|
uint64_t _last_command_timestamp = 0;
|
||||||
uint16_t _encoded_frame_value;
|
uint16_t _encoded_frame_value = 0;
|
||||||
dshot_packet_t _packet;
|
dshot_packet_t _packet{};
|
||||||
uint16_t _pulse_level; // DShot protocol: Signal is idle-low, so pulses start by going HIGH.
|
uint16_t _pulse_level = 1; // DShot protocol: Signal is idle-low, so pulses start by going HIGH.
|
||||||
uint16_t _idle_level; // DShot protocol: Signal returns to LOW after the high pulse.
|
uint16_t _idle_level = 0; // DShot protocol: Signal returns to LOW after the high pulse.
|
||||||
|
|
||||||
// RMT Hardware Handles
|
// RMT Hardware Handles
|
||||||
rmt_channel_handle_t _rmt_tx_channel;
|
rmt_channel_handle_t _rmt_tx_channel = nullptr;
|
||||||
rmt_channel_handle_t _rmt_rx_channel;
|
rmt_channel_handle_t _rmt_rx_channel = nullptr;
|
||||||
rmt_encoder_handle_t _dshot_encoder;
|
rmt_encoder_handle_t _dshot_encoder = nullptr;
|
||||||
|
|
||||||
// RMT Configuration Structures
|
// RMT Configuration Structures
|
||||||
rmt_tx_channel_config_t _tx_channel_config;
|
rmt_tx_channel_config_t _tx_channel_config{};
|
||||||
rmt_rx_channel_config_t _rx_channel_config;
|
rmt_rx_channel_config_t _rx_channel_config{};
|
||||||
rmt_transmit_config_t _rmt_tx_config;
|
rmt_transmit_config_t _rmt_tx_config{};
|
||||||
rmt_receive_config_t _rmt_rx_config;
|
rmt_receive_config_t _rmt_rx_config{};
|
||||||
|
|
||||||
// Bidirectional / Telemetry Variables
|
// Bidirectional / Telemetry Variables
|
||||||
rmt_rx_event_callbacks_t _rx_event_callbacks;
|
rmt_rx_event_callbacks_t _rx_event_callbacks{};
|
||||||
std::atomic<uint16_t> _last_erpm_atomic;
|
std::atomic<uint16_t> _last_erpm_atomic{0};
|
||||||
std::atomic<bool> _telemetry_ready_flag_atomic;
|
std::atomic<bool> _telemetry_ready_flag_atomic{false};
|
||||||
|
|
||||||
// Private Initialization Functions
|
// Private Initialization Functions
|
||||||
dshot_result_t _initTXChannel();
|
dshot_result_t _initTXChannel();
|
||||||
|
|
@ -152,19 +125,78 @@ private:
|
||||||
dshot_result_t _initDShotEncoder();
|
dshot_result_t _initDShotEncoder();
|
||||||
|
|
||||||
// Private Packet Management Functions
|
// Private Packet Management Functions
|
||||||
dshot_packet_t _buildDShotPacket(const uint16_t &value);
|
dshot_packet_t _buildDShotPacket(const uint16_t &value) const;
|
||||||
uint16_t _buildDShotFrameValue(const dshot_packet_t &packet);
|
uint16_t _buildDShotFrameValue(const dshot_packet_t &packet) const;
|
||||||
uint16_t _calculateCRC(const uint16_t &data);
|
uint16_t _calculateCRC(const uint16_t &data) const;
|
||||||
void _preCalculateRMTTicks();
|
void _preCalculateRMTTicks();
|
||||||
|
|
||||||
// Private Frame Processing Functions
|
// Private Frame Processing Functions
|
||||||
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet);
|
dshot_result_t _sendDShotFrame(const dshot_packet_t &packet);
|
||||||
uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols);
|
uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols) const;
|
||||||
|
|
||||||
// Private Timing Control Functions
|
// Private Timing Control Functions
|
||||||
bool _isFrameIntervalElapsed();
|
bool _isFrameIntervalElapsed() const;
|
||||||
void _recordFrameTransmissionTime();
|
void _recordFrameTransmissionTime();
|
||||||
|
|
||||||
// Static Callback Functions
|
// Static Callback Functions
|
||||||
static bool _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
static bool _on_rx_done(rmt_channel_handle_t rmt_rx_channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper to quick print DShot result codes
|
||||||
|
inline void printDShotResult(dshot_result_t &result, Stream &output = Serial)
|
||||||
|
{
|
||||||
|
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", _get_result_code_str(result.result_code));
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to print DShot signal info
|
||||||
|
inline void printDShotInfo(const DShotRMT &dshot_rmt, Stream &output = Serial)
|
||||||
|
{
|
||||||
|
output.println("\n === DShot Signal Info === ");
|
||||||
|
|
||||||
|
uint16_t dshot_mode_val = 0;
|
||||||
|
switch (dshot_rmt.getMode())
|
||||||
|
{
|
||||||
|
case DSHOT150:
|
||||||
|
dshot_mode_val = 150;
|
||||||
|
break;
|
||||||
|
case DSHOT300:
|
||||||
|
dshot_mode_val = 300;
|
||||||
|
break;
|
||||||
|
case DSHOT600:
|
||||||
|
dshot_mode_val = 600;
|
||||||
|
break;
|
||||||
|
case DSHOT1200:
|
||||||
|
dshot_mode_val = 1200;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.printf("Current Mode: DSHOT%d\n", dshot_mode_val);
|
||||||
|
output.printf("Bidirectional: %s\n", dshot_rmt.isBidirectional() ? "YES" : "NO");
|
||||||
|
output.printf("Current Packet: ");
|
||||||
|
|
||||||
|
for (int i = DSHOT_BITS_PER_FRAME - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
output.print((dshot_rmt.getEncodedFrameValue() >> i) & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.printf("\nCurrent Value: %u\n", dshot_rmt.getThrottleValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to print CPU info
|
||||||
|
inline void printCpuInfo(Stream &output = Serial)
|
||||||
|
{
|
||||||
|
output.println("\n === CPU Info === ");
|
||||||
|
output.printf("Chip Model: %s\n", ESP.getChipModel());
|
||||||
|
output.printf("Chip Revision: %d\n", ESP.getChipRevision());
|
||||||
|
output.printf("CPU Freq = %lu MHz\n", ESP.getCpuFreqMHz());
|
||||||
|
output.printf("XTAL Freq = %lu MHz\n", getXtalFrequencyMhz());
|
||||||
|
output.printf("APB Freq = %lu Hz\n", getApbFrequency());
|
||||||
|
}
|
||||||
|
|
@ -6,14 +6,15 @@
|
||||||
#include <driver/rmt_rx.h>
|
#include <driver/rmt_rx.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
// Defines the available DShot communication speeds with type safety.
|
// Defines the available DShot communication speeds.
|
||||||
enum class dshot_mode_t
|
enum dshot_mode_t
|
||||||
{
|
{
|
||||||
DSHOT_OFF,
|
DSHOT_OFF,
|
||||||
DSHOT150,
|
DSHOT150,
|
||||||
DSHOT300,
|
DSHOT300,
|
||||||
DSHOT600,
|
DSHOT600,
|
||||||
DSHOT1200
|
DSHOT1200,
|
||||||
|
DSHOT_MODE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents the 16-bit DShot data packet sent to the ESC.
|
// Represents the 16-bit DShot data packet sent to the ESC.
|
||||||
|
|
@ -157,7 +158,8 @@ const dshot_timing_us_t DSHOT_TIMING_US[] = {
|
||||||
{6.67, 5.00}, // DSHOT150
|
{6.67, 5.00}, // DSHOT150
|
||||||
{3.33, 2.50}, // DSHOT300
|
{3.33, 2.50}, // DSHOT300
|
||||||
{1.67, 1.25}, // DSHOT600
|
{1.67, 1.25}, // DSHOT600
|
||||||
{0.83, 0.67} // DSHOT1200
|
{0.83, 0.67}, // DSHOT1200
|
||||||
|
{0.00, 0.00} // DSHOT_MODE_MAX (dummy entry)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Error Messages
|
// Error Messages
|
||||||
|
|
@ -246,17 +248,3 @@ inline const char *_get_result_code_str(dshot_msg_code_t code)
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to quick print DShot result codes
|
|
||||||
inline void printDShotResult(dshot_result_t &result, Stream &output = Serial)
|
|
||||||
{
|
|
||||||
output.printf("Status: %s - %s", result.success ? "SUCCESS" : "FAILED", _get_result_code_str(result.result_code));
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @file ota_update.h
|
* @file ota_update.h
|
||||||
* @brief DShot signal generation using ESP32 RMT with bidirectional support
|
* @brief Contains the HTML, CSS, and JavaScript for the OTA (Over-The-Air) update web page.
|
||||||
* @author Wastl Kraus
|
* @author Wastl Kraus
|
||||||
* @date 2025-09-13
|
* @date 2025-09-13
|
||||||
* @license MIT
|
* @license MIT
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @file web_content.h
|
* @file web_content.h
|
||||||
* @brief DShot signal generation using ESP32 RMT with bidirectional support
|
* @brief Contains the HTML, CSS, and JavaScript for the main DShot control web page.
|
||||||
* @author Wastl Kraus
|
* @author Wastl Kraus
|
||||||
* @date 2025-09-13
|
* @date 2025-09-13
|
||||||
* @license MIT
|
* @license MIT
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue