Skip to content

Initialisation

Vortex::EnsureInitialized() brings every manager up, one at a time, in a fixed order. Call it once, early in app_main(), before you touch any manager.

Initialisation order: NvsManager, CommChannelsManager, GpioManager, LedManager are required; then MotorController, AdcManager, ImuManager, EncoderManager, TemperatureManager are best effort and only produce warnings if they fail.Initialisation order: NvsManager, CommChannelsManager, GpioManager, LedManager are required; then MotorController, AdcManager, ImuManager, EncoderManager, TemperatureManager are best effort and only produce warnings if they fail.
Vortex::EnsureInitialized()
Figure description and sources

Left to right, then the second row. The facade initialises the managers one at a time, in the order of the calls in its init function. The first group is required: if any of them fails, EnsureInitialized() returns false and the application should not continue. The second group is best effort: a failure there is logged as a warning, the manager stays unavailable and the system reports itself as degraded, so a bench with only some chips fitted still comes up. The order and the required / best-effort split are read from the init function, which returns false only in the required branches.

Drawn from: lib/api/Vortex.cpp Vortex::InitializeAllComponents; figure module docs/diagrams/figures/init-order.py.

The order

From Vortex.cpp (Vortex::InitializeAllComponents); do not edit.

Step Manager Member If it fails
1 NvsManager vortex.nvs initialisation fails (EnsureInitialized() returns false)
2 CommChannelsManager vortex.comms initialisation fails (EnsureInitialized() returns false)
3 GpioManager vortex.gpio initialisation fails (EnsureInitialized() returns false)
4 LedManager vortex.leds initialisation fails (EnsureInitialized() returns false)
5 MotorController vortex.motors warning; the system runs degraded
6 AdcManager vortex.adc warning; the system runs degraded
7 ImuManager vortex.imu warning; the system runs degraded
8 EncoderManager vortex.encoders warning; the system runs degraded
9 TemperatureManager vortex.temp warning; the system runs degraded

The order follows the dependencies: storage first, so configuration and calibration can be read early; then the buses; then the GPIO pins, which include the PCAL95555 expander lines the TMC9660 needs; then the status LED, early so an LED-only bench works without the motor controller. After that come the managers that depend on the TMC9660: AdcManager reads its channels through the TMC9660, and TemperatureManager reads the NTC through AdcManager and the chip temperature from the TMC9660.

What happens when a step fails

  • Required steps (NVS, comms, GPIO, LEDs). If one fails, EnsureInitialized() fails closed: it shuts down, in reverse order, every manager that had come up, so no bus, pin or handler is left open behind a facade that says it is not initialised. It returns false, GetLastError() says why (BusUnavailable, InitFailed, ...), and calling EnsureInitialized() again retries from the start. Each manager also fails closed on its own: a manager whose Initialize() fails releases what it had opened before it returns.
  • Best-effort steps (motors, ADC, IMU, encoders, temperature). A failure is logged as a warning and the manager stays unavailable; the remaining steps still run and EnsureInitialized() returns true. The log then says Initialized in degraded mode and lists which of Motors, ADC, IMU, Enc and Temp are OFF. Check vortex.motors.IsInitialized() (or the diagnostics) before relying on a best-effort manager.
  • The motor controller is the exception to "just a warning". If MotorController does not come up, the facade drives the TMC9660 driver-enable line (PCAL_TMC_DRV_EN) inactive, so a chip that half-booted cannot leave its gate drivers enabled. Shutdown() does the same before it releases the motor controller.

This lets a bench with only some chips fitted, or with the motor supply off, still come up and log.

The onboard TMC9660 and its transport

Step 5 creates the onboard TMC9660 before initialising MotorController. It takes the four TMC9660 control lines (reset, driver enable, fault, wake) from GpioManager, which is why GPIO comes first, and registers the chip on one of two host links:

Transport How to select it What happens
UART (default) nothing TMCL over the UART at TMCL address 1; the SPI mux pin PCAL_TMC_SPI_COMM_EN stays released
SPI Vortex::SetOnboardTmc9660Transport(VortexOnboardTmc9660Transport::Spi) before EnsureInitialized() TMCL over SPI2; MotorController asserts the SPI mux while it talks to the chip

SetOnboardTmc9660Transport() is ignored (with a warning) once initialisation has completed.

Calling a manager directly

Every manager has its own EnsureInitialized(), which returns true at once if the manager is already up. Code that uses one manager on its own can call it, but going through Vortex::EnsureInitialized() gives the right order, the onboard TMC9660 registration and the system diagnostics. EncoderManager creates no device by itself; see EncoderManager.

Shutting down

Vortex::Shutdown() de-initialises every initialised manager, in this order: temperature, LEDs, encoders, IMU, ADC, motors, GPIO, comms, NVS. That is the start-up order reversed except for the LED manager, which is shut down second although it starts fourth. It then clears the initialised flag, so a later EnsureInitialized() starts again from the beginning. It returns false if the HAL was not initialised.