...sync branch
* ...squashed ...some simple info display ...fixing possible overflow ...reenable "telemetric bit" choice * Update DShotRMT.h * ...update buffer size ...increase RX Buffer and calculate RMT Sybmbol size * ...update Workflow badges * Update .gitignore
This commit is contained in:
parent
8f08a789bb
commit
443d032d56
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
# Caching ESP32 Builds
|
||||
buildCache
|
||||
build
|
||||
examples/dshot300/debug.cfg
|
||||
examples/dshot300/esp32.svd
|
||||
examples/dshot300/debug_custom.json
|
||||
|
|
|
|||
77
DShotRMT.cpp
77
DShotRMT.cpp
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include "DShotRMT.h"
|
||||
#include <driver/rmt_tx.h>
|
||||
|
||||
// --- DShot Timings ---
|
||||
// frame_length_us, ticks_per_bit, ticks_one_high, ticks_one_low, ticks_zero_high, ticks_zero_low
|
||||
|
|
@ -19,8 +20,7 @@ constexpr dshot_timing_t DSHOT_TIMINGS[] = {
|
|||
};
|
||||
|
||||
// --- DShot Config Constructor ---
|
||||
DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional):
|
||||
_gpio(gpio),
|
||||
DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional) : _gpio(gpio),
|
||||
_mode(mode),
|
||||
_is_bidirectional(is_bidirectional),
|
||||
_timing_config(DSHOT_TIMINGS[mode]),
|
||||
|
|
@ -44,12 +44,10 @@ DShotRMT::DShotRMT(gpio_num_t gpio, dshot_mode_t mode, bool is_bidirectional):
|
|||
}
|
||||
|
||||
// Easy Constructor
|
||||
DShotRMT::DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional):
|
||||
DShotRMT(
|
||||
DShotRMT::DShotRMT(uint16_t pin_nr, dshot_mode_t mode, bool is_bidirectional) : DShotRMT(
|
||||
(gpio_num_t)pin_nr,
|
||||
mode,
|
||||
is_bidirectional
|
||||
)
|
||||
is_bidirectional)
|
||||
{
|
||||
// ...just to accept pin numbers and GPIO_NUMs
|
||||
}
|
||||
|
|
@ -91,14 +89,19 @@ bool DShotRMT::setThrottle(uint16_t throttle)
|
|||
// Sends a valid throttle value
|
||||
bool DShotRMT::sendThrottle(uint16_t throttle)
|
||||
{
|
||||
// Make sure throttle value is valid by force
|
||||
// Validate throttle value
|
||||
if (throttle < DSHOT_THROTTLE_MIN || throttle > DSHOT_THROTTLE_MAX)
|
||||
{
|
||||
Serial.println(DSHOT_MSG_05);
|
||||
return DSHOT_ERROR;
|
||||
}
|
||||
|
||||
// Constrain throttle value
|
||||
auto value = constrain(throttle, DSHOT_THROTTLE_MIN, DSHOT_THROTTLE_MAX);
|
||||
|
||||
// Converts throttle value to dshot packet RMT symbols
|
||||
// Build and send packet
|
||||
_packet = _buildDShotPacket(value);
|
||||
|
||||
// Actually send the RMT symbols
|
||||
return (_sendDShotFrame(_packet));
|
||||
return _sendDShotFrame(_packet);
|
||||
}
|
||||
|
||||
// Deprecated, use "sendCommand()"" instead
|
||||
|
|
@ -117,8 +120,7 @@ bool DShotRMT::sendCommand(uint16_t command)
|
|||
}
|
||||
|
||||
_packet = _buildDShotPacket(command);
|
||||
|
||||
return (_sendDShotFrame(_packet));
|
||||
return _sendDShotFrame(_packet);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -220,20 +222,28 @@ bool DShotRMT::_initDShotEncoder()
|
|||
// Uses RMT to transmit a prepared DShot packet and returns it
|
||||
bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
||||
{
|
||||
// Excluding calculation from timing is more timing stable
|
||||
_encodeDShotFrame(packet, _tx_symbols);
|
||||
|
||||
// Checking timer signal
|
||||
if (_timer_signal())
|
||||
// Check if we can send (timing check)
|
||||
if (!_timer_signal())
|
||||
{
|
||||
// Triggers RMT Transmit
|
||||
rmt_transmit(_rmt_tx_channel, _dshot_encoder, _tx_symbols, DSHOT_SYMBOLS_SIZE, &_transmit_config);
|
||||
|
||||
// Time Stamp
|
||||
return _timer_reset();
|
||||
return DSHOT_ERROR;
|
||||
}
|
||||
|
||||
// Encode the frame
|
||||
_encodeDShotFrame(packet, _tx_symbols);
|
||||
|
||||
// Attempt to transmit
|
||||
size_t tx_size_bytes = DSHOT_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
|
||||
bool result = rmt_transmit(_rmt_tx_channel, _dshot_encoder, _tx_symbols, tx_size_bytes, &_transmit_config);
|
||||
|
||||
if (result != DSHOT_OK)
|
||||
{
|
||||
return DSHOT_ERROR;
|
||||
}
|
||||
|
||||
// Update timestamp
|
||||
_timer_reset();
|
||||
|
||||
return DSHOT_OK;
|
||||
}
|
||||
|
||||
// Calculates checksum for given package
|
||||
|
|
@ -266,7 +276,7 @@ dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value)
|
|||
|
||||
// Creates DShot packet
|
||||
packet.throttle_value = value;
|
||||
packet.telemetric_request = 1; // needed to get the motor spinning
|
||||
packet.telemetric_request = _is_bidirectional ? 1 : 0;
|
||||
packet.checksum = _calculateCRC(packet);
|
||||
|
||||
//
|
||||
|
|
@ -336,11 +346,26 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
|
|||
return data >> 1;
|
||||
}
|
||||
|
||||
//
|
||||
void DShotRMT::printTimingDiagnostics() const
|
||||
{
|
||||
uint32_t current_time = micros();
|
||||
Serial.println("\n=== DShot Timing Diagnostics ===");
|
||||
Serial.printf("Current mode: DSHOT%d\n", _mode == DSHOT150 ? 150 : _mode == DSHOT300 ? 300
|
||||
: _mode == DSHOT600 ? 600
|
||||
: _mode == DSHOT1200);
|
||||
Serial.printf("Protocol Frame length: %u µs\n", _timing_config.frame_length_us);
|
||||
Serial.printf("Frame to Frame: %u µs\n", _frame_timer_us);
|
||||
Serial.printf("Bidirectional: %s\n", _is_bidirectional ? "Yes" : "No");
|
||||
}
|
||||
|
||||
// Timer triggered
|
||||
bool DShotRMT::_timer_signal()
|
||||
{
|
||||
// trying new tricks
|
||||
return __builtin_expect((micros() - _last_transmission_time >= _frame_timer_us), 1);
|
||||
// fixing possible overflow
|
||||
uint32_t current_time = micros();
|
||||
uint32_t elapsed = current_time - _last_transmission_time;
|
||||
return elapsed >= _frame_timer_us;
|
||||
}
|
||||
|
||||
// Updates timestamp
|
||||
|
|
|
|||
11
DShotRMT.h
11
DShotRMT.h
|
|
@ -27,7 +27,7 @@ static constexpr auto DSHOT_NULL_PACKET = 0b0000000000000000;
|
|||
static constexpr auto DSHOT_CLOCK_SRC_DEFAULT = RMT_CLK_SRC_DEFAULT;
|
||||
static constexpr auto DSHOT_RMT_RESOLUTION = 10 * 1000 * 1000; // 10 MHz
|
||||
static constexpr auto TX_BUFFER_SIZE = DSHOT_BITS_PER_FRAME;
|
||||
static constexpr auto RX_BUFFER_SIZE = 64; // debug
|
||||
static constexpr auto RX_BUFFER_SIZE = 128;
|
||||
static constexpr auto DSHOT_SYMBOLS_SIZE = 64;
|
||||
|
||||
// --- DShot Mode Select ---
|
||||
|
|
@ -51,7 +51,7 @@ typedef struct dshot_packet_s
|
|||
// --- DShot Timing Config ---
|
||||
typedef struct dshot_timing_s
|
||||
{
|
||||
uint16_t frame_length_us;
|
||||
uint32_t frame_length_us;
|
||||
uint16_t ticks_per_bit;
|
||||
uint16_t ticks_one_high;
|
||||
uint16_t ticks_one_low;
|
||||
|
|
@ -98,12 +98,15 @@ public:
|
|||
//
|
||||
bool is_bidirectional() const { return _is_bidirectional; }
|
||||
|
||||
// --- Performance monitoring functions ---
|
||||
void printTimingDiagnostics() const;
|
||||
|
||||
private:
|
||||
// --- Config ---
|
||||
gpio_num_t _gpio;
|
||||
dshot_mode_t _mode;
|
||||
bool _is_bidirectional;
|
||||
uint16_t _frame_timer_us;
|
||||
uint32_t _frame_timer_us;
|
||||
|
||||
// --- DShot Timings ---
|
||||
const dshot_timing_t &_timing_config;
|
||||
|
|
@ -114,7 +117,7 @@ private:
|
|||
rmt_encoder_handle_t _dshot_encoder;
|
||||
|
||||
// --- RMT Config ---
|
||||
rmt_symbol_word_t _tx_symbols[DSHOT_BITS_PER_FRAME];
|
||||
rmt_symbol_word_t _tx_symbols[DSHOT_SYMBOLS_SIZE];
|
||||
rmt_symbol_word_t _rx_symbols[RX_BUFFER_SIZE];
|
||||
rmt_tx_channel_config_t _tx_channel_config;
|
||||
rmt_rx_channel_config_t _rx_channel_config;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ void setup()
|
|||
// Initializes DShot Signal
|
||||
motor01.begin();
|
||||
|
||||
USB_SERIAL.printf("CPU Freq = %lu MHz\n", getCpuFrequencyMhz());
|
||||
USB_SERIAL.printf("XTAL Freq = %lu MHz\n", getXtalFrequencyMhz());
|
||||
USB_SERIAL.printf("APB Freq = %lu Hz\n", getApbFrequency());
|
||||
|
||||
USB_SERIAL.println("***********************************");
|
||||
USB_SERIAL.println(" === DShotRMT Demo started. === ");
|
||||
USB_SERIAL.println("Enter a throttle value (48 – 2047):");
|
||||
|
|
@ -50,8 +54,11 @@ void loop()
|
|||
// Safety first: start with DSHOT_MIN_THROTTLE
|
||||
static auto throttle = DSHOT_THROTTLE_MIN;
|
||||
|
||||
// Performance monitoring
|
||||
static uint32_t last_stats_print = 0;
|
||||
|
||||
// Takes "every" throttle value
|
||||
if (USB_SERIAL.available() > NULL)
|
||||
if (USB_SERIAL.available() > 0)
|
||||
{
|
||||
throttle = (USB_SERIAL.readStringUntil('\n').toInt());
|
||||
|
||||
|
|
@ -66,8 +73,13 @@ void loop()
|
|||
// Prints out RPM if BiDirectional DShot is enabled every 2 seconds
|
||||
// printRPMPeriodically(2000);
|
||||
|
||||
// Debug: Prints out "raw" DShot packet every 2 seconds
|
||||
print_RMT_packet(2000);
|
||||
// Print performance statistics every 2 seconds
|
||||
if (millis() - last_stats_print >= 2000)
|
||||
{
|
||||
motor01.printTimingDiagnostics();
|
||||
print_RMT_packet();
|
||||
last_stats_print = millis();
|
||||
}
|
||||
}
|
||||
|
||||
// Prints RPM every X_ms
|
||||
|
|
@ -90,14 +102,12 @@ void printRPMPeriodically(auto timer_ms)
|
|||
}
|
||||
|
||||
// Prints "raw" packet every ms
|
||||
void print_RMT_packet(auto timer_ms)
|
||||
void print_RMT_packet()
|
||||
{
|
||||
static auto last_print_time = 0;
|
||||
|
||||
if (millis() - last_print_time >= timer_ms)
|
||||
{
|
||||
auto packet = motor01.getDShotPacket();
|
||||
|
||||
USB_SERIAL.print("Current Frame: ");
|
||||
|
||||
// Print bit by bit
|
||||
for (auto i = 15; i >= 0; --i)
|
||||
{
|
||||
|
|
@ -112,6 +122,4 @@ void print_RMT_packet(auto timer_ms)
|
|||
}
|
||||
|
||||
USB_SERIAL.println("");
|
||||
last_print_time = millis();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue