|
HF-TMC51x0 Driver (TMC5130 & TMC5160) 0.1.0-dev
Hardware Agnostic C++ Driver for the TMC51x0 (TMC5130 & TMC5160)
|
Fatigue test unit with ESP-NOW communication. More...
#include <algorithm>#include <cmath>#include <cstring>#include <string>#include <vector>#include <cstdarg>#include <new>#include <cstdint>#include <inttypes.h>#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "freertos/queue.h"#include "freertos/semphr.h"#include "esp_log.h"#include "esp_timer.h"#include "driver/uart.h"#include "tmc51x0.hpp"#include "test_config/esp32_tmc51x0_bus.hpp"#include "test_config/esp32_tmc_mutex.hpp"#include "registers/tmc51x0_registers.hpp"#include "test_config/esp32_tmc51x0_test_config.hpp"#include "espnow_protocol.hpp"#include "espnow_receiver.hpp"#include "fatigue_motion.hpp"Classes | |
| struct | ParsedCommand |
| Parsed command structure for UART command processing. More... | |
| class | OptionParser |
| Option parser for SET command. More... | |
| struct | OptionParser::OptionDef |
| Option definition structure for SET command options. More... | |
| class | UartCommandParser |
| Redesigned UART command parser with word-based commands. More... | |
Namespaces | |
| namespace | TaskTiming |
| Centralized timing constants for FreeRTOS tasks in this application. | |
| namespace | BoundsCache |
| namespace | FatigueTest |
| namespace | CommandOutput |
| Visual output formatting system for UART command interface. | |
Enumerations | |
| enum class | InternalState : uint8_t { IDLE = 0 , BOUNDS_FINDING , MANUAL_BOUNDS , RUNNING , PAUSED , ERROR } |
| Internal application state machine for the fatigue test unit. More... | |
| enum class | PendingStartKind : uint8_t { NONE = 0 , START , RESUME } |
| Pending start request type. More... | |
| enum class | BoundsTaskMode : uint8_t { FIND_AND_START , FIND_ONLY } |
| Pretty-print motor-current calculated and cached register values under the FatigueTestUnit tag. More... | |
| enum class | CommandType { SET , START , STOP , PAUSE , RESUME , BOUNDS , PAIR , RESET , STATUS , HELP } |
| Command types for word-based commands. More... | |
| enum class | OptionType { VELOCITY , ACCELERATION , DWELL , BOUNDS , CYCLES } |
| Option types for SET command. More... | |
Functions | |
| static void | espnow_command_task (void *arg) |
| FreeRTOS task: process inbound ESP-NOW protocol events. | |
| static void | motion_control_task (void *arg) |
| FreeRTOS task: drive the motion update loop and detect completion. | |
| static void | status_update_task (void *arg) |
FreeRTOS task: periodically send STATUS_UPDATE to the remote controller. | |
| static void | bounds_finding_task (void *arg) |
| FreeRTOS task: perform bounds finding, then start motion. | |
| bool | BoundsCache::AreBoundsValid () noexcept |
| Check if bounds are still valid (within time window and motor energized). | |
| uint32_t | BoundsCache::GetRemainingValiditySec () noexcept |
| Get remaining time until bounds expire (seconds). | |
| void | BoundsCache::MarkBoundsFound () noexcept |
| Mark bounds as freshly found and start de-energize timer. | |
| void | BoundsCache::CancelDeenergizeTimer () noexcept |
| Cancel de-energize timer (e.g., when test starts). | |
| void | BoundsCache::InvalidateBounds () noexcept |
| Invalidate bounds (e.g., on config change or explicit request). | |
| void | BoundsCache::SetValidityMinutes (uint32_t minutes) noexcept |
| Set the validity window in minutes. | |
| void | BoundsCache::Init () noexcept |
| Initialize the bounds cache system (create timer). | |
| static uint8_t | GetBoundsValidFlag_ () noexcept |
| Get bounds validity flag for protocol status updates. | |
| static void | ApplyMotionConfigFromSettings_ () noexcept |
| Apply motion configuration from global settings to the motion controller. | |
| static bool | ShouldCancelBounds () |
| Cancel callback for library homing/bounds routines. | |
| static TestState | ToProtoState (InternalState s) noexcept |
Map the internal application state machine to the protocol-visible TestState. | |
| static void | MotorStopHold () noexcept |
| Immediately stop motion and enter HOLD mode, but keep motor energized. | |
| static void | MotorStopHoldDisable () noexcept |
| Immediately stop motion, enter HOLD, and de-energize (disable) the motor. | |
| static void | FatalInitError (const char *what, uint8_t err_code) noexcept |
| Handle fatal initialization errors. | |
| static bool | MotorEnable () noexcept |
| Enable (energize) the motor power stage. | |
| static bool | SetReducedCurrentForManualBounds () noexcept |
| Set motor current to a reduced level for manual bounds engagement. | |
| static bool | RestoreFullCurrent () noexcept |
| Restore motor current to full rated level after manual bounds positioning. | |
| static void | DeenergizeTimerCallback (void *arg) |
| Timer callback to de-energize motor after bounds validity expires. | |
| static void | RequestStart (PendingStartKind kind) noexcept |
| Request a START/RESUME with optional bounds caching. | |
| static bool | RequestBoundsOnly () noexcept |
| Run bounds finding independently (without starting test). | |
| static bool | HandleSet (const ParsedCommand &cmd, FatigueTest::FatigueTestMotion &motion) noexcept |
| Apply SET command options to the motion controller. | |
| static bool | HandleStart (FatigueTest::FatigueTestMotion &motion) noexcept |
| Handle START command. | |
| static bool | HandleStop (FatigueTest::FatigueTestMotion &motion) noexcept |
| Handle STOP command. | |
| static bool | HandlePause (FatigueTest::FatigueTestMotion &motion) noexcept |
| Handle PAUSE command (UART path). | |
| static bool | HandleResume (FatigueTest::FatigueTestMotion &motion) noexcept |
| Handle RESUME command (UART path). | |
| static bool | HandleReset (FatigueTest::FatigueTestMotion &motion) noexcept |
| Handle RESET command. | |
| static bool | HandleStatus (FatigueTest::FatigueTestMotion &motion) noexcept |
| Handle STATUS command. | |
| static bool | HandleHelp (const std::string &topic) noexcept |
| Handle HELP command. | |
| static bool | HandlePair () noexcept |
| static bool | HandleBounds () noexcept |
| Handle PAIR command. | |
| void | CommandOutput::PrintSuccess (const char *format,...) |
| Print a success message to the ESP-IDF log. | |
| void | CommandOutput::PrintError (const char *format,...) |
| Print an error message to the ESP-IDF log. | |
| void | CommandOutput::PrintInfo (const char *format,...) |
| Print an informational message to the ESP-IDF log. | |
| void | CommandOutput::PrintWarning (const char *format,...) |
| Print a warning message to the ESP-IDF log. | |
| void | CommandOutput::PrintHeader (const char *title) |
| Print a boxed header line for human-readable UART output. | |
| void | CommandOutput::PrintSeparator () |
| Print a boxed separator line for UART output. | |
| void | CommandOutput::PrintFooter () |
| Print a boxed footer line for UART output. | |
| void | CommandOutput::PrintTableRow (const char *label, const char *value) |
| Print a key/value row within the boxed UART output format. | |
| void | CommandOutput::PrintEmptyLine () |
| Print an empty boxed line for spacing in UART output. | |
| void | CommandOutput::PrintCommandResult (const char *command, bool success, const char *details=nullptr) |
| Print a success/failure result line for a command. | |
| static void | uart_command_task (void *arg) |
| FreeRTOS task: poll UART and process commands. | |
| void | app_main () |
Variables | |
| static const char * | TAG = "FatigueTestUnit" |
| static constexpr tmc51x0_test_config::TestRigType | SELECTED_TEST_RIG |
| static constexpr float | BOUNDS_FINDING_CENTER_OFFSET_DEG = -3.6f |
| static constexpr float | OSCILLATION_EDGE_BACKOFF_DEG = 3.6f |
| static constexpr int64_t | TaskTiming::LOG_INTERVAL_US = 5'000'000 |
| static constexpr int64_t | TaskTiming::LOG_INTERVAL_LONG_US = 30'000'000 |
| static constexpr uint32_t | TaskTiming::MOTION_UPDATE_PERIOD_MS = 10 |
| static constexpr int64_t | TaskTiming::SG_LOG_INTERVAL_US = 200'000 |
| static constexpr int64_t | TaskTiming::SG_LOG_INTERVAL_ALWAYS_US = 1'000'000 |
| static constexpr uint32_t | TaskTiming::STATUS_UPDATE_PERIOD_MS = 1'000 |
| static constexpr uint32_t | TaskTiming::UART_POLL_PERIOD_MS = 50 |
| static tmc51x0::TMC51x0< Esp32SPI > * | g_driver = nullptr |
| static Esp32TmcMutex * | g_driver_mutex = nullptr |
| static Settings | g_settings {} |
| static QueueHandle_t | g_espnowQueue = nullptr |
| static uint8_t | g_spi_storage [sizeof(Esp32SPI)] |
| static uint8_t | g_driver_storage [sizeof(tmc51x0::TMC51x0< Esp32SPI >)] |
| static uint8_t | g_motion_storage [sizeof(FatigueTest::FatigueTestMotion)] |
| static Esp32SPI * | g_spi = nullptr |
| static volatile InternalState | g_state = InternalState::IDLE |
| static volatile bool | g_cancel_bounds = false |
| static volatile bool | g_bounds_task_running = false |
| static TaskHandle_t | g_bounds_task_handle = nullptr |
| static bool | g_bounds_found = false |
| static bool | g_use_stallguard = true |
| static bool | g_enable_sg_monitoring = false |
| static constexpr uint32_t | BoundsCache::DEFAULT_VALIDITY_MINUTES = 2 |
| Default time window (in minutes) during which bounds remain valid. | |
| static volatile int64_t | BoundsCache::g_bounds_timestamp_us = 0 |
| Time (microseconds, from esp_timer_get_time) when bounds were last found. | |
| static volatile int64_t | BoundsCache::g_bounds_validity_us = DEFAULT_VALIDITY_MINUTES * 60 * 1000000LL |
| Bounds validity window in microseconds. | |
| static volatile bool | BoundsCache::g_motor_energized_for_bounds = false |
| True if motor is currently energized from bounds finding. | |
| static esp_timer_handle_t | BoundsCache::g_deenergize_timer = nullptr |
| Timer handle for de-energize timeout. | |
| static FatigueTest::FatigueTestMotion * | g_motion = nullptr |
| static volatile PendingStartKind | g_pending_start = PendingStartKind::NONE |
| static constexpr float | MANUAL_BOUNDS_CURRENT_FACTOR = 0.3f |
| Current reduction factor for manual bounds engagement (matches auto bounds) | |
| static volatile BoundsTaskMode | g_bounds_task_mode = BoundsTaskMode::FIND_AND_START |
| static constexpr int | CommandOutput::BOX_WIDTH = 78 |
Fatigue test unit with ESP-NOW communication.
This is the test unit (receiver) that:
Supports both StallGuard2 and encoder-based bounds detection.
|
strong |
Pretty-print motor-current calculated and cached register values under the FatigueTestUnit tag.
The driver already logs these values under the "TMC5160" tag during Initialize(). This function prints the same information again under the application tag so field logs are easier to scan without mixing driver/component tags.
Values are sourced from the driver’s internal calculated fields and write-only register cache via TMC51x0::GetMotorCurrentDebugInfo() (no duplicated math).
| driver | Initialized TMC51x0 driver instance. |
Begin a START/RESUME sequence by launching cancellable bounds finding.
This function transitions the application into InternalState::BOUNDS_FINDING, clears any prior bounds, and starts bounds_finding_task in its own FreeRTOS task.
Bounds are always re-found (even if previously found) to handle the case where mechanical limits may have moved between runs.
| kind | Whether this request originated from START or RESUME. |
ERROR, stops and disables the motor, and sends an error frame.Mode for bounds finding task.
| Enumerator | |
|---|---|
| FIND_AND_START | Find bounds then start test (normal START flow) |
| FIND_ONLY | Find bounds only, keep motor energized with timeout. |
|
strong |
|
strong |
Internal application state machine for the fatigue test unit.
Tracks the current operational state of the test unit. This is separate from the protocol-visible TestState which is mapped via ToProtoState().
State transitions:
|
strong |
|
strong |
| void app_main | ( | void | ) |
ESP-IDF application entry point.
Performs one-time initialization:
Safety policy:
|
inlinestaticnoexcept |
Apply motion configuration from global settings to the motion controller.
Updates the motion controller with current settings from g_settings.test_unit. This includes target cycles, velocity, acceleration, and dwell times.
g_motion is null.
|
static |
FreeRTOS task: perform bounds finding, then start motion.
This task is launched by RequestStart() and exists specifically so that PAUSE/STOP can cancel bounds finding while it is in progress (the bounds finders poll the g_cancel_bounds flag).
Sequence:
g_settings.test_unit) and method (g_use_stallguard)g_driver->homing.FindBounds(..., cancel_cb))g_motion and start motionCancellation rules:
g_cancel_bounds becomes true at any time, the task stops motion, disables the motor, and exits. A later RESUME will re-run bounds finding from scratch.| arg | Unused (FreeRTOS task signature). |
|
static |
Timer callback to de-energize motor after bounds validity expires.
|
static |
FreeRTOS task: process inbound ESP-NOW protocol events.
Events arrive via g_espnowQueue from EspNowReceiver. This task:
g_settings and g_motion| arg | Unused (FreeRTOS task signature). |
bounds_finding_task) so PAUSE/STOP remain responsive.
|
staticnoexcept |
Handle fatal initialization errors.
Called when a critical initialization step fails. This function:
| what | Description of what failed |
| err_code | Error code to send to remote controller |
|
inlinestaticnoexcept |
Get bounds validity flag for protocol status updates.
|
staticnoexcept |
Handle PAIR command.
Enters pairing mode for 30 seconds to allow a remote controller to securely pair with this test unit. The remote controller must also initiate pairing and know the shared PAIRING_SECRET.
Handle BOUNDS command - run bounds finding independently.
Runs bounds finding without starting the test. After bounds are found, the motor stays energized for the configured validity period. If START is requested within this window, bounds finding is skipped.
|
staticnoexcept |
Handle HELP command.
| topic | Optional help topic (e.g. "set", "start"). |
|
staticnoexcept |
|
staticnoexcept |
Handle PAUSE command (UART path).
UART pause/resume are currently not implemented (remote control handles PAUSE/RESUME).
| motion | Motion controller instance (unused). |
|
staticnoexcept |
Handle RESET command.
Resets the cycle counter to 0 (does not start motion).
| motion | Motion controller instance. |
|
staticnoexcept |
Handle RESUME command (UART path).
UART pause/resume are currently not implemented (remote control handles PAUSE/RESUME).
| motion | Motion controller instance (unused). |
|
staticnoexcept |
Apply SET command options to the motion controller.
Validates arguments, applies parameters to motion, and prints a structured success/failure summary. Some options also update global settings (e.g., cycle target).
| cmd | Parsed command containing SET options. |
| motion | Motion controller instance to update. |
|
staticnoexcept |
Handle START command.
UART START behaves like remote START: it launches cancellable bounds finding and then starts motion if bounds succeed. The motor is enabled only during bounds finding and active motion.
| motion | Motion controller instance. |
|
staticnoexcept |
Handle STATUS command.
Prints a human-readable status snapshot (state, bounds, frequency, cycles, dwell).
| motion | Motion controller instance. |
|
staticnoexcept |
Handle STOP command.
STOP is a hard stop: cancels bounds finding (if active), stops motion, sets the internal state to IDLE, and de-energizes the motor.
| motion | Motion controller instance. |
|
static |
FreeRTOS task: drive the motion update loop and detect completion.
Runs at ~10ms period. When g_state == RUNNING, it calls g_motion->Update(). It also logs StallGuard telemetry when StallGuard bounds mode is selected.
Completion:
| arg | Unused (FreeRTOS task signature). |
|
staticnoexcept |
Enable (energize) the motor power stage.
Per requirements, the motor must remain disabled at boot and only be enabled during active operations (bounds finding and active motion).
|
staticnoexcept |
Immediately stop motion and enter HOLD mode, but keep motor energized.
This is used by PAUSE to stop motion while still delivering hold current. The motor remains energized and will hold position.
|
staticnoexcept |
Immediately stop motion, enter HOLD, and de-energize (disable) the motor.
This is the hard-stop safety primitive used by:
It is safe to call multiple times.
g_state; the caller owns state transitions.
|
staticnoexcept |
Run bounds finding independently (without starting test).
After bounds are found, motor stays energized for the configured validity period. If START is requested within this window, bounds finding is skipped.
|
staticnoexcept |
Request a START/RESUME with optional bounds caching.
If bounds were recently found (within validity window) and motor is still energized, bounds finding is skipped and motion starts immediately. Otherwise, bounds finding runs first.
| kind | START or RESUME request type |
|
staticnoexcept |
Restore motor current to full rated level after manual bounds positioning.
Re-applies the original MotorSpec from the driver config to restore run and hold current to their configured values. Called after the motor reaches center position.
|
staticnoexcept |
Set motor current to a reduced level for manual bounds engagement.
Uses ConfigureMotorCurrent() with a modified MotorSpec where run_current_ma and hold_current_ma are scaled by MANUAL_BOUNDS_CURRENT_FACTOR (0.3x rated). This matches the auto bounds finding behavior and prevents excessive holding torque during initial engagement, reducing magnetic misalignment risk.
|
static |
Cancel callback for library homing/bounds routines.
This function is called by the TMC51x0 library's bounds finding routines to check if the operation should be cancelled. The library polls this function during bounds finding to allow graceful cancellation.
|
static |
FreeRTOS task: periodically send STATUS_UPDATE to the remote controller.
Runs at 1Hz and publishes cycle count and a protocol state mapping. While bounds finding is active, we currently report RUNNING via ToProtoState().
| arg | Unused (FreeRTOS task signature). |
|
inlinestaticnoexcept |
Map the internal application state machine to the protocol-visible TestState.
The on-wire protocol only supports a limited set of states. Internally we track additional phases (notably BOUNDS_FINDING). While bounds finding is active the motor is energized and moving, so we currently report TestState::Running.
| s | Internal state value. |
STATUS_UPDATE.
|
static |
FreeRTOS task: poll UART and process commands.
This task calls UartCommandParser::ProcessUartCommands() periodically.
| arg | Pointer to a UartCommandParser instance. |
|
staticconstexpr |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
staticconstexpr |
Current reduction factor for manual bounds engagement (matches auto bounds)
|
staticconstexpr |
|
staticconstexpr |
|
static |