Skip to content

Commit 6c3c79f

Browse files
committed
fix: mise à jour de la doc TMC
1 parent 6e74903 commit 6c3c79f

1 file changed

Lines changed: 62 additions & 117 deletions

File tree

doc/TMC4671.md

Lines changed: 62 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,110 @@
11
# TMC4671 Class State Machine Documentation
22

3-
This document describes the operation of the state machine for the `TMC4671` class, which is responsible for controlling the Trinamic TMC4671 motor driver.
3+
This document describes the operation of the asynchronous state machine for the `TMC4671` class, responsible for controlling the Trinamic TMC4671 motor driver.
44

55
## 1. Possible States
66

7-
The `TMC_ControlState` enum defines all possible states of the machine:
7+
The `TMC_ControlState` enum defines the primary states of the machine:
88

99
```cpp
1010
enum class TMC_ControlState : uint32_t {
11-
uninitialized,
12-
waitPower,
13-
Shutdown,
14-
Running,
15-
EncoderInit,
16-
EncoderFinished,
17-
HardError,
18-
OverTemp,
19-
IndexSearch,
20-
FullCalibration,
21-
ExternalEncoderInit,
22-
Pidautotune,
23-
CoggingCalibration,
24-
SlewRateCalibration
11+
uninitialized, // Initial startup and hardware detection
12+
waitPower, // Waiting for VM (Motor Voltage) to be stable
13+
Shutdown, // Motor stopped, PWM off
14+
Running, // Main operational state (Torque/Velocity/Position)
15+
EncoderInit, // Internal encoder alignment sequence
16+
EncoderFinished, // Encoder ready, waiting for start
17+
HardError, // Fatal error, requires reset
18+
OverTemp, // Thermal protection triggered
19+
IndexSearch, // Searching for encoder index pulse
20+
FullCalibration, // Complete commissioning routine
21+
ExternalEncoderInit, // External encoder setup
22+
Pidautotune, // torque PID auto-tuning
23+
CoggingCalibration, // Anti-cogging map generation
24+
SlewRateCalibration, // Maximum current ramp measurement
25+
NONE // Placeholder for recovery logic
2526
};
2627
```
2728
2829
## 2. State Control Variables
2930
30-
- `TMC_ControlState state`: Contains the current state of the machine.
31-
- `TMC_ControlState laststate`: Saves the previous state before a transition to a temporary state (like a calibration), allowing a return to the normal operating state.
32-
- `TMC_ControlState requestedState`: The desired destination state. The transition only occurs if `allowStateChange` is true.
33-
- `bool allowStateChange`: A lock that prevents state changes during critical operations to ensure their complete execution.
31+
- `TMC_ControlState state`: The current active state.
32+
- `TMC_ControlState laststate`: Saves the previous state to allow returning after temporary routines (e.g., calibrations).
33+
- `TMC_ControlState requestedState`: The next intended state, applied in the next loop tick.
34+
- `TMC_ControlState postPowerState`: Stores a calibration state to be resumed automatically after a power loss/recovery cycle.
35+
- `bool allowStateChange`: A lock that prevents external state transitions during critical internal procedures.
3436
35-
## 3. Transition Mechanism
37+
## 3. Asynchronous Transition Mechanism
3638
3739
The `changeState(TMC_ControlState newState, bool force = false)` method manages transitions:
38-
- **`force = true`**: The state change is immediate (`state = newState`). Used for critical or internal machine transitions.
39-
- **`force = false`**: The request is stored in `requestedState`. The actual transition occurs in the main `Run()` loop when `allowStateChange` is `true`.
40+
- **`force = true`**: Immediate state change (`state = newState`). Used for critical failures or internal state machine logic.
41+
- **`force = false`**: Requests a transition by setting `requestedState`. The change is applied at the beginning of the next `Run()` iteration if `allowStateChange` is `true`.
4042
4143
## 4. Detailed Description of States and Transitions
4244
43-
The main logic is implemented in the `Run()` method, which is an infinite loop containing a `switch` on the current state.
45+
The logic is executed within the `Run()` thread loop. To maintain responsiveness and prevent stack overflows, the state machine is strictly non-blocking.
4446
4547
---
4648
4749
### **State: `uninitialized`**
48-
- **Role**: First state on startup.
49-
- **Actions**:
50-
1. Attempts to communicate with the TMC4671 driver via the `pingDriver()` function.
51-
2. If communication is successful, calls `initialize()` to write the basic configuration (PWM frequency, motor type, etc.).
52-
- **Transitions**:
53-
- **➡️ `waitPower`**: If `pingDriver()` and `initialize()` succeed.
54-
- **(Stays)**: If `pingDriver()` fails, remains in this state and retries after a delay.
55-
- **Associated Commands**: No direct user commands. This is an automatic initialization step.
50+
- **Role**: Hardware discovery.
51+
- **Actions**: Pings the driver and calls `initialize()` to set PWM frequency, motor type, and basic registers.
52+
- **Transition**: ➡️ `waitPower` on success.
5653
5754
---
5855
5956
### **State: `waitPower`**
60-
- **Role**: Wait for the motor power supply to be stable and sufficient.
61-
- **Actions**:
62-
1. Periodically checks the supply voltage via `hasPower()`.
63-
2. Once the voltage is stable, calls `initializeWithPower()`, which performs ADC calibration.
64-
- **Transitions**:
65-
- **➡️ `EncoderInit`** or **`ExternalEncoderInit`**: If the power is stable but the encoder is not yet aligned (`!encoderAligned`).
66-
- **➡️ `requestedState`** (usually `Running` or `Shutdown`): If the power is stable and the encoder is already aligned.
67-
- **(Stays)**: As long as `hasPower()` returns `false`.
68-
- **Special Logic**: If a voltage loss is detected in another state (e.g., `Running`), the machine immediately switches to `waitPower` to ensure a clean recovery when the voltage returns.
69-
70-
---
71-
72-
### **State: `Shutdown`**
73-
- **Role**: A safe resting state where the motor is stopped.
57+
- **Role**: Monitors supply voltage (VM).
7458
- **Actions**:
75-
1. Ensures that PWM is disabled (`setPwm(TMC_PwmMode::off)`).
76-
2. The motor is freewheeling or braked, depending on the hardware configuration.
77-
- **Transitions**:
78-
- **➡️ `Running`**: Triggered by a call to `startMotor()`.
79-
- **Associated Commands**: `stopMotor()` leads to this state.
59+
1. Checks `hasPower()`.
60+
2. Once stable (5 consecutive successful checks), calls `initializeWithPower()` for ADC calibration.
61+
- **Post-Power Recovery**: If `postPowerState` is not `NONE`, the machine automatically transitions to that state (e.g., resuming a Cogging calibration that was interrupted by a power cut).
8062
8163
---
8264
8365
### **State: `Running`**
84-
- **Role**: The main operational state where the motor is active and controlled.
85-
- **Actions**:
86-
1. Applies the requested torque, velocity, or position.
87-
2. Continuously monitors the driver status (`statusCheck()`), temperature (`getTemp()`), and the hardware emergency stop status.
88-
3. Applies torque compensation (anti-cogging) if enabled.
89-
- **Transitions**:
90-
- **➡️ `waitPower`**: If an undervoltage is detected.
91-
- **➡️ `OverTemp`**: If the temperature exceeds the configured limit.
92-
- **➡️ `Shutdown`**: Triggered by a call to `stopMotor()`.
93-
- **Associated Commands**: `turn()`, `setTargetPos()`, `setTargetVelocity()`.
66+
- **Role**: Main control loop.
67+
- **Actions**: Applies real-time torque, velocity, or position. Monitors temperature and driver status flags.
68+
- **Anti-Cogging**: Applies real-time torque compensation from the Flash-stored map at ~1kHz.
9469
9570
---
9671
97-
### **Encoder Initialization States: `EncoderInit` & `ExternalEncoderInit`**
98-
- **Role**: Manage the complex sequence of aligning the encoder with the motor.
99-
- **Actions**:
100-
- This is a "super-state" that executes a sequence of sub-steps:
101-
1. `estimateABNparams()` / `calibrateAenc()`: Estimates encoder parameters.
102-
2. `findEncoderIndex()`: Searches for the encoder's index pulse (if configured).
103-
3. `bangInitEnc()`: Forces an angle on the motor with high current to determine the offset between the electrical position and the encoder position.
104-
4. `checkEncoder()`: Verifies that the encoder correctly follows the motor's movement.
105-
- **Transitions**:
106-
- **➡️ `EncoderFinished`**: If all steps succeed.
107-
- **➡️ `HardError`**: If a step fails repeatedly.
108-
- **Special Logic**: This state is critical and cannot be interrupted (`allowStateChange = false`).
72+
### **Calibration Sub-State Machines**
10973
110-
---
74+
To avoid blocking the 1KB TMC thread, long calibrations use internal sub-states:
11175
112-
### **State: `EncoderFinished`**
113-
- **Role**: A transient state marking the end of encoder initialization.
114-
- **Actions**:
115-
1. Sets the `encoderAligned` flag to `true`.
116-
- **Transitions**:
117-
- **➡️ `Running`**: If a motor start was requested (`motorEnabledRequested`).
118-
- **➡️ `Shutdown`**: Otherwise, waits in a safe mode.
119-
120-
---
76+
#### **Cogging Calibration (`CoggingState`)**
77+
- **Mechanism**: Iterates through `ForwardWait`, `ForwardMeasure`, `BackwardWait`, `BackwardMeasure`, and `Compute`.
78+
- **Memory Management**: Large calibration arrays (~34KB) are allocated on the **heap** using `std::make_unique<CoggingCalibData>()` only when the calibration starts, and are freed immediately after completion to prevent stack overflow.
12179
122-
### **Calibration States: `FullCalibration`, `Pidautotune`, `CoggingCalibration`, `SlewRateCalibration`**
123-
- **Role**: Execute specific calibration routines initiated by the user.
124-
- **Actions**:
125-
- Each state executes a specific calibration algorithm (e.g., `calibrateCogging()` measures the motor's detent torque).
126-
- **Transitions**:
127-
- **➡️ `laststate`**: After the calibration is finished, the machine returns to the previous state (usually `Running` or `Shutdown`).
128-
- **Associated Commands**: `calibrate`, `pidautotune`, `calibrateCogging`.
129-
- **Special Logic**: These states are blocking (`allowStateChange = false`).
130-
- **Prerequisites**: For the calibrations to work correctly, the motor must be in a fully initialized state (encoder aligned, etc.) and powered. The state machine checks for power (`hasPower()`) before launching the routine.
80+
#### **PID Auto-Tune (`PidTuneState`)**
81+
- **Mechanism**: Iterates through `RampFluxP`, `TuneFluxI_Pulse`, and `TuneFluxI_Measure`.
82+
- **Asynchronicity**: Replaces `while` loops with tick-based measurements. If power is lost during tuning, it resets to `waitPower` and marks `postPowerState` for resumption.
13183
13284
---
13385
134-
### **Error States: `HardError` & `OverTemp`**
135-
- **Role**: Handle critical error conditions.
136-
- **`OverTemp`**:
137-
- **Cause**: Driver temperature is too high.
138-
- **Action**: Immediately stops the motor.
139-
- **Transition**: **➡️ `HardError`**.
140-
- **`HardError`**:
141-
- **Cause**: Unrecoverable error (ADC calibration failure, repeated encoder alignment failure, overheating).
142-
- **Action**: Blocks the state machine. The driver is completely disabled.
143-
- **Transition**: None. A hardware reset is required to exit this state.
144-
145-
## 5. Notable Points and Potential "Illogisms"
146-
147-
1. **Complex Transition Management**: The `requestedState` and `allowStateChange` system is powerful but can make debugging difficult. A user command may not have an immediate effect if the machine is in a critical state that has locked transitions.
148-
2. **Recovery after Power Loss**: The systematic transition to `waitPower` in case of undervoltage is a good design practice, as it ensures the system will not attempt to operate under unstable conditions and will re-initialize correctly (re-calibrating ADCs, etc.) when power is restored.
149-
3. **`HardError` is a Final State**: Once in the `HardError` state, the system is blocked. This is a safety measure, but it means that no software recovery attempt is possible without a restart.
150-
4. **Encoder Initialization Sequence**: The `encoderInit()` function is the core of the motor's commissioning. It is long and complex, with multiple steps that must succeed. A failure at any stage can lead to an error state, which makes it robust but potentially difficult to diagnose without detailed logs.
151-
5. **Use of `laststate`**: Storing `laststate` is essential for calibration routines. It allows the user to launch a calibration from the `Running` state and then automatically return to it without manual intervention.
86+
## 5. Memory and Stack Vigilance
87+
88+
- **Stack Limit**: The TMC thread stack is limited (`TMC_THREAD_MEM = 256` words / 1KB).
89+
- **Heap Allocation**: Any large data structure (like the `CoggingCalibData` struct) **must** be allocated on the heap.
90+
- **Safety**: Always initialize local variables (e.g., when reading from Flash) to prevent erratic behavior from uninitialized memory.
15291
15392
---
15493
155-
## 6. Interaction with User Commands and Safety
94+
## 6. FreeRTOS Safety and Critical Sections
95+
96+
There is a strict orchestration requirement for hardware initialization to avoid FreeRTOS crashes:
15697
157-
When a user command triggers a long action like a calibration (`calibrateCogging`, `pidautotune`, etc.), the `CommandHandler` calls `changeState()` to request a transition to the corresponding calibration state (e.g., `TMC_ControlState::CoggingCalibration`).
98+
1. **No Blocking in Critical Sections**: Calls like `xSemaphoreTake` (used in SPI transfers), `vTaskDelay`, or `Task Creation` must **never** occur inside a `cpp_freertos::CriticalSection`.
99+
2. **Driver Instantiation Pattern**: In `Axis::setDrvType`, the `TMC4671` object is instantiated **outside** the critical section. This allows its constructor to safely use SPI/Semaphores to read Flash and configure registers.
100+
3. **The Swap**: The critical section is used only for the micro-second duration required to swap the `std::unique_ptr` driver pointers and update the slew rate values.
101+
4. **Deferred Cleanup**: Old driver objects are deleted **after** exiting the critical section to ensure their destructors do not block while interrupts are disabled.
158102
159-
The safety of these operations is guaranteed by the following mechanism:
103+
---
160104
161-
1. **State Locking**: At the beginning of each calibration state, the `allowStateChange` variable is set to `false`. This "locks" the state machine, preventing any new command or event (like a power loss) from causing an unexpected state change while the calibration routine is in progress.
162-
2. **Blocking Execution**: The calibration function (`calibrateCogging()`, `measureMaxSlewRate()`, etc.) is called and runs to completion.
163-
3. **Unlocking and Return**: Once the calibration is finished, `allowStateChange` is set back to `true`, and a call to `changeState(laststate, false)` is made. This requests the machine to return cleanly to the state it was in before the calibration began (usually `Running` or `Shutdown`).
105+
## 7. Interaction with User Commands
164106
165-
This model ensures that a calibration cannot be interrupted and that the system cannot end up in an inconsistent state following a user command.
107+
User commands (`calibrate`, `cogging`, `pidautotune`) trigger a `changeState()` request.
108+
1. The command sets `allowStateChange = false` to lock the machine.
109+
2. The `Run()` loop processes the calibration sub-states tick-by-tick.
110+
3. Upon completion (Success or Fail), `allowStateChange` is set to `true`, and the machine returns to `laststate` (usually `Running` or `Shutdown`).

0 commit comments

Comments
 (0)