working hack
This commit is contained in:
parent
4f731edaea
commit
86d6823132
|
|
@ -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,7 +58,7 @@ dshot_result_t DShotRMT::begin() {
|
|||
}
|
||||
}
|
||||
|
||||
result = init_dshot_encoder(&_dshot_encoder, _rmt_ticks, _pulse_level,
|
||||
result = init_dshot_encoder_tail(&_dshot_encoder, _rmt_ticks, _pulse_level,
|
||||
_idle_level);
|
||||
|
||||
if (!result.success) {
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
.flags = {
|
||||
.invert_out = static_cast<uint32_t>(is_bidirectional ? 1 : 0),
|
||||
.with_dma = 0,
|
||||
.init_level = 0,
|
||||
.with_dma = 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(©_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};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue