...add simple error messages

This commit is contained in:
Wastl Kraus 2025-08-06 00:32:03 +02:00
parent 51bdeeedc4
commit 772024671b
3 changed files with 55 additions and 78 deletions

View File

@ -46,21 +46,21 @@ bool DShotRMT::begin()
// Init TX Channel // Init TX Channel
if (!_initTXChannel()) if (!_initTXChannel())
{ {
Serial.println("Failed to initialize TX channel"); Serial.println(DSHOT_MSG_01);
return DSHOT_ERROR; return DSHOT_ERROR;
} }
// Init RX Channel // Init RX Channel
if (!_initRXChannel() && _is_bidirectional) if (!_initRXChannel() && _is_bidirectional)
{ {
Serial.println("Failed to initialize RX channel"); Serial.println(DSHOT_MSG_02);
return DSHOT_ERROR; return DSHOT_ERROR;
} }
// Init DShot Decoder // Init DShot Decoder
if (!_initDShotEncoder()) if (!_initDShotEncoder())
{ {
Serial.println("Failed to initialize encoder"); Serial.println(DSHOT_MSG_02);
return DSHOT_ERROR; return DSHOT_ERROR;
} }
@ -74,6 +74,7 @@ bool DShotRMT::setThrottle(uint16_t throttle)
// Precheck throttle value // Precheck throttle value
if (throttle < DSHOT_THROTTLE_MIN || throttle > DSHOT_THROTTLE_MAX) if (throttle < DSHOT_THROTTLE_MIN || throttle > DSHOT_THROTTLE_MAX)
{ {
Serial.println(DSHOT_MSG_06);
return DSHOT_ERROR; return DSHOT_ERROR;
} }
@ -86,9 +87,10 @@ bool DShotRMT::setThrottle(uint16_t throttle)
// //
bool DShotRMT::sendDShotCommand(uint16_t command) bool DShotRMT::sendDShotCommand(uint16_t command)
{ {
// Precheck throttle value // Precheck command value
if (command < DSHOT_CMD_MOTOR_STOP || command > DSHOT_CMD_MAX) if (command < DSHOT_CMD_MOTOR_STOP || command > DSHOT_CMD_MAX)
{ {
Serial.println(DSHOT_MSG_07);
return DSHOT_ERROR; return DSHOT_ERROR;
} }
@ -99,21 +101,24 @@ bool DShotRMT::sendDShotCommand(uint16_t command)
} }
// //
uint32_t DShotRMT::getERPM() uint16_t DShotRMT::getERPM()
{ {
if (!_is_bidirectional || !_rmt_rx_channel) if (!_is_bidirectional || !_rmt_rx_channel)
{ {
Serial.println(DSHOT_MSG_08);
return _last_erpm; return _last_erpm;
} }
// Try to receive telemetry data // Try to receive telemetry data
rmt_symbol_word_t _rx_symbols[RX_BUFFER_SIZE];
if (!rmt_receive(_rmt_rx_channel, _rx_symbols, DSHOT_SYMBOLS_SIZE, &_receive_config)) if (!rmt_receive(_rmt_rx_channel, _rx_symbols, DSHOT_SYMBOLS_SIZE, &_receive_config))
{ {
Serial.println(DSHOT_MSG_09);
return _last_erpm; return _last_erpm;
} }
// Decode the response // Decode the response
uint16_t new_erpm = _decodeDShotFrame(_rx_symbols, DSHOT_BITS_PER_FRAME); uint16_t new_erpm = _decodeDShotFrame(_rx_symbols);
if (new_erpm != 0) if (new_erpm != 0)
{ {
_last_erpm = new_erpm; _last_erpm = new_erpm;
@ -139,12 +144,13 @@ bool DShotRMT::_initTXChannel()
_tx_channel_config.mem_block_symbols = DSHOT_SYMBOLS_SIZE; _tx_channel_config.mem_block_symbols = DSHOT_SYMBOLS_SIZE;
_tx_channel_config.trans_queue_depth = TX_BUFFER_SIZE; _tx_channel_config.trans_queue_depth = TX_BUFFER_SIZE;
//
_transmit_config.loop_count = 0; _transmit_config.loop_count = 0;
// ...it's a trap // ...it's a trap
_transmit_config.flags.eot_level = _is_bidirectional ? 1 : 0; _transmit_config.flags.eot_level = _is_bidirectional ? 1 : 0;
// Creates and activate RMT TX Channel // Creates and activates RMT TX Channel
if (rmt_new_tx_channel(&_tx_channel_config, &_rmt_tx_channel) != DSHOT_OK) if (rmt_new_tx_channel(&_tx_channel_config, &_rmt_tx_channel) != DSHOT_OK)
{ {
return DSHOT_ERROR; return DSHOT_ERROR;
@ -165,7 +171,7 @@ bool DShotRMT::_initRXChannel()
_receive_config.signal_range_min_ns = 300; _receive_config.signal_range_min_ns = 300;
_receive_config.signal_range_max_ns = 5000; _receive_config.signal_range_max_ns = 5000;
// Create and activate RMT TX Channel // Creates and activates RMT TX Channel
if (rmt_new_rx_channel(&_rx_channel_config, &_rmt_rx_channel) != DSHOT_OK) if (rmt_new_rx_channel(&_rx_channel_config, &_rmt_rx_channel) != DSHOT_OK)
{ {
return DSHOT_ERROR; return DSHOT_ERROR;
@ -185,16 +191,16 @@ bool DShotRMT::_initDShotEncoder()
// Use RMT to transmit a prepared DShot packet and returns it // Use RMT to transmit a prepared DShot packet and returns it
bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet) bool DShotRMT::_sendDShotFrame(const dshot_packet_t &packet)
{ {
// // Exclude calculation from timing is more stable
rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME];
_encodeDShotFrame(packet, tx_symbols);
// Checking timer signal
if (_timer_signal()) if (_timer_signal())
{ {
// Encodes packet directly into RMT Buffer
rmt_symbol_word_t tx_symbols[DSHOT_BITS_PER_FRAME];
_encodeDShotFrame(packet, tx_symbols);
// Trigger RMT Transmit // Trigger RMT Transmit
rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, DSHOT_SYMBOLS_SIZE, &_transmit_config); rmt_transmit(_rmt_tx_channel, _dshot_encoder, tx_symbols, DSHOT_SYMBOLS_SIZE, &_transmit_config);
// Time Stamp // Time Stamp
return _timer_reset(); return _timer_reset();
} }
@ -217,14 +223,14 @@ uint16_t DShotRMT::_calculateCRC(const dshot_packet_t &packet)
return crc; return crc;
} }
// // Returns bitwise parsed DShot packet
uint16_t DShotRMT::_parseDShotPacket(const dshot_packet_t &packet) uint16_t DShotRMT::_parseDShotPacket(const dshot_packet_t &packet)
{ {
// Parses DShot Frame
uint16_t data = (packet.throttle_value << 1) | packet.telemetric_request; uint16_t data = (packet.throttle_value << 1) | packet.telemetric_request;
return (data << 4) | _calculateCRC(packet); return (data << 4) | _calculateCRC(packet);
} }
// Returns a "true" DShot Packet ready to roll
dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value) dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value)
{ {
// DShot Frame Container // DShot Frame Container
@ -239,10 +245,10 @@ dshot_packet_t DShotRMT::_buildDShotPacket(const uint16_t value)
return packet; return packet;
} }
// // Encodes DShot packet into RMT buffer
bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols) bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols)
{ {
// Decoding "raw" DShot Packet // Parse actual packet into buffer
_current_packet = _parseDShotPacket(packet); _current_packet = _parseDShotPacket(packet);
// Convert the parsed dshot frame to rmt_tx data // Convert the parsed dshot frame to rmt_tx data
@ -269,7 +275,7 @@ bool IRAM_ATTR DShotRMT::_encodeDShotFrame(const dshot_packet_t &packet, rmt_sym
} }
// //
uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t symbol_count) uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols)
{ {
uint16_t received_frame = 0; uint16_t received_frame = 0;
@ -282,10 +288,10 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t sy
// Extract payload and CRC // Extract payload and CRC
uint16_t data = received_frame >> 4; uint16_t data = received_frame >> 4;
uint8_t received_crc = received_frame & 0b0000000000001111; uint16_t received_crc = received_frame & 0b0000000000001111;
// Calculate CRC for received frame // Calculate CRC for received frame
uint8_t calculated_crc = (data ^ (data >> 4) ^ (data >> 8)) & 0b0000000000001111; uint16_t calculated_crc = (data ^ (data >> 4) ^ (data >> 8)) & 0b0000000000001111;
if (_is_bidirectional) if (_is_bidirectional)
{ {
calculated_crc = (~calculated_crc) & 0b0000000000001111; calculated_crc = (~calculated_crc) & 0b0000000000001111;
@ -294,25 +300,23 @@ uint16_t DShotRMT::_decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t sy
// Compare CRC // Compare CRC
if (received_crc != calculated_crc) if (received_crc != calculated_crc)
{ {
Serial.println("RX CRC Check failed"); Serial.println(DSHOT_MSG_04);
return 0b0000000000000000; return 0b0000000000000000;
} }
// Remove telemetry bit and return eRPM // Removes telemetry bit and returns 10bit value
return data >> 1; return data >> 1;
} }
// // Timer triggered
bool DShotRMT::_timer_signal() bool DShotRMT::_timer_signal()
{ {
// Timer triggered
return (micros() - _last_transmission_time) >= _frame_time_us; return (micros() - _last_transmission_time) >= _frame_time_us;
} }
// // Updates timestamp
bool DShotRMT::_timer_reset() bool DShotRMT::_timer_reset()
{ {
// Timestamp update
_last_transmission_time = micros(); _last_transmission_time = micros();
return DSHOT_OK; return DSHOT_OK;
} }

View File

@ -13,10 +13,6 @@
#include <driver/gpio.h> #include <driver/gpio.h>
#include <driver/rmt_tx.h> #include <driver/rmt_tx.h>
#include <driver/rmt_rx.h> #include <driver/rmt_rx.h>
#include <hw_defaults.h>
static constexpr bool DSHOT_OK = 0;
static constexpr bool DSHOT_ERROR = 1;
// --- DShot Protocol Constants --- // --- DShot Protocol Constants ---
static constexpr uint16_t DSHOT_THROTTLE_FAILSAFE = 0; static constexpr uint16_t DSHOT_THROTTLE_FAILSAFE = 0;
@ -35,7 +31,7 @@ static constexpr size_t RX_BUFFER_SIZE = 32;
static constexpr size_t DSHOT_SYMBOLS_SIZE = 64; static constexpr size_t DSHOT_SYMBOLS_SIZE = 64;
// --- DShot Mode Select --- // --- DShot Mode Select ---
typedef enum typedef enum dshot_mode_e
{ {
DSHOT_OFF, DSHOT_OFF,
DSHOT150, DSHOT150,
@ -45,7 +41,7 @@ typedef enum
} dshot_mode_t; } dshot_mode_t;
// --- DShot Packet Structure --- // --- DShot Packet Structure ---
typedef struct typedef struct dshot_packet_s
{ {
uint16_t throttle_value : 11; uint16_t throttle_value : 11;
bool telemetric_request : 1; bool telemetric_request : 1;
@ -53,7 +49,7 @@ typedef struct
} dshot_packet_t; } dshot_packet_t;
// --- DShot Timing Config --- // --- DShot Timing Config ---
typedef struct typedef struct dshot_timing_s
{ {
uint16_t frame_length_us; uint16_t frame_length_us;
uint16_t ticks_per_bit; uint16_t ticks_per_bit;
@ -83,14 +79,18 @@ public:
bool sendDShotCommand(uint16_t command); bool sendDShotCommand(uint16_t command);
// Gets eRPM from ESC telemetry // Gets eRPM from ESC telemetry
uint32_t getERPM(); uint16_t getERPM();
// Converts eRPM to motor RPM // Converts eRPM to motor RPM
uint32_t getMotorRPM(uint8_t magnet_count); uint32_t getMotorRPM(uint8_t magnet_count);
// // Returns GPIO Pin
gpio_num_t getGPIO() const { return _gpio; } uint16_t getGPIO() const { return _gpio; }
// Returns "raw" Dshot packet sent by RMT
uint16_t getDShotPacket() { return _current_packet; } uint16_t getDShotPacket() { return _current_packet; }
//
bool is_bidirectional() const { return _is_bidirectional; } bool is_bidirectional() const { return _is_bidirectional; }
private: private:
@ -98,7 +98,7 @@ private:
gpio_num_t _gpio; gpio_num_t _gpio;
dshot_mode_t _mode; dshot_mode_t _mode;
bool _is_bidirectional; bool _is_bidirectional;
uint32_t _frame_time_us; uint16_t _frame_time_us;
// --- DShot Timings --- // --- DShot Timings ---
const dshot_timing_t &_timing_config; const dshot_timing_t &_timing_config;
@ -115,10 +115,9 @@ private:
rmt_receive_config_t _receive_config; rmt_receive_config_t _receive_config;
// --- Buffers --- // --- Buffers ---
rmt_symbol_word_t _rx_symbols[RX_BUFFER_SIZE];
uint16_t _last_erpm; uint16_t _last_erpm;
unsigned long _last_transmission_time;
uint16_t _current_packet; uint16_t _current_packet;
unsigned long _last_transmission_time;
// //
bool _initTXChannel(); bool _initTXChannel();
@ -130,10 +129,20 @@ private:
dshot_packet_t _buildDShotPacket(const uint16_t value); dshot_packet_t _buildDShotPacket(const uint16_t value);
uint16_t _parseDShotPacket(const dshot_packet_t &packet); uint16_t _parseDShotPacket(const dshot_packet_t &packet);
bool IRAM_ATTR _encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols); bool IRAM_ATTR _encodeDShotFrame(const dshot_packet_t &packet, rmt_symbol_word_t *symbols);
uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols, size_t symbol_count); uint16_t _decodeDShotFrame(const rmt_symbol_word_t *symbols);
bool _timer_signal(); bool _timer_signal();
bool _timer_reset(); bool _timer_reset();
// // Error Handling
static constexpr bool DSHOT_OK = 0;
static constexpr bool DSHOT_ERROR = 1;
static constexpr char *DSHOT_MSG_01 = "Failed to initialize TX channel!";
static constexpr char *DSHOT_MSG_02 = "Failed to initialize RX channe!l";
static constexpr char *DSHOT_MSG_03 = "Failed to initialize encoder!";
static constexpr char *DSHOT_MSG_04 = "RX CRC Check failed!";
static constexpr char *DSHOT_MSG_06 = "Throttle value not in range (48 - 2047)!";
static constexpr char *DSHOT_MSG_07 = "Not a valid DShot Command (0 - 47)!";
static constexpr char *DSHOT_MSG_08 = "Bidirectional DShot support not enabled!";
static constexpr char *DSHOT_MSG_09 = "RX RMT module failure!";
}; };

