Skip to main content
Joseph.Paul
Associate II
July 14, 2026
Question

MCSDK PI loop anti-windup?

  • July 14, 2026
  • 3 replies
  • 29 views

I reviewed the code and found anti-windup is not implemented in the loop, is that correct?  Let me know if there is a version with anti-windup implemented, thank you.

3 replies

Gael A
ST Employee
July 15, 2026

Hello Joseph.Paul,

Could you please tell me which version of the MCSDK you are using ? Also, are you evaluating the 6-STEP or the FOC algorithm ?

If you agree with my answer, please consider accepting it by clicking on 'Accept as solution'.
Joseph.Paul
Associate II
July 21, 2026

Thank you for the help, it is MCSDK ver 6.4.2 with FOC

Gael A
ST Employee
July 21, 2026

Hello Joseph.Paul,

In the MCSDK ver 6.4.2, using FOC algorithms that are not the High Sensitivity Observer, the Anti-Windup is integrated as following.

The output of the integral part of the PID is clamped to maximum_output - Kp_output. This means that the sum of Kp x Error + Ki x Sum(Error) cannot exceed the maximum output. This way, even when the integral term should build up, the total output never stays at its maximum for a long time after the error shrinks.
 

If you agree with my answer, please consider accepting it by clicking on 'Accept as solution'.
Joseph.Paul
Associate II
July 21, 2026

Thank you, also I’m starting FOC code generation for H5 using MCSDK as noted in previous reply.

Blocks I am configuring in MC Workbench include , STMH563ZI (Nucleo Bd) and IHM07M1 (Power module), and motor. 

 

I noticed the PWM configuration is not for general purpose, it is specifically configured for L6230 in IMH07M1.

But I’d like to configure PWM for general purpose,  such as for the STEVAL-LVLP01 board I have evaluated already, is this possible?

 

Please let me know and thank you for your consideration.

Joseph.Paul
Associate II
July 21, 2026

Also, which section of code is assigned to do anti-windup?

 

This is the PI controller from SDK.

 

__weak int16_t PI_Controller(PID_Handle_t *pHandle, int32_t wProcessVarError)

{

  int16_t returnValue;

#ifdef NULL_PTR_CHECK_PID_REG

  if (MC_NULL == pHandle)

  {

    returnValue = 0;

  }

  else

  {

#endif

    int32_t wProportional_Term;

    int32_t wIntegral_Term;

    int32_t wOutput_32;

    int32_t wIntegral_sum_temp;

    int32_t wDischarge = 0;

    int16_t hUpperOutputLimit = pHandle->hUpperOutputLimit;

    int16_t hLowerOutputLimit = pHandle->hLowerOutputLimit;

 

    /* Proportional term computation*/

    wProportional_Term = pHandle->hKpGain * wProcessVarError;

 

    /* Integral term computation */

    if (0 == pHandle->hKiGain)

    {

      pHandle->wIntegralTerm = 0;

    }

    else

    {

      wIntegral_Term = pHandle->hKiGain * wProcessVarError;

      wIntegral_sum_temp = pHandle->wIntegralTerm + wIntegral_Term;

 

      if (wIntegral_sum_temp < 0)

      {

        if (pHandle->wIntegralTerm > 0)

        {

          if (wIntegral_Term > 0)

          {

            wIntegral_sum_temp = INT32_MAX;

          }

          else

          {

            /* Nothing to do */

          }

        }

        else

        {

          /* Nothing to do */

        }

      }

      else

      {

        if (pHandle->wIntegralTerm < 0)

        {

          if (wIntegral_Term < 0)

          {

            wIntegral_sum_temp = -INT32_MAX;

          }

          else

          {

            /* Nothing to do */

          }

        }

        else

        {

          /* Nothing to do */

        }

      }

 

      if (wIntegral_sum_temp > pHandle->wUpperIntegralLimit)

      {

        pHandle->wIntegralTerm = pHandle->wUpperIntegralLimit;

      }

      else if (wIntegral_sum_temp < pHandle->wLowerIntegralLimit)

      {

        pHandle->wIntegralTerm = pHandle->wLowerIntegralLimit;

      }

      else

      {

        pHandle->wIntegralTerm = wIntegral_sum_temp;

      }

    }

 

#ifndef FULL_MISRA_C_COMPLIANCY_PID_REGULATOR

    /* WARNING: the below instruction is not MISRA compliant, user should verify

               that Cortex-M3 assembly instruction ASR (arithmetic shift right)

               is used by the compiler to perform the shifts (instead of LSR

               logical shift right)*/

    //cstat !MISRAC2012-Rule-1.3_n !ATH-shift-neg !MISRAC2012-Rule-10.1_R6

    wOutput_32 = (wProportional_Term >> pHandle->hKpDivisorPOW2) + (pHandle->wIntegralTerm >> pHandle->hKiDivisorPOW2);

#else

    wOutput_32 = (wProportional_Term / (int32_t)pHandle->hKpDivisor)

              + (pHandle->wIntegralTerm / (int32_t)pHandle->hKiDivisor);

#endif

 

    if (wOutput_32 > hUpperOutputLimit)

    {

      wDischarge = hUpperOutputLimit - wOutput_32;

      wOutput_32 = hUpperOutputLimit;

    }

    else if (wOutput_32 < hLowerOutputLimit)

    {

      wDischarge = hLowerOutputLimit - wOutput_32;

      wOutput_32 = hLowerOutputLimit;

    }

    else

    {

      /* Nothing to do here */

    }

 

    pHandle->wIntegralTerm += wDischarge;

    returnValue = (int16_t)wOutput_32;

#ifdef NULL_PTR_CHECK_PID_REG

  }

#endif

  return (returnValue);

}