working hack

This commit is contained in:
franchioping 2026-04-19 15:47:03 +01:00
parent 4f731edaea
commit 86d6823132
4 changed files with 170 additions and 12 deletions

View File

@ -39,7 +39,7 @@ DShotRMT::~DShotRMT() { _cleanupRmtResources(); }
// Initialize DShotRMT
dshot_result_t DShotRMT::begin() {
_tx_payload = (uint16_t *)heap_caps_malloc(sizeof(uint16_t),
_tx_payload = (uint32_t *)heap_caps_malloc(sizeof(uint32_t),
MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
dshot_result_t result =
init_rmt_tx_channel(_gpio, &_rmt_tx_channel, _is_bidirectional);
@ -58,8 +58,8 @@ dshot_result_t DShotRMT::begin() {
}
}
result = init_dshot_encoder(&_dshot_encoder, _rmt_ticks, _pulse_level,
_idle_level);
result = init_dshot_encoder_tail(&_dshot_encoder, _rmt_ticks, _pulse_level,
_idle_level);
if (!result.success) {
_cleanupRmtResources(); // Clean up any allocated resources on failure
@ -408,7 +408,7 @@ dshot_result_t DShotRMT::_sendPacket(const dshot_packet_t &packet) {
&tx_config) != DSHOT_OK) {
return {false, DSHOT_TRANSMISSION_FAILED};
}
delayMicroseconds(50);
delayMicroseconds(60);
rmt_disable(_rmt_tx_channel);
rmt_enable(_rmt_tx_channel);

View File

@ -92,7 +92,7 @@ public:
void _cleanupRmtResources();
private:
uint16_t *_tx_payload;
uint32_t *_tx_payload;
dshot_result_t _sendRawDshotFrame(uint16_t value);
static bool IRAM_ATTR _on_rx_done(rmt_channel_handle_t rmt_rx_channel,
const rmt_rx_done_event_data_t *edata,

View File

@ -7,6 +7,7 @@
*/
#include "dshot_init.h"
#include "esp_log.h"
// Function to initialize the RMT TX channel
dshot_result_t init_rmt_tx_channel(gpio_num_t gpio,
@ -18,9 +19,11 @@ dshot_result_t init_rmt_tx_channel(gpio_num_t gpio,
.resolution_hz = DSHOT_RMT_RESOLUTION,
.mem_block_symbols = 48,
.trans_queue_depth = RMT_QUEUE_DEPTH,
.flags = {.invert_out = static_cast<uint32_t>(is_bidirectional ? 1 : 0),
.init_level = 0,
.with_dma = 0}};
.flags = {
.invert_out = static_cast<uint32_t>(is_bidirectional ? 1 : 0),
.with_dma = 0,
.init_level = 0,
}};
if (rmt_new_tx_channel(&tx_channel_config, out_channel) != DSHOT_OK) {
return {false, DSHOT_TX_INIT_FAILED};
@ -91,3 +94,145 @@ dshot_result_t init_dshot_encoder(rmt_encoder_handle_t *out_encoder,
return {true, DSHOT_ENCODER_INIT_SUCCESS};
}
typedef struct {
rmt_encoder_t base;
rmt_encoder_t *bytes_encoder; // Handles the 16-bit DShot frame
rmt_encoder_t *copy_encoder; // Handles the ending symbols
rmt_symbol_word_t tail_symbol;
uint32_t state;
} rmt_dshot_plus_tail_encoder_t;
static size_t rmt_encode_dshot_with_tail(rmt_encoder_t *encoder,
rmt_channel_handle_t channel,
const void *primary_data,
size_t data_size,
rmt_encode_state_t *ret_state) {
rmt_dshot_plus_tail_encoder_t *dshot_encoder =
__containerof(encoder, rmt_dshot_plus_tail_encoder_t, base);
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
uint32_t state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
uint16_t *dshot_frame = (uint16_t *)primary_data;
rmt_encoder_handle_t bytes_encoder = dshot_encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = dshot_encoder->copy_encoder;
switch (dshot_encoder->state) {
case 0: // Phase 1: Encode the 16-bit DShot Frame
encoded_symbols += bytes_encoder->encode(
bytes_encoder, channel, dshot_frame, sizeof(uint16_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
dshot_encoder->state = 1;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out;
}
// fall-through
case 1: // Phase 2: Encode the 50us Low Tail
encoded_symbols +=
copy_encoder->encode(copy_encoder, channel, &dshot_encoder->tail_symbol,
sizeof(rmt_symbol_word_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
dshot_encoder->state = 0; // Reset for next transmission
state |= RMT_ENCODING_COMPLETE;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out;
}
}
out:
*ret_state = (rmt_encode_state_t)state;
return encoded_symbols;
}
static esp_err_t rmt_del_dshot_with_tail_encoder(rmt_encoder_t *encoder) {
rmt_dshot_plus_tail_encoder_t *dshot_encoder =
__containerof(encoder, rmt_dshot_plus_tail_encoder_t, base);
rmt_del_encoder(dshot_encoder->bytes_encoder);
rmt_del_encoder(dshot_encoder->copy_encoder);
free(dshot_encoder);
return ESP_OK;
}
static esp_err_t rmt_reset_dshot_with_tail_encoder(rmt_encoder_t *encoder) {
rmt_dshot_plus_tail_encoder_t *dshot_encoder =
__containerof(encoder, rmt_dshot_plus_tail_encoder_t, base);
dshot_encoder->state = 0;
rmt_encoder_reset(dshot_encoder->bytes_encoder);
rmt_encoder_reset(dshot_encoder->copy_encoder);
return ESP_OK;
}
dshot_result_t init_dshot_encoder_tail(rmt_encoder_handle_t *out_encoder,
const rmt_ticks_t &rmt_ticks,
uint16_t pulse_level,
uint16_t idle_level) {
auto *dshot_encoder = (rmt_dshot_plus_tail_encoder_t *)calloc(
1, sizeof(rmt_dshot_plus_tail_encoder_t));
if (!dshot_encoder)
return {false, DSHOT_ENCODER_INIT_FAILED};
// 1. Initialize Bytes Encoder (DShot Logic)
rmt_bytes_encoder_config_t bytes_config = {
.bit0 = {.duration0 = rmt_ticks.t0h_ticks,
.level0 = pulse_level,
.duration1 = rmt_ticks.t0l_ticks,
.level1 = idle_level},
.bit1 = {.duration0 = rmt_ticks.t1h_ticks,
.level0 = pulse_level,
.duration1 = rmt_ticks.t1l_ticks,
.level1 = idle_level},
.flags = {.msb_first = 1}};
if (rmt_new_bytes_encoder(&bytes_config, &dshot_encoder->bytes_encoder) !=
ESP_OK) {
free(dshot_encoder);
return {false, DSHOT_ENCODER_INIT_FAILED};
}
// 2. Initialize Copy Encoder (Tail Logic)
rmt_copy_encoder_config_t copy_config = {};
if (rmt_new_copy_encoder(&copy_config, &dshot_encoder->copy_encoder) !=
ESP_OK) {
rmt_del_encoder(dshot_encoder->bytes_encoder);
free(dshot_encoder);
return {false, DSHOT_ENCODER_INIT_FAILED};
}
// 3. Setup the 50us Tail Symbol
// Assuming 80MHz resolution if not provided, or calculate based on rmt_ticks
// Since we don't have resolution_hz, we can estimate from rmt_ticks.t0h_ticks
// + t0l_ticks DShot600 total bit time is ~1.67us.
uint32_t ticks_per_us =
(rmt_ticks.t0h_ticks + rmt_ticks.t0l_ticks) * 600000 / 1000000;
if (ticks_per_us == 0)
ticks_per_us = 80; // Fallback for 80MHz
//
uint32_t ticks_50us = ticks_per_us * 50;
// Assigning members directly to avoid union/struct initialization ambiguity
dshot_encoder->tail_symbol.duration0 =
(uint16_t)(ticks_50us & 0x7FFF); // Mask to 15 bits
dshot_encoder->tail_symbol.level0 = (uint16_t)idle_level;
dshot_encoder->tail_symbol.duration1 = 0;
dshot_encoder->tail_symbol.level1 = (uint16_t)idle_level;
// 4. Link Interface
dshot_encoder->base.encode = rmt_encode_dshot_with_tail;
dshot_encoder->base.reset = rmt_reset_dshot_with_tail_encoder;
// dshot_encoder->base.del = rmt_del_dshot_with_tail_encoder;
*out_encoder = &dshot_encoder->base;
ESP_LOGI("DSHOT", "Encoder initialized at %p, encode fn at %p", dshot_encoder,
dshot_encoder->base.encode);
ESP_LOGI("DSHOT", "Internal Bytes Encoder: %p", dshot_encoder->bytes_encoder);
ESP_LOGI("DSHOT", "Internal Copy Encoder: %p", dshot_encoder->copy_encoder);
return {true, DSHOT_ENCODER_INIT_SUCCESS};
}

View File

@ -1,6 +1,7 @@
/**
* @file dshot_init.h
* @brief RMT configuration and initialization function declarations for DShotRMT library
* @brief RMT configuration and initialization function declarations for
* DShotRMT library
* @author Wastl Kraus
* @date 2025-10-04
* @license MIT
@ -14,10 +15,22 @@
#include "dshot_definitions.h"
// Function to initialize the RMT TX channel
dshot_result_t init_rmt_tx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_channel, bool is_bidirectional);
dshot_result_t init_rmt_tx_channel(gpio_num_t gpio,
rmt_channel_handle_t *out_channel,
bool is_bidirectional);
// Function to initialize the RMT RX channel
dshot_result_t init_rmt_rx_channel(gpio_num_t gpio, rmt_channel_handle_t *out_channel, rmt_rx_event_callbacks_t *rx_event_callbacks, void *user_data);
dshot_result_t init_rmt_rx_channel(gpio_num_t gpio,
rmt_channel_handle_t *out_channel,
rmt_rx_event_callbacks_t *rx_event_callbacks,
void *user_data);
// Function to initialize the DShot RMT encoder
dshot_result_t init_dshot_encoder(rmt_encoder_handle_t *out_encoder, const rmt_ticks_t &rmt_ticks, uint16_t pulse_level, uint16_t idle_level);
dshot_result_t init_dshot_encoder(rmt_encoder_handle_t *out_encoder,
const rmt_ticks_t &rmt_ticks,
uint16_t pulse_level, uint16_t idle_level);
dshot_result_t init_dshot_encoder_tail(rmt_encoder_handle_t *out_encoder,
const rmt_ticks_t &rmt_ticks,
uint16_t pulse_level,
uint16_t idle_level);