/**
******************************************************************************
* @file mc_interface.c
* @author Motor Control SDK Team, ST Microelectronics
* @brief This file provides firmware functions that implement the features
* of the MC Interface component of the Motor Control SDK:
*
******************************************************************************
* @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 "mc_math.h"
#include "speed_torq_ctrl.h"
#include "mc_interface.h"
/** @addtogroup MCSDK
* @{
*/
/** @defgroup MCInterface Motor Control Interface
* @brief MC Interface component of the Motor Control SDK
*
* @todo Document the MC Interface "module".
*
* @{
*/
/* Private macros ------------------------------------------------------------*/
/**
* @brief This macro converts the exported enum from the state machine to the corresponding bit field.
*/
#define BC(state) (1u<<((uint16_t)((uint8_t)(state))))
/* Functions -----------------------------------------------*/
/**
* @brief Initializes all the object variables, usually it has to be called
* once right after object creation. It is also used to assign the
* state machine object, the speed and torque controller, and the FOC
* drive object to be used by MC Interface.
* @param pHandle pointer on the component instance to initialize.
* @param pSTM the state machine object used by the MCI.
* @param pSTC the speed and torque controller used by the MCI.
* @param pFOCVars pointer to FOC vars to be used by MCI.
* @retval none.
*/
__weak void MCI_Init( MCI_Handle_t * pHandle, STM_Handle_t * pSTM, SpeednTorqCtrl_Handle_t * pSTC, pFOCVars_t pFOCVars )
{
pHandle->pSTM = pSTM;
pHandle->pSTC = pSTC;
pHandle->pFOCVars = pFOCVars;
/* Buffer related initialization */
pHandle->lastCommand = MCI_NOCOMMANDSYET;
pHandle->hFinalSpeed = 0;
pHandle->hFinalTorque = 0;
pHandle->hDurationms = 0;
pHandle->CommandState = MCI_BUFFER_EMPTY;
}
/**
* @brief This is a buffered command to set a motor speed ramp. This commands
* don't become active as soon as it is called but it will be executed
* when the pSTM state is START_RUN or RUN. User can check the status
* of the command calling the MCI_IsCommandAcknowledged method.
* @param pHandle Pointer on the component instance to operate on.
* @param hFinalSpeed is the value of mechanical rotor speed reference at the
* end of the ramp expressed in tenths of HZ.
* @param hDurationms the duration of the ramp expressed in milliseconds. It
* is possible to set 0 to perform an instantaneous change in the
* value.
* @retval none.
*/
__weak void MCI_ExecSpeedRamp( MCI_Handle_t * pHandle, int16_t hFinalSpeed, uint16_t hDurationms )
{
pHandle->lastCommand = MCI_EXECSPEEDRAMP;
pHandle->hFinalSpeed = hFinalSpeed;
pHandle->hDurationms = hDurationms;
pHandle->CommandState = MCI_COMMAND_NOT_ALREADY_EXECUTED;
pHandle->LastModalitySetByUser = STC_SPEED_MODE;
}
/**
* @brief This is a buffered command to set a motor torque ramp. This commands
* don't become active as soon as it is called but it will be executed
* when the pSTM state is START_RUN or RUN. User can check the status
* of the command calling the MCI_IsCommandAcknowledged method.
* @param pHandle Pointer on the component instance to work on.
* @param hFinalTorque is the value of motor torque reference at the end of
* the ramp. This value represents actually the Iq current expressed in
* digit.
* To convert current expressed in Amps to current expressed in digit
* is possible to use the formula:
* Current (digit) = [Current(Amp) * 65536 * Rshunt * Aop] / Vdd micro.
* @param hDurationms the duration of the ramp expressed in milliseconds. It
* is possible to set 0 to perform an instantaneous change in the
* value.
* @retval none.
*/
__weak void MCI_ExecTorqueRamp( MCI_Handle_t * pHandle, int16_t hFinalTorque, uint16_t hDurationms )
{
pHandle->lastCommand = MCI_EXECTORQUERAMP;
pHandle->hFinalTorque = hFinalTorque;
pHandle->hDurationms = hDurationms;
pHandle->CommandState = MCI_COMMAND_NOT_ALREADY_EXECUTED;
pHandle->LastModalitySetByUser = STC_TORQUE_MODE;
}
/**
* @brief This is a buffered command to set directly the motor current
* references Iq and Id. This commands don't become active as soon as
* it is called but it will be executed when the pSTM state is
* START_RUN or RUN. User can check the status of the command calling
* the MCI_IsCommandAcknowledged method.
* @param pHandle Pointer on the component instance to work on.
* @param Iqdref current references on qd reference frame in qd_t
* format.
* @retval none.
*/
__weak void MCI_SetCurrentReferences( MCI_Handle_t * pHandle, qd_t Iqdref )
{
pHandle->lastCommand = MCI_SETCURRENTREFERENCES;
pHandle->Iqdref.q = Iqdref.q;
pHandle->Iqdref.d = Iqdref.d;
pHandle->CommandState = MCI_COMMAND_NOT_ALREADY_EXECUTED;
pHandle->LastModalitySetByUser = STC_TORQUE_MODE;
}
/**
* @brief This is a user command used to begin the start-up procedure.
* If the state machine is in IDLE state the command is executed
* instantaneously otherwise the command is discarded. User must take
* care of this possibility by checking the return value.
* Before calling MCI_StartMotor it is mandatory to execute one of
* these commands:\n
* MCI_ExecSpeedRamp\n
* MCI_ExecTorqueRamp\n
* MCI_SetCurrentReferences\n
* Otherwise the behaviour in run state will be unpredictable.\n
* Note: The MCI_StartMotor command is used just to begin the
* start-up procedure moving the state machine from IDLE state to
* IDLE_START. The command MCI_StartMotor is not blocking the execution
* of project until the motor is really running; to do this, the user
* have to check the state machine and verify that the RUN state (or
* any other state) has been reached.
* @param pHandle Pointer on the component instance to work on.
* @retval bool It returns true if the command is successfully executed
* otherwise it return false.
*/
__weak bool MCI_StartMotor( MCI_Handle_t * pHandle )
{
bool RetVal = STM_NextState( pHandle->pSTM, IDLE_START );
if ( RetVal == true )
{
pHandle->CommandState = MCI_COMMAND_NOT_ALREADY_EXECUTED;
}
return RetVal;
}
/**
* @brief This is a user command used to begin the stop motor procedure.
* If the state machine is in RUN or START states the command is
* executed instantaneously otherwise the command is discarded. User
* must take care of this possibility by checking the return value.\n
* Note: The MCI_StopMotor command is used just to begin the
* stop motor procedure moving the state machine to ANY_STOP.
* The command MCI_StopMotor is not blocking the execution of project
* until the motor is really stopped; to do this, the user have to
* check the state machine and verify that the IDLE state has been
* reached again.
* @param pHandle Pointer on the component instance to work on.
* @retval bool It returns true if the command is successfully executed
* otherwise it return false.
*/
__weak bool MCI_StopMotor( MCI_Handle_t * pHandle )
{
return STM_NextState( pHandle->pSTM, ANY_STOP );
}
/**
* @brief This is a user command used to indicate that the user has seen the
* error condition. If is possible, the command is executed
* instantaneously otherwise the command is discarded. User must take
* care of this possibility by checking the return value.
* @param pHandle Pointer on the component instance to work on.
* @retval bool It returns true if the command is successfully executed
* otherwise it return false.
*/
__weak bool MCI_FaultAcknowledged( MCI_Handle_t * pHandle )
{
return STM_FaultAcknowledged( pHandle->pSTM );
}
/**
* @brief This is a user command used to begin the encoder alignment procedure.
* If the state machine is in IDLE state the command is executed
* instantaneously otherwise the command is discarded. User must take
* care of this possibility by checking the return value.\n
* Note: The MCI_EncoderAlign command is used just to begin the
* encoder alignment procedure moving the state machine from IDLE state
* to IDLE_ALIGNMENT. The command MCI_EncoderAlign is not blocking the
* execution of project until the encoder is really calibrated; to do
* this, the user have to check the state machine and verify that the
* IDLE state has been reached again.
* @param pHandle Pointer on the component instance to work on.
* @retval bool It returns true if the command is successfully executed
* otherwise it return false.
*/
__weak bool MCI_EncoderAlign( MCI_Handle_t * pHandle )
{
return STM_NextState( pHandle->pSTM, IDLE_ALIGNMENT );
}
/**
* @brief This is usually a method managed by task. It must be called
* periodically in order to check the status of the related pSTM object
* and eventually to execute the buffered command if the condition
* occurs.
* @param pHandle Pointer on the component instance to work on.
* @retval none.
*/
__weak void MCI_ExecBufferedCommands( MCI_Handle_t * pHandle )
{
if ( pHandle != MC_NULL )
{
if ( pHandle->CommandState == MCI_COMMAND_NOT_ALREADY_EXECUTED )
{
bool commandHasBeenExecuted = false;
switch ( pHandle->lastCommand )
{
case MCI_EXECSPEEDRAMP:
{
pHandle->pFOCVars->bDriveInput = INTERNAL;
STC_SetControlMode( pHandle->pSTC, STC_SPEED_MODE );
commandHasBeenExecuted = STC_ExecRamp( pHandle->pSTC, pHandle->hFinalSpeed, pHandle->hDurationms );
}
break;
case MCI_EXECTORQUERAMP:
{
pHandle->pFOCVars->bDriveInput = INTERNAL;
STC_SetControlMode( pHandle->pSTC, STC_TORQUE_MODE );
commandHasBeenExecuted = STC_ExecRamp( pHandle->pSTC, pHandle->hFinalTorque, pHandle->hDurationms );
}
break;
case MCI_SETCURRENTREFERENCES:
{
pHandle->pFOCVars->bDriveInput = EXTERNAL;
pHandle->pFOCVars->Iqdref = pHandle->Iqdref;
commandHasBeenExecuted = true;
}
break;
default:
break;
}
if ( commandHasBeenExecuted )
{
pHandle->CommandState = MCI_COMMAND_EXECUTED_SUCCESFULLY;
}
else
{
pHandle->CommandState = MCI_COMMAND_EXECUTED_UNSUCCESFULLY;
}
}
}
}
/**
* @brief It returns information about the state of the last buffered command.
* @param pHandle Pointer on the component instance to work on.
* @retval CommandState_t It can be one of the following codes:
* - MCI_BUFFER_EMPTY if no buffered command has been called.
* - MCI_COMMAND_NOT_ALREADY_EXECUTED if the buffered command
* condition hasn't already occurred.
* - MCI_COMMAND_EXECUTED_SUCCESFULLY if the buffered command has
* been executed successfully. In this case calling this function reset
* the command state to BC_BUFFER_EMPTY.
* - MCI_COMMAND_EXECUTED_UNSUCCESFULLY if the buffered command has
* been executed unsuccessfully. In this case calling this function
* reset the command state to BC_BUFFER_EMPTY.
*/
__weak MCI_CommandState_t MCI_IsCommandAcknowledged( MCI_Handle_t * pHandle )
{
MCI_CommandState_t retVal = pHandle->CommandState;
if ( ( retVal == MCI_COMMAND_EXECUTED_SUCCESFULLY ) |
( retVal == MCI_COMMAND_EXECUTED_UNSUCCESFULLY ) )
{
pHandle->CommandState = MCI_BUFFER_EMPTY;
}
return retVal;
}
/**
* @brief It returns information about the state of the related pSTM object.
* @param pHandle Pointer on the component instance to work on.
* @retval State_t It returns the current state of the related pSTM object.
*/
__weak State_t MCI_GetSTMState( MCI_Handle_t * pHandle )
{
return STM_GetState( pHandle->pSTM );
}
/**
* @brief It returns a 16 bit fields containing information about faults
* historically occurred since the state machine has been moved into
* FAULT_NOW state.
* \n\link Fault_generation_error_codes Returned error codes are listed here \endlink
* @param pHandle Pointer on the component instance to work on.
* @retval uint16_t 16 bit fields with information about the faults
* historically occurred since the state machine has been moved into
* FAULT_NOW state.
* \n\link Fault_generation_error_codes Returned error codes are listed here \endlink
*/
__weak uint16_t MCI_GetOccurredFaults( MCI_Handle_t * pHandle )
{
return ( uint16_t )( STM_GetFaultState( pHandle->pSTM ) );
}
/**
* @brief It returns a 16 bit fields containing information about faults
* currently present.
* \n\link Fault_generation_error_codes Returned error codes are listed here \endlink
* @param pHandle Pointer on the component instance to work on.
* @retval uint16_t 16 bit fields with information about about currently
* present faults.
* \n\link Fault_generation_error_codes Returned error codes are listed here \endlink
*/
__weak uint16_t MCI_GetCurrentFaults( MCI_Handle_t * pHandle )
{
return ( uint16_t )( STM_GetFaultState( pHandle->pSTM ) >> 16 );
}
/**
* @brief It returns the modality of the speed and torque controller.
* @param pHandle Pointer on the component instance to work on.
* @retval STC_Modality_t It returns the modality of STC. It can be one of
* these two values: STC_TORQUE_MODE or STC_SPEED_MODE.
*/
__weak STC_Modality_t MCI_GetControlMode( MCI_Handle_t * pHandle )
{
return pHandle->LastModalitySetByUser;
}
/**
* @brief It returns the motor direction imposed by the last command
* (MCI_ExecSpeedRamp, MCI_ExecTorqueRamp or MCI_SetCurrentReferences).
* @param pHandle Pointer on the component instance to work on.
* @retval int16_t It returns 1 or -1 according the sign of hFinalSpeed,
* hFinalTorque or Iqdref.q of the last command.
*/
__weak int16_t MCI_GetImposedMotorDirection( MCI_Handle_t * pHandle )
{
int16_t retVal = 1;
switch ( pHandle->lastCommand )
{
case MCI_EXECSPEEDRAMP:
if ( pHandle->hFinalSpeed < 0 )
{
retVal = -1;
}
break;
case MCI_EXECTORQUERAMP:
if ( pHandle->hFinalTorque < 0 )
{
retVal = -1;
}
break;
case MCI_SETCURRENTREFERENCES:
if ( pHandle->Iqdref.q < 0 )
{
retVal = -1;
}
break;
default:
break;
}
return retVal;
}
/**
* @brief It returns information about the last ramp final speed sent by the
* user expressed in tenths of HZ.
* @param pHandle Pointer on the component instance to work on.
* @retval int16_t last ramp final speed sent by the user expressed in tehts
* of HZ.
*/
__weak int16_t MCI_GetLastRampFinalSpeed( MCI_Handle_t * pHandle )
{
int16_t hRetVal = 0;
/* Examine the last buffered commands */
if ( pHandle->lastCommand == MCI_EXECSPEEDRAMP )
{
hRetVal = pHandle->hFinalSpeed;
}
return hRetVal;
}
/**
* @brief Check if the settled speed or torque ramp has been completed.
* @param pHandle Pointer on the component instance to work on.
* @retval bool It returns true if the ramp is completed, false otherwise.
*/
__weak bool MCI_RampCompleted( MCI_Handle_t * pHandle )
{
bool retVal = false;
if ( ( STM_GetState( pHandle->pSTM ) ) == RUN )
{
retVal = STC_RampCompleted( pHandle->pSTC );
}
return retVal;
}
/**
* @brief Stop the execution of speed ramp.
* @param pHandle Pointer on the component instance to work on.
* @retval bool It returns true if the command is executed, false otherwise.
*/
__weak bool MCI_StopSpeedRamp( MCI_Handle_t * pHandle )
{
return STC_StopSpeedRamp( pHandle->pSTC );
}
/**
* @brief Stop the execution of ongoing ramp.
* @param pHandle Pointer on the component instance to work on.
*/
__weak void MCI_StopRamp( MCI_Handle_t * pHandle)
{
STC_StopRamp( pHandle->pSTC );
}
/**
* @brief It returns speed sensor reliability with reference to the sensor
* actually used for reference frame transformation
* @param pHandle Pointer on the component instance to work on.
* @retval bool It returns true if the speed sensor utilized for reference
* frame transformation and (in speed control mode) for speed
* regulation is reliable, false otherwise
*/
__weak bool MCI_GetSpdSensorReliability( MCI_Handle_t * pHandle )
{
SpeednPosFdbk_Handle_t * SpeedSensor = STC_GetSpeedSensor( pHandle->pSTC );
return ( SPD_Check( SpeedSensor ) );
}
/**
* @brief Returns the last computed average mechanical speed, expressed in
* the unit defined by #SPEED_UNIT and related to the sensor actually
* used by FOC algorithm
* @param pHandle Pointer on the component instance to work on.
*/
__weak int16_t MCI_GetAvrgMecSpeedUnit( MCI_Handle_t * pHandle )
{
SpeednPosFdbk_Handle_t * SpeedSensor = STC_GetSpeedSensor( pHandle->pSTC );
return ( SPD_GetAvrgMecSpeedUnit( SpeedSensor ) );
}
/**
* @brief Returns the current mechanical rotor speed reference expressed in the unit defined by #SPEED_UNIT
*
* @param pHandle Pointer on the component instance to work on.
*
*/
__weak int16_t MCI_GetMecSpeedRefUnit( MCI_Handle_t * pHandle )
{
return ( STC_GetMecSpeedRefUnit( pHandle->pSTC ) );
}
/**
* @brief It returns stator current Iab in ab_t format
* @param pHandle Pointer on the component instance to work on.
* @retval ab_t Stator current Iab
*/
__weak ab_t MCI_GetIab( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->Iab );
}
/**
* @brief It returns stator current Ialphabeta in alphabeta_t format
* @param pHandle Pointer on the component instance to work on.
* @retval alphabeta_t Stator current Ialphabeta
*/
__weak alphabeta_t MCI_GetIalphabeta( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->Ialphabeta );
}
/**
* @brief It returns stator current Iqd in qd_t format
* @param pHandle Pointer on the component instance to work on.
* @retval qd_t Stator current Iqd
*/
__weak qd_t MCI_GetIqd( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->Iqd );
}
/**
* @brief It returns stator current IqdHF in qd_t format
* @param pHandle Pointer on the component instance to work on.
* @retval qd_t Stator current IqdHF if HFI is selected as main
* sensor. Otherwise it returns { 0, 0}.
*/
__weak qd_t MCI_GetIqdHF( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->IqdHF );
}
/**
* @brief It returns stator current Iqdref in qd_t format
* @param pHandle Pointer on the component instance to work on.
* @retval qd_t Stator current Iqdref
*/
__weak qd_t MCI_GetIqdref( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->Iqdref );
}
/**
* @brief It returns stator current Vqd in qd_t format
* @param pHandle Pointer on the component instance to work on.
* @retval qd_t Stator current Vqd
*/
__weak qd_t MCI_GetVqd( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->Vqd );
}
/**
* @brief It returns stator current Valphabeta in alphabeta_t format
* @param pHandle Pointer on the component instance to work on.
* @retval alphabeta_t Stator current Valphabeta
*/
__weak alphabeta_t MCI_GetValphabeta( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->Valphabeta );
}
/**
* @brief It returns the rotor electrical angle actually used for reference
* frame transformation
* @param pHandle Pointer on the component instance to work on.
* @retval int16_t Rotor electrical angle in dpp format
*/
__weak int16_t MCI_GetElAngledpp( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->hElAngle );
}
/**
* @brief It returns the reference eletrical torque, fed to derived class for
* Iqref and Idref computation
* @param pHandle Pointer on the component instance to work on.
* @retval int16_t Teref
*/
__weak int16_t MCI_GetTeref( MCI_Handle_t * pHandle )
{
return ( pHandle->pFOCVars->hTeref );
}
/**
* @brief It returns the motor phase current amplitude (0-to-peak) in s16A
* To convert s16A into Ampere following formula must be used:
* Current(Amp) = [Current(s16A) * Vdd micro] / [65536 * Rshunt * Aop]
* @param pHandle Pointer on the component instance to work on.
* @retval int16_t Motor phase current (0-to-peak) in s16A
*/
__weak int16_t MCI_GetPhaseCurrentAmplitude( MCI_Handle_t * pHandle )
{
alphabeta_t Local_Curr;
int32_t wAux1, wAux2;
Local_Curr = pHandle->pFOCVars->Ialphabeta;
wAux1 = ( int32_t )( Local_Curr.alpha ) * Local_Curr.alpha;
wAux2 = ( int32_t )( Local_Curr.beta ) * Local_Curr.beta;
wAux1 += wAux2;
wAux1 = MCM_Sqrt( wAux1 );
if ( wAux1 > INT16_MAX )
{
wAux1 = ( int32_t ) INT16_MAX;
}
return ( ( int16_t )wAux1 );
}
/**
* @brief It returns the applied motor phase voltage amplitude (0-to-peak) in
* s16V. To convert s16V into Volts following formula must be used:
* PhaseVoltage(V) = [PhaseVoltage(s16A) * Vbus(V)] /[sqrt(3) *32767]
* @param pHandle Pointer on the component instance to work on.
* @retval int16_t Motor phase voltage (0-to-peak) in s16V
*/
__weak int16_t MCI_GetPhaseVoltageAmplitude( MCI_Handle_t * pHandle )
{
alphabeta_t Local_Voltage;
int32_t wAux1, wAux2;
Local_Voltage = pHandle->pFOCVars->Valphabeta;
wAux1 = ( int32_t )( Local_Voltage.alpha ) * Local_Voltage.alpha;
wAux2 = ( int32_t )( Local_Voltage.beta ) * Local_Voltage.beta;
wAux1 += wAux2;
wAux1 = MCM_Sqrt( wAux1 );
if ( wAux1 > INT16_MAX )
{
wAux1 = ( int32_t ) INT16_MAX;
}
return ( ( int16_t ) wAux1 );
}
/**
* @brief When bDriveInput is set to INTERNAL, Idref should is normally managed
* by FOC_CalcCurrRef. Neverthless, this method allows forcing changing
* Idref value. Method call has no effect when either flux weakening
* region is entered or MTPA is enabled
* @param pHandle Pointer on the component instance to work on.
* @param int16_t New target Id value
* @retval none
*/
__weak void MCI_SetIdref( MCI_Handle_t * pHandle, int16_t hNewIdref )
{
pHandle->pFOCVars->Iqdref.d = hNewIdref;
pHandle->pFOCVars->UserIdref = hNewIdref;
}
/**
* @brief It re-initializes Iqdref variables with their default values.
* @param pHandle Pointer on the component instance to work on.
* @retval none
*/
__weak void MCI_Clear_Iqdref( MCI_Handle_t * pHandle )
{
pHandle->pFOCVars->Iqdref = STC_GetDefaultIqdref( pHandle->pSTC );
}
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT 2019 STMicroelectronics *****END OF FILE****/