This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28069M: QEP control issue

Part Number: TMS320F28069M


Hi TI team,

I would modify my original software (based on TI labs) which is using the sensorless FOC to use a QEP sensor (1023 PPT).If I only monitor speed value from QEP (using sensorless FOC to control), output is very good. I modified my software as follows :

  • In STVELCTL_setVelocityFeedback I modified the speedFeedback to use the one from STPOSCONV_getVelocityFiltered(stObj->posConvHandle);
  • I changed the ctrl.h/c files (to keep a compatible firmware and avoid 2 ctrl files) to mach the ctrlQEP.h/c for the CTRL_runOnline_User
  • I added the necessary stuff (encoder handles, position converter...)

But I am facing the 2 following issues :

  • Iq reference is stucked or almost stucked at maximum value, even if the spin has begun
  • The rotor spins alternatively forward and backward with a fixed period

Do you have an idea where it comes from ?

Why there isn't a notion of current control in ctrlQEP files ?

Thanks in advance,

  • Which lab are you using? And could you post the detailed changing code? What angle and speed are you using for FOC?

    You might refer to lab12a and lab12b to identify the motor inertia and run with encoder, and you should only use ctrlQEP.h/c , not to change the ctrl.h/c for the sensored-FOC project.
  • Hi Yanming

    I've adapted to use the ctrlQEP.h/c files as you requested it. I would only use the angle and speed of encoder if possible (as done in the lab12).

    I still have the same issues, here is  my code (based on lab 12 + use of STVELMOVE)

    Here is my code : 

    interrupt void mainISR(void)
    {
    	// Get encoder before acknowledging the interrupt
    	ENC_calcElecAngle(mc_encHandle, qep_GetPositionCounter());
    
    	// acknowledge the ADC interrupt
    	HAL_acqAdcInt(mc_halHandle, ADC_IntNumber_1);
    
    	// convert the ADC data
    	HAL_readAdcData(mc_halHandle, (HAL_AdcData_t*)&mc_adcData);
    
    	// Reconstruct the current
    	const SVGENCURRENT_MeasureShunt_e measurableShuntThisCycle = SVGENCURRENT_getMode(mc_svgenCurrentHandle);
    	mc_ReconstructCurrent(measurableShuntThisCycle);
    
    	if (mc_ctrlHandle == NULL)
    	{
    		return;
    	}
    
    	// Disable Speed regulation loop (bypassed)
    	CTRL_setFlag_enableSpeedCtrl(mc_ctrlHandle, false);
    
    	// Run the SpinTAC Components
    	if (mc_tickCounter++ >= ISR_TICKS_PER_SPINTAC_TICK)		 // Once each 15 loops
    	{
    		ST_Obj *stObj = (ST_Obj *)mc_spinTacHandle;
    
    		// get the electrical angle from the ENC module
    		STPOSCONV_setElecAngle_erev(stObj->posConvHandle, ENC_getElecAngle(mc_encHandle));
    
    		// run the SpinTAC Position Converter
    		STPOSCONV_run(stObj->posConvHandle);
    
    		CTRL_Obj *ctrlObj = (CTRL_Obj *)mc_ctrlHandle;
    
    		// Run SpinTAC Move
    		// If we are not in reset, and the SpeedRef_krpm has been modified
    		if (EST_getState(ctrlObj->estHandle) == EST_State_OnLine)
    		{
    			// Get the configuration for SpinTAC Move
    			STVELMOVE_setCurveType(stObj->velMoveHandle, mc_motorData.SpinTAC.VelMoveCurveType);
    			STVELMOVE_setVelocityEnd(stObj->velMoveHandle, _IQmpy(mc_motorData.SpeedRef_krpm, _IQ(ST_SPEED_PU_PER_KRPM)));
    			STVELMOVE_setAccelerationLimit(stObj->velMoveHandle, _IQmpy(mc_motorData.MaxAccel_krpmps, _IQ(ST_SPEED_PU_PER_KRPM)));
    			STVELMOVE_setJerkLimit(stObj->velMoveHandle, _IQ20mpy(MC_MAX_JERK_KRPMPS2, _IQ20(ST_SPEED_PU_PER_KRPM)));
    
    			// Enable SpinTAC Move
    			STVELMOVE_setEnable(stObj->velMoveHandle, true);
    
    		}
    
    		// Get the mechanical speed in pu
    		_iq speedFeedback = EST_getFm_pu(ctrlObj->estHandle);
    		speedFeedback = STPOSCONV_getVelocityFiltered(stObj->posConvHandle);
    
    		// Run the SpinTAC Controller
    		STVELCTL_setVelocityReference(stObj->velCtlHandle, STVELMOVE_getVelocityReference(stObj->velMoveHandle));
    		STVELCTL_setAccelerationReference(stObj->velCtlHandle, STVELMOVE_getAccelerationReference(stObj->velMoveHandle));
    		STVELCTL_setVelocityFeedback(stObj->velCtlHandle, speedFeedback);
    		STVELCTL_run(stObj->velCtlHandle);
    
    		// Get the Torque Reference from the SpinTAC Speed Controller
    		const _iq iqReference = STVELCTL_getTorqueReference(stObj->velCtlHandle);
    
    		// Set the Iq reference that came out of SpinTAC Velocity Control
    		CTRL_setIq_ref_pu(ctrlHandle, iqReference);
    
    		mc_RunVelCtl(mc_spinTacHandle, mc_ctrlHandle);
    		mc_tickCounter = 1;
    	}
    
    	// FW is always enabled
    	FW_setFlag_enableFw(mc_fieldWeakeningHandle, true);
    
    	// run the controller
    	CTRL_run(mc_ctrlHandle,
    			 mc_halHandle,
    			 (HAL_AdcData_t*)&mc_adcData,
    			 (HAL_PwmData_t*)&mc_pwmData,
    			 ENC_getElecAngle(mc_encHandle));
    
    	FW_incCounter(mc_fieldWeakeningHandle);
    
    	if (FW_getCounter(mc_fieldWeakeningHandle) > FW_getNumIsrTicksPerFwTick(mc_fieldWeakeningHandle))
    	{
    		FW_clearCounter(mc_fieldWeakeningHandle);
    
    		const _iq vsValue = mc_motorData.Vs;
    
    		_iq output;
    		FW_run(mc_fieldWeakeningHandle, MC_FIXED_VS_REF, vsValue, &output);
    
    		CTRL_setId_ref_pu(mc_ctrlHandle, output);
    	}
    
    	// setup the controller
    	CTRL_setup(mc_ctrlHandle);
    
    	// If we are forcing alignment, using the Rs Recalculation, align the eQEP angle with the rotor angle
    	if (EST_getState(ctrlObj->estHandle) == EST_State_Rs)
    	{
    		ENC_setZeroOffset(mc_encHandle, (uint32_t)(qep_GetMaximumPositionCounter() - qep_GetPositionCounter()));
    	}
    
    	// run the pwm compensation
    	mc_RunPwmCompensation();
    
    	return;
    }
    

  • interrupt void mainISR(void)
    {
    	// Get encoder before acknowledging the interrupt
    	ENC_calcElecAngle(mc_encHandle, qep_GetPositionCounter());
    
    	// acknowledge the ADC interrupt
    	HAL_acqAdcInt(mc_halHandle, ADC_IntNumber_1);
    
    	// convert the ADC data
    	HAL_readAdcData(mc_halHandle, (HAL_AdcData_t*)&mc_adcData);
    
    	// Reconstruct the current
    	const SVGENCURRENT_MeasureShunt_e measurableShuntThisCycle = SVGENCURRENT_getMode(mc_svgenCurrentHandle);
    	mc_ReconstructCurrent(measurableShuntThisCycle);
    
    	if (mc_ctrlHandle == NULL)
    	{
    		return;
    	}
    
    	// Disable Speed regulation loop (bypassed)
    	CTRL_setFlag_enableSpeedCtrl(mc_ctrlHandle, false);
    
    	// Run the SpinTAC Components
    	if (mc_tickCounter++ >= ISR_TICKS_PER_SPINTAC_TICK)		 // Once each 15 loops
    	{
    		ST_Obj *stObj = (ST_Obj *)mc_spinTacHandle;
    
    		// get the electrical angle from the ENC module
    		STPOSCONV_setElecAngle_erev(stObj->posConvHandle, ENC_getElecAngle(mc_encHandle));
    
    		// run the SpinTAC Position Converter
    		STPOSCONV_run(stObj->posConvHandle);
    
    		CTRL_Obj *ctrlObj = (CTRL_Obj *)mc_ctrlHandle;
    
    		// Run SpinTAC Move
    		// If we are not in reset, and the SpeedRef_krpm has been modified
    		if (EST_getState(ctrlObj->estHandle) == EST_State_OnLine)
    		{
    			// Get the configuration for SpinTAC Move
    			STVELMOVE_setCurveType(stObj->velMoveHandle, mc_motorData.SpinTAC.VelMoveCurveType);
    			STVELMOVE_setVelocityEnd(stObj->velMoveHandle, _IQmpy(mc_motorData.SpeedRef_krpm, _IQ(ST_SPEED_PU_PER_KRPM)));
    			STVELMOVE_setAccelerationLimit(stObj->velMoveHandle, _IQmpy(mc_motorData.MaxAccel_krpmps, _IQ(ST_SPEED_PU_PER_KRPM)));
    			STVELMOVE_setJerkLimit(stObj->velMoveHandle, _IQ20mpy(MC_MAX_JERK_KRPMPS2, _IQ20(ST_SPEED_PU_PER_KRPM)));
    
    			// Enable SpinTAC Move
    			STVELMOVE_setEnable(stObj->velMoveHandle, true);
    
    		}
    
    		// Get the mechanical speed in pu
    		_iq speedFeedback = EST_getFm_pu(ctrlObj->estHandle);
    		speedFeedback = STPOSCONV_getVelocityFiltered(stObj->posConvHandle);
    
    		// Run the SpinTAC Controller
    		STVELCTL_setVelocityReference(stObj->velCtlHandle, STVELMOVE_getVelocityReference(stObj->velMoveHandle));
    		STVELCTL_setAccelerationReference(stObj->velCtlHandle, STVELMOVE_getAccelerationReference(stObj->velMoveHandle));
    		STVELCTL_setVelocityFeedback(stObj->velCtlHandle, speedFeedback);
    		STVELCTL_run(stObj->velCtlHandle);
    
    		// Get the Torque Reference from the SpinTAC Speed Controller
    		const _iq iqReference = STVELCTL_getTorqueReference(stObj->velCtlHandle);
    
    		// Set the Iq reference that came out of SpinTAC Velocity Control
    		CTRL_setIq_ref_pu(ctrlHandle, iqReference);
    
    		mc_RunVelCtl(mc_spinTacHandle, mc_ctrlHandle);
    		mc_tickCounter = 1;
    	}
    
    	// FW is always enabled
    	FW_setFlag_enableFw(mc_fieldWeakeningHandle, true);
    
    	// run the controller
    	CTRL_run(mc_ctrlHandle,
    			 mc_halHandle,
    			 (HAL_AdcData_t*)&mc_adcData,
    			 (HAL_PwmData_t*)&mc_pwmData,
    			 ENC_getElecAngle(mc_encHandle));
    
    	FW_incCounter(mc_fieldWeakeningHandle);
    
    	if (FW_getCounter(mc_fieldWeakeningHandle) > FW_getNumIsrTicksPerFwTick(mc_fieldWeakeningHandle))
    	{
    		FW_clearCounter(mc_fieldWeakeningHandle);
    
    		const _iq vsValue = mc_motorData.Vs;
    
    		_iq output;
    		FW_run(mc_fieldWeakeningHandle, MC_FIXED_VS_REF, vsValue, &output);
    
    		CTRL_setId_ref_pu(mc_ctrlHandle, output);
    	}
    
    	// setup the controller
    	CTRL_setup(mc_ctrlHandle);
    
    	// If we are forcing alignment, using the Rs Recalculation, align the eQEP angle with the rotor angle
    	if (EST_getState(ctrlObj->estHandle) == EST_State_Rs)
    	{
    		ENC_setZeroOffset(mc_encHandle, (uint32_t)(qep_GetMaximumPositionCounter() - qep_GetPositionCounter()));
    	}
    
    	// run the pwm compensation
    	mc_RunPwmCompensation();
    
    	return;
    }
    
    Hi Yanming

    I've adapted to use the ctrlQEP.h/c files as you requested it. I would only use the angle and speed of encoder if possible (as done in the lab12).

    I still have the same issues, here is  my code (based on lab 12 + use of STVELMOVE)

    Here is my code attached.

  • Hi Yanming,

    I found the issue (the current reconstruction function used in sensorless FOC).

    I have a question concerning the following function : ENC_setup(encHandle, 1, USER_MOTOR_NUM_POLE_PAIRS, USER_MOTOR_ENCODER_LINES, 0, USER_IQ_FULL_SCALE_FREQ_Hz, USER_ISR_FREQ_Hz, 12000.f);

    the last parameter is said to be the cut-off frequency of a filter, but no many details help to set it at a correct value. What is a good value ? how do I have to tune it ? (our motor goes up to 11000 RPM)

    Thanks for you help

  • Hi,

    I am now suffering from issue using both 256 and 1024 points encoders above >~4000RPM. RPM stalls suddenly and control is not possible anymore. Do I have to change something in the ST_setupPosConv function ?

    Many thanks

  • 1. The cut-off frequency of the low pass filter depends on the maximum speed of the motor and what the speed response do you want.

    2. Just need to tune the USER_SYSTEM_BANDWIDTH first.