How to properly force sensor recalibration without hardware reset or full re-initialization?

Background:
I have a BLDC motor control system using SimpleFOC. The system is installed in a location where power cycling is inconvenient, so I need to perform sensor recalibration (specifically zero_electric_angle and sensor_direction) on-demand while the MCU remains powered.

What I’m trying to do:
I’ve implemented a command doCalib() that should re-run the calibration procedure to determine the electrical angle offset and sensor direction. The idea is to reset the motor’s calibration state and call motor.initFOC() again to trigger the full alignment routine.

My current approach:

cpp

void doCalib(char* cmd) {
    motor.disable();
    
    // Reset calibration parameters
    motor.zero_electric_angle = 0;
    motor.sensor_direction = Direction::UNKNOWN;
    motor.motor_status = FOCMotorStatus::motor_uninitialized;
    
    // Re-initialize hardware components
    driver.init();
    current_sense.init();
    sensor.init();
    motor.linkDriver(&driver);
    motor.linkCurrentSense(&current_sense);
    motor.linkSensor(&sensor);
    
    if (motor.initFOC()) {
        foc_initialized = true;
        motor.enable();
    }
}

The problem:

  • If I skip re-initializing driver, current_sense, and sensor (calling only motor.initFOC() after resetting calibration params), the control loop becomes confused after calibration - the motor starts rotating unexpectedly without receiving a command.

  • If I do re-initialize them, driver.init() fails in the middle of operation and I got “STM32-DRV: no workable combination found on these pins”

  • According to this Pull Request discussion, motor.initFOC() will run calibration if zero_electric_angle and sensor_direction are set to zero and UNKNOWN . But it seems the motor’s internal state isn’t fully reset.

My questions:

  1. Is there a documented or recommended procedure to safely force a re-calibration without a full hardware re-initialization?

  2. Are there internal motor state variables beyond motor_status that need to be reset before calling initFOC() again?

  3. Could the “confused control loop” issue be related to motor.enable() being called after calibration without properly resetting the target values or PID controllers? I’m controlling the motor in torque mode, but after recalibration, it spins without a command.

Hardware details:

  • MCU: STM32

  • Sensor: Magnetic encoder AS5147 - I understand absolute encoders can store calibration values and skip the routine , but I specifically want to re-run the full alignment.

What I’ve tried:

  • Resetting motor.zero_electric_angle = 0 and motor.sensor_direction = Direction::UNKNOWN (works in theory per the API docs )

  • Resetting motor.motor_status = FOCMotorStatus::motor_uninitialized

  • Calling motor.disable() before and motor.enable() after calibration

  • Re-initializing the hardware modules, which fails

Any guidance would be greatly appreciated!

1 Answer

1

A quick search looks like NVIC_SystemReset will do it.

Clearing zero_electric_angle and sensor_direction and calling initFOC should indeed work to recalibrate them without resetting everything else, but if the reason you’re needing to recalibrate is because shaft_angle has grown too large and become unstable due to float precision, then there’s currently no built-in way to recover. I had proposed a solution here a couple years ago, but even better would be for all sensor classes to have a setAngle function as requested here. But it would be a lot of work to implement and test for all sensor classes.

It might work to simply set motor = BLDCMotor(motor.pole_pairs) and sensor = MagneticSensorSPI(AS5147_SPI, 10) or whatever sensor class you’re using, to reset its internal variables. There’s no way to de-init/re-init the driver or current sense, but probably no need to. Although it would be nice if the calibrateOffsets functions in the current sense classes were public so you could re-call them if the readings ever drift for whatever reason.