/** ****************************************************************************** * @file mc_tasks.c * @author Motor Control SDK Team, ST Microelectronics * @brief This file implements tasks definition * ****************************************************************************** * @attention * *

© Copyright (c) 2019 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "mc_type.h" #include "mc_math.h" #include "motorcontrol.h" #include "regular_conversion_manager.h" #include "mc_interface.h" #include "mc_tuning.h" #include "digital_output.h" #include "state_machine.h" #include "pwm_common.h" #include "mc_tasks.h" #include "parameters_conversion.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* USER CODE BEGIN Private define */ /* Private define ------------------------------------------------------------*/ #define CHARGE_BOOT_CAP_MS 10 #define CHARGE_BOOT_CAP_MS2 10 #define OFFCALIBRWAIT_MS 0 #define OFFCALIBRWAIT_MS2 0 #define STOPPERMANENCY_MS 400 #define STOPPERMANENCY_MS2 400 #define CHARGE_BOOT_CAP_TICKS (uint16_t)((SYS_TICK_FREQUENCY * CHARGE_BOOT_CAP_MS)/ 1000) #define CHARGE_BOOT_CAP_TICKS2 (uint16_t)((SYS_TICK_FREQUENCY * CHARGE_BOOT_CAP_MS2)/ 1000) #define OFFCALIBRWAITTICKS (uint16_t)((SYS_TICK_FREQUENCY * OFFCALIBRWAIT_MS)/ 1000) #define OFFCALIBRWAITTICKS2 (uint16_t)((SYS_TICK_FREQUENCY * OFFCALIBRWAIT_MS2)/ 1000) #define STOPPERMANENCY_TICKS (uint16_t)((SYS_TICK_FREQUENCY * STOPPERMANENCY_MS)/ 1000) #define STOPPERMANENCY_TICKS2 (uint16_t)((SYS_TICK_FREQUENCY * STOPPERMANENCY_MS2)/ 1000) /* Un-Comment this macro define in order to activate the smooth braking action on over voltage */ /* #define MC.SMOOTH_BRAKING_ACTION_ON_OVERVOLTAGE */ /* USER CODE END Private define */ #define VBUS_TEMP_ERR_MASK (MC_OVER_VOLT| MC_UNDER_VOLT| MC_OVER_TEMP) /* Private variables----------------------------------------------------------*/ FOCVars_t FOCVars[NBR_OF_MOTORS]; MCI_Handle_t Mci[NBR_OF_MOTORS]; MCI_Handle_t * oMCInterface[NBR_OF_MOTORS]; MCT_Handle_t MCT[NBR_OF_MOTORS]; STM_Handle_t STM[NBR_OF_MOTORS]; SpeednTorqCtrl_Handle_t *pSTC[NBR_OF_MOTORS]; PID_Handle_t *pPIDSpeed[NBR_OF_MOTORS]; PID_Handle_t *pPIDIq[NBR_OF_MOTORS]; PID_Handle_t *pPIDId[NBR_OF_MOTORS]; RDivider_Handle_t *pBusSensorM1; NTC_Handle_t *pTemperatureSensor[NBR_OF_MOTORS]; PWMC_Handle_t * pwmcHandle[NBR_OF_MOTORS]; DOUT_handle_t *pR_Brake[NBR_OF_MOTORS]; DOUT_handle_t *pOCPDisabling[NBR_OF_MOTORS]; PQD_MotorPowMeas_Handle_t *pMPM[NBR_OF_MOTORS]; CircleLimitation_Handle_t *pCLM[NBR_OF_MOTORS]; RampExtMngr_Handle_t *pREMNG[NBR_OF_MOTORS]; /*!< Ramp manager used to modify the Iq ref during the start-up switch over.*/ static volatile uint16_t hMFTaskCounterM1 = 0; static volatile uint16_t hBootCapDelayCounterM1 = 0; static volatile uint16_t hStopPermanencyCounterM1 = 0; uint8_t bMCBootCompleted = 0; /* USER CODE BEGIN Private Variables */ /* USER CODE END Private Variables */ /* Private functions ---------------------------------------------------------*/ void TSK_MediumFrequencyTaskM1(void); void FOC_Clear(uint8_t bMotor); void FOC_InitAdditionalMethods(uint8_t bMotor); void FOC_CalcCurrRef(uint8_t bMotor); static uint16_t FOC_CurrControllerM1(void); void TSK_SetChargeBootCapDelayM1(uint16_t hTickCount); bool TSK_ChargeBootCapDelayHasElapsedM1(void); void TSK_SetStopPermanencyTimeM1(uint16_t hTickCount); bool TSK_StopPermanencyTimeHasElapsedM1(void); void TSK_SafetyTask_PWMOFF(uint8_t motor); void UI_Scheduler(void); /* USER CODE BEGIN Private Functions */ /* USER CODE END Private Functions */ /** * @brief It initializes the whole MC core according to user defined * parameters. * @param pMCIList pointer to the vector of MCInterface objects that will be * created and initialized. The vector must have length equal to the * number of motor drives. * @param pMCTList pointer to the vector of MCTuning objects that will be * created and initialized. The vector must have length equal to the * number of motor drives. * @retval None */ __weak void MCboot( MCI_Handle_t* pMCIList[NBR_OF_MOTORS],MCT_Handle_t* pMCTList[NBR_OF_MOTORS] ) { /* USER CODE BEGIN MCboot 0 */ /* USER CODE END MCboot 0 */ /**************************************/ /* State machine initialization */ /**************************************/ STM_Init(&STM[M1]); bMCBootCompleted = 0; pCLM[M1] = &CircleLimitationM1; /**********************************************************/ /* PWM and current sensing component initialization */ /**********************************************************/ pwmcHandle[M1] = &PWM_Handle_M1._Super; R3_2_Init(&PWM_Handle_M1); /* USER CODE BEGIN MCboot 1 */ /* USER CODE END MCboot 1 */ /**************************************/ /* Start timers synchronously */ /**************************************/ startTimers(); /******************************************************/ /* PID component initialization: speed regulation */ /******************************************************/ PID_HandleInit(&PIDSpeedHandle_M1); pPIDSpeed[M1] = &PIDSpeedHandle_M1; /******************************************************/ /* Main speed sensor component initialization */ /******************************************************/ pSTC[M1] = &SpeednTorqCtrlM1; STO_PLL_Init (&STO_PLL_M1); /******************************************************/ /* Speed & torque component initialization */ /******************************************************/ STC_Init(pSTC[M1],pPIDSpeed[M1], &STO_PLL_M1._Super); /****************************************************/ /* Virtual speed sensor component initialization */ /****************************************************/ VSS_Init (&VirtualSpeedSensorM1); /**************************************/ /* Rev-up component initialization */ /**************************************/ RUC_Init(&RevUpControlM1,pSTC[M1],&VirtualSpeedSensorM1, &STO_M1, pwmcHandle[M1]); /********************************************************/ /* PID component initialization: current regulation */ /********************************************************/ PID_HandleInit(&PIDIqHandle_M1); PID_HandleInit(&PIDIdHandle_M1); pPIDIq[M1] = &PIDIqHandle_M1; pPIDId[M1] = &PIDIdHandle_M1; /********************************************************/ /* Bus voltage sensor component initialization */ /********************************************************/ pBusSensorM1 = &RealBusVoltageSensorParamsM1; RVBS_Init(pBusSensorM1); /*************************************************/ /* Power measurement component initialization */ /*************************************************/ pMPM[M1] = &PQD_MotorPowMeasM1; pMPM[M1]->pVBS = &(pBusSensorM1->_Super); pMPM[M1]->pFOCVars = &FOCVars[M1]; /*******************************************************/ /* Temperature measurement component initialization */ /*******************************************************/ NTC_Init(&TempSensorParamsM1); pTemperatureSensor[M1] = &TempSensorParamsM1; pREMNG[M1] = &RampExtMngrHFParamsM1; REMNG_Init(pREMNG[M1]); FOC_Clear(M1); FOCVars[M1].bDriveInput = EXTERNAL; FOCVars[M1].Iqdref = STC_GetDefaultIqdref(pSTC[M1]); FOCVars[M1].UserIdref = STC_GetDefaultIqdref(pSTC[M1]).d; oMCInterface[M1] = & Mci[M1]; MCI_Init(oMCInterface[M1], &STM[M1], pSTC[M1], &FOCVars[M1] ); MCI_ExecSpeedRamp(oMCInterface[M1], STC_GetMecSpeedRefUnitDefault(pSTC[M1]),0); /*First command to STC*/ pMCIList[M1] = oMCInterface[M1]; MCT[M1].pPIDSpeed = pPIDSpeed[M1]; MCT[M1].pPIDIq = pPIDIq[M1]; MCT[M1].pPIDId = pPIDId[M1]; MCT[M1].pPIDFluxWeakening = MC_NULL; /* if M1 doesn't has FW */ MCT[M1].pPWMnCurrFdbk = pwmcHandle[M1]; MCT[M1].pRevupCtrl = &RevUpControlM1; /* only if M1 is sensorless*/ MCT[M1].pSpeedSensorMain = (SpeednPosFdbk_Handle_t *) &STO_PLL_M1; MCT[M1].pSpeedSensorAux = MC_NULL; MCT[M1].pSpeedSensorVirtual = &VirtualSpeedSensorM1; /* only if M1 is sensorless*/ MCT[M1].pSpeednTorqueCtrl = pSTC[M1]; MCT[M1].pStateMachine = &STM[M1]; MCT[M1].pTemperatureSensor = (NTC_Handle_t *) pTemperatureSensor[M1]; MCT[M1].pBusVoltageSensor = &(pBusSensorM1->_Super); MCT[M1].pBrakeDigitalOutput = MC_NULL; /* brake is defined, oBrakeM1*/ MCT[M1].pNTCRelay = MC_NULL; /* relay is defined, oRelayM1*/ MCT[M1].pMPM = (MotorPowMeas_Handle_t*)pMPM[M1]; MCT[M1].pFW = MC_NULL; MCT[M1].pFF = MC_NULL; MCT[M1].pPosCtrl = MC_NULL; MCT[M1].pSCC = MC_NULL; MCT[M1].pOTT = MC_NULL; pMCTList[M1] = &MCT[M1]; /* USER CODE BEGIN MCboot 2 */ /* USER CODE END MCboot 2 */ bMCBootCompleted = 1; } /** * @brief Runs all the Tasks of the Motor Control cockpit * * This function is to be called periodically at least at the Medium Frequency task * rate (It is typically called on the Systick interrupt). Exact invokation rate is * the Speed regulator execution rate set in the Motor Contorl Workbench. * * The following tasks are executed in this order: * * - Medium Frequency Tasks of each motors * - Safety Task * - Power Factor Correction Task (if enabled) * - User Interface task. */ __weak void MC_RunMotorControlTasks(void) { if ( bMCBootCompleted ) { /* ** Medium Frequency Tasks ** */ MC_Scheduler(); /* Safety task is run after Medium Frequency task so that * it can overcome actions they initiated if needed. */ TSK_SafetyTask(); /* ** User Interface Task ** */ UI_Scheduler(); } } /** * @brief Executes the Medium Frequency Task functions for each drive instance. * * It is to be clocked at the Systick frequency. */ __weak void MC_Scheduler(void) { /* USER CODE BEGIN MC_Scheduler 0 */ /* USER CODE END MC_Scheduler 0 */ if (bMCBootCompleted == 1) { if(hMFTaskCounterM1 > 0u) { hMFTaskCounterM1--; } else { TSK_MediumFrequencyTaskM1(); /* USER CODE BEGIN MC_Scheduler 1 */ /* USER CODE END MC_Scheduler 1 */ hMFTaskCounterM1 = MF_TASK_OCCURENCE_TICKS; } if(hBootCapDelayCounterM1 > 0u) { hBootCapDelayCounterM1--; } if(hStopPermanencyCounterM1 > 0u) { hStopPermanencyCounterM1--; } } else { } /* USER CODE BEGIN MC_Scheduler 2 */ /* USER CODE END MC_Scheduler 2 */ } /** * @brief Executes medium frequency periodic Motor Control tasks * * This function performs some of the control duties on Motor 1 according to the * present state of its state machine. In particular, duties requiring a periodic * execution at a medium frequency rate (such as the speed controller for instance) * are executed here. */ __weak void TSK_MediumFrequencyTaskM1(void) { /* USER CODE BEGIN MediumFrequencyTask M1 0 */ /* USER CODE END MediumFrequencyTask M1 0 */ State_t StateM1; int16_t wAux = 0; bool IsSpeedReliable = STO_PLL_CalcAvrgMecSpeedUnit( &STO_PLL_M1, &wAux ); PQD_CalcElMotorPower( pMPM[M1] ); StateM1 = STM_GetState( &STM[M1] ); switch ( StateM1 ) { case IDLE_START: RUC_Clear( &RevUpControlM1, MCI_GetImposedMotorDirection( oMCInterface[M1] ) ); R3_2_TurnOnLowSides( pwmcHandle[M1] ); TSK_SetChargeBootCapDelayM1( CHARGE_BOOT_CAP_TICKS ); STM_NextState( &STM[M1], CHARGE_BOOT_CAP ); break; case CHARGE_BOOT_CAP: if ( TSK_ChargeBootCapDelayHasElapsedM1() ) { PWMC_CurrentReadingCalibr( pwmcHandle[M1], CRC_START ); /* USER CODE BEGIN MediumFrequencyTask M1 Charge BootCap elapsed */ /* USER CODE END MediumFrequencyTask M1 Charge BootCap elapsed */ STM_NextState(&STM[M1],OFFSET_CALIB); } break; case OFFSET_CALIB: if ( PWMC_CurrentReadingCalibr( pwmcHandle[M1], CRC_EXEC ) ) { STM_NextState( &STM[M1], CLEAR ); } break; case CLEAR: /* In a sensorless configuration. Initiate the Revup procedure */ FOCVars[M1].bDriveInput = EXTERNAL; STC_SetSpeedSensor( pSTC[M1], &VirtualSpeedSensorM1._Super ); STO_PLL_Clear( &STO_PLL_M1 ); if ( STM_NextState( &STM[M1], START ) == true ) { FOC_Clear( M1 ); R3_2_SwitchOnPWM( pwmcHandle[M1] ); } break; case START: { /* Mechanical speed as imposed by the Virtual Speed Sensor during the Rev Up phase. */ int16_t hForcedMecSpeedUnit; qd_t IqdRef; bool ObserverConverged = false; /* Execute the Rev Up procedure */ if( ! RUC_Exec( &RevUpControlM1 ) ) { /* The time allowed for the startup sequence has expired */ STM_FaultProcessing( &STM[M1], MC_START_UP, 0 ); } else { /* Execute the torque open loop current start-up ramp: * Compute the Iq reference current as configured in the Rev Up sequence */ IqdRef.q = STC_CalcTorqueReference( pSTC[M1] ); IqdRef.d = FOCVars[M1].UserIdref; /* Iqd reference current used by the High Frequency Loop to generate the PWM output */ FOCVars[M1].Iqdref = IqdRef; } (void) VSS_CalcAvrgMecSpeedUnit( &VirtualSpeedSensorM1, &hForcedMecSpeedUnit ); ObserverConverged = STO_PLL_IsObserverConverged( &STO_PLL_M1,hForcedMecSpeedUnit ); (void) VSS_SetStartTransition( &VirtualSpeedSensorM1, ObserverConverged ); if ( ObserverConverged ) { qd_t StatorCurrent = MCM_Park( FOCVars[M1].Ialphabeta, SPD_GetElAngle( &STO_PLL_M1._Super ) ); /* Start switch over ramp. This ramp will transition from the revup to the closed loop FOC. */ REMNG_Init( pREMNG[M1] ); REMNG_ExecRamp( pREMNG[M1], FOCVars[M1].Iqdref.q, 0 ); REMNG_ExecRamp( pREMNG[M1], StatorCurrent.q, TRANSITION_DURATION ); STM_NextState( &STM[M1], SWITCH_OVER ); } } break; case SWITCH_OVER: { bool LoopClosed; int16_t hForcedMecSpeedUnit; if( ! RUC_Exec( &RevUpControlM1 ) ) { /* The time allowed for the startup sequence has expired */ STM_FaultProcessing( &STM[M1], MC_START_UP, 0 ); } else { /* Compute the virtual speed and positions of the rotor. The function returns true if the virtual speed is in the reliability range */ LoopClosed = VSS_CalcAvrgMecSpeedUnit(&VirtualSpeedSensorM1,&hForcedMecSpeedUnit); /* Check if the transition ramp has completed. */ LoopClosed |= VSS_TransitionEnded( &VirtualSpeedSensorM1 ); /* If any of the above conditions is true, the loop is considered closed. The state machine transitions to the START_RUN state. */ if ( LoopClosed == true ) { #if ( PID_SPEED_INTEGRAL_INIT_DIV == 0 ) PID_SetIntegralTerm( pPIDSpeed[M1], 0 ); #else PID_SetIntegralTerm( pPIDSpeed[M1], (int32_t) ( FOCVars[M1].Iqdref.q * PID_GetKIDivisor(pPIDSpeed[M1]) / PID_SPEED_INTEGRAL_INIT_DIV ) ); #endif STM_NextState( &STM[M1], START_RUN ); } } } break; case START_RUN: /* only for sensor-less control */ STC_SetSpeedSensor(pSTC[M1], &STO_PLL_M1._Super); /*Observer has converged*/ { /* USER CODE BEGIN MediumFrequencyTask M1 1 */ /* USER CODE END MediumFrequencyTask M1 1 */ FOC_InitAdditionalMethods(M1); FOC_CalcCurrRef( M1 ); STM_NextState( &STM[M1], RUN ); } STC_ForceSpeedReferenceToCurrentSpeed( pSTC[M1] ); /* Init the reference speed to current speed */ MCI_ExecBufferedCommands( oMCInterface[M1] ); /* Exec the speed ramp after changing of the speed sensor */ break; case RUN: /* USER CODE BEGIN MediumFrequencyTask M1 2 */ /* USER CODE END MediumFrequencyTask M1 2 */ MCI_ExecBufferedCommands( oMCInterface[M1] ); FOC_CalcCurrRef( M1 ); if( !IsSpeedReliable ) { STM_FaultProcessing( &STM[M1], MC_SPEED_FDBK, 0 ); } /* USER CODE BEGIN MediumFrequencyTask M1 3 */ /* USER CODE END MediumFrequencyTask M1 3 */ break; case ANY_STOP: R3_2_SwitchOffPWM( pwmcHandle[M1] ); FOC_Clear( M1 ); MPM_Clear( (MotorPowMeas_Handle_t*) pMPM[M1] ); TSK_SetStopPermanencyTimeM1( STOPPERMANENCY_TICKS ); /* USER CODE BEGIN MediumFrequencyTask M1 4 */ /* USER CODE END MediumFrequencyTask M1 4 */ STM_NextState( &STM[M1], STOP ); break; case STOP: if ( TSK_StopPermanencyTimeHasElapsedM1() ) { STM_NextState( &STM[M1], STOP_IDLE ); } break; case STOP_IDLE: STC_SetSpeedSensor( pSTC[M1],&VirtualSpeedSensorM1._Super ); /* sensor-less */ VSS_Clear( &VirtualSpeedSensorM1 ); /* Reset measured speed in IDLE */ /* USER CODE BEGIN MediumFrequencyTask M1 5 */ /* USER CODE END MediumFrequencyTask M1 5 */ STM_NextState( &STM[M1], IDLE ); break; default: break; } /* USER CODE BEGIN MediumFrequencyTask M1 6 */ /* USER CODE END MediumFrequencyTask M1 6 */ } /** * @brief It re-initializes the current and voltage variables. Moreover * it clears qd currents PI controllers, voltage sensor and SpeednTorque * controller. It must be called before each motor restart. * It does not clear speed sensor. * @param bMotor related motor it can be M1 or M2 * @retval none */ __weak void FOC_Clear(uint8_t bMotor) { /* USER CODE BEGIN FOC_Clear 0 */ /* USER CODE END FOC_Clear 0 */ ab_t NULL_ab = {(int16_t)0, (int16_t)0}; qd_t NULL_qd = {(int16_t)0, (int16_t)0}; alphabeta_t NULL_alphabeta = {(int16_t)0, (int16_t)0}; FOCVars[bMotor].Iab = NULL_ab; FOCVars[bMotor].Ialphabeta = NULL_alphabeta; FOCVars[bMotor].Iqd = NULL_qd; FOCVars[bMotor].Iqdref = NULL_qd; FOCVars[bMotor].hTeref = (int16_t)0; FOCVars[bMotor].Vqd = NULL_qd; FOCVars[bMotor].Valphabeta = NULL_alphabeta; FOCVars[bMotor].hElAngle = (int16_t)0; PID_SetIntegralTerm(pPIDIq[bMotor], (int32_t)0); PID_SetIntegralTerm(pPIDId[bMotor], (int32_t)0); STC_Clear(pSTC[bMotor]); PWMC_SwitchOffPWM(pwmcHandle[bMotor]); /* USER CODE BEGIN FOC_Clear 1 */ /* USER CODE END FOC_Clear 1 */ } /** * @brief Use this method to initialize additional methods (if any) in * START_TO_RUN state * @param bMotor related motor it can be M1 or M2 * @retval none */ __weak void FOC_InitAdditionalMethods(uint8_t bMotor) { /* USER CODE BEGIN FOC_InitAdditionalMethods 0 */ /* USER CODE END FOC_InitAdditionalMethods 0 */ } /** * @brief It computes the new values of Iqdref (current references on qd * reference frame) based on the required electrical torque information * provided by oTSC object (internally clocked). * If implemented in the derived class it executes flux weakening and/or * MTPA algorithm(s). It must be called with the periodicity specified * in oTSC parameters * @param bMotor related motor it can be M1 or M2 * @retval none */ __weak void FOC_CalcCurrRef(uint8_t bMotor) { /* USER CODE BEGIN FOC_CalcCurrRef 0 */ /* USER CODE END FOC_CalcCurrRef 0 */ if(FOCVars[bMotor].bDriveInput == INTERNAL) { FOCVars[bMotor].hTeref = STC_CalcTorqueReference(pSTC[bMotor]); FOCVars[bMotor].Iqdref.q = FOCVars[bMotor].hTeref; } /* USER CODE BEGIN FOC_CalcCurrRef 1 */ /* USER CODE END FOC_CalcCurrRef 1 */ } /** * @brief It set a counter intended to be used for counting the delay required * for drivers boot capacitors charging of motor 1 * @param hTickCount number of ticks to be counted * @retval void */ __weak void TSK_SetChargeBootCapDelayM1(uint16_t hTickCount) { hBootCapDelayCounterM1 = hTickCount; } /** * @brief Use this function to know whether the time required to charge boot * capacitors of motor 1 has elapsed * @param none * @retval bool true if time has elapsed, false otherwise */ __weak bool TSK_ChargeBootCapDelayHasElapsedM1(void) { bool retVal = false; if (hBootCapDelayCounterM1 == 0) { retVal = true; } return (retVal); } /** * @brief It set a counter intended to be used for counting the permanency * time in STOP state of motor 1 * @param hTickCount number of ticks to be counted * @retval void */ __weak void TSK_SetStopPermanencyTimeM1(uint16_t hTickCount) { hStopPermanencyCounterM1 = hTickCount; } /** * @brief Use this function to know whether the permanency time in STOP state * of motor 1 has elapsed * @param none * @retval bool true if time is elapsed, false otherwise */ __weak bool TSK_StopPermanencyTimeHasElapsedM1(void) { bool retVal = false; if (hStopPermanencyCounterM1 == 0) { retVal = true; } return (retVal); } #if defined (CCMRAM_ENABLED) #if defined (__ICCARM__) #pragma location = ".ccmram" #elif defined (__CC_ARM) __attribute__((section (".ccmram"))) #endif #endif /** * @brief Executes the Motor Control duties that require a high frequency rate and a precise timing * * This is mainly the FOC current control loop. It is executed depending on the state of the Motor Control * subsystem (see the state machine(s)). * * @retval Number of the motor instance which FOC loop was executed. */ __weak uint8_t TSK_HighFrequencyTask(void) { /* USER CODE BEGIN HighFrequencyTask 0 */ /* USER CODE END HighFrequencyTask 0 */ uint8_t bMotorNbr = 0; uint16_t hFOCreturn; uint16_t hState; /* only if sensorless main*/ Observer_Inputs_t STO_Inputs; /* only if sensorless main*/ STO_Inputs.Valfa_beta = FOCVars[M1].Valphabeta; /* only if sensorless*/ if ( STM[M1].bState == SWITCH_OVER ) { if (!REMNG_RampCompleted(pREMNG[M1])) { FOCVars[M1].Iqdref.q = REMNG_Calc(pREMNG[M1]); } } /* USER CODE BEGIN HighFrequencyTask SINGLEDRIVE_1 */ /* USER CODE END HighFrequencyTask SINGLEDRIVE_1 */ hFOCreturn = FOC_CurrControllerM1(); /* USER CODE BEGIN HighFrequencyTask SINGLEDRIVE_2 */ /* USER CODE END HighFrequencyTask SINGLEDRIVE_2 */ if(hFOCreturn == MC_FOC_DURATION) { STM_FaultProcessing(&STM[M1], MC_FOC_DURATION, 0); } else { bool IsAccelerationStageReached = RUC_FirstAccelerationStageReached(&RevUpControlM1); STO_Inputs.Ialfa_beta = FOCVars[M1].Ialphabeta; /* only if sensorless*/ STO_Inputs.Vbus = VBS_GetAvBusVoltage_d(&(pBusSensorM1->_Super)); /* only for sensorless*/ STO_PLL_CalcElAngle (&STO_PLL_M1, &STO_Inputs); STO_PLL_CalcAvrgElSpeedDpp (&STO_PLL_M1); /* Only in case of Sensor-less */ if (IsAccelerationStageReached == false) { STO_ResetPLL(&STO_PLL_M1); } hState = STM_GetState(&STM[M1]); if((hState == START) || (hState == SWITCH_OVER) || (hState == START_RUN)) /* only for sensor-less*/ { int16_t hObsAngle = SPD_GetElAngle(&STO_PLL_M1._Super); VSS_CalcElAngle(&VirtualSpeedSensorM1,&hObsAngle); } /* USER CODE BEGIN HighFrequencyTask SINGLEDRIVE_3 */ /* USER CODE END HighFrequencyTask SINGLEDRIVE_3 */ } /* USER CODE BEGIN HighFrequencyTask 1 */ /* USER CODE END HighFrequencyTask 1 */ return bMotorNbr; } #if defined (CCMRAM) #if defined (__ICCARM__) #pragma location = ".ccmram" #elif defined (__CC_ARM) || defined(__GNUC__) __attribute__((section (".ccmram"))) #endif #endif /** * @brief It executes the core of FOC drive that is the controllers for Iqd * currents regulation. Reference frame transformations are carried out * accordingly to the active speed sensor. It must be called periodically * when new motor currents have been converted * @param this related object of class CFOC. * @retval int16_t It returns MC_NO_FAULTS if the FOC has been ended before * next PWM Update event, MC_FOC_DURATION otherwise */ inline uint16_t FOC_CurrControllerM1(void) { qd_t Iqd, Vqd; ab_t Iab; alphabeta_t Ialphabeta, Valphabeta; int16_t hElAngle; uint16_t hCodeError; SpeednPosFdbk_Handle_t *speedHandle; speedHandle = STC_GetSpeedSensor(pSTC[M1]); hElAngle = SPD_GetElAngle(speedHandle); hElAngle += SPD_GetInstElSpeedDpp(speedHandle)*PARK_ANGLE_COMPENSATION_FACTOR; PWMC_GetPhaseCurrents(pwmcHandle[M1], &Iab); Ialphabeta = MCM_Clarke(Iab); Iqd = MCM_Park(Ialphabeta, hElAngle); Vqd.q = PI_Controller(pPIDIq[M1], (int32_t)(FOCVars[M1].Iqdref.q) - Iqd.q); Vqd.d = PI_Controller(pPIDId[M1], (int32_t)(FOCVars[M1].Iqdref.d) - Iqd.d); Vqd = Circle_Limitation(pCLM[M1], Vqd); hElAngle += SPD_GetInstElSpeedDpp(speedHandle)*REV_PARK_ANGLE_COMPENSATION_FACTOR; Valphabeta = MCM_Rev_Park(Vqd, hElAngle); hCodeError = PWMC_SetPhaseVoltage(pwmcHandle[M1], Valphabeta); FOCVars[M1].Vqd = Vqd; FOCVars[M1].Iab = Iab; FOCVars[M1].Ialphabeta = Ialphabeta; FOCVars[M1].Iqd = Iqd; FOCVars[M1].Valphabeta = Valphabeta; FOCVars[M1].hElAngle = hElAngle; return(hCodeError); } /** * @brief Executes safety checks (e.g. bus voltage and temperature) for all drive instances. * * Faults flags are updated here. */ __weak void TSK_SafetyTask(void) { /* USER CODE BEGIN TSK_SafetyTask 0 */ /* USER CODE END TSK_SafetyTask 0 */ if (bMCBootCompleted == 1) { TSK_SafetyTask_PWMOFF(M1); /* User conversion execution */ RCM_ExecUserConv (); /* USER CODE BEGIN TSK_SafetyTask 1 */ /* USER CODE END TSK_SafetyTask 1 */ } } /** * @brief Safety task implementation if MC.ON_OVER_VOLTAGE == TURN_OFF_PWM * @param bMotor Motor reference number defined * \link Motors_reference_number here \endlink * @retval None */ __weak void TSK_SafetyTask_PWMOFF(uint8_t bMotor) { /* USER CODE BEGIN TSK_SafetyTask_PWMOFF 0 */ /* USER CODE END TSK_SafetyTask_PWMOFF 0 */ uint16_t CodeReturn = MC_NO_ERROR; uint16_t errMask[NBR_OF_MOTORS] = {VBUS_TEMP_ERR_MASK}; CodeReturn |= errMask[bMotor] & NTC_CalcAvTemp(pTemperatureSensor[bMotor]); /* check for fault if FW protection is activated. It returns MC_OVER_TEMP or MC_NO_ERROR */ CodeReturn |= PWMC_CheckOverCurrent(pwmcHandle[bMotor]); /* check for fault. It return MC_BREAK_IN or MC_NO_FAULTS (for STM32F30x can return MC_OVER_VOLT in case of HW Overvoltage) */ if(bMotor == M1) { CodeReturn |= errMask[bMotor] &RVBS_CalcAvVbus(pBusSensorM1); } STM_FaultProcessing(&STM[bMotor], CodeReturn, ~CodeReturn); /* Update the STM according error code */ switch (STM_GetState(&STM[bMotor])) /* Acts on PWM outputs in case of faults */ { case FAULT_NOW: PWMC_SwitchOffPWM(pwmcHandle[bMotor]); FOC_Clear(bMotor); MPM_Clear((MotorPowMeas_Handle_t*)pMPM[bMotor]); /* USER CODE BEGIN TSK_SafetyTask_PWMOFF 1 */ /* USER CODE END TSK_SafetyTask_PWMOFF 1 */ break; case FAULT_OVER: PWMC_SwitchOffPWM(pwmcHandle[bMotor]); /* USER CODE BEGIN TSK_SafetyTask_PWMOFF 2 */ /* USER CODE END TSK_SafetyTask_PWMOFF 2 */ break; default: break; } /* USER CODE BEGIN TSK_SafetyTask_PWMOFF 3 */ /* USER CODE END TSK_SafetyTask_PWMOFF 3 */ } /** * @brief This function returns the reference of the MCInterface relative to * the selected drive. * @param bMotor Motor reference number defined * \link Motors_reference_number here \endlink * @retval MCI_Handle_t * Reference to MCInterface relative to the selected drive. * Note: it can be MC_NULL if MCInterface of selected drive is not * allocated. */ __weak MCI_Handle_t * GetMCI(uint8_t bMotor) { MCI_Handle_t * retVal = MC_NULL; if (bMotor < NBR_OF_MOTORS) { retVal = oMCInterface[bMotor]; } return retVal; } /** * @brief This function returns the reference of the MCTuning relative to * the selected drive. * @param bMotor Motor reference number defined * \link Motors_reference_number here \endlink * @retval MCT_Handle_t motor control tuning handler for the selected drive. * Note: it can be MC_NULL if MCInterface of selected drive is not * allocated. */ __weak MCT_Handle_t* GetMCT(uint8_t bMotor) { MCT_Handle_t* retVal = MC_NULL; if (bMotor < NBR_OF_MOTORS) { retVal = &MCT[bMotor]; } return retVal; } /** * @brief Puts the Motor Control subsystem in in safety conditions on a Hard Fault * * This function is to be executed when a general hardware failure has been detected * by the microcontroller and is used to put the system in safety condition. */ __weak void TSK_HardwareFaultTask(void) { /* USER CODE BEGIN TSK_HardwareFaultTask 0 */ /* USER CODE END TSK_HardwareFaultTask 0 */ R3_2_SwitchOffPWM(pwmcHandle[M1]); STM_FaultProcessing(&STM[M1], MC_SW_ERROR, 0); /* USER CODE BEGIN TSK_HardwareFaultTask 1 */ /* USER CODE END TSK_HardwareFaultTask 1 */ } /** * @brief Locks GPIO pins used for Motor Control to prevent accidental reconfiguration */ __weak void mc_lock_pins (void) { LL_GPIO_LockPin(M1_OPAMP3_OUT_GPIO_Port, M1_OPAMP3_OUT_Pin); LL_GPIO_LockPin(M1_OPAMP3_INT_GAIN_GPIO_Port, M1_OPAMP3_INT_GAIN_Pin); LL_GPIO_LockPin(M1_TEMPERATURE_GPIO_Port, M1_TEMPERATURE_Pin); LL_GPIO_LockPin(M1_BUS_VOLTAGE_GPIO_Port, M1_BUS_VOLTAGE_Pin); LL_GPIO_LockPin(M1_CURR_SHUNT_W_GPIO_Port, M1_CURR_SHUNT_W_Pin); LL_GPIO_LockPin(M1_CURR_SHUNT_V_GPIO_Port, M1_CURR_SHUNT_V_Pin); LL_GPIO_LockPin(M1_CURR_SHUNT_U_GPIO_Port, M1_CURR_SHUNT_U_Pin); LL_GPIO_LockPin(M1_OPAMP1_INT_GAIN_GPIO_Port, M1_OPAMP1_INT_GAIN_Pin); LL_GPIO_LockPin(M1_OPAMP1_OUT_GPIO_Port, M1_OPAMP1_OUT_Pin); LL_GPIO_LockPin(M1_OPAMP2_OUT_GPIO_Port, M1_OPAMP2_OUT_Pin); LL_GPIO_LockPin(M1_OPAMP2_INT_GAIN_GPIO_Port, M1_OPAMP2_INT_GAIN_Pin); LL_GPIO_LockPin(M1_PWM_INPUT_GPIO_Port, M1_PWM_INPUT_Pin); LL_GPIO_LockPin(M1_PWM_UH_GPIO_Port, M1_PWM_UH_Pin); LL_GPIO_LockPin(M1_PWM_VH_GPIO_Port, M1_PWM_VH_Pin); LL_GPIO_LockPin(M1_PWM_WH_GPIO_Port, M1_PWM_WH_Pin); LL_GPIO_LockPin(M1_PWM_VL_GPIO_Port, M1_PWM_VL_Pin); LL_GPIO_LockPin(M1_PWM_WL_GPIO_Port, M1_PWM_WL_Pin); LL_GPIO_LockPin(M1_PWM_UL_GPIO_Port, M1_PWM_UL_Pin); } /* USER CODE BEGIN mc_task 0 */ /* USER CODE END mc_task 0 */ /******************* (C) COPYRIGHT 2019 STMicroelectronics *****END OF FILE****/