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.

INSTASPINFOCMOTORWAREGUI: Additional features of FWC and online RS identification in dual motor control

Part Number: INSTASPINFOCMOTORWAREGUI
Other Parts Discussed in Thread: MOTORWARE

Hi,

I am working of dual motor control with Motorware SDK on LaunchXL-F290049C. I would like to implement all functionalities like FW and RS online, torque control. So far I have been successful in torque/ speed control for either motor. However, I am unable to get FW and RS online to work.

Field weakening - As I understand, Just setting the motorvars[x].flagEnableFWC to 1 should be enough to enable FW as the PI is already defined. However, this does not work. I notice that unlike the other labs, the motorVars[x].Vs_V does not get updated with the motor speed. It remains at 0.

Rs online - This is used this when FW is not active

//
// runRsOnLine for Rs online calibration
//
void runRsOnLine(EST_Handle estHandle, HAL_MotorNum_e ctrlNum)
{
    //
    // execute Rs OnLine code
    //
    if(motorVars[ctrlNum].flagRunIdentAndOnLine == true)
    {
        if((EST_getState(estHandle) == EST_STATE_ONLINE) &&
                (motorVars[ctrlNum].flagEnableRsOnLine == true))
        {
            EST_setFlag_enableRsOnLine(estHandle, true);
            EST_setRsOnLineId_mag_A(estHandle, motorVars[ctrlNum].RsOnLineCurrent_A);

            float32_t RsError_Ohm = motorVars[ctrlNum].RsOnLine_Ohm - motorVars[ctrlNum].Rs_Ohm;

            if(abs(RsError_Ohm) < (motorVars[ctrlNum].Rs_Ohm * 0.05))     // 5% Error
            {
                EST_setFlag_updateRs(estHandle, true);
            }
        }
        else
        {
            EST_setRsOnLineId_mag_A(estHandle, 0.0);
            EST_setRsOnLineId_A(estHandle, 0.0);
            EST_setRsOnLine_Ohm(estHandle, EST_getRs_Ohm(estHandle));
            EST_setFlag_enableRsOnLine(estHandle, false);
            EST_setFlag_updateRs(estHandle, false);
        }
    }

    return;
} // end of runRsOnLine() function

In the mainISR()

            // store the input data into a buffer
            estInputData[isrNum].dcBus_V = adcData[isrNum].dcBus_V;

            if(EST_getState(estHandle[isrNum]) != EST_STATE_ONLINE)
            {
                Idq_ref_A[isrNum].value[0] = EST_getIntValue_Id_A(estHandle[isrNum]);
                estInputData[isrNum].speed_ref_Hz = EST_getIntValue_spd_Hz(estHandle[isrNum]);
                estInputData[isrNum].speed_int_Hz = EST_getIntValue_spd_Hz(estHandle[isrNum]);
            }
            else
            {
                Idq_ref_A[isrNum].value[0] = EST_getIdRated_A(estHandle[isrNum]);
                estInputData[isrNum].speed_ref_Hz = motorVars[isrNum].speedTraj_Hz;
                estInputData[isrNum].speed_int_Hz = motorVars[isrNum].speedTraj_Hz;
            }

            // update Id reference for Rs OnLine
            EST_updateId_ref_A(estHandle[isrNum],
                               (float32_t *)&(Idq_ref_A[isrNum].value[0]));

            // run the estimator
            EST_run(estHandle[isrNum],
                    &estInputData[isrNum],
                    &estOutputData[isrNum]);

            // get Idq, reutilizing a Park transform used inside the estimator.
            // This is optional, user's Park works as well
            EST_getIdq_A(estHandle[isrNum], (MATH_Vec2 *)(&(Idq_in_A[isrNum])));

            // run the speed controller
            // run the speed controller
            if(EST_doSpeedCtrl(estHandle[isrNum]))
            {
                counterSpeed[isrNum]++;

                if(counterSpeed[isrNum] >= userParams[isrNum].numCtrlTicksPerSpeedTick)
                {
                    counterSpeed[isrNum] = 0;

                    PI_run_series(piHandle_spd[isrNum],
                                  estInputData[isrNum].speed_ref_Hz,
                                  estOutputData[isrNum].fm_lp_rps * MATH_ONE_OVER_TWO_PI,
                                  0.0,
                                  (float32_t *)(&(motorVars[isrNum].IsRef_A)));

                    PI_run_series(piHandle_fwc[isrNum],
                                  motorVars[isrNum].VsRef_V,
                                  motorVars[isrNum].Vs_V,
                                  0.0,
                                  (float32_t *)(&(motorVars[isrNum].angleCurrent_rad)));

                    // compute the sin/cos phasor using fast RTS function, callable assembly
                    fwcPhasor[isrNum].value[0] = sinf(motorVars[isrNum].angleCurrent_rad);
                    fwcPhasor[isrNum].value[1] = cosf(motorVars[isrNum].angleCurrent_rad);

//                    Idq_ref_A[isrNum].value[0] = motorVars[isrNum].IsRef_A *
//                                                    fwcPhasor[isrNum].value[0];

                    Idq_ref_A[isrNum].value[1] = motorVars[isrNum].IsRef_A *
                                                    fwcPhasor[isrNum].value[1];
                }
            }

SetUp for Rs online

motorVars[ctrlNum].flagEnableRsRecalc = true;
motorVars[ctrlNum].flagEnableRsOnLine = true;
motorVars[ctrlNum].RsOnLineCurrent_A = USER_M2_MOTOR_RES_EST_CURRENT_A;

Call Rs online in main()

            //
            // run Rs online
            //
            runRsOnLine(estHandle[ctrlNum], ctrlNum);

            // enable or disable force angle
            EST_setFlag_enableForceAngle(estHandle[ctrlNum],
                                         motorVars[ctrlNum].flagEnableForceAngle);

            EST_setFlag_enableRsRecalc(estHandle[ctrlNum],
                                       motorVars[ctrlNum].flagEnableRsRecalc);

            EST_setFlag_enableRsOnLine(estHandle[ctrlNum],
                                       motorVars[ctrlNum].flagEnableRsOnLine);

While Rs online running, the motors don't run but make a buzzing noise.

It will be very helpful if someone could guide me what I am doing wrong and how I can fix it.

 

  • 1. You need to check if the CPU bandwidth is enough for dual motor control with RsOline if the PWM frequency is a higher one.

    2. Setting the motorvars[x].flagEnableFWC to 1 that only means the field weakening function is enabled, does not mean the field weakening must enter. The field weakening will be entered only when the dc bus voltage is not enough for high speed running.

  • Thank you for you're response Yanming.

    You're right!! The ISR execution time is around 60 us, so yes, at 16 KHz, Rs online does not work but 10 KHz, it does. The values oscillate a bit but I will have a deeper look.

    However, i tried running the FW by demanding higher speeds but the speed reaches up to the point defined by the modulation index without id current injection.

  • That's right, the FW will enter or exit automatically if the dc-bus input voltage is enough or not. Please refer to the lab (is13_fwc_mtpa) for FWC, the FWC is not enabled in the lab (is11_dual_motor).

  • Hi Yanming,

    I did try that but I am unable to get that to work, FWC pi works as I get the motorVars[isrNum].angleCurrent_rad as the speed increases but the Idq_ref_A value does not get updated. 

    The Rs online varies a lot basically making the value useless.

    I have attached the C-file. Could you provide you're feedback on what is wrong.

    Thanks in advance.

    //#############################################################################
    // $TI Release: MotorControl SDK v1.00.00.00 $
    // $Release Date: Mon Apr  1 10:21:04 CDT 2019 $
    // $Copyright:
    // Copyright (C) 2017-2019 Texas Instruments Incorporated - http://www.ti.com/
    //
    // 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.
    // $
    //#############################################################################
    
    //! \file   solutions/common/sensorless_foc/source/is11_dual_motor.c
    //! \brief  This lab is used to control two inverters independently from one MCU.
    //!         Only support LaunchXL-F280049C + BoostXL-DRV8320RS
    //!
    
    // **************************************************************************
    
    // solutions
    #include "labs_dm.h"
    
    #pragma CODE_SECTION(mainISR, ".TI.ramfunc");
    #pragma CODE_SECTION(runOffsetsCalculation, ".TI.ramfunc");
    
    uint16_t counterLED = 0;  //!< Counter used to divide down the ISR rate for
                               //!< visually blinking an LED
    
    uint32_t offsetCalcWaitTime = 50000;   //!< Wait time setting for current/voltage
                                            //!< offset calibration, unit: ISR cycles
    
    // the globals
    HAL_ADCData_t adcData[2] = { {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, 0.0},
                                  {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, 0.0} };
    
    HAL_PWMData_t pwmData[2] = { {0.0, 0.0, 0.0},
                                  {0.0, 0.0, 0.0} };
    
    uint16_t counterSpeed[2] = {0, 0};
    uint16_t counterTrajSpeed[2] = {0, 0};
    uint16_t counterTrajId[2] = {0, 0};
    uint32_t offsetCalcCount[2] = {0, 0};   //!< Counter used to count the wait time
                                            //!< for offset calibration, unit: ISR cycles
    
    EST_InputData_t estInputData[2] = { {0, {0.0, 0.0}, {0.0, 0.0}, 0.0, 0.0},
                                      {0, {0.0, 0.0}, {0.0, 0.0}, 0.0, 0.0} };
    
    EST_OutputData_t estOutputData[2] = { {0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                                         {0.0, 0.0}, {0.0, 0.0}, 0, 0.0} ,
                                        {0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                                         {0.0, 0.0}, {0.0, 0.0}, 0, 0.0} };
    
    float32_t angleDelta_rad[2]= {0.0, 0.0};     //!< the rotor angle compensation value
    float32_t angleEst_rad[2] = {0.0, 0.0};      //!< the rotor angle from FAST estimator
    float32_t angleFoc_rad[2]= {0.0, 0.0};       //!< the rotor angle for FOC modules
    
    MATH_Vec2 Idq_in_A[2] = {{0.0, 0.0}, {0.0, 0.0}};   //!< the d&q axis current are converter from
                                                        //!< 3-phase sampling input current of motor
    MATH_Vec2 Idq_ref_A[2] = {{0.0, 0.0}, {0.0, 0.0}};  //!< the reference current on d&q rotation axis
    MATH_Vec2 Idq_offset_A[2] = {{0.0, 0.0}, {0.0, 0.0}};   //!< the offsetting current on d&q rotation axis
    
    MATH_Vec2 Vab_out_V[2] = {{0.0, 0.0}, {0.0, 0.0}};  //!< the output control voltage on alpha&beta axis
    MATH_Vec2 Vdq_out_V[2] = {{0.0, 0.0}, {0.0, 0.0}};  //!< the output control voltage on d&q axis
    
    USER_Params userParams[2];
    #pragma DATA_SECTION(userParams,"ctrl_data");
    
    volatile MOTOR_Vars_t motorVars[2] = {MOTOR1_VARS_INIT, MOTOR2_VARS_INIT};
    #pragma DATA_SECTION(motorVars,"ctrl_data");
    
    HAL_Handle    halHandle;          //!< the handle for the hardware abstraction layer
    HAL_Obj       hal;                //!< the hardware abstraction layer object
    
    HAL_MTR_Handle halMtrHandle[2];   //!< the handle for the hardware abstraction
                                      //!< layer to motor control
    HAL_MTR_Obj    halMtr[2];         //!< the hardware abstraction layer object
                                      //!< to motor control
    
    EST_Handle    estHandle[2];       //!< the handle for the estimator
    
    CLARKE_Handle clarkeHandle_I[2];  //!< the handle for the current Clarke transform
    CLARKE_Obj    clarke_I[2];        //!< the current Clarke transform object
    
    CLARKE_Handle clarkeHandle_V[2];  //!< the handle for the voltage Clarke transform
    CLARKE_Obj    clarke_V[2];        //!< the voltage Clarke transform object
    
    IPARK_Handle  iparkHandle_V[2];   //!< the handle for the inverse Park transform
    IPARK_Obj     ipark_V[2];         //!< the inverse Park transform object
    
    PARK_Handle   parkHandle_I[2];    //!< the handle for the Park object
    PARK_Obj      park_I[2];          //!< the Park transform object
    
    PARK_Handle   parkHandle_V[2];    //!< the handle for the Park object
    PARK_Obj      park_V[2];          //!< the Park transform object
    
    PI_Handle     piHandle_Id[2];     //!< the handle for the Id PI controller
    PI_Obj        pi_Id[2];           //!< the Id PI controller object
    
    PI_Handle     piHandle_Iq[2];     //!< the handle for the Iq PI controller
    PI_Obj        pi_Iq[2];           //!< the Iq PI controller object
    
    PI_Handle     piHandle_fwc[2];    //!< the handle for the fwc PI controller
    PI_Obj        pi_fwc[2];          //!< the fwc PI controller object
    
    PI_Handle     piHandle_spd[2];    //!< the handle for the speed PI controller
    PI_Obj        pi_spd[2];          //!< the speed PI controller object
    
    SVGEN_Handle  svgenHandle[2];     //!< the handle for the space vector generator
    SVGEN_Obj     svgen[2];           //!< the space vector generator object
    
    SVGENCURRENT_Obj svgencurrent[2];   //!< the handle for the space vector generator current
    SVGENCURRENT_Handle svgencurrentHandle[2];  //<! the space vector generator current object
    
    TRAJ_Handle   trajHandle_spd[2];  //!< the handle for the speed reference trajectory
    TRAJ_Obj      traj_spd[2];        //!< the speed reference trajectory object
    
    TRAJ_Handle   trajHandle_Id[2];   //!< the handle for the id reference trajectory
    TRAJ_Obj      traj_Id[2];         //!< the id reference trajectory object
    
    TRAJ_Handle   trajHandle_Iq[2];   //!< the handle for the iq reference trajectory
    TRAJ_Obj      traj_Iq[2];         //!< the iq reference trajectory object
    
    TRAJ_Handle   trajHandle_fwc[2];  //!< the handle for the fwc reference trajectory
    TRAJ_Obj      traj_fwc[2];        //!< the fwc reference trajectory object
    
    //!< the handles for the current offset calculation
    FILTER_FO_Handle  filterHandle_I[2][USER_M1_NUM_CURRENT_SENSORS];
    
    //!< the current offset calculation
    FILTER_FO_Obj     filter_I[2][USER_M1_NUM_CURRENT_SENSORS];
    
    //!< the handles for the voltage offset calculation
    FILTER_FO_Handle  filterHandle_V[2][USER_M1_NUM_CURRENT_SENSORS];
    
    //!< the voltage offset calculation
    FILTER_FO_Obj     filter_V[2][USER_M1_NUM_VOLTAGE_SENSORS];
    
    #ifdef DRV8320_SPI
    // Watch window interface to the 8320 SPI
    DRV8320_SPIVars_t drvSPI8320Vars[2];
    #pragma DATA_SECTION(drvSPI8320Vars,"ctrl_data");
    #endif
    
    #ifdef DRV8301_SPI
    // Watch window interface to the 8301 SPI
    DRV8301_SPIVars_t drvSPI8301Vars[2];
    #pragma DATA_SECTION(drvSPI8301Vars, "ctrl_data");
    #endif
    
    HAL_MotorNum_e ctrlNum = HAL_MTR_1;
    HAL_MotorNum_e isrNum  = HAL_MTR_1;
    
    MATH_Vec2 fwcPhasor[2] = {{0.0, 0.0}, {0.0, 0.0}};
    uint16_t faultFlag[2] = {0, 0};
    
    //
    volatile SYSTEM_Vars_t systemVars = SYSTEM_VARS_INIT;
    
    // define CPU time for performance test
    CPU_TIME_Obj     cpuTime;
    CPU_TIME_Handle  cpuTimeHandle;
    
    
    #ifdef _PWMDAC_EN_
    HAL_PWMDACData_t pwmDACData;
    
    #pragma DATA_SECTION(pwmDACData,"ctrl_data");
    #endif  // _PWMDAC_EN_
    
    // **************************************************************************
    // the functions
    
    void main(void)
    {
    
        for(ctrlNum = HAL_MTR_1; ctrlNum <= HAL_MTR_2; ctrlNum++)
        {
            // initialize the user parameters
            USER_setDualMotorParams(&userParams[ctrlNum], ctrlNum);
    
            #ifdef _HVKIT_REV1p1_
            motorVars[ctrlNum].boardKit = BOARD_HVMTRPFC_REV1P1;
            #endif // _HVKIT_REV1p1_
    
            #ifdef _DRV8301_KIT_REVD_
            motorVars[ctrlNum].boardKit = BOARD_DRV8301_REVD;
            #endif  // _DRV8301_KIT_REVD_
    
            #ifdef _BOOSTXL_8320RS_REVA_
            motorVars[ctrlNum].boardKit = BOARD_BSXL8320RS_REVA;
            #endif  // _BOOSTXL_8320RS_REVA_
    
            userParams[ctrlNum].flag_bypassMotorId = true;
    
            // initialize the user parameters
            USER_setParams_priv(&userParams[ctrlNum]);
        }
    
        // initialize the driver
        halHandle = HAL_init(&hal,sizeof(hal));
    
        // set the driver parameters
        HAL_setParams(halHandle);
    
        for(ctrlNum = HAL_MTR_1; ctrlNum <= HAL_MTR_2; ctrlNum++)
        {
            // initialize the driver
            halMtrHandle[ctrlNum] = HAL_MTR_init(&halMtr[ctrlNum],
                                                  sizeof(halMtr[ctrlNum]), ctrlNum);
    
            // set the driver parameters
            HAL_MTR_setParams(halMtrHandle[ctrlNum], ctrlNum);
    
            // initialize the Clarke modules
            clarkeHandle_I[ctrlNum] = CLARKE_init(&clarke_I[ctrlNum],
                                                   sizeof(clarke_I[ctrlNum]));
            clarkeHandle_V[ctrlNum] = CLARKE_init(&clarke_V[ctrlNum],
                                                   sizeof(clarke_V[ctrlNum]));
    
            // set the Clarke parameters
            setupClarke_I(clarkeHandle_I[ctrlNum],
                          userParams[ctrlNum].numCurrentSensors);
            setupClarke_V(clarkeHandle_V[ctrlNum],
                          userParams[ctrlNum].numVoltageSensors);
    
            // initialize the estimator
            estHandle[ctrlNum] = EST_initEst(ctrlNum);
    
            // set the default estimator parameters
            EST_setParams(estHandle[ctrlNum],&userParams[ctrlNum]);
            EST_setFlag_enableForceAngle(estHandle[ctrlNum],
                                         motorVars[ctrlNum].flagEnableForceAngle);
            EST_setFlag_enableRsRecalc(estHandle[ctrlNum],
                                       motorVars[ctrlNum].flagEnableRsRecalc);
    
            // if motor is an induction motor, configure default state of PowerWarp
            if(userParams[ctrlNum].motor_type == MOTOR_TYPE_INDUCTION)
            {
                EST_setFlag_enablePowerWarp(estHandle[ctrlNum],
                                            motorVars[ctrlNum].flagEnablePowerWarp);
                EST_setFlag_bypassLockRotor(estHandle[ctrlNum],
                                            motorVars[ctrlNum].flagBypassLockRotor);
            }
    
            // initialize the inverse Park module
            iparkHandle_V[ctrlNum] = IPARK_init(&ipark_V[ctrlNum],
                                                 sizeof(ipark_V[ctrlNum]));
    
            // initialize the Park module
            parkHandle_I[ctrlNum] = PARK_init(&park_I[ctrlNum],
                                               sizeof(park_I[ctrlNum]));
            parkHandle_V[ctrlNum] = PARK_init(&park_V[ctrlNum],
                                               sizeof(park_V[ctrlNum]));
    
            // initialize the PI controllers
            piHandle_Id[ctrlNum]  = PI_init(&pi_Id[ctrlNum], sizeof(pi_Id[ctrlNum]));
            piHandle_Iq[ctrlNum]  = PI_init(&pi_Iq[ctrlNum], sizeof(pi_Iq[ctrlNum]));
            piHandle_fwc[ctrlNum] = PI_init(&pi_fwc[ctrlNum], sizeof(pi_fwc[ctrlNum]));
            piHandle_spd[ctrlNum] = PI_init(&pi_spd[ctrlNum], sizeof(pi_spd[ctrlNum]));
    
            // setup the controllers, speed, d/q-axis current pid regulator
            setupControllers(ctrlNum);
    
            //
            // setup the FWC parameters, same for both motors
            //
            pi_fwc[ctrlNum].Kp = USER_M1_FWC_KP;
            pi_fwc[ctrlNum].Ki = USER_M1_FWC_KI;
            pi_fwc[ctrlNum].outMax = USER_M1_FWC_MIN_ANGLE_RAD;
            pi_fwc[ctrlNum].outMin = USER_M1_FWC_MAX_ANGLE_RAD;
    
    
            // initialize the space vector generator module
            svgenHandle[ctrlNum] = SVGEN_init(&svgen[ctrlNum],
                                               sizeof(svgen[ctrlNum]));
    
            // initialize the speed reference trajectory
            trajHandle_spd[ctrlNum] = TRAJ_init(&traj_spd[ctrlNum],
                                                 sizeof(traj_spd[ctrlNum]));
    
            // initialize the Id reference trajectory
            trajHandle_Id[ctrlNum] = TRAJ_init(&traj_Id[ctrlNum],
                                                sizeof(traj_Id[ctrlNum]));
    
            // initialize the Iq reference trajectory
            trajHandle_Iq[ctrlNum] = TRAJ_init(&traj_Iq[ctrlNum],
                                                sizeof(traj_Iq[ctrlNum]));
    
            // initialize the fwc reference trajectory
            trajHandle_fwc[ctrlNum] = TRAJ_init(&traj_fwc[ctrlNum],
                                                 sizeof(traj_fwc[ctrlNum]));
    
            // configure the speed reference trajectory (Hz)
            TRAJ_setTargetValue(trajHandle_spd[ctrlNum], 0.0);
            TRAJ_setIntValue(trajHandle_spd[ctrlNum], 0.0);
            TRAJ_setMinValue(trajHandle_spd[ctrlNum],
                             -userParams[ctrlNum].maxFrequency_Hz);         // Maximum Frequency
            TRAJ_setMaxValue(trajHandle_spd[ctrlNum],
                             userParams[ctrlNum].maxFrequency_Hz);          // Maximum Frequency
            TRAJ_setMaxDelta(trajHandle_spd[ctrlNum],
                             (userParams[ctrlNum].maxAccel_Hzps / userParams[ctrlNum].ctrlFreq_Hz));
    
            // configure the Id reference trajectory
            TRAJ_setTargetValue(trajHandle_Id[ctrlNum], 0.0);
            TRAJ_setIntValue(trajHandle_Id[ctrlNum], 0.0);
            TRAJ_setMinValue(trajHandle_Id[ctrlNum],
                             -userParams[ctrlNum].maxCurrent_A);
            TRAJ_setMaxValue(trajHandle_Id[ctrlNum],
                             userParams[ctrlNum].maxCurrent_A);
            TRAJ_setMaxDelta(trajHandle_Id[ctrlNum],
                             (userParams[ctrlNum].maxCurrent_resEst_A / userParams[ctrlNum].ctrlFreq_Hz));
    
            // configure the Iq reference trajectory
            TRAJ_setTargetValue(trajHandle_Iq[ctrlNum], 0.0);
            TRAJ_setIntValue(trajHandle_Iq[ctrlNum], 0.0);
            TRAJ_setMinValue(trajHandle_Iq[ctrlNum],
                             -userParams[ctrlNum].maxCurrent_A);
            TRAJ_setMaxValue(trajHandle_Iq[ctrlNum],
                             userParams[ctrlNum].maxCurrent_A);
            TRAJ_setMaxDelta(trajHandle_Iq[ctrlNum],
                             (userParams[ctrlNum].maxCurrent_resEst_A / userParams[ctrlNum].ctrlFreq_Hz));
    
            // configure the fwc reference trajectory
            TRAJ_setTargetValue(trajHandle_fwc[ctrlNum], 0.0);
            TRAJ_setIntValue(trajHandle_fwc[ctrlNum], 0.0);
            TRAJ_setMinValue(trajHandle_fwc[ctrlNum],
                             -userParams[ctrlNum].maxCurrent_A);
            TRAJ_setMaxValue(trajHandle_fwc[ctrlNum],
                             userParams[ctrlNum].maxCurrent_A);
            TRAJ_setMaxDelta(trajHandle_fwc[ctrlNum],
                             (userParams[ctrlNum].maxCurrent_resEst_A / userParams[ctrlNum].ctrlFreq_Hz));
    
            // initialize and configure offsets using filters
            {
                uint16_t filterCnt = 0;
                float32_t b0 = userParams[ctrlNum].offsetPole_rps / userParams[ctrlNum].ctrlFreq_Hz;
                float32_t a1 = (b0 - 1.0);
                float32_t b1 = 0.0;
    
                // For Current offset calibration filter
                for(filterCnt = 0; filterCnt<USER_M1_NUM_CURRENT_SENSORS; filterCnt++)
                {
                    filterHandle_I[ctrlNum][filterCnt] = FILTER_FO_init(&filter_I[ctrlNum][filterCnt],
                                                             sizeof(filter_I[ctrlNum][filterCnt]));
    
                    FILTER_FO_setDenCoeffs(filterHandle_I[ctrlNum][filterCnt], a1);
                    FILTER_FO_setNumCoeffs(filterHandle_I[ctrlNum][filterCnt], b0, b1);
    
                    FILTER_FO_setInitialConditions(filterHandle_I[ctrlNum][filterCnt],
                                                   motorVars[ctrlNum].offsets_I_A.value[filterCnt],
                                                   motorVars[ctrlNum].offsets_I_A.value[filterCnt]);
                }
    
                // For Voltage offset calibration filter
                for(filterCnt=0; filterCnt<USER_M1_NUM_VOLTAGE_SENSORS; filterCnt++)
                {
                    filterHandle_V[ctrlNum][filterCnt] = FILTER_FO_init(&filter_V[ctrlNum][filterCnt],
                                                             sizeof(filter_V[ctrlNum][filterCnt]));
    
                    FILTER_FO_setDenCoeffs(filterHandle_V[ctrlNum][filterCnt], a1);
                    FILTER_FO_setNumCoeffs(filterHandle_V[ctrlNum][filterCnt], b0, b1);
    
                    FILTER_FO_setInitialConditions(filterHandle_V[ctrlNum][filterCnt],
                                                   motorVars[ctrlNum].offsets_V_V.value[filterCnt],
                                                   motorVars[ctrlNum].offsets_V_V.value[filterCnt]);
                }
    
                motorVars[ctrlNum].flagEnableOffsetCalc = false;
                offsetCalcCount[ctrlNum] = 0;
            }
    
            motorVars[ctrlNum].offset_invVbus_invV = 0.5;   // the scale factor of half of dc bus
    
            motorVars[ctrlNum].faultMask.all = FAULT_MASK_OC_FU_OT;
    
            motorVars[ctrlNum].flagEnableForceAngle = true;
            motorVars[ctrlNum].flagEnableRsRecalc = false;
            motorVars[ctrlNum].flagEnableRsOnLine = true;
            motorVars[ctrlNum].RsOnLineCurrent_A = USER_M2_MOTOR_RES_EST_CURRENT_A;
            // Enable field weakening
            motorVars[ctrlNum].flagEnableFWC = true;
    
    #ifdef _PGA_GAIN_6_EN_
            motorVars[ctrlNum].dacaVal = 2045U;
            motorVars[ctrlNum].dacbVal = 2045U;
    #endif
    
    #ifdef _PGA_GAIN_12_EN_
            motorVars[ctrlNum].dacaVal = 1023U;
            motorVars[ctrlNum].dacbVal = 1023U;
    #endif
    
            // setup faults
            HAL_setupFaults(halMtrHandle[ctrlNum], ctrlNum);
    
      #ifdef DRV8320_SPI
            // turn on the DRV8320 if present
            HAL_enableDRV(halMtrHandle[ctrlNum]);
    
            // initialize the DRV8320 interface
            HAL_setupDRVSPI(halMtrHandle[ctrlNum], &drvSPI8320Vars[ctrlNum]);
    
            drvSPI8320Vars[ctrlNum].Ctrl_Reg_05.VDS_LVL = DRV8320_VDS_LEVEL_1P300_V;
            drvSPI8320Vars[ctrlNum].Ctrl_Reg_05.DEAD_TIME = DRV8320_DEADTIME_100_NS;
            drvSPI8320Vars[ctrlNum].writeCmd = 1;
      #endif
    
      #ifdef DRV8301_SPI
            // turn on the DRV8301 if present
            HAL_enableDRV(halHandle[ctrlNum]);
    
            // initialize the DRV8301 interface
            HAL_setupDRVSPI(halMtrHandle[ctrlNum],&drvSPI8301Vars[ctrlNum]);
    
            drvSPI8301Vars[ctrlNum].Ctrl_Reg_1.OC_ADJ_SET = DRV8301_VDSLEVEL_1P892_V;
            drvSPI8301Vars[ctrlNum].sndCmd = 1;
      #endif
    
            // Set some global variables
            motorVars[ctrlNum].pwmISRCount = 0;
    
            // set the default target frequency to 20.0Hz
            motorVars[ctrlNum].speedRef_Hz = 20.0;
    
            // disable the PWM
            HAL_disablePWM(halMtrHandle[ctrlNum]);
        }
    
        // initialize the CPU usage module
        cpuTimeHandle = CPU_TIME_init(&cpuTime,sizeof(cpuTime));
        CPU_TIME_setParams(cpuTimeHandle,
                    EPWM_getTimeBasePeriod(halMtrHandle[HAL_MTR_1]->pwmHandle[0]));
    
    #ifdef _PWMDAC_EN_
        // set DAC parameters
        pwmDACData.periodMax =
                PWMDAC_getPeriod(halHandle->pwmDACHandle[PWMDAC_NUMBER_1]);
    
        pwmDACData.ptrData[0] = &svgen[MTR_NUM_1].Ta;
        pwmDACData.ptrData[1] = &svgen[MTR_NUM_1].Tb;
        pwmDACData.ptrData[2] = &svgen[MTR_NUM_1].Tc;
        pwmDACData.ptrData[3] = &angleFoc_rad[MTR_NUM_1];
    
        pwmDACData.offset[0] = 0.5;
        pwmDACData.offset[1] = 0.5;
        pwmDACData.offset[2] = 0.5;
        pwmDACData.offset[3] = 1.0;
    
    
        pwmDACData.gain[0] = 2.0;
        pwmDACData.gain[1] = 2.0;
        pwmDACData.gain[2] = 2.0;
        pwmDACData.gain[3] = -MATH_ONE_OVER_TWO_PI;
    #endif  // _PWMDAC_EN_
    
    #ifdef _DATALOG_EN_
        // Initialize Datalog
        datalogHandle = DATALOG_init(&datalog,sizeof(datalog));
        DATALOG_Obj *datalogObj = (DATALOG_Obj *)datalogHandle;
    
        HAL_resetDlogWithDMA();
        HAL_setupDlogWithDMA(halHandle, 0, &datalogBuff1[0], &datalogBuff1[1]);
        HAL_setupDlogWithDMA(halHandle, 1, &datalogBuff2[0], &datalogBuff2[1]);
        HAL_setupDlogWithDMA(halHandle, 2, &datalogBuff3[0], &datalogBuff3[1]);
        HAL_setupDlogWithDMA(halHandle, 3, &datalogBuff4[0], &datalogBuff4[1]);
    
        // set datalog parameters
        datalogObj->iptr[0] = &angleFoc_rad[HAL_MTR_2];
        datalogObj->iptr[1] = &adcData[HAL_MTR_2].I_A.value[0];
        datalogObj->iptr[2] = &Idq_ref_A[0].value[0];
        datalogObj->iptr[3] = &Idq_ref_A[0].value[1];
    #endif  // _DATALOG_EN_
    
        systemVars.flagEnableSystem = false;
    
        // initialize the interrupt vector table
        HAL_initIntVectorTable(halHandle);
    
        // enable the ADC interrupts
        HAL_enableADCInts(halHandle);
    
        // disable global interrupts
        HAL_enableGlobalInts(halHandle);
    
        // enable debug interrupts
        HAL_enableDebugInt(halHandle);
    
        // Waiting for enable system flag to be set
        while(systemVars.flagEnableSystem == false)
        {
    
        }
    
        motorVars[HAL_MTR_1].flagEnableSys = systemVars.flagEnableSystem;
        motorVars[HAL_MTR_2].flagEnableSys = systemVars.flagEnableSystem;
    
        //
        // loop while the enable system flag is true
        //
        while(systemVars.flagEnableSystem == true)
        {
            if(systemVars.flagEnableSynControl == true)
            {
                motorVars[HAL_MTR_1].flagEnableRunAndIdentify = systemVars.flagEnableRun;
                motorVars[HAL_MTR_1].speedRef_Hz = systemVars.speedSet_Hz;
                motorVars[HAL_MTR_1].accelerationMax_Hzps = systemVars.accelerationMaxSet_Hzps;
    
                motorVars[HAL_MTR_2].flagEnableRunAndIdentify = systemVars.flagEnableRun;
                motorVars[HAL_MTR_2].speedRef_Hz = systemVars.speedSet_Hz;
                motorVars[HAL_MTR_2].accelerationMax_Hzps = systemVars.accelerationMaxSet_Hzps;
            }
    
            //
            // 1ms time base
            //
            if(HAL_getTimerStatus(halHandle, HAL_CPU_TIMER0))
            {
                motorVars[0].timerCnt_1ms++;
    
                HAL_clearTimerFlag(halHandle, HAL_CPU_TIMER0);
            }
    
    
            for(ctrlNum = HAL_MTR_1; ctrlNum <= HAL_MTR_2; ctrlNum++)
            {
                if(motorVars[ctrlNum].flagEnableRunAndIdentify == true)
                {
                    if(motorVars[ctrlNum].flagRunIdentAndOnLine == false)
                    {
                        motorVars[ctrlNum].flagRunIdentAndOnLine = true;
                        motorVars[ctrlNum].faultNow.all = 0;
                    }
                }
                else
                {
                    motorVars[ctrlNum].flagRunIdentAndOnLine = false;
                }
    
                //
                // CPU Timer 2 reserve for testing
                //
    
                motorVars[ctrlNum].mainLoopCount++;
    
                //
                // set internal DAC value for on-chip comparator for current protection
                //
                {
                    uint_least8_t  cmpssCnt;
    
                    for(cmpssCnt=0; cmpssCnt<HAL_NUM_CMPSS_CURRENT; cmpssCnt++)
                    {
                        HAL_setCMPSSDACValueHigh(halMtrHandle[ctrlNum],
                                                 cmpssCnt, motorVars[ctrlNum].dacValH);
    
                        HAL_setCMPSSDACValueLow(halMtrHandle[ctrlNum],
                                                cmpssCnt, motorVars[ctrlNum].dacValL);
                    }
                }
    
                //
                // run Rs online
                //
    //            runRsOnLine(estHandle[ctrlNum], ctrlNum);
    
                // enable or disable force angle
                EST_setFlag_enableForceAngle(estHandle[ctrlNum],
                                             motorVars[ctrlNum].flagEnableForceAngle);
    
                EST_setFlag_enableRsRecalc(estHandle[ctrlNum],
                                           motorVars[ctrlNum].flagEnableRsRecalc);
    
                EST_setFlag_enableRsOnLine(estHandle[ctrlNum],
                                           motorVars[ctrlNum].flagEnableRsOnLine);
    
                // enable or disable bypassLockRotor flag
                if(userParams[ctrlNum].motor_type == MOTOR_TYPE_INDUCTION)
                {
                    EST_setFlag_bypassLockRotor(estHandle[ctrlNum],
                                                motorVars[ctrlNum].flagBypassLockRotor);
                }
    
                if(HAL_getPwmEnableStatus(halMtrHandle[ctrlNum]) == true)
                {
                    if(HAL_getTripFaults(halMtrHandle[ctrlNum]) !=0)
                    {
                        motorVars[ctrlNum].faultNow.bit.moduleOverCurrent = 1;
                        faultFlag[ctrlNum] = HAL_getTripFaults(halMtrHandle[ctrlNum]);
                    }
                }
    
                motorVars[ctrlNum].faultUse.all = motorVars[ctrlNum].faultNow.all &
                                                    motorVars[ctrlNum].faultMask.all;
    
                // Had some faults to stop the motor
                if(motorVars[ctrlNum].faultUse.all != 0)
                {
                    motorVars[ctrlNum].flagEnableRunAndIdentify = false;
                    motorVars[ctrlNum].flagRunIdentAndOnLine = false;
                }
    
                if((motorVars[ctrlNum].flagRunIdentAndOnLine == true) &&
                        (motorVars[ctrlNum].flagEnableOffsetCalc == false))
                {
                    if(HAL_getPwmEnableStatus(halMtrHandle[ctrlNum]) == false)
                    {
                        // enable the estimator
                        EST_enable(estHandle[ctrlNum]);
    
                        // enable the trajectory generator
                        EST_enableTraj(estHandle[ctrlNum]);
    
                        // enable the PWM
                        HAL_enablePWM(halMtrHandle[ctrlNum]);
                    }
    
                    TRAJ_setTargetValue(trajHandle_spd[ctrlNum], motorVars[ctrlNum].speedRef_Hz);
                    TRAJ_setMaxDelta(trajHandle_spd[ctrlNum],
                                     (motorVars[ctrlNum].accelerationMax_Hzps / USER_M1_ISR_FREQ_Hz));
                }
                else if(motorVars[ctrlNum].flagEnableOffsetCalc == false)
                {
                    // disable the estimator
                    EST_disable(estHandle[ctrlNum]);
    
                    // disable the trajectory generator
                    EST_disableTraj(estHandle[ctrlNum]);
    
                    // disable the PWM
                    HAL_disablePWM(halMtrHandle[ctrlNum]);
    
                    // clear integral outputs of the controllers
                    PI_setUi(piHandle_Id[ctrlNum], 0.0);
                    PI_setUi(piHandle_Iq[ctrlNum], 0.0);
                    PI_setUi(piHandle_fwc[ctrlNum], 0.0);
                    PI_setUi(piHandle_spd[ctrlNum], 0.0);
    
                    // clear current references
                    Idq_ref_A[ctrlNum].value[0] = 0.0;
                    Idq_ref_A[ctrlNum].value[1] = 0.0;
    
                    Idq_offset_A[ctrlNum].value[0] = 0.0;
                    Idq_offset_A[ctrlNum].value[1] = 0.0;
    
                    motorVars[ctrlNum].IdRated_A = EST_getIdRated_A(estHandle[ctrlNum]);
    
                    motorVars[ctrlNum].IsRef_A = 0.0;
                    motorVars[ctrlNum].angleCurrent_rad = 0.0;
    
                    TRAJ_setTargetValue(trajHandle_spd[ctrlNum], 0.0);
                    TRAJ_setIntValue(trajHandle_spd[ctrlNum], 0.0);
                }
    
                // check the trajectory generator
                if(EST_isTrajError(estHandle[ctrlNum]) == true)
                {
                    // disable the PWM
                    HAL_disablePWM(halMtrHandle[ctrlNum]);
    
                    // set the enable system flag to false
                    motorVars[ctrlNum].flagEnableSys = false;
                }
                else
                {
                    // update the trajectory generator state
                    EST_updateTrajState(estHandle[ctrlNum]);
                }
    
                // check the estimator
                if(EST_isError(estHandle[ctrlNum]) == true)
                {
                    // disable the PWM
                    HAL_disablePWM(halMtrHandle[ctrlNum]);
    
                    // set the enable system flag to false
                    motorVars[ctrlNum].flagEnableSys = false;
                }
                else        // No any estimator error
                {
                    motorVars[ctrlNum].Id_target_A = EST_getIntValue_Id_A(estHandle[ctrlNum]);
    
                    bool flagEstStateChanged = EST_updateState(estHandle[ctrlNum],0.0);
    
                    if(flagEstStateChanged == true)
                    {
                        // configure the trajectory generator
                        EST_configureTraj(estHandle[ctrlNum]);
    
                        if(EST_isLockRotor(estHandle[ctrlNum]) ||
                                (EST_isMotorIdentified(estHandle[ctrlNum])
                                        && EST_isIdle(estHandle[ctrlNum])))
                        {
                            motorVars[ctrlNum].flagMotorIdentified = true;
    
                            // clear the flag
                            motorVars[ctrlNum].flagRunIdentAndOnLine = false;
                        }
                    }
                }
    
                if(EST_isMotorIdentified(estHandle[ctrlNum]) == true)
                {
                    if(motorVars[ctrlNum].flagSetupController == true)
                    {
                        // update the controller
                        updateControllers(ctrlNum);
                    }
                    else
                    {
                        motorVars[ctrlNum].flagMotorIdentified = true;
                        motorVars[ctrlNum].flagSetupController = true;
    
                        setupControllers(ctrlNum);
                    }
                }
    
                // update the global variables
                updateGlobalVariables(estHandle[ctrlNum], ctrlNum);
    
                #ifdef DRV8320_SPI
                HAL_writeDRVData(halMtrHandle[ctrlNum], &drvSPI8320Vars[ctrlNum]);
    
                HAL_readDRVData(halMtrHandle[ctrlNum], &drvSPI8320Vars[ctrlNum]);
                #endif
    
                #ifdef DRV8301_SPI
                HAL_writeDRVData(halMtrHandle[ctrlNum], &drvSPI8301Vars[ctrlNum]);
    
                HAL_readDRVData(halMtrHandle[ctrlNum], &drvSPI8301Vars[ctrlNum]);
                #endif
            } // end of for(ctrlNum;)
        } // end of while() loop
    
        // disable the PWM
        HAL_disablePWM(halMtrHandle[0]);
        HAL_disablePWM(halMtrHandle[1]);
    } // end of main() function
    
    __interrupt void mainISR(void)
    {
        // check ISR executing time
        HAL_setGPIOHigh(halHandle, HAL_GPIO_ISR);
    
        // read the timer 1 value and update the CPU usage module
        uint32_t timer1Cnt = HAL_readTimerCnt(halHandle, 2);
        CPU_TIME_updateCnts(cpuTimeHandle,timer1Cnt);
    
        // toggle status LED
        counterLED++;
    
        if(counterLED > (uint32_t)(USER_M1_ISR_FREQ_Hz / LED_BLINK_FREQ_Hz))
        {
            HAL_toggleLED(halHandle,HAL_GPIO_LED2);
            counterLED = 0;
        }
    
        // acknowledge the ADC interrupt
        HAL_ackADCInt(halHandle,ADC_INT_NUMBER1);
    
    
        for(isrNum = HAL_MTR_1; isrNum <= HAL_MTR_2; isrNum++)
        {
            // read the ADC data with offsets
            HAL_readADCDataWithOffsets(halHandle, halMtrHandle[isrNum],
                                       &adcData[isrNum], isrNum);
    
            // calculate Vbus scale factor to scale offsets with Vbus
            motorVars[isrNum].Vbus_sf = adcData[isrNum].dcBus_V *
                                           motorVars[isrNum].offset_invVbus_invV;
    
            // remove offsets
            adcData[isrNum].I_A.value[0] -= motorVars[isrNum].offsets_I_A.value[0];
            adcData[isrNum].I_A.value[1] -= motorVars[isrNum].offsets_I_A.value[1];
            adcData[isrNum].I_A.value[2] -= motorVars[isrNum].offsets_I_A.value[2];
            adcData[isrNum].V_V.value[0] -= motorVars[isrNum].offsets_V_V.value[0] *
                                                         motorVars[isrNum].Vbus_sf;
            adcData[isrNum].V_V.value[1] -= motorVars[isrNum].offsets_V_V.value[1] *
                                                         motorVars[isrNum].Vbus_sf;
            adcData[isrNum].V_V.value[2] -= motorVars[isrNum].offsets_V_V.value[2] *
                                                         motorVars[isrNum].Vbus_sf;
        }
    
        // Dual Motor Control
        for(isrNum = HAL_MTR_1; isrNum <= HAL_MTR_2; isrNum++)
        {
            // Verify close speed loop sensorless by low speed with FAST,
            // and high speed with Field Weakening Control & OVM
            if(motorVars[isrNum].flagEnableOffsetCalc == false)
            {
                float32_t outMax_V;
                MATH_Vec2 phasor;
    
                // run Clarke transform on current
                CLARKE_run(clarkeHandle_I[isrNum],
                           &adcData[isrNum].I_A, &(estInputData[isrNum].Iab_A));
    
                // run Clarke transform on voltage
                CLARKE_run(clarkeHandle_V[isrNum],
                           &adcData[isrNum].V_V, &(estInputData[isrNum].Vab_V));
    
                counterTrajSpeed[isrNum]++;
    
                if(counterTrajSpeed[isrNum] >= userParams[isrNum].numIsrTicksPerTrajTick)
                {
                    // clear counter
                    counterTrajSpeed[isrNum] = 0;
    
                    // run a trajectory for speed reference,
                    // so the reference changes with a ramp instead of a step
                    TRAJ_run(trajHandle_spd[isrNum]);
    
                    motorVars[isrNum].speedTraj_Hz = TRAJ_getIntValue(trajHandle_spd[isrNum]);
                }
    
                // run the trajectories
                EST_runTraj(estHandle[isrNum]);
    
                // store the input data into a buffer
                estInputData[isrNum].dcBus_V = adcData[isrNum].dcBus_V;
    
                if(EST_getState(estHandle[isrNum]) != EST_STATE_ONLINE)
                {
                    Idq_ref_A[isrNum].value[0] = EST_getIntValue_Id_A(estHandle[isrNum]);
                    estInputData[isrNum].speed_ref_Hz = EST_getIntValue_spd_Hz(estHandle[isrNum]);
                    estInputData[isrNum].speed_int_Hz = EST_getIntValue_spd_Hz(estHandle[isrNum]);
                }
                else
                {
                    Idq_ref_A[isrNum].value[0] = EST_getIdRated_A(estHandle[isrNum]);
                    estInputData[isrNum].speed_ref_Hz = motorVars[isrNum].speedTraj_Hz;
                    estInputData[isrNum].speed_int_Hz = motorVars[isrNum].speedTraj_Hz;
                }
    
                // update Id reference for Rs OnLine
                EST_updateId_ref_A(estHandle[isrNum],
                                   (float32_t *)&(Idq_ref_A[isrNum].value[0]));
    
                // run the estimator
                EST_run(estHandle[isrNum],
                        &estInputData[isrNum],
                        &estOutputData[isrNum]);
    
                // get Idq, reutilizing a Park transform used inside the estimator.
                // This is optional, user's Park works as well
                EST_getIdq_A(estHandle[isrNum], (MATH_Vec2 *)(&(Idq_in_A[isrNum])));
    
                // run the speed controller
                // run the speed controller
    //            if(EST_doSpeedCtrl(estHandle[isrNum]))
    //            {
                if(motorVars[isrNum].motorCtrlMode == MOTORCTRL_MODE_SPEED)
                {
                    counterSpeed[isrNum]++;
    
                    if(counterSpeed[isrNum] >= userParams[isrNum].numCtrlTicksPerSpeedTick)
                    {
                        counterSpeed[isrNum] = 0;
    
                        PI_run_series(piHandle_spd[isrNum],
                                      estInputData[isrNum].speed_ref_Hz,
                                      estOutputData[isrNum].fm_lp_rps * MATH_ONE_OVER_TWO_PI,
                                      0.0,
                                      (float32_t *)(&(motorVars[isrNum].IsRef_A)));
    
                        //
                        // Compute the output and reference vector voltage
                        //
                        motorVars[isrNum].Vs_V = sqrt((Vdq_out_V[isrNum].value[0] * Vdq_out_V[isrNum].value[0]) +
                                              (Vdq_out_V[isrNum].value[1] * Vdq_out_V[isrNum].value[1]));
                        motorVars[isrNum].VsRef_V = motorVars[isrNum].VsRef_pu * adcData[isrNum].dcBus_V;
    
                        PI_run_series(piHandle_fwc[isrNum],
                                      motorVars[isrNum].VsRef_V,
                                      motorVars[isrNum].Vs_V,
                                      0.0,
                                      (float32_t *)(&(motorVars[isrNum].angleCurrent_rad)));
    
                        // compute the sin/cos phasor using fast RTS function, callable assembly
                        fwcPhasor[isrNum].value[0] = sinf(motorVars[isrNum].angleCurrent_rad);
                        fwcPhasor[isrNum].value[1] = cosf(motorVars[isrNum].angleCurrent_rad);
    
                        if(motorVars[isrNum].IsRef_A >= 0.0)
                        {
                            Idq_ref_A[isrNum].value[0] = motorVars[isrNum].IsRef_A * fwcPhasor[isrNum].value[0];
                        }
                        else
                        {
                            Idq_ref_A[isrNum].value[0] = -(motorVars[isrNum].IsRef_A *
                                    fwcPhasor[isrNum].value[0]);
                        }
    
                        Idq_ref_A[isrNum].value[1] = motorVars[isrNum].IsRef_A * fwcPhasor[isrNum].value[1];
                    }
                }
                else
                {
                    Idq_ref_A[isrNum].value[1] = 0.0;
                }
    
    
    
                // Maximum voltage output
                userParams[isrNum].maxVsMag_V = userParams[isrNum].maxVsMag_pu *
                                                     adcData[isrNum].dcBus_V;
                PI_setMinMax(piHandle_Id[isrNum],
                             -userParams[isrNum].maxVsMag_V, userParams[isrNum].maxVsMag_V);
    
                // run the Id controller
                PI_run_series(piHandle_Id[isrNum],
                              Idq_ref_A[isrNum].value[0] + Idq_offset_A[isrNum].value[0],
                              Idq_in_A[isrNum].value[0],
                              0.0,
                              &(Vdq_out_V[isrNum].value[0]));
    
                // calculate Iq controller limits, and run Iq controller using fast RTS
                // function, callable assembly
                #ifdef __TMS320C28XX_TMU__
                outMax_V = sqrt((userParams[isrNum].maxVsMag_V * userParams[isrNum].maxVsMag_V) -
                                (Vdq_out_V[isrNum].value[0] * Vdq_out_V[isrNum].value[0]));
                #else
                outMax_V = sqrt_fastRTS((userParams[isrNum].maxVsMag_V * userParams[isrNum].maxVsMag_V) -
                                        (Vdq_out_V[isrNum].value[0] * Vdq_out_V[isrNum].value[0]));
                #endif
    
                PI_setMinMax(piHandle_Iq[isrNum], -outMax_V, outMax_V);
                PI_run_series(piHandle_Iq[isrNum],
                              Idq_ref_A[isrNum].value[1] + Idq_offset_A[isrNum].value[1],
                              Idq_in_A[isrNum].value[1],
                              0.0,
                              &(Vdq_out_V[isrNum].value[1]));
    
                // compute angle with delay compensation
                angleDelta_rad[isrNum] = userParams[isrNum].angleDelayed_sf_sec *
                                 estOutputData[isrNum].fm_lp_rps;
    
                angleEst_rad[isrNum] = MATH_incrAngle(estOutputData[isrNum].angle_rad,
                                              angleDelta_rad[isrNum]);
    
                angleFoc_rad[isrNum] = angleEst_rad[isrNum];
    
                // compute the sin/cos phasor using fast RTS function, callable assembly
                phasor.value[0] = cosf(angleFoc_rad[isrNum]);
                phasor.value[1] = sinf(angleFoc_rad[isrNum]);
    
                // set the phasor in the inverse Park transform
                IPARK_setPhasor(iparkHandle_V[isrNum], &phasor);
    
                // run the inverse Park module
                IPARK_run(iparkHandle_V[isrNum],
                          &Vdq_out_V[isrNum], &Vab_out_V[isrNum]);
    
                // setup the space vector generator (SVGEN) module
                SVGEN_setup(svgenHandle[isrNum],
                            estOutputData[isrNum].oneOverDcBus_invV);
    
                // run the space vector generator (SVGEN) module
                SVGEN_run(svgenHandle[isrNum],
                          &Vab_out_V[isrNum], &(pwmData[isrNum].Vabc_pu));
            }
            else if(motorVars[isrNum].flagEnableOffsetCalc == true)
            {
                runOffsetsCalculation(isrNum);
            }
    
            if(HAL_getPwmEnableStatus(halMtrHandle[isrNum]) == false)
            {
                // clear PWM data
                pwmData[isrNum].Vabc_pu.value[0] = 0.0;
                pwmData[isrNum].Vabc_pu.value[1] = 0.0;
                pwmData[isrNum].Vabc_pu.value[2] = 0.0;
            }
    
            // write the PWM compare values
            HAL_writePWMData(halMtrHandle[isrNum], &pwmData[isrNum]);
        }
    
    #ifdef _PWMDAC_EN_
        // connect inputs of the PWMDAC module.
        pwmDACData.value[0] = (*pwmDACData.ptrData[0]);
        pwmDACData.value[1] = (*pwmDACData.ptrData[1]);
        pwmDACData.value[2] = (*pwmDACData.ptrData[2]);
        pwmDACData.value[3] = (*pwmDACData.ptrData[3]);
    
        HAL_writePWMDACData(halHandle,&pwmDACData);
    #endif  // _PWMDAC_EN_
    
    #ifdef _DATALOG_EN_
        DATALOG_updateWithDMA(datalogHandle);
    
        // Force trig DMA channel to save the data
        HAL_trigDlogWithDMA(halHandle, 0);
        HAL_trigDlogWithDMA(halHandle, 1);
        HAL_trigDlogWithDMA(halHandle, 2);
        HAL_trigDlogWithDMA(halHandle, 3);
    #endif  // _DATALOG_EN_
    
        // read the timer 2 value and update the CPU usage module
        timer1Cnt = HAL_readTimerCnt(halHandle, 2);
        CPU_TIME_run(cpuTimeHandle, timer1Cnt);
    
        return;
    } // end of mainISR() function
    
    
    void runOffsetsCalculation(const uint16_t motorNum)
    {
        uint16_t filterCnt;
    
        if(motorVars[motorNum].flagEnableSys == true)
        {
            // enable the PWM
            HAL_enablePWM(halMtrHandle[motorNum]);
    
            float32_t Vin;
            float32_t invVdcbus;
    
            // half of inversus dc bus voltage
            invVdcbus = 2.0 / adcData[motorNum].dcBus_V;
    
            // Set the 3-phase output PWMs to 50% duty cycle
            pwmData[motorNum].Vabc_pu.value[0] = 0.0;
            pwmData[motorNum].Vabc_pu.value[1] = 0.0;
            pwmData[motorNum].Vabc_pu.value[2] = 0.0;
    
            for(filterCnt=0; filterCnt< USER_M1_NUM_CURRENT_SENSORS; filterCnt++)
            {
                // reset current offsets used
                motorVars[motorNum].offsets_I_A.value[filterCnt] = 0.0;
    
                // run current offset estimation
                FILTER_FO_run(filterHandle_I[motorNum][filterCnt],
                              adcData[motorNum].I_A.value[filterCnt]);
            }
    
            for(filterCnt=0; filterCnt< USER_M1_NUM_VOLTAGE_SENSORS; filterCnt++)
            {
                // reset voltage offsets used
                motorVars[motorNum].offsets_V_V.value[filterCnt] = 0.0;
    
                Vin = adcData[motorNum].V_V.value[filterCnt] * invVdcbus;
    
                // run voltage offset estimation
                FILTER_FO_run(filterHandle_V[motorNum][filterCnt], Vin);
            }
    
            offsetCalcCount[motorNum]++;
    
            if(offsetCalcCount[motorNum] >= offsetCalcWaitTime)
            {
                for(filterCnt=0; filterCnt<USER_M1_NUM_CURRENT_SENSORS; filterCnt++)
                {
                    // get calculated current offsets from filter
                    motorVars[motorNum].offsets_I_A.value[filterCnt] =
                            FILTER_FO_get_y1(filterHandle_I[motorNum][filterCnt]);
    
    
                    // clear current filters
                    FILTER_FO_setInitialConditions(filterHandle_I[motorNum][filterCnt],
                                                   motorVars[motorNum].offsets_I_A.value[filterCnt],
                                                   motorVars[motorNum].offsets_I_A.value[filterCnt]);
                }
    
                for(filterCnt = 0; filterCnt < USER_M1_NUM_VOLTAGE_SENSORS; filterCnt++)
                {
                    // get calculated voltage offsets from filter
                    motorVars[motorNum].offsets_V_V.value[filterCnt] =
                            FILTER_FO_get_y1(filterHandle_V[motorNum][filterCnt]);
    
                    // clear voltage filters
                    FILTER_FO_setInitialConditions(filterHandle_V[motorNum][filterCnt],
                                  motorVars[motorNum].offsets_V_V.value[filterCnt],
                                  motorVars[motorNum].offsets_V_V.value[filterCnt]);
                }
    
                offsetCalcCount[motorNum] = 0;
                motorVars[motorNum].flagEnableOffsetCalc = false;
    
                // disable the PWM
                HAL_disablePWM(halMtrHandle[motorNum]);
            }
            // Reset GPIO pin
            GPIO_writePin(30, 0);
        }
    
        return;
    } // end of runOffsetsCalculation() function
    
    //
    // runRsOnLine for Rs online calibration
    //
    void runRsOnLine(EST_Handle estHandle, HAL_MotorNum_e ctrlNum)
    {
        //
        // execute Rs OnLine code
        //
        if(motorVars[ctrlNum].flagRunIdentAndOnLine == true)
        {
            if((EST_getState(estHandle) == EST_STATE_ONLINE) &&
                    (motorVars[ctrlNum].flagEnableRsOnLine == true))
            {
                EST_setFlag_enableRsOnLine(estHandle, true);
                EST_setRsOnLineId_mag_A(estHandle, motorVars[ctrlNum].RsOnLineCurrent_A);
    
                float32_t RsError_Ohm = motorVars[ctrlNum].RsOnLine_Ohm - motorVars[ctrlNum].Rs_Ohm;
    
                if(abs(RsError_Ohm) < (motorVars[ctrlNum].Rs_Ohm * 0.05))     // 5% Error
                {
                    EST_setFlag_updateRs(estHandle, true);
                }
            }
            else
            {
                EST_setRsOnLineId_mag_A(estHandle, 0.0);
                EST_setRsOnLineId_A(estHandle, 0.0);
                EST_setRsOnLine_Ohm(estHandle, EST_getRs_Ohm(estHandle));
                EST_setFlag_enableRsOnLine(estHandle, false);
                EST_setFlag_updateRs(estHandle, false);
            }
        }
    
        return;
    } // end of runRsOnLine() function
    
    // end of file
    

  • You might run the lab13 with FWC and use this lab as a basis to support dual motor if you want to integrate more functions in your project, and please pay attention to the PWM frequency that can not be set to a higher value for running dual motor.