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.

TMS320F280037C: (accidentally marked resolved, see new thread)

Part Number: TMS320F280037C

This post accidentally marked resolved, see new thread: e2e.ti.com/.../tms320f280037c-tms320f280037c-universal-motor-control-lab-estimator-estoutputdata-bad-despite-good-inputs-dmc_level_3-from-successful-dmc_level_2

Hey,

Spinning a BLDC motor, attempting to implement FAST. I have tested this motor on an evaluation kit using the InstaSPIN labs successfully.

I had some trouble getting DMC_LEVEL_2 to spin my motor on custom hardware.

On closer examination of the code, the V/Hz angle generator was NOT being used to command the motor, but the Estimator was instead.

I ended up stumbling on this because the InstaSPIN labs 'is03' the angle generator in the open loop V/Hz control DID work on my prototype, and it (properly?) bypasses the angle generated by the estimator.

I then turned on the estimator, without hooking it up to the control system, just to see if it was working correctly.

Here is the ISR I am using:

__interrupt void motor1CtrlISR(void)
{
    //motorVars_M1.ISRCount++;
    MOTOR_Vars_t *obj = (MOTOR_Vars_t *)motorHandle_M1;
    USER_Params *objUser = (USER_Params *)(obj->userParamsHandle);
    HAL_ackMtr1ADCInt();        // acknowledge the ADC interrupt
    HAL_readMtr1ADCData(&obj->adcData);    // read the ADC data with offsets
    obj->ISRCount++;
    obj->adcData.V_V.value[0] -=obj->adcData.offset_V_sf.value[0] * obj->adcData.VdcBus_V; // remove offsets
    obj->adcData.V_V.value[1] -=obj->adcData.offset_V_sf.value[1] * obj->adcData.VdcBus_V;
    obj->adcData.V_V.value[2] -=obj->adcData.offset_V_sf.value[2] * obj->adcData.VdcBus_V;
    // Verifies the ADC for current and voltage, offset compensation,
    // clarke / park transformations. (Without using estimator angle)
    MATH_Vec2 phasor;
    CLARKE_run(obj->clarkeHandle_I, &obj->adcData.I_A, &obj->estInputData.Iab_A);
    CLARKE_run(obj->clarkeHandle_V, &obj->adcData.V_V, &obj->estInputData.Vab_V);

#if (DMC_BUILDLEVEL == DMC_LEVEL_2)
        //---------------------------------------
        if(obj->flagRunIdentAndOnLine == true){
            obj->counterTrajSpeed++;
            if(obj->counterTrajSpeed >= objUser->numIsrTicksPerTrajTick){
                obj->counterTrajSpeed = 0;
                TRAJ_run(obj->trajHandle_spd); // run a trajectory for speed reference,  so the reference changes with a ramp instead of a step
                obj->estInputData.speed_ref_Hz= TRAJ_getIntValue(obj->trajHandle_spd);
            }

            //obj->enableCurrentCtrl = obj->flagEnableCurrentCtrl;
            //obj->enableSpeedCtrl = obj->flagEnableSpeedCtrl;
        }
        else{
            obj->enableSpeedCtrl = false;
            obj->enableCurrentCtrl = false;
        }

        obj->estInputData.dcBus_V = obj->adcData.VdcBus_V;
        obj->speed_int_Hz = obj->estInputData.speed_ref_Hz;

        EST_run(obj->estHandle, &obj->estInputData, &obj->estOutputData);
        //obj->oneOverDcBus_invV = obj->estOutputData.oneOverDcBus_invV;
        //obj->estOutputData.oneOverDcBus_invV = 1.0 / obj->estInputData.dcBus_V;
        obj->oneOverDcBus_invV = 1.0 / obj->estInputData.dcBus_V;

        ANGLE_GEN_run(obj->angleGenHandle, obj->estInputData.speed_ref_Hz);
        obj->angleGen_rad = ANGLE_GEN_getAngle(obj->angleGenHandle);//angleFoc_rad = ANGLE_GEN_getAngle(obj->angleGenHandle);
        obj->angleFOC_rad = obj->angleGen_rad;
        
        VS_FREQ_run(obj->VsFreqHandle, obj->estInputData.speed_ref_Hz);
        obj->Vdq_out_V.value[0] = VsFreq_M1.Vdq_out.value[0];//VS_FREQ_getVd_out(obj->VsFreqHandle);
        obj->Vdq_out_V.value[1] = VsFreq_M1.Vdq_out.value[1];//VS_FREQ_getVq_out(obj->VsFreqHandle);

        phasor.value[0] = __cos(obj->angleFOC_rad);
        phasor.value[1] = __sin(obj->angleFOC_rad);
        IPARK_setPhasor(obj->iparkHandle_V, &phasor);    // set the phasor in the inverse Park transform
        IPARK_run(obj->iparkHandle_V, &obj->Vdq_out_V, &obj->Vab_out_V);    // run the inverse Park module
        //SVGEN_setup(obj->svgenHandle, obj->estOutputData.oneOverDcBus_invV);    // setup the space vector generator (SVGEN) module
        SVGEN_setup(obj->svgenHandle, obj->oneOverDcBus_invV);
        SVGEN_run(obj->svgenHandle, &obj->Vab_out_V, &obj->pwmData.Vabc_pu);    // run the space vector generator (SVGEN) module

        if(HAL_getPwmEnableStatus(obj->halMtrHandle) == false)
        {
            obj->pwmData.Vabc_pu.value[0] = 0.0;
            obj->pwmData.Vabc_pu.value[1] = 0.0;
            obj->pwmData.Vabc_pu.value[2] = 0.0;
        }
        HAL_writePWMData(obj->halMtrHandle, &obj->pwmData);

Note here that the estimator is NOT used to generate the phase angle for the PWM; the ANGLE_GEN_Run directly receives the target speed and provides phasors to the PWM signal chain.

Here are some datalog snaps of the ADC readings using V/Hz control method:

(for each set of 4 graphs: top left, top right, bottom left, bottom right)

(edit)(left) I_A.value[0], I_A.value[1], I_A.value[2], angleGen_rad           

(middle) V_V.value[0], V_V.value[1], V_V.value[2], angleGen_rad        

(right) Iab_A.value[0], Iab_A.value[1], Vab_V.value[0], Vab_V.value[1]

              

So the Clarke transform outputs pretty sharp looking waveforms given the inputs. These are produced commanding a fairly low speed of 20 Hz. One would think the estimator would have no problem finding, for example, the rotor position from this feedback.

Instead, I get this:

when the motor isnt spinning, angle_rad is an actual number between -pi and pi, and when the motor starts spinning it immediately shoots to +Inf.

oneOverDcBus_invV is constant.

All the other numbers wildly change. RPS swings between -25000 and 25000.

How do I fix my estimator?

  • I immediately see an error in my ways: the FAST estimation is NOT yet enabled in DMC level 3 / is04, only the PI loop is added for current sensing/control.

    Gonna dig a bit more into the code. There is still something funny going on here.

  • There is still something funny going on here.

    Right though ESTrun() being called before the angle generator - let me have a look at my code and report any difference.

     EST_run(obj->estHandle, &obj->estInputData, &obj->estOutputData);

  • Oddly phasors are set to Park motor1_drive.c in SDK4.0 UMC project. It's set one time only after motor is reset.

    #if(DMC_BUILDLEVEL <= DMC_LEVEL_3)
    obj->angleFOC_rad = obj->angleGen_rad;
    #endif

    // compute the sin/cos phasor
    phasor.value[0] = __cos(obj->angleFOC_rad);
    phasor.value[1] = __sin(obj->angleFOC_rad);

    // set the phasor in the Park transform
    PARK_setPhasor(obj->parkHandle_I, &phasor);

    // run the Park transform
    PARK_run(obj->parkHandle_I, &(obj->estInputData.Iab_A),
    (MATH_vec2 *)&(obj->Idq_in_A));

    // End of MOTOR1_FAST && MOTOR1_ESMO

  • Oddly phasors are set to Park motor1_drive.c in SDK4.0 UMC project. It's set one time only after motor is reset.

    #if(DMC_BUILDLEVEL <= DMC_LEVEL_3)
    obj->angleFOC_rad = obj->angleGen_rad;
    #endif

    // compute the sin/cos phasor
    phasor.value[0] = __cos(obj->angleFOC_rad);
    phasor.value[1] = __sin(obj->angleFOC_rad);

    // set the phasor in the Park transform
    PARK_setPhasor(obj->parkHandle_I, &phasor);

    I am using the SDK 5.0 (saw it was new and was starting from scratch anyway), the universal_motor_control_lab_f28003x, this code is in 'motor1_drive.c' in the ISR '__interrupt void motor1CtrlISR' , and the ISR is called once per PWM cycle (at the end of every ADC read).

  • Angle generator is also run in motor1_ctrlISR() when ESMO && FAST symbols are defined. Seemingly should be || but I haven't debugged it that far yet. The phasers are set to Park in build level 3 shown above code snip and FocRad sets the alignment angle in the ISR. IPARK is not used in build level4 ISR that I have been able to find, appears as if PARK phasers are enabled build level 4.  

    Edit: Park is enabled and part of above snip disabled: obj->angleFOC_rad = obj->angleGen_rad;

    #if defined(MOTOR1_FAST) && defined(MOTOR1_ESMO)    //WAS && (OK<->OK)
        // sensorless-FOC
        MATH_Vec2 phasor;
    
        ANGLE_GEN_run(obj->angleGenHandle, obj->speed_int_Hz);
        obj->angleGen_rad = ANGLE_GEN_getAngle(obj->angleGenHandle);
        
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
            // Running state
        if(obj->estimatorMode == ESTIMATOR_MODE_FAST)
        {
        
            else if(obj->motorState == MOTOR_ALIGNMENT)
            {
                obj->angleFOC_rad = 0.0f;
                obj->enableSpeedCtrl = false;
    
                obj->stateRunTimeCnt++;
    
                obj->IsRef_A = 0.0f;
                obj->Idq_out_A.value[0] = obj->alignCurrent_A;
                obj->Idq_out_A.value[1] = 0.0f;
    
                TRAJ_setIntValue(obj->trajHandle_spd, 0.0f);
                EST_setAngle_rad(obj->estHandle, obj->angleFOC_rad);
                ESMO_setAnglePu(obj->esmoHandle, obj->angleFOC_rad);
                ANGLE_GEN_setAngle(obj->angleGenHandle, obj->angleFOC_rad);