working hack
This commit is contained in:
parent
4f731edaea
commit
86d6823132
|
|
@ -39,7 +39,7 @@ DShotRMT::~DShotRMT() { _cleanupRmtResources(); }
|
||||||
|
|
||||||
// Initialize DShotRMT
|
// Initialize DShotRMT
|
||||||
dshot_result_t DShotRMT::begin() {
|
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);
|
MALLOC_CAP_8BIT | MALLOC_CAP_DMA);
|
||||||
dshot_result_t result =
|
dshot_result_t result =
|
||||||
init_rmt_tx_channel(_gpio, &_rmt_tx_channel, _is_bidirectional);
|
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);
|
_idle_level);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
|
|
@ -408,7 +408,7 @@ dshot_result_t DShotRMT::_sendPacket(const dshot_packet_t &packet) {
|
||||||
&tx_config) != DSHOT_OK) {
|
&tx_config) != DSHOT_OK) {
|
||||||
return {false, DSHOT_TRANSMISSION_FAILED};
|
return {false, DSHOT_TRANSMISSION_FAILED};
|
||||||
}
|
}
|
||||||
delayMicroseconds(50);
|
delayMicroseconds(60);
|
||||||
rmt_disable(_rmt_tx_channel);
|
rmt_disable(_rmt_tx_channel);
|
||||||
rmt_enable(_rmt_tx_channel);
|
rmt_enable(_rmt_tx_channel);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ public:
|
||||||
void _cleanupRmtResources();
|
void _cleanupRmtResources();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t *_tx_payload;
|
uint32_t *_tx_payload;
|
||||||
dshot_result_t _sendRawDshotFrame(uint16_t value);
|
dshot_result_t _sendRawDshotFrame(uint16_t value);
|
||||||
static bool IRAM_ATTR _on_rx_done(rmt_channel_handle_t rmt_rx_channel,
|
static bool IRAM_ATTR _on_rx_done(rmt_channel_handle_t rmt_rx_channel,
|
||||||
const rmt_rx_done_event_data_t *edata,
|
const rmt_rx_done_event_data_t *edata,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dshot_init.h"
|
#include "dshot_init.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
// Function to initialize the RMT TX channel
|
// Function to initialize the RMT TX channel
|
||||||
dshot_result_t init_rmt_tx_channel(gpio_num_t gpio,
|
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,
|
.resolution_hz = DSHOT_RMT_RESOLUTION,
|
||||||
.mem_block_symbols = 48,
|
.mem_block_symbols = 48,
|
||||||
.trans_queue_depth = RMT_QUEUE_DEPTH,
|
.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,
|
.init_level = 0,
|
||||||
.with_dma = 0}};
|
}};
|
||||||
|
|
||||||
if (rmt_new_tx_channel(&tx_channel_config, out_channel) != DSHOT_OK) {
|
if (rmt_new_tx_channel(&tx_channel_config, out_channel) != DSHOT_OK) {
|
||||||
return {false, DSHOT_TX_INIT_FAILED};
|
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};
|
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
|
* @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
|
* @author Wastl Kraus
|
||||||
* @date 2025-10-04
|
* @date 2025-10-04
|
||||||
* @license MIT
|
* @license MIT
|
||||||
|
|
@ -14,10 +15,22 @@
|
||||||
#include "dshot_definitions.h"
|
#include "dshot_definitions.h"
|
||||||
|
|
||||||
// Function to initialize the RMT TX channel
|
// 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
|
// 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
|
// 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