...add simple error messages
This commit is contained in:
parent
51bdeeedc4
commit
772024671b
58
DShotRMT.cpp
58
DShotRMT.cpp
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
DShotRMT.h
39
DShotRMT.h
|
|
@ -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!";
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
Loading…
Reference in New Issue