View File

@ -1,36 +0,0 @@
/**
* @file hw_defaults.h
* @brief Some Shortcuts
* @author Wastl Kraus
* @date 2025-08-02
* @license MIT
*/
#ifdef ESP32
// USB-Serial (UART0): GPIO1/3 in use by default
// Serial1
constexpr auto PIN_UART1_TX = GPIO_NUM_13;
constexpr auto PIN_UART1_RX = GPIO_NUM_14;
// Serial2
constexpr auto PIN_UART2_TX = GPIO_NUM_16;
constexpr auto PIN_UART2_RX = GPIO_NUM_17;
// SPI (VSPI)
constexpr auto PIN_SPI_SCLK = GPIO_NUM_18;
constexpr auto PIN_SPI_MISO = GPIO_NUM_19;
constexpr auto PIN_SPI_MOSI = GPIO_NUM_23;
constexpr auto PIN_SPI_SS = GPIO_NUM_5;
// I2C (Wire)
constexpr auto PIN_I2C_SDA = GPIO_NUM_21;
constexpr auto PIN_I2C_SCL = GPIO_NUM_22;
// RMT (5 Channels)
constexpr auto PIN_RMT_CH0 = GPIO_NUM_25;
constexpr auto PIN_RMT_CH1 = GPIO_NUM_26;
constexpr auto PIN_RMT_CH2 = GPIO_NUM_27;
constexpr auto PIN_RMT_CH3 = GPIO_NUM_32;
constexpr auto PIN_RMT_CH4 = GPIO_NUM_33;
#endif // ESP32