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.

flying start overvoltage

Other Parts Discussed in Thread: DRV8301, DRV8312, MOTORWARE

Hi everybody,

I'm actually working on flying start.

I'have done flying start following other posts :

"Another option that actually works better is to take over in torque mode with an inital command of Iq = 0A, and hold this 0A command for a certain amount of time (will have to test with your application), at which you switch to speed mode with a new reference (either the current speed or your new target speed)."

So my code is :

gMotorVars.Flag_enableRsRecalc=0;			//desactivation recalcul de la mesure de resistance
 gMotorVars.Flag_enableOffsetcalc=0;			//desactivation du recalcul des offsets
gMotorVars.Flag_enableForceAngle=0;		//desactivation du force angle
CTRL_setFlag_enableSpeedCtrl(ctrlHandle,false);	//desactivation de la regulation en vitesse
PID_setUi(obj->pidHandle_Iq,_IQ(0.0));			//init integrateur courant a 0
PID_setUi(obj->pidHandle_spd,_IQ(0.0));		//init integrateur vitesse a 0
CTRL_setIq_ref_pu(ctrlHandle,0);				//on met le regu de courant Iq a une consigne nulle

gMotorVars.Flag_Run_Identify=1;	

And then, during 5 seconds, i do the following :

 CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.Speed_krpm);	//on met la vitesse actuelle en consigne vitesse
CTRL_setIq_ref_pu(ctrlHandle,0);			//on met le regu de courant Iq a une consigne nulle
TRAJ_setIntValue(obj->trajHandle_spd,_IQmpy(gMotorVars.Speed_krpm,EST_get_krpm_to_pu_sf(obj->estHandle)));	//initialisation du generateur de trajectoire a la vitesse actuelle en PU

At the end of the 5s timeout, if the motor is running (speed threshold), i do this :

CTRL_setFlag_enableSpeedCtrl(ctrlHandle,true);		//on réactive la regulation en vitesse
CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.SpeedRef_krpm);	//on met la vitesse de reference en consigne
	

I have also modify the KP value regarding

"You will also want to make sure that your current controller is stiffened for this application, so instead of using the default Kp values (which are the bandwidth *0.25 StiffnessFactor you want to use the full bandwidth, or a *1.0 factor). This is because when the inverter is first enabled, a 50% duty cycle is at the output, which can generate current flowing, so the current controller needs to get that back to zero. "

The flying start at the end of my timeout is quite good but when I take over in current mode with 0A, there is a flowing curent from the motor. The value of this current depends off the motor speed. In fact this current is not the main problem, with the inductance of the motor, this create a powerfull boost power supply wich create overvoltage on the DC link capacitor :

  

Is there a way to remove this pulse?

Regards.

Emmanuel

  • Manu,

    Here is how I would recommend doing flying start

    1. Enable current controllers in torque mode commanding a zero Iq.
    2. Let the current controllers settle. From experience, this would take a few milliseconds. And also, the higher the bandwidth in the current controllers, the faster it will settle.
    3. Then enable the speed controller with a reference equal to the latest estimated speed to avoid any kicks
    4. Once you are in control of the motor, then change the speed reference freely as needed.

     

  • This is exactly what I have done.

    The flowing current seems to be link to the current controller settle (about 5ms), this is not when I enable the speed controller (when I enable the speed controller, there is no kicks).

    Changing the default Kp value from 0.25 to 1 factor has a poor effect, i try to increase to *2 and it is the same (with *3 or *4 there is a problem).

    I also try to increase Ki but the change is also poor.

    Is there a way to increase again the bandwidth? What are the limits for Kp and Ki increase? What about Kd, have you ever try to put derivative effect?

    Regards.

    Emmanuel

  • do you get the estimated value and use it for this Speed_krpm command?  I don't see that in your code

    CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.Speed_krpm);

    It's important to match the flying speed first...it seems like you are using your TARGET speed and the speed controller saturates and puts out a large IqRef command once enabled.

     

  • I do this during the 5 second timeout:

    "And then, during 5 seconds, i do the following :

    CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.Speed_krpm);
    ......"
     
    The problem is not the speed controller, there is 5 seconds before I enable the speed controller, and I'm sure the current flowing is not linked to the speed controller but it is linked to the activation of the current controller.

  • Sorry it seems the end of the last message doesn't appear :

    Manu36 said:

    I do this during the 5 second timeout:

    "And then, during 5 seconds, i do the following :

    CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.Speed_krpm);
    ......"
     
    The problem is not the speed controller, there is 5 seconds before I enable the speed controller, and I'm sure the current flowing is not linked to the speed controller but it is linked to the activation of the current controller.

    Regards.

    Emmanuel

  • I don't understand a part of my post has disapear again :

    I do this during the 5 second timeout:

    "And then, during 5 seconds, i do the following :

    CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.Speed_krpm);"
     
    The problem is not the speed controller, there is 5 seconds before I enable the speed controller, and I'm sure the current flowing is not linked to the speed controller but it is linked to the activation of the current controller.
    Regards.
    Emmanuel
  • I don't know why but a part of my posts dosen't appear.

    I will reformulate it from the beginning :

    The code you suggest me is present and I do it during 5 seconds.

    I'm sure the current flowing is not when I enable the speed controller because this is done 5 seconds after I start up the flying start and the current flowing is at the beginning, when I enable the current control.

    Sorry for all those incomplete posts.

    Regards.

    Emmanuel

  • Manu,

    Do you have your inverter OFF for any portion of this?

    You want the PWMs off to the inverter, so there will be no current flow through the inverter.

    Except I know that with the DRV8312 you are actually setting all the low side PWMs on...so there is some current flow from the generating motor....I can't recall with the DRV8301...it should be actually no PWMs on I believe.

     

    ForceAngle disabled.

    PWM disabled.

    And then you set-up torque mode with IqRef_A = 0

    PWM enabled (current will start flowing as the rotor is moving across a circuit created by your inverter)

    let the current loop stabilize for some mili-seconds

    Then you get the estimated speed, and immediately use that for your SpeedRef.

    Then enable speed mode.

    Then set a new SpeedRef to your desired speed.

  • That will cause a kick, right? I need to update the intermediate trajectory speed to actually catch the motor, similar to Manu36, here's my code going from torque controller to speed controller.

    // Switch from torque control to speed control
    TRAJ_setIntValue(obj->trajHandle_spd, _IQdiv(gMotorVars.Speed_krpm,EST_get_pu_to_krpm_sf(obj->estHandle)));
    CTRL_setFlag_enableSpeedCtrl(ctrlHandle, true);

    Setting the gMotorVars.Speed_krpm does not help in my case because the intermediate trajectory value starts from 0.0 causing the motor to brake on start.

    Please confirm whether this is correct, thanks.

  • I agree with you Soon Yet Chan, it is necessary to update the trajectory and as you can see in my code, i do this:

    TRAJ_setIntValue(obj->trajHandle_spd,_IQmpy(gMotorVars.Speed_krpm,EST_get_krpm_to_pu_sf(obj->estHandle)));

    My probleme is not when I enable the speed controller but before, when I enable the torque controller.

    @ Chris : the PWM is disabled and enabled only after seting the torque mode as you can see in my code (Run_identify =1 after setting Iq=0).

    For me it is a problem of current regulator wich take about 5ms to stabilise to 0, and this is too long, I need to stiffen it.

    Regards.

    Emmanuel

  • Take a look at this :

    The green curve is GPIO I toggle before setting run_identify=1(so it seems PWM is on 5 ms after setting run_identify=1)

    The red is the ouptut of a half-bridge (we can see the votage generated by the running motor so inverter is off)

    Yellow = curent 

    blue = DC voltage

    This one is also very good with 1 second time base :

  • Something else interesting I have note (I use DRV8301 and 28027 controle card):

    The gate driver is not ready directly after we enable it, there is delay due to capacitor charging, so when we enable the driver, it stay in fault mode for several ms and after that only it starts to work correctly.

    I have thought that perhaps this fault mode was disturbing the current regulator, so to bypasss this charging capacitor timing, i have enable the driver earlier (before i have check that PWM were all off when the control was off). The result was poor, the inrush was much higher.

    I also try to enable the driver 20ms after setting the current regulator ON, but it was the same than original.

  • Our expert Jorge knows the exact solution for this...he will reply on Monday. 

  • I'm happy to know this, this will help me to have a nice week-end.

    Regards.

    Emmanuel

  • Essentially you have a current spike because the back EMF of the motor doesn't match the output voltage of the inverter when you first enable it. So what you need to do is to seed both of your current controllers to the backEMF of the motor before you enable your current controllers.

    How do you seed your current controllers? Here's how. Before enabling your inverter, while FAST is working purely as an observer (without controlling the motor) you can calculate the back EMF from the voltage feedback of the motor. So the first thing you need to do is to calculate Vd and Vq from the voltage feedback. You already have this code, plus some additional code marked with comment "// new code" (also highlighted)

    // new code
    // declare this global variable in your main project file
    MATH_vec2 gVdq_in;

    // new code
    // reference this global variable in ctrl.h
    extern MATH_vec2 gVdq_in;

    inline void CTRL_runOnLine_User(CTRL_Handle handle,
                               const HAL_AdcData_t *pAdcData,HAL_PwmData_t *pPwmData)
    {
      CTRL_Obj *obj = (CTRL_Obj *)handle;

      _iq angle_pu;

      MATH_vec2 phasor;


     // run Clarke transform on current
     CLARKE_run(obj->clarkeHandle_I,&pAdcData->I,CTRL_getIab_in_addr(handle));


     // run Clarke transform on voltage
     CLARKE_run(obj->clarkeHandle_V,&pAdcData->V,CTRL_getVab_in_addr(handle));


     // run the estimator
     EST_run(obj->estHandle,CTRL_getIab_in_addr(handle),CTRL_getVab_in_addr(handle),
             pAdcData->dcBus,TRAJ_getIntValue(obj->trajHandle_spd));


     // generate the motor electrical angle
     angle_pu = EST_getAngle_pu(obj->estHandle);


     // compute the sin/cos phasor
     CTRL_computePhasor(angle_pu,&phasor);


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


     // run the Park transform
     PARK_run(obj->parkHandle,CTRL_getIab_in_addr(handle),CTRL_getIdq_in_addr(handle));
     
     // new code
     // calculate the park transform of the input voltages
     PARK_run(obj->parkHandle,CTRL_getVab_in_addr(handle),&gVdq_in);
     
    At this point, before enabling the inverter, you have Vdq of the motor. Since the inverter is off, there is no current through the motor, hence this Vdq is the back EMF of the motor.

    The next thing to do is to seed the current controllers with this voltage. So wherever you are enabling the inverter, you need to do this prior to enabling the inverter:

     // seed Id controller prior to enabling the inverter
     PID_setUi(obj->pidHandle_Id,gVdq_in.value[0]);
     
     // seed Iq controller prior to enabling the inverter
     PID_setUi(obj->pidHandle_Iq,gVdq_in.value[1]);
     
     // enable inverter
     // your existing inverter enable logic

    Please try this out and let us know how it goes.

    -Jorge

  • The result is a little bit better, the overvoltage induced by the flowing current has reduce around 20% to 40% (the overvoltage is not always the same) .

    The fact that we don't have a better result can be linked to the delay between the enable of the DRV8301 and the time it is operationnal (several ms)? During this time, perhaps the output of the PID start to change?

    Emmanuel

  • I agree, I think the fact the DRV8301 device is not enabling its outputs right away, the current controller has some time to change its outputs from the original seed value, and motor also moves, so backEMF also changes. So the seeding becomes less effecting as more time elapses between enabling the DRV8301 and outputs are alive.

    Could you try having a timeout counter, and even though the 8301 is enabled, still output Low on both high and low PWM outputs, so that when you enable the current controllers seeding, the 8301 chip is already alive, but waiting for the inputs to have an actual PWM input.

    As far as I know, from the input enable going high, to when the device has its outputs active, is not a fixed delay.

    -Jorge

  • I will try if I have time, perhaps I can poll the Fault output of the driver, waiting this one to be ready, but I think I will wait for my own hardware which will be ready last week. On this hardware, the driver is not the DRV8301 and no delay will be present.

    Another question, I can't see any bootstrap capacitor charging phase before enabling the control, so perhaps there is an additional delay before the TOP mosfet are ready?

    Regards.

    Emmanuel

  • This is from the drv8301 team

    There’s a 5-10 ms. delay from ENABLE going high till the charge pump is ready (bias for the high side NFET). It’s so long due to the large size of the charge pump on this device.

     I would go with what Jorge recommended and just leave the DRV8301 active with the PWM inputs low to Hi-Z the bridges. That should solve the problem.

  • I have take some measure of the charge pump voltage, could I have some explanation?

    On a classsic charge pump driver, the capacitor is charged when the low side mosfet is ON but on DRV8301, the capacitor is charged when the driver is enabled, by another mean isn't it? How does it work, the DRV8301 datasheet is poor about this, is it the "trickle charge circuitry"?

    What about the HVMTR drive, this one use a classic charge pump driver so capacitor is charged only with bottom mosfet isn'it?

    Regarding Jorge answer, afer I enable the driver, I have made a "while loop" like this :

     while (DRV_getfault (drvHandle) ==0)
    	 		 {
    	 			DRV_toggleLed(drvHandle,(GPIO_Number_e)DRV_Gpio_LED2);//for scope debug
    	 			PID_setUi(obj->pidHandle_Id,gVdq_in.value[0]);
    	 			// seed Iq controller prior to enabling the inverter
    	 			PID_setUi(obj->pidHandle_Iq,gVdq_in.value[1]);
    
    	 		 }

    With this, the current controller is seeded just before the driver is ready (and not just before the driver is enabled), the result is about the same that without this extra-code.

    Regards.

    Emmanuel.

  • In order for this to work, you have to make sure that the PWM high and PWM low are both inactive (both low, or zero). Otherwise, when you are in this while loop, if the outputs are active before you seed the controllers, you will be generating a previously calculated duty cycle, or zero, or some voltage different than the back EMF, which will cause this current spike.

    -Jorge

  • The while loop is made only during the fault state of the driver so, regardless of the PWM, there will no switching transistors. I have take a look with the oscillo ( I toggle a pin during the while loop) and I can see the current is flowing when the while loop is ended (and not during the while loop).

    Green : GPIO I toggle during the loop

    Yellow : current

    blue : DC bus voltage

    regards.

    Emmanuel

  • Where is that while loop executed? Could you make sure that the backEMF is being calculated while you are in this while loop? Is there a way you can plot the calculated backEMF while you are in this while loop?

    -Jorge

  • The while loop is in the main, I was thinking the backEMF was calculated during interrupt isn'it?

    If I take a look closer at the oscilloscope waveform, with 100µs timebase, I can see the GPIO stop toggleing during 20us to 60us every 100us => this is my PWM frequency, during the time GPIO stop toggle, this is the interrupt execution.

    The best will be to toggle a GPIO when the extra code wich calculate the park transform of the input voltages in ctrl.h is executed but I think I will be very difficult for me (C++, obj, handle,... this is new for me).

    During the while loop, the result of EST_getSpeed_krpm(obj->estHandle); seems correct.

    Next step will be tomorrow for me.

    Regards.

    Emmanuel

  • Yes, the backEMF should be in the ISR, as this is in ctrl.h, under runOnLine function.

    This is how you can do a pin toggle inside of CTRL_runOnLine_User function:

    First add this to ctrl.h (I assume you are not on release 12, since you call DRV instead of HAL which was one of the main changes from release 11 to release 12)

    #include "drv.h"  // This is #include "hal.h" in release 12

    Then, change the way you call CTRL_runOnLine_User in ctrl.c

    CTRL_runOnLine_User(handle,drvHandle,pAdcData,pPwmData);

    then, in ctrl.h, change the header of this function:

    inline void CTRL_runOnLine_User(CTRL_Handle handle,DRV_Handle drvHandle,
                               const HAL_AdcData_t *pAdcData,HAL_PwmData_t *pPwmData)

    Then you can add your pin toggle inside of this function:

    DRV_toggleLed(drvHandle,(GPIO_Number_e)DRV_Gpio_LED2);//for scope debug

    -Jorge

     

  • Hi Manu,

    I support the DRV devices. To clarify on some things (the datasheet is ambiguous here, in the works to be fixed).

    I'll be refering to the block diagram on page 5 in the DRV8301 datasheet.

    When the DRV8301 ENABLE pin is low, it shuts off the charge pump regulator and other internal regulators in order to go into a low power mode. They 5-10 ms delay after bringing ENABLE high is how long it takes to wake everything back (I believe the charge pump regulator is the dominating factor here).

    The charge pump regulator provides the bias for the low side NFET and also charges the bootstraps when the low side FET is ON. We utilize a charge pump regulator to support operation down to 6V on PVDD. The Trickle Charge circuit is to support 100% duty cycle operation. When the bootstrap depletes the trickle charge will take over.

    I cannot comment on the HVMTR kit but it looks like it also uses a gate driver. I am not sure on it's architecture for the high side bias.

  • So this is the result of the toggling pin, in CTRL_runOnLine_User, just before  PARK_run(obj->parkHandle,CTRL_getVab_in_addr(handle),&gVdq_in) :

    green : GPIO toggling

    yellow : flowing current

    blue : dc voltage

    We can see the togglingg is never interupted, so the calcul must be OK.

    If I zoom on the waveform, I can see that the code is executed 2 times every 200µs (Tpwm = 100µs) but not exactly every 100µs, it seem that a fonction is longer to execute 1 out of 2 (USER_NUM_CTRL_TICKS_PER_EST_TICK =2).

    When I set USER_NUM_CTRL_TICKS_PER_EST_TICK=1, toggling is regular.

    Regards.

    Emmanuel 

  • Could you please capture these signals with the oscilloscope while doing a fly start?

    1. PWM High of phase A

    2. PWM Low of phase A

    3. EN_GATE signal to the DRV8301 device

    4. Current of phase A

    Also please confirm the version of MotorWare you are using.

    -Jorge

  • Hello Jorge,

    You will found below the waveform (with 2 different timebase):

    Yellow : current of phase A (positive = curent going out of inverter)

    green : PWM_AH

    blue : PWM_AL

    red : EN_GATE

    Regarding Motorware, I use _10 or _11 (I don't remember and I have made a copy of all source file) but I think i is _10.

    If you could point a difference in the source file, I can check.

    Do you think it could be linked to a bad offset parameter (current and voltage)?

    Regards.

    Emmanuel

  • I did some experiments today, and I was able to run with no kicks at all. Please upgrade to MotorWare release 12, so you can use the files I am attaching here.

    The first file is a revised lab 3b, so that you can just replace the existing 3b.c file and give this a try.

    /* --COPYRIGHT--,BSD
     * Copyright (c) 2012, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * --/COPYRIGHT--*/
    //! \file   solutions/instaspin_foc/src/proj_lab03b.c
    //!
    //! \brief Using your own hardware (current and voltage offsets) settings from user.h
    //!
    //! (C) Copyright 2011, Texas Instruments, Inc.
    
    //! \defgroup PROJ_LAB03b PROJ_LAB03b
    //@{
    
    //! \defgroup PROJ_LAB03b_OVERVIEW Project Overview
    //!
    //! Saving your hardware parameters and loading from user.h
    //!
    
    // **************************************************************************
    // the includes
    
    // system includes
    #include <math.h>
    #include "main.h"
    
    #ifdef FLASH
    #pragma CODE_SECTION(mainISR,"ramfuncs");
    #endif
    
    // Include header files used in the main function
    
    
    // **************************************************************************
    // the defines
    
    #define LED_BLINK_FREQ_Hz   5
    
    
    // **************************************************************************
    // the globals
    
    uint_least16_t gCounter_updateGlobals = 0;
    
    bool Flag_Latch_softwareUpdate = true;
    
    CTRL_Handle ctrlHandle;
    
    HAL_Handle halHandle;
    
    USER_Params gUserParams;
    
    HAL_PwmData_t gPwmData = {_IQ(0.0), _IQ(0.0), _IQ(0.0)};
    
    HAL_AdcData_t gAdcData;
    
    FEM_Handle femHandle;
    FEM_Obj    fem;
    uint32_t   gNumFreqErrors = 0;
    uint32_t   gMaxDeltaCntObserved = 0;
    
    CPU_USAGE_Handle cpu_usageHandle;
    CPU_USAGE_Obj    cpu_usage;
    float_t          gCpuUsagePercentageMin = 0.0;
    float_t          gCpuUsagePercentageAvg = 0.0;
    float_t          gCpuUsagePercentageMax = 0.0;
    
    _iq gMaxCurrentSlope = _IQ(0.0);
    
    #ifdef FAST_ROM_V1p6
    CTRL_Obj *controller_obj;
    #else
    CTRL_Obj ctrl;				//v1p7 format
    #endif
    
    uint16_t gLEDcnt = 0;
    
    volatile MOTOR_Vars_t gMotorVars = MOTOR_Vars_INIT;
    
    #ifdef FLASH
    // Used for running BackGround in flash, and ISR in RAM
    extern uint16_t *RamfuncsLoadStart, *RamfuncsLoadEnd, *RamfuncsRunStart;
    #endif
    
    
    #ifdef DRV8301_SPI
    // Watch window interface to the 8301 SPI
    DRV_SPI_8301_Vars_t gDrvSpi8301Vars;
    #endif
    
    volatile bool Flag_Enable_Inverter = false;
    
    volatile bool Flag_is_Inverter_Enabled = false;
    
    _iq FlyingStartSpeedRef_krpm = _IQ(2.0);
    
    _iq FlyingStartInitSpeedRef_krpm = _IQ(2.0);
    
    uint_least32_t TorqueModeCounter = 0;
    
    uint_least32_t TorqueModeCounterMaxCnt = (uint_least32_t)(0.05 * USER_ISR_FREQ_Hz);
    
    MATH_vec2 gVdq_in;
    
    // **************************************************************************
    // the functions
    
    void main(void)
    {
      uint_least8_t estNumber = 0;
    
    #ifdef FAST_ROM_V1p6
      uint_least8_t ctrlNumber = 0;
    #endif
    
      // Only used if running from FLASH
      // Note that the variable FLASH is defined by the project
      #ifdef FLASH
      // Copy time critical code and Flash setup code to RAM
      // The RamfuncsLoadStart, RamfuncsLoadEnd, and RamfuncsRunStart
      // symbols are created by the linker. Refer to the linker files.
      memCopy((uint16_t *)&RamfuncsLoadStart,(uint16_t *)&RamfuncsLoadEnd,(uint16_t *)&RamfuncsRunStart);
      #endif
    
      // initialize the hardware abstraction layer
      halHandle = HAL_init(&hal,sizeof(hal));
    
    
      // check for errors in user parameters
      USER_checkForErrors(&gUserParams);
    
    
      // store user parameter error in global variable
      gMotorVars.UserErrorCode = USER_getErrorCode(&gUserParams);
    
    
      // do not allow code execution if there is a user parameter error
      if(gMotorVars.UserErrorCode != USER_ErrorCode_NoError)
        {
          for(;;)
            {
              gMotorVars.Flag_enableSys = false;
            }
        }
    
    
      // initialize the user parameters
      USER_setParams(&gUserParams);
    
    
      // set the hardware abstraction layer parameters
      HAL_setParams(halHandle,&gUserParams);
    
    
      // initialize the controller
    #ifdef FAST_ROM_V1p6
      ctrlHandle = CTRL_initCtrl(ctrlNumber, estNumber);  		//v1p6 format (06xF and 06xM devices)
      controller_obj = (CTRL_Obj *)ctrlHandle;
    #else
      ctrlHandle = CTRL_initCtrl(estNumber,&ctrl,sizeof(ctrl));	//v1p7 format default
    #endif
    
    
      {
        CTRL_Version version;
    
        // get the version number
        CTRL_getVersion(ctrlHandle,&version);
    
        gMotorVars.CtrlVersion = version;
      }
    
    
      // set the default controller parameters
      CTRL_setParams(ctrlHandle,&gUserParams);
    
    
      // initialize the frequency of execution monitoring module
      femHandle = FEM_init(&fem,sizeof(fem));
      FEM_setParams(femHandle,
                    USER_SYSTEM_FREQ_MHz * 1000000.0,                  // timer frequency, Hz
                    (uint32_t)USER_SYSTEM_FREQ_MHz * 1000000,          // timer period, cnts
                    USER_CTRL_FREQ_Hz,                                 // set point frequency, Hz
                    1000.0);                                           // max frequency error, Hz
    
    
      // initialize the CPU usage module
      cpu_usageHandle = CPU_USAGE_init(&cpu_usage,sizeof(cpu_usage));
      CPU_USAGE_setParams(cpu_usageHandle,
                         (uint32_t)USER_SYSTEM_FREQ_MHz * 1000000,     // timer period, cnts
                         (uint32_t)USER_ISR_FREQ_Hz);                  // average over 1 second of ISRs
    
    
      // setup faults
      HAL_setupFaults(halHandle);
    
    
      // initialize the interrupt vector table
      HAL_initIntVectorTable(halHandle);
    
    
      // enable the ADC interrupts
      HAL_enableAdcInts(halHandle);
    
    
      // reload timer to start running frequency of execution monitoring
      HAL_reloadTimer(halHandle,0);
    
    
      // enable global interrupts
      HAL_enableGlobalInts(halHandle);
    
    
      // enable debug interrupts
      HAL_enableDebugInt(halHandle);
    
    
      // disable the PWM
      HAL_disablePwm(halHandle);
    
    
    #ifdef DRV8301_SPI
      // turn on the DRV8301 if present
      HAL_enableDrv(halHandle);
      // initialize the DRV8301 interface
      HAL_setupDrvSpi(halHandle,&gDrvSpi8301Vars);
    #endif
    
    
      // enable DC bus compensation
      CTRL_setFlag_enableDcBusComp(ctrlHandle, true);
    
    
      // disable offsets recalibration by default
      gMotorVars.Flag_enableOffsetcalc = false;
    
    
      for(;;)
      {
        // Waiting for enable system flag to be set
        while(!(gMotorVars.Flag_enableSys));
    
        // loop while the enable system flag is true
        while(gMotorVars.Flag_enableSys)
          {
            CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle;
    
            // increment counters
            gCounter_updateGlobals++;
    
            // enable/disable the use of motor parameters being loaded from user.h
            CTRL_setFlag_enableUserMotorParams(ctrlHandle,true);
    
            // enable/disable Rs recalibration during motor startup
            EST_setFlag_enableRsRecalc(obj->estHandle,false);
    
            // enable/disable automatic calculation of bias values
            CTRL_setFlag_enableOffset(ctrlHandle,false);
    
            // enable/disable the forced angle
            EST_setFlag_enableForceAngle(obj->estHandle,false);
    
            if(CTRL_isError(ctrlHandle))
              {
                // set the enable controller flag to false
                CTRL_setFlag_enableCtrl(ctrlHandle,false);
    
                // set the enable system flag to false
                gMotorVars.Flag_enableSys = false;
    
                // disable the PWM
                HAL_disablePwm(halHandle);
              }
            else
              {
                // update the controller state
                bool flag_ctrlStateChanged = CTRL_updateState(ctrlHandle);
    
                // enable or disable the control
                CTRL_setFlag_enableCtrl(ctrlHandle, gMotorVars.Flag_Run_Identify);
    
                if(flag_ctrlStateChanged)
                  {
                    CTRL_State_e ctrlState = CTRL_getState(ctrlHandle);
    
                    if(ctrlState == CTRL_State_OnLine)
                      {
                        // set the current bias
                        HAL_setBias(halHandle,HAL_SensorType_Current,0,_IQ(I_A_offset));
                        HAL_setBias(halHandle,HAL_SensorType_Current,1,_IQ(I_B_offset));
                        HAL_setBias(halHandle,HAL_SensorType_Current,2,_IQ(I_C_offset));
    
                        // set the voltage bias
                        HAL_setBias(halHandle,HAL_SensorType_Voltage,0,_IQ(V_A_offset));
                        HAL_setBias(halHandle,HAL_SensorType_Voltage,1,_IQ(V_B_offset));
                        HAL_setBias(halHandle,HAL_SensorType_Voltage,2,_IQ(V_C_offset));
                      }
                    else if(ctrlState == CTRL_State_Idle)
                      {
                        // disable the PWM
                        HAL_disablePwm(halHandle);
                        gMotorVars.Flag_Run_Identify = false;
                      }
                  }
              }
    
    
            if(EST_isMotorIdentified(obj->estHandle))
              {
                // set the current ramp
                EST_setMaxCurrentSlope_pu(obj->estHandle,gMaxCurrentSlope);
                gMotorVars.Flag_MotorIdentified = true;
    
                // set the speed reference
                CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.SpeedRef_krpm);
    
                // set the speed acceleration
                CTRL_setMaxAccel_pu(ctrlHandle,_IQmpy(MAX_ACCEL_KRPMPS_SF,gMotorVars.MaxAccel_krpmps));
    
                if(Flag_Latch_softwareUpdate)
                {
                  Flag_Latch_softwareUpdate = false;
    
    #ifdef FAST_ROM_V1p6
                  if(CTRL_getFlag_enableUserMotorParams(ctrlHandle) == true)
                  {
                      // call this function to fix 1p6
                      softwareUpdate1p6(ctrlHandle);
                  }
    #endif
    
                  calcPIgains(ctrlHandle);
                }
    
              }
            else
              {
                Flag_Latch_softwareUpdate = true;
    
                // the estimator sets the maximum current slope during identification
                gMaxCurrentSlope = EST_getMaxCurrentSlope_pu(obj->estHandle);
              }
    
    
            // when appropriate, update the global variables
            if(gCounter_updateGlobals >= NUM_MAIN_TICKS_FOR_GLOBAL_VARIABLE_UPDATE)
              {
                // reset the counter
                gCounter_updateGlobals = 0;
    
                updateGlobalVariables_motor(ctrlHandle);
              }
    
            // get the maximum delta count observed
            gMaxDeltaCntObserved = FEM_getMaxDeltaCntObserved(femHandle);
    
            // check for errors
            if(FEM_isFreqError(femHandle))
              {
                gNumFreqErrors = FEM_getErrorCnt(femHandle);
              }
    
            // enable/disable the forced angle
            EST_setFlag_enableForceAngle(obj->estHandle,gMotorVars.Flag_enableForceAngle);
    
            // enable or disable power warp
            CTRL_setFlag_enablePowerWarp(ctrlHandle,gMotorVars.Flag_enablePowerWarp);
    
    #ifdef DRV8301_SPI
            HAL_writeDrvData(halHandle,&gDrvSpi8301Vars);
    
            HAL_readDrvData(halHandle,&gDrvSpi8301Vars);
    #endif
    
          } // end of while(gFlag_enableSys) loop
    
    
        // disable the PWM
        HAL_disablePwm(halHandle);
    
        // set the default controller parameters (Reset the control to re-identify the motor)
        CTRL_setParams(ctrlHandle,&gUserParams);
        gMotorVars.Flag_Run_Identify = false;
    
      } // end of for(;;) loop
    
    } // end of main() function
    
    
    interrupt void mainISR(void)
    {
      uint32_t timer0Cnt;
      uint32_t timer1Cnt;
    
    
      // read the timer 1 value and update the CPU usage module
      timer1Cnt = HAL_readTimerCnt(halHandle,1);
      CPU_USAGE_updateCnts(cpu_usageHandle,timer1Cnt);
    
    
      // read the timer 0 value and update the FEM
      timer0Cnt = HAL_readTimerCnt(halHandle,0);
      FEM_updateCnts(femHandle,timer0Cnt);
      FEM_run(femHandle);
    
    
      // toggle status LED
      if(gLEDcnt++ > (uint_least32_t)(USER_ISR_FREQ_Hz / LED_BLINK_FREQ_Hz))
      {
        HAL_toggleLed(halHandle,(GPIO_Number_e)HAL_Gpio_LED2);
        gLEDcnt = 0;
      }
    
    
      // acknowledge the ADC interrupt
      HAL_acqAdcInt(halHandle,ADC_IntNumber_1);
    
    
      // convert the ADC data
      HAL_readAdcData(halHandle,&gAdcData);
    
    
      // run the controller
      CTRL_run(ctrlHandle,halHandle,&gAdcData,&gPwmData);
    
    
      if(CTRL_getState(ctrlHandle) == CTRL_State_OnLine)
        {
          if((Flag_Enable_Inverter == false)&&(Flag_is_Inverter_Enabled == true))
            {
      	      // disable the PWM
              HAL_disablePwm(halHandle);
    
      	      Flag_is_Inverter_Enabled = false;
            }
          else if((Flag_Enable_Inverter == false)&&(Flag_is_Inverter_Enabled == false))
            {
              CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle;
    
        	  if((gMotorVars.Speed_krpm > _IQ(0.0)) && (gMotorVars.Speed_krpm < FlyingStartSpeedRef_krpm))
                {
                  Flag_Enable_Inverter = true;
                }
              else if((gMotorVars.Speed_krpm < _IQ(0.0)) && (gMotorVars.Speed_krpm > FlyingStartSpeedRef_krpm))
                {
                  Flag_Enable_Inverter = true;
                }
    
              // Reset Speed, Id and Iq integral outputs Ui
              PID_setUi(obj->pidHandle_Id,gVdq_in.value[0]);
              PID_setUi(obj->pidHandle_Iq,gVdq_in.value[1]);
    
              CTRL_setVdq_out_pu(ctrlHandle,&gVdq_in);
    
              CTRL_setFlag_enableSpeedCtrl(ctrlHandle,false);
    
              TorqueModeCounter = 0;
            }
          else if((Flag_Enable_Inverter == true)&&(Flag_is_Inverter_Enabled == true)&&(CTRL_getFlag_enableSpeedCtrl(ctrlHandle) == false))
            {
        	  TorqueModeCounter++;
              if(TorqueModeCounter > TorqueModeCounterMaxCnt)
                {
                  CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle;
    
                  PID_setUi(obj->pidHandle_spd,_IQ(0.0));
    
            	  // Set Speed Reference target and intermediate values to estimated speed
            	  TRAJ_setIntValue(obj->trajHandle_spd, EST_getFm_pu(obj->estHandle));
            	  gMotorVars.SpeedRef_krpm = FlyingStartInitSpeedRef_krpm; //EST_getSpeed_krpm(obj->estHandle)
    
                  // set the speed reference
                  CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.SpeedRef_krpm);
    
            	  CTRL_setFlag_enableSpeedCtrl(ctrlHandle,true);
                }
            }
          else if((Flag_Enable_Inverter == true)&&(Flag_is_Inverter_Enabled == false))
            {
              // enable the PWM
              HAL_enablePwm(halHandle);
    
              Flag_is_Inverter_Enabled = true;
            }
        }
      else if(CTRL_getState(ctrlHandle) == CTRL_State_Idle)
        {
          Flag_Enable_Inverter = false;
          Flag_is_Inverter_Enabled = false;
        }
    
    
      // write the PWM compare values
      HAL_writePwmData(halHandle,&gPwmData);
    
    
      // setup the controller
      CTRL_setup(ctrlHandle);
    
    
      // read the timer 1 value and update the CPU usage module
      timer1Cnt = HAL_readTimerCnt(halHandle,1);
      CPU_USAGE_updateCnts(cpu_usageHandle,timer1Cnt);
    
    
      // run the CPU usage module
      CPU_USAGE_run(cpu_usageHandle);
    
    
      return;
    } // end of mainISR() function
    
    
    void updateGlobalVariables_motor(CTRL_Handle handle)
    {
      CTRL_Obj *obj = (CTRL_Obj *)handle;
      uint32_t minDeltaCntObserved = CPU_USAGE_getMinDeltaCntObserved(cpu_usageHandle);
      uint32_t avgDeltaCntObserved = CPU_USAGE_getAvgDeltaCntObserved(cpu_usageHandle);
      uint32_t maxDeltaCntObserved = CPU_USAGE_getMaxDeltaCntObserved(cpu_usageHandle);
      uint16_t pwmPeriod = HAL_readPwmPeriod(halHandle,PWM_Number_1);
      float_t  cpu_usage_den = (float_t)pwmPeriod * (float_t)USER_NUM_PWM_TICKS_PER_ISR_TICK * 2.0;
    
      // get the speed estimate
      gMotorVars.Speed_krpm = EST_getSpeed_krpm(obj->estHandle);
    
      // get the real time speed reference coming out of the speed trajectory generator
      gMotorVars.SpeedTraj_krpm = _IQmpy(CTRL_getSpd_int_ref_pu(handle),EST_get_pu_to_krpm_sf(obj->estHandle));
    
      // get the torque estimate
      gMotorVars.Torque_lbin = calcTorque_lbin(handle);
    
      // get the magnetizing current
      gMotorVars.MagnCurr_A = EST_getIdRated(obj->estHandle);
    
      // get the rotor resistance
      gMotorVars.Rr_Ohm = EST_getRr_Ohm(obj->estHandle);
    
      // get the stator resistance
      gMotorVars.Rs_Ohm = EST_getRs_Ohm(obj->estHandle);
    
      // get the stator inductance in the direct coordinate direction
      gMotorVars.Lsd_H = EST_getLs_d_H(obj->estHandle);
    
      // get the stator inductance in the quadrature coordinate direction
      gMotorVars.Lsq_H = EST_getLs_q_H(obj->estHandle);
    
      // get the flux
      gMotorVars.Flux_VpHz = EST_getFlux_VpHz(obj->estHandle);
    
      // get the controller state
      gMotorVars.CtrlState = CTRL_getState(handle);
    
      // get the estimator state
      gMotorVars.EstState = EST_getState(obj->estHandle);
    
      // calculate the minimum cpu usage percentage
      gCpuUsagePercentageMin = (float_t)minDeltaCntObserved / cpu_usage_den * 100.0;
    
      // calculate the average cpu usage percentage
      gCpuUsagePercentageAvg = (float_t)avgDeltaCntObserved / cpu_usage_den * 100.0;
    
      // calculate the maximum cpu usage percentage
      gCpuUsagePercentageMax = (float_t)maxDeltaCntObserved / cpu_usage_den * 100.0;
    
      // Get the DC buss voltage
      gMotorVars.VdcBus_kV = _IQmpy(gAdcData.dcBus,_IQ(USER_IQ_FULL_SCALE_VOLTAGE_V/1000.0));
    
      return;
    } // end of updateGlobalVariables_motor() function
    
    
    #ifdef FAST_ROM_V1p6
    void softwareUpdate1p6(CTRL_Handle handle)
    {
      CTRL_Obj *obj = (CTRL_Obj *)handle;
    
      float_t fullScaleInductance = EST_getFullScaleInductance(obj->estHandle);
      float_t Ls_coarse_max = _IQ30toF(EST_getLs_coarse_max_pu(obj->estHandle));
      int_least8_t lShift = ceil(log(obj->motorParams.Ls_d_H/(Ls_coarse_max*fullScaleInductance))/log(2.0));
      uint_least8_t Ls_qFmt = 30 - lShift;
      float_t L_max = fullScaleInductance * pow(2.0,lShift);
      _iq Ls_d_pu = _IQ30(obj->motorParams.Ls_d_H / L_max);
      _iq Ls_q_pu = _IQ30(obj->motorParams.Ls_q_H / L_max);
    
    
      // store the results
      EST_setLs_d_pu(obj->estHandle,Ls_d_pu);
      EST_setLs_q_pu(obj->estHandle,Ls_q_pu);
      EST_setLs_qFmt(obj->estHandle,Ls_qFmt);
    
      return;
    } // end of softwareUpdate1p6() function
    #endif
    
    void calcPIgains(CTRL_Handle handle)
    {
      CTRL_Obj *obj = (CTRL_Obj *)handle;
    
      float_t Ls_d = EST_getLs_d_H(obj->estHandle);
      float_t Ls_q = EST_getLs_q_H(obj->estHandle);
      float_t Rs = EST_getRs_Ohm(obj->estHandle);
      float_t RoverLs_d = Rs/Ls_d;
      float_t RoverLs_q = Rs/Ls_q;
      float_t fullScaleCurrent = EST_getFullScaleCurrent(obj->estHandle);
      float_t fullScaleVoltage = EST_getFullScaleVoltage(obj->estHandle);
      float_t ctrlPeriod_sec = CTRL_getCtrlPeriod_sec(handle);
      _iq Kp_Id = _IQ((0.25*Ls_d*fullScaleCurrent)/(ctrlPeriod_sec*fullScaleVoltage));
      _iq Ki_Id = _IQ(RoverLs_d*ctrlPeriod_sec);
      _iq Kp_Iq = _IQ((0.25*Ls_q*fullScaleCurrent)/(ctrlPeriod_sec*fullScaleVoltage));
      _iq Ki_Iq = _IQ(RoverLs_q*ctrlPeriod_sec);
      _iq Kd = _IQ(0.0);
    
      // set the Id controller gains
      PID_setKi(obj->pidHandle_Id,Ki_Id);
      CTRL_setGains(handle,CTRL_Type_PID_Id,Kp_Id,Ki_Id,Kd);
    
      // set the Iq controller gains
      PID_setKi(obj->pidHandle_Iq,Ki_Iq);
      CTRL_setGains(handle,CTRL_Type_PID_Iq,Kp_Iq,Ki_Iq,Kd);
    
      return;
    } // end of calcPIgains() function
    
    float_t calcTorque_Nm(CTRL_Handle handle)
    {
      CTRL_Obj *obj = (CTRL_Obj *)handle;
      float_t Id_A = _IQtoF(PID_getFbackValue(obj->pidHandle_Id)) * USER_IQ_FULL_SCALE_CURRENT_A;
      float_t Iq_A = _IQtoF(PID_getFbackValue(obj->pidHandle_Iq)) * USER_IQ_FULL_SCALE_CURRENT_A;
      float_t Polepairs = (float_t)USER_MOTOR_NUM_POLE_PAIRS;
      float_t Flux_Wb = EST_getFlux_Wb(obj->estHandle);
      float_t Lsd_H = EST_getLs_d_H(obj->estHandle);
      float_t Lsq_H = EST_getLs_q_H(obj->estHandle);
    
      return((Flux_Wb * Iq_A + (Lsd_H - Lsq_H) * Id_A * Iq_A) * Polepairs * 1.5);
    } // end of calcTorque_Nm() function
    
    
    float_t calcTorque_lbin(CTRL_Handle handle)
    {
    
      return(calcTorque_Nm(handle) * MATH_Nm_TO_lbin_SF);
    } // end of calcTorque_lbin() function
    
    
    //@} //defgroup
    // end of file
    
    
    
    

    You can load the variables with the revised 3b.js (attached is a .txt file, rename to .js please)

    expRemoveAll();
    expAdd ("gMotorVars");
    expAdd ("gMotorVars.UserErrorCode");
    expAdd ("gMotorVars.CtrlVersion");
    expAdd ("gMotorVars.Flag_enableSys", getDecimal());
    expAdd ("gMotorVars.Flag_Run_Identify", getDecimal());
    expAdd ("gMotorVars.Flag_enableUserParams", getDecimal());
    expAdd ("gMotorVars.Flag_enableRsRecalc", getDecimal());
    expAdd ("gMotorVars.Flag_enableForceAngle", getDecimal());
    expAdd ("gMotorVars.Flag_enableOffsetcalc", getDecimal());
    expAdd ("gMotorVars.Flag_enablePowerWarp", getDecimal());
    
    expAdd ("gMotorVars.CtrlState");
    expAdd ("gMotorVars.EstState");
    
    expAdd ("gMotorVars.SpeedRef_krpm", getQValue(24));
    expAdd ("gMotorVars.MaxAccel_krpmps", getQValue(24));
    
    expAdd ("gMotorVars.Speed_krpm", getQValue(24));
    expAdd ("gMotorVars.Torque_lbin");
    
    expAdd ("gMotorVars.MagnCurr_A");
    expAdd ("gMotorVars.Rr_Ohm");
    expAdd ("gMotorVars.Rs_Ohm");
    expAdd ("gMotorVars.Lsd_H");
    expAdd ("gMotorVars.Lsq_H");
    expAdd ("gMotorVars.Flux_VpHz");
    
    expAdd ("gMotorVars.VdcBus_kV", getQValue(24));
    
    expAdd ("gDrvSpi8301Vars");
    
    expAdd ("gCpuUsagePercentageMin");
    expAdd ("gCpuUsagePercentageAvg");
    expAdd ("gCpuUsagePercentageMax");
    expAdd ("cpu_usage.flag_resetStats", getDecimal());
    
    expAdd ("Flag_Enable_Inverter", getDecimal());
    expAdd ("FlyingStartSpeedRef_krpm", getQValue(24));
    expAdd ("FlyingStartInitSpeedRef_krpm", getQValue(24));
    expAdd ("TorqueModeCounterMaxCnt", getDecimal());
    

    A revised ctrl.h that calculates the input Vd and Vq.

    6787.ctrl.h

    There are a few issues that I found when testins this. Here is for your information:

    1. I was able to see the spike, this was because when the inverter is first enabled, the very first duty cycle used is from the last output before disabling the controllers

    2. For best results, I am setting Vd to zero when I enabling the inverter.

    3. There is a 2x scaling if you use input voltage as output voltage, so I multiply the calculated Vq_in * 2 to get Vq_out. You will see this in ctrl.h

    4. It is important to use release 12, since the EN_GATE pin of the DRV8301 is never set to low once it's enabled. So you won't have the delay you have right now with a previous release.

    5. It is a must to run lab 3a prior to this to make sure you have the right offsets loaded into user.h, since the fly start will bypass all the calibration of offsets and Rs.

    Now here is a small procedure on how to run this code.

    1. gMotorVars.Flag_enableSys to 1

    2. gMotorVars.Flag_Run_Identify to 1

    3. Change gMotorVars.SpeedRef_krpm to a higher speed, for example 4.0 (for 4000 rpm)

    4. Flag_Enable_Inverter to 0

    5. The motor will freely stop, and when the measured speed is less than FlyingStartSpeedRef_krpm, the inverter will be enabled in torque mode for TorqueModeCounterMaxCnt number of interrupts (default of 50 ms in torque mode)

    6. Once the torque mode counter is timed out, the speed reference will automatically change to FlyingStartInitSpeedRef_krpm.

    Doing this procedure, I get the no spikes at all. Please give this a try and let us know how it works.

    -Jorge

  • Hi jorge,

    I just receive my own hardware so I have a lot of work with it so the "flying start improvement" will be leave aside for some days.

    Could you confirm that FlyingStartInitSpeedRef_krpm is updated to the current speed before the speed regulator is enabled? Or perhaps I need to update it in my own code?

    Regards.

    Emmanuel

  • There is this line of code:

    gMotorVars.SpeedRef_krpm = FlyingStartInitSpeedRef_krpm;

    So if you want a fixed speed after the inverter is enabled, use it like that, and update FlyingStartInitSpeedRef_krpm to your desired initial speed.

    If you want the actual speed to be the reference, then replace the above line of code with this:

    gMotorVars.SpeedRef_krpm = EST_getSpeed_krpm(obj->estHandle);

    -Jorge

  • Hi,

    A question to Jorge - since you're relying on the measurement of phase voltage (Vdq_in) to set the output (Vdq_out), shouldn't you account for the HW filter ? I didn't quite understand from this post on which frequencies we're talking about, but I think that some phase shift is required (and maybe some amplification adjustment) in order to match the real BEMF.

    Another thought - did you check that the BEMF is truely sinusoidal ? otherwise I think that spikes are unavoidable since the whole vector control assumes sinusoidal distribution...

    what do you think ?

    By the way, this is one of the more interesting posts here..control engineering at it's best ! thanks ! Even though I don't deal with fly start, I would love to see the solution.

  • Both are good questions. The first one, about the HW filter, it is true, there will be a delay and gain effect by this filter, although it is a first order low pass filter with a very well defined gain and delay response, so you can compensate for that when calculating Vdq_in. So for very high speed fly start, yes this needs to be calculated on Va, Vb and Vc feedback before flying start the motor.

    About sine vs trapezoidal backEMF, I wouldn't worry about this too much. The Vdq_in calculation takes into account the angle coming from the estimator, and the input voltages also come from measured values, so the calculation will be accurate.

    I actually tested this on a BLDC motor myself, and I don't see any kick or jump. The fastest fly start I did was 10,000 RPM in a 1 pole pair motor, so in Hz is 10000/60*1 = 166.67 Hz.

    I hope this information helps.

    -Jorge

  • Hi Jorge,

    Yes, the information is helpful.

    BTW, at was freq. was your HW pole set to when you did the experiment with the BLDC ?

    Another question - When designing our own HW, can we use a higher order filter ? or does the FAST "needs" a first order one ?

    Thanks a lot

  • I am using the DRV8301 kit, so the hw filter pole is at 335.648 Hz.

    A first order filter is required.

    -Jorge