re-enable bidirectional support
re-enable bidirectional support
This commit is contained in:
commit
7985030df6
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
An Arduino IDE library for generating DShot signals on ESP32 microcontrollers using the **modern ESP-IDF 5 RMT Encoder API** (`rmt_tx.h` / `rmt_rx.h`). This library specifically leverages the official `rmt_bytes_encoder` API for an efficient, hardware-timed and maintainable implementation. It provides a simple way to control BLHeli ESCs in both Arduino and ESP-IDF projects.
|
||||
|
||||
### Bidirectional DShot re-enabled for testing.
|
||||
|
||||
The legacy version using the old `rmt.h` API is available in the `oldAPI` branch.
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
* @license MIT
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <DShotRMT.h>
|
||||
|
||||
// USB serial port settings
|
||||
|
|
@ -15,14 +14,13 @@ static constexpr auto USB_SERIAL_BAUD = 115200;
|
|||
|
||||
// Motor configuration - Pin number or GPIO_PIN
|
||||
static constexpr gpio_num_t MOTOR01_PIN = GPIO_NUM_27;
|
||||
// static constexpr auto MOTOR01_PIN = 17;
|
||||
// static constexpr auto MOTOR01_PIN = 27;
|
||||
|
||||
// Supported: DSHOT150, DSHOT300, DSHOT600, (DSHOT1200)
|
||||
static constexpr dshot_mode_t DSHOT_MODE = DSHOT300;
|
||||
|
||||
// BiDirectional DShot Support (default: false)
|
||||
// Note: Bidirectional DShot is currently not officially supported
|
||||
// due to instability and external hardware requirements.
|
||||
// re-enabled for testing
|
||||
static constexpr auto IS_BIDIRECTIONAL = false;
|
||||
|
||||
// Motor magnet count for RPM calculation
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
name=DShotRMT
|
||||
version=0.9.0
|
||||
version=0.9.1
|
||||
author=Wastl Kraus <wir-sind-die-matrix.de>
|
||||
maintainer=Wastl Kraus <wir-sind-die-matrix.de>
|
||||
license=MIT
|
||||
sentence=DShotRMT Library supporting all DShot Types and speeds. Tested with BlHeli_S.
|
||||
paragraph=This library can control a BlHeli_S by using encoded DShot commands.
|
||||
sentence=DShotRMT Library supporting all DShot Types and speeds. Bidirectional support re-enabled. Tested with BlHeli_S.
|
||||
paragraph=This library can control a BlHeli_S by using encoded DShot commands. Bidirectional support re-enabled.
|
||||
category=Signal Input/Output
|
||||
url=https://github.com/derdoktor667/DShotRMT
|
||||
architectures=esp32
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ dshot_result_t DShotRMT::sendThrottlePercent(float percent)
|
|||
dshot_result_t DShotRMT::sendCommand(uint16_t command_value)
|
||||
{
|
||||
// Validate the integer command value before casting
|
||||
if (command_value < DSHOT_CMD_MOTOR_STOP || command_value > DSHOT_CMD_MAX)
|
||||
if (command_value < DSHOT_CMD_MOTOR_STOP || command_value > DSHOT_CMD_MAX_VALUE)
|
||||
{
|
||||
return {false, DSHOT_COMMAND_NOT_VALID};
|
||||
}
|
||||
|
|
@ -134,6 +134,7 @@ dshot_result_t DShotRMT::sendCommand(dshotCommands_e command)
|
|||
|
||||
switch (command)
|
||||
{
|
||||
case DSHOT_CMD_MOTOR_STOP:
|
||||
case DSHOT_CMD_SAVE_SETTINGS:
|
||||
case DSHOT_CMD_SPIN_DIRECTION_NORMAL:
|
||||
case DSHOT_CMD_SPIN_DIRECTION_REVERSED:
|
||||
|
|
@ -235,6 +236,13 @@ dshot_result_t DShotRMT::setMotorSpinDirection(bool reversed)
|
|||
return sendCommand(command, SETTINGS_COMMAND_REPEATS, SETTINGS_COMMAND_DELAY_US);
|
||||
}
|
||||
|
||||
// Sends a raw DShot command to the ESC.
|
||||
dshot_result_t DShotRMT::sendRawCommand(uint16_t command_value)
|
||||
{
|
||||
_packet = _buildDShotPacket(command_value);
|
||||
return _sendDShotFrame(_packet);
|
||||
}
|
||||
|
||||
// Use with caution
|
||||
dshot_result_t DShotRMT::saveESCSettings()
|
||||
{
|
||||
|
|
@ -325,6 +333,24 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
|||
return {true, DSHOT_NONE};
|
||||
}
|
||||
|
||||
if (_is_bidirectional)
|
||||
{
|
||||
// Start the receiver to wait for incoming telemetry data
|
||||
rmt_symbol_word_t rx_symbols[GCR_BITS_PER_FRAME];
|
||||
size_t rx_size_bytes = GCR_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
|
||||
|
||||
rmt_receive_config_t rmt_rx_config = {
|
||||
.signal_range_min_ns = DSHOT_PULSE_MIN_NS,
|
||||
.signal_range_max_ns = DSHOT_PULSE_MAX_NS,
|
||||
};
|
||||
|
||||
if (rmt_receive(_rmt_rx_channel, rx_symbols, rx_size_bytes, &rmt_rx_config) != DSHOT_OK)
|
||||
{
|
||||
return {false, DSHOT_RECEIVER_FAILED};
|
||||
}
|
||||
}
|
||||
|
||||
// Now let's prepare the actual frame
|
||||
_encoded_frame_value = _buildDShotFrameValue(packet);
|
||||
|
||||
// Byte-swap the 16-bit value for correct transmission order (ESP32 is little-endian, DShot is MSB first)
|
||||
|
|
@ -335,20 +361,37 @@ dshot_result_t DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
|
|||
|
||||
rmt_transmit_config_t tx_config = {}; // Initialize all members to zero
|
||||
tx_config.loop_count = 0; // No automatic loops - real-time calculation
|
||||
tx_config.flags.eot_level = _is_bidirectional ? 1 : 0;
|
||||
|
||||
// TODO: Find out, why this is needed
|
||||
if (_is_bidirectional)
|
||||
{
|
||||
// Disable RMT RX for sending
|
||||
if (rmt_disable(_rmt_rx_channel) != DSHOT_OK)
|
||||
{
|
||||
return {false, DSHOT_RECEIVER_FAILED};
|
||||
}
|
||||
}
|
||||
|
||||
if (rmt_transmit(_rmt_tx_channel, _dshot_encoder, &swapped_value, tx_size_bytes, &tx_config) != DSHOT_OK)
|
||||
{
|
||||
return {false, DSHOT_TRANSMISSION_FAILED};
|
||||
}
|
||||
|
||||
// Re-enable RMT RX
|
||||
if (_is_bidirectional)
|
||||
{
|
||||
if (rmt_enable(_rmt_rx_channel) != DSHOT_OK)
|
||||
{
|
||||
return {false, DSHOT_RECEIVER_FAILED};
|
||||
}
|
||||
}
|
||||
|
||||
_recordFrameTransmissionTime(); // Reset the timer for the next frame
|
||||
|
||||
return {true, DSHOT_TRANSMISSION_SUCCESS};
|
||||
}
|
||||
|
||||
// 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.
|
||||
uint16_t IRAM_ATTR DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ public:
|
|||
// Sends a DShot command to the ESC with a specified repeat count and delay.
|
||||
dshot_result_t sendCommand(dshotCommands_e command, uint16_t repeat_count, uint16_t delay_us);
|
||||
|
||||
// Sends a raw DShot command to the ESC.
|
||||
dshot_result_t sendRawCommand(uint16_t command_value);
|
||||
|
||||
// Retrieves telemetry data from the ESC.
|
||||
dshot_result_t getTelemetry();
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ static constexpr uint16_t DSHOT_CRC_MASK = 0x000F; // Bit mask for CRC
|
|||
static constexpr uint16_t DEFAULT_MOTOR_MAGNET_COUNT = 14;
|
||||
|
||||
// Defines the available DShot communication speeds.
|
||||
enum dshot_mode_t
|
||||
enum dshot_mode_t : uint8_t
|
||||
{
|
||||
DSHOT_OFF,
|
||||
DSHOT150,
|
||||
|
|
@ -127,7 +127,8 @@ enum dshotCommands_e
|
|||
DSHOT_CMD_LED2_OFF,
|
||||
DSHOT_CMD_LED3_OFF,
|
||||
DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF = 30,
|
||||
DSHOT_CMD_SILENT_MODE_ON_OFF = 31
|
||||
DSHOT_CMD_SILENT_MODE_ON_OFF = 31,
|
||||
DSHOT_CMD_MAX_VALUE = 47
|
||||
};
|
||||
|
||||
// Custom status codes
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@ dshot_result_t init_rmt_tx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_ch
|
|||
.resolution_hz = DSHOT_RMT_RESOLUTION,
|
||||
.mem_block_symbols = RMT_BUFFER_SYMBOLS,
|
||||
.trans_queue_depth = RMT_QUEUE_DEPTH,
|
||||
};
|
||||
.flags = {
|
||||
.invert_out = is_bidirectional ? 1 : 0,
|
||||
.init_level = is_bidirectional ? 0 : 1}};
|
||||
|
||||
rmt_transmit_config_t rmt_tx_config = {}; // Initialize all members to zero
|
||||
rmt_tx_config.loop_count = 0; // No automatic loops - real-time calculation
|
||||
rmt_tx_config.flags.eot_level = is_bidirectional ? 1 : 0;
|
||||
|
||||
if (rmt_new_tx_channel(&tx_channel_config, out_channel) != DSHOT_OK)
|
||||
{
|
||||
|
|
@ -61,20 +62,6 @@ dshot_result_t init_rmt_rx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_ch
|
|||
return {false, DSHOT_RX_INIT_FAILED};
|
||||
}
|
||||
|
||||
// Start the receiver to wait for incoming telemetry data
|
||||
rmt_symbol_word_t rx_symbols[GCR_BITS_PER_FRAME];
|
||||
size_t rx_size_bytes = GCR_BITS_PER_FRAME * sizeof(rmt_symbol_word_t);
|
||||
|
||||
rmt_receive_config_t rmt_rx_config = {
|
||||
.signal_range_min_ns = DSHOT_PULSE_MIN_NS,
|
||||
.signal_range_max_ns = DSHOT_PULSE_MAX_NS,
|
||||
};
|
||||
|
||||
if (rmt_receive(*out_channel, rx_symbols, rx_size_bytes, &rmt_rx_config) != DSHOT_OK)
|
||||
{
|
||||
return {false, DSHOT_RECEIVER_FAILED};
|
||||
}
|
||||
|
||||
return {true, DSHOT_RX_INIT_SUCCESS};
|
||||
}
|
||||
|
||||
|
|
@ -94,6 +81,7 @@ dshot_result_t init_dshot_encoder(rmt_encoder_handle_t *out_encoder, const rmt_t
|
|||
.duration1 = rmt_ticks.t1l_ticks,
|
||||
.level1 = idle_level,
|
||||
},
|
||||
|
||||
.flags = {
|
||||
.msb_first = 1 // DShot is MSB first
|
||||
}};
|
||||
|
|
|
|||
Loading…
Reference in New Issue