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.
Hi Yanming Luo,
I have a question on an InstaSPIN-FOC Lab project in motorware.
Particularly it is on Lab11a.
We are presently attempting to implement the function of variable PWM frequency on Lab11a.
For this work, we need to split the source codes in mainISR() into two ISR funtions of fixed frequency and variable frequency as in the is12_variable_pwm_frequency lab in MotorControl_SDK.
Meanwhile in my previous post, you advised how to split the source codes in mainISR() into two ISR funtions; it is to run all of the speed, Id and Iq controllers in estISR().
However, with reference to the is12_variable_pwm_frequency lab in MotorControl_SDK, I have found out that the estISR() runs the speed controller while the mainISR() runs the Id and Iq controllers.
Please comment on this observation.
Thank you for your guidance.
With regards,
JS Yoo
Yes, the Id and Iq PI controller can be called in either estISR or mainISR. It's better to call in mainISR(). It's better to change the Kp and Ki with PWM frequency if you need a good current control performance.
Hi Yanming Luo,
Thank you for your review.
First of all, our inverter built by using the TMS320F28069F runs very well in the environment of Lab11a.
In order to implement the function of variable PWM frequency on Lab11a, I have completed the work of splitting the source codes in mainISR() into two ISR funtions of estISR() and mainISR() similar to is12_variable_pwm_frequency lab in MotorControl_SDK.
All functions associated with reading the ADC result, writing PWM compare registers, the overmodulation and current reconstruction, and the Id and Iq controls reside in mainISR(), whereas the other functions associated with the speed control and ESTrun() reside in estISR().
Now when I attempt to run the motor with this modified Lab11a project, the motor generates noisy sound. It seems that the magnetic flux is not generated suitably.
Therefore I compared the source codes in estISR() of the is12_variable_pwm_frequency project with those in mainISR() of the Lab11a.
First, the source codes in estISR() of the is12_variable_pwm_frequency project are as follows:
//
// store the input data into a buffer
//
estInputData.dcBus_V = adcData.dcBus_V;
estInputData.speed_ref_Hz = motorVars.speedTraj_Hz;
estInputData.speed_int_Hz = motorVars.speedTraj_Hz;
//
// run the estimator
//
EST_run(estHandle, &estInputData, &estOutputData);
The input parameters for EST_run() are provided ahead of calling the EST_run() function.
Second, the source codes in mainISR() of the Lab11a are as follows:
// run Clarke transform on current
CLARKE_run(clarkeHandle_I,&gAdcData.I,&Iab_pu);
// run Clarke transform on voltage
CLARKE_run(clarkeHandle_V,&gAdcData.V,&Vab_pu);
// run a trajectory for Id reference, so the reference changes with a ramp instead of a step
TRAJ_run(trajHandle_Id);
// run the estimator
EST_run(estHandle,
&Iab_pu,
&Vab_pu,
gAdcData.dcBus,
TRAJ_getIntValue(trajHandle_spd));
Two CLARKE_run() functions need to reside in mainISR() while the EST_run() function need to reside in estISR().
The parameters for this EST_run() seem to be input parameters except the estHandle.
In summary the ways that EST_run() function is used in the is12_variable_pwm_frequency project and Lab11a are quite different.
Please inform us if it is impossible to implement the function of variable PWM frequency with the motorware FAST estimator library.
We are ready to build a new inverter by using the TMS320F28004xC device and the MotorControl_SDK FAST estimator library.
Otherwise please provide us with the modified Lab11a project which have the function of variable PWM frequency .
Thank you for your guidance.
With regards,
JS Yoo
You might try to use the same frequency for mainISR() and EST_run() without online change PWM frequency to see what happens.
And which frequency are you using to calculate the estimator parameters?
Hi Yanming Luo,
Thank you for your review.
What I did is as follows.
(1) With respect to the original Lab11a, the PWM frequency was 8kHz and the inverter runs the motor very well.
(2) With respect to the modified Lab11a, at first, the execution frequency for estISR() was set to 20kHz and the execution frequency for mainISR() was set to 8kHz. The motor does not run and generates noisy sound.
(3) With respect to the modified Lab11a, secondly, the execution frequency for both estISR() and mainISR() was set to 8kHz. The motor does not run and generates noisy sound.
What do mean by "to calculate the estimator parameters"?
What are the estimator parameters?
Thank you for your guidance.
With regards,
JS Yoo
Hi Yanming Luo,
Thank you for your review.
Please enclosed find the source codes for estISR() and mainISR().
I just splitted the source codes of the original mainISR() in Lab11a into two ISR funtions of estISR() and the new mainISR().
------------------------------------------------------------------------------------------------------------------------------------
_iq angle_pu = _IQ(0.0);
_iq speed_pu = _IQ(0.0);
MATH_vec2 Iab_pu;
MATH_vec2 Vab_pu;
MATH_vec2 phasor;
//
// the CPU timer0 interrupt as FAST estimator ISR
//
interrupt void estISR(void)
{
// acknowledge the interrupt that is set for estimator
HAL_acqTimer0Int(halHandle);
// if(gTrjCnt >= gUserParams.numCtrlTicksPerTrajTick)
// {
// // clear counter
// gTrjCnt = 0;
// run a trajectory for speed reference, so the reference changes with a ramp instead of a step
TRAJ_run(trajHandle_spd);
// }
// run the estimator
EST_run(estHandle,
&Iab_pu,
&Vab_pu,
gAdcData.dcBus,
TRAJ_getIntValue(trajHandle_spd));
// generate the motor electrical angle
angle_pu = EST_getAngle_pu(estHandle);
speed_pu = EST_getFm_pu(estHandle);
// get Idq from estimator to avoid sin and cos
EST_getIdq_pu(estHandle,&gIdq_pu);
// run the appropriate controller
if((gMotorVars.Flag_Run_Identify) || (gMotorVars.Flag_enableRsRecalc))
{
// when appropriate, run the PID speed controller
if((pidCntSpeed++ >= gUserVars.numCtrlTicksPerSpeedTick) && (!gMotorVars.Flag_enableRsRecalc))
{
// calculate Id reference squared
_iq Id_ref_squared_pu = _IQmpy(PID_getRefValue(pidHandle[1]),PID_getRefValue(pidHandle[1]));
// Take into consideration that Iq^2+Id^2 = Is^2
_iq Iq_Max_pu = _IQsqrt(gIs_Max_squared_pu - Id_ref_squared_pu);
// clear counter
pidCntSpeed = 0;
// Set new min and max for the speed controller output
PID_setMinMax(pidHandle[0], -Iq_Max_pu, Iq_Max_pu);
// run speed controller
PID_run_spd(pidHandle[0],TRAJ_getIntValue(trajHandle_spd),speed_pu,&(gIdq_ref_pu.value[1]));
}
}
}
//! \brief The main ISR that implements the motor control.
interrupt void mainISR(void)
{
_iq oneOverDcBus;
// acknowledge the ADC interrupt
HAL_acqAdcInt(halHandle,ADC_IntNumber_1);
// convert the ADC data
HAL_readAdcDataWithOffsets(halHandle,&gAdcData);
// remove offsets
gAdcData.I.value[0] = gAdcData.I.value[0] - gOffsets_I_pu.value[0];
gAdcData.I.value[1] = gAdcData.I.value[1] - gOffsets_I_pu.value[1];
gAdcData.I.value[2] = gAdcData.I.value[2] - gOffsets_I_pu.value[2];
gAdcData.V.value[0] = gAdcData.V.value[0] - gOffsets_V_pu.value[0];
gAdcData.V.value[1] = gAdcData.V.value[1] - gOffsets_V_pu.value[1];
gAdcData.V.value[2] = gAdcData.V.value[2] - gOffsets_V_pu.value[2];
// run the current reconstruction algorithm
runCurrentReconstruction();
// run Clarke transform on current
CLARKE_run(clarkeHandle_I,&gAdcData.I,&Iab_pu);
// run Clarke transform on voltage
CLARKE_run(clarkeHandle_V,&gAdcData.V,&Vab_pu);
// run a trajectory for Id reference, so the reference changes with a ramp instead of a step
TRAJ_run(trajHandle_Id);
// run the appropriate controller
if((gMotorVars.Flag_Run_Identify) || (gMotorVars.Flag_enableRsRecalc))
{
_iq refValue;
_iq fbackValue;
_iq outMax_pu;
// get the reference value from the trajectory module
refValue = TRAJ_getIntValue(trajHandle_Id) + EST_getRsOnLineId_pu(estHandle);
// get the feedback value
fbackValue = gIdq_pu.value[0];
// run the Id PID controller
PID_run(pidHandle[1],refValue,fbackValue,&(gVdq_out_pu.value[0]));
// set Iq reference to zero when doing Rs recalculation
if(gMotorVars.Flag_enableRsRecalc) gIdq_ref_pu.value[1] = _IQ(0.0);
// get the Iq reference value
refValue = gIdq_ref_pu.value[1];
// get the feedback value
fbackValue = gIdq_pu.value[1];
// calculate Iq controller limits, and run Iq controller
_iq max_vs = _IQmpy(gMotorVars.OverModulation,EST_getDcBus_pu(estHandle));
outMax_pu = _IQsqrt(_IQmpy(max_vs,max_vs) - _IQmpy(gVdq_out_pu.value[0],gVdq_out_pu.value[0]));
PID_setMinMax(pidHandle[2],-outMax_pu,outMax_pu);
PID_run(pidHandle[2],refValue,fbackValue,&(gVdq_out_pu.value[1]));
// compensate angle for PWM delay
angle_pu = angleDelayComp(speed_pu, angle_pu);
// compute the sin/cos phasor
phasor.value[0] = _IQcosPU(angle_pu);
phasor.value[1] = _IQsinPU(angle_pu);
// set the phasor in the inverse Park transform
IPARK_setPhasor(iparkHandle,&phasor);
// run the inverse Park module
IPARK_run(iparkHandle,&gVdq_out_pu,&Vab_pu);
// run the space Vector Generator (SVGEN) module
oneOverDcBus = EST_getOneOverDcBus_pu(estHandle);
Vab_pu.value[0] = _IQmpy(Vab_pu.value[0],oneOverDcBus);
Vab_pu.value[1] = _IQmpy(Vab_pu.value[1],oneOverDcBus);
SVGEN_run(svgenHandle,&Vab_pu,&(gPwmData.Tabc));
// run the PWM compensation and current ignore algorithm
SVGENCURRENT_compPwmData(svgencurrentHandle,&(gPwmData.Tabc),&gPwmData_prev);
// gTrjCnt++;
}
else if(gMotorVars.Flag_enableOffsetcalc == true)
{
runOffsetsCalculation();
}
else
{
// disable the PWM
HAL_disablePwm(halHandle);
// Set the PWMs to 50% duty cycle
gPwmData.Tabc.value[0] = _IQ(0.0);
gPwmData.Tabc.value[1] = _IQ(0.0);
gPwmData.Tabc.value[2] = _IQ(0.0);
}
// write the PWM compare values
HAL_writePwmData(halHandle,&gPwmData);
// run function to set next trigger
if(!gMotorVars.Flag_enableRsRecalc) runSetTrigger();
return;
} // end of mainISR() function
//! \brief Acknowledges an interrupt from Timer 0 so that another Timer 0 interrupt
//! can happen again.
//! \param[in] handle The hardware abstraction layer (HAL) handle
static inline void HAL_acqTimer0Int(HAL_Handle handle)
{
HAL_Obj *obj = (HAL_Obj *)handle;
// clear the Timer 0 interrupt flag
TIMER_clearFlag(obj->timerHandle[0]);
// Acknowledge interrupt from PIE group 1
PIE_clearInt(obj->pieHandle,PIE_GroupNumber_1);
return;
} // end of HAL_acqTimer0Int() function
---------------------------------------------------------------------------------------------------------------------------
A more explanation is as follows:
(1) Timer0 interrupt generates the estISR(). I have confirmed that the estISR() is executed with a period of 8kHz.
(2) The mainISR() is also executed with a period of 8kHz.
(3) That is all. I just splitted two ISRs.
(4) You may have to check if my splitting work is correct.
Thank you for your guidance.
With regards,
JS Yoo
Please upload the files user.h and proj_x.c, so we understand how do you calculate the parameters for the instaspin-foc and FAST estimator. Don't paste the code directly.
Hi Yanming Luo,
Thank you for your review.
I have uploaded four files including hal.c and hal.h.
(I have just dragged the files into this window. Is this correct?)
I have not yet implemented the function of the variable PWM frequency.
I just splitted the original mainISR() into two ISRs of estISR() and mainISR() in order to confirm whether our motor runs well or not when two ISRs are employed.
With the original mainISR(), our motor runs very well.
Two ISRs are executed at 8kHz.
Thank you for guidance.
With regards,
JS Yoo
/* --COPYRIGHT--,BSD (proj_lab11a_TI) * 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/boards/hvkit_rev1p1/f28x/f2806xF/src/hal.c //! \brief Contains the various functions related to the HAL object (everything outside the CTRL system) //! //! (C) Copyright 2011, Texas Instruments, Inc. // ************************************************************************** // the includes // drivers // modules // platforms #include "hal.h" #include "user.h" #include "hal_obj.h" #ifdef FLASH #pragma CODE_SECTION(HAL_setupFlash,"ramfuncs"); #endif // ************************************************************************** // the defines #define US_TO_CNT(A) ((((long double) A * (long double)USER_SYSTEM_FREQ_MHz) - 9.0L) / 5.0L) // ************************************************************************** // the globals HAL_Obj hal; // ************************************************************************** // the functions void HAL_cal(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; // enable the ADC clock CLK_enableAdcClock(obj->clkHandle); // Run the Device_cal() function // This function copies the ADC and oscillator calibration values from TI reserved // OTP into the appropriate trim registers // This boot ROM automatically calls this function to calibrate the interal // oscillators and ADC with device specific calibration data. // If the boot ROM is bypassed by Code Composer Studio during the development process, // then the calibration must be initialized by the application ENABLE_PROTECTED_REGISTER_WRITE_MODE; (*Device_cal)(); DISABLE_PROTECTED_REGISTER_WRITE_MODE; // run offsets calibration in user's memory HAL_AdcOffsetSelfCal(handle); // run oscillator compensation HAL_OscTempComp(handle); // disable the ADC clock CLK_disableAdcClock(obj->clkHandle); return; } // end of HAL_cal() function void HAL_OscTempComp(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; uint16_t Temperature; // disable the ADCs ADC_disable(obj->adcHandle); // power up the bandgap circuit ADC_enableBandGap(obj->adcHandle); // set the ADC voltage reference source to internal ADC_setVoltRefSrc(obj->adcHandle,ADC_VoltageRefSrc_Int); // enable the ADC reference buffers ADC_enableRefBuffers(obj->adcHandle); // Set main clock scaling factor (max45MHz clock for the ADC module) ADC_setDivideSelect(obj->adcHandle,ADC_DivideSelect_ClkIn_by_2); // power up the ADCs ADC_powerUp(obj->adcHandle); // enable the ADCs ADC_enable(obj->adcHandle); // enable non-overlap mode ADC_enableNoOverlapMode(obj->adcHandle); // connect channel A5 internally to the temperature sensor ADC_setTempSensorSrc(obj->adcHandle, ADC_TempSensorSrc_Int); // set SOC0 channel select to ADCINA5 ADC_setSocChanNumber(obj->adcHandle, ADC_SocNumber_0, ADC_SocChanNumber_A5); // set SOC0 acquisition period to 26 ADCCLK ADC_setSocSampleDelay(obj->adcHandle, ADC_SocNumber_0, ADC_SocSampleDelay_64_cycles); // connect ADCINT1 to EOC0 ADC_setIntSrc(obj->adcHandle, ADC_IntNumber_1, ADC_IntSrc_EOC0); // clear ADCINT1 flag ADC_clearIntFlag(obj->adcHandle, ADC_IntNumber_1); // enable ADCINT1 ADC_enableInt(obj->adcHandle, ADC_IntNumber_1); // force start of conversion on SOC0 ADC_setSocFrc(obj->adcHandle, ADC_SocFrc_0); // wait for end of conversion while (ADC_getIntFlag(obj->adcHandle, ADC_IntNumber_1) == 0){} // clear ADCINT1 flag ADC_clearIntFlag(obj->adcHandle, ADC_IntNumber_1); Temperature = ADC_readResult(obj->adcHandle, ADC_ResultNumber_0); HAL_osc1Comp(handle, Temperature); HAL_osc2Comp(handle, Temperature); return; } // end of HAL_OscTempComp() function void HAL_osc1Comp(HAL_Handle handle, const int16_t sensorSample) { int16_t compOscFineTrim; HAL_Obj *obj = (HAL_Obj *)handle; ENABLE_PROTECTED_REGISTER_WRITE_MODE; compOscFineTrim = ((sensorSample - getRefTempOffset())*(int32_t)getOsc1FineTrimSlope() + OSC_POSTRIM_OFF + FP_ROUND )/FP_SCALE + getOsc1FineTrimOffset() - OSC_POSTRIM; if(compOscFineTrim > 31) { compOscFineTrim = 31; } else if(compOscFineTrim < -31) { compOscFineTrim = -31; } OSC_setTrim(obj->oscHandle, OSC_Number_1, HAL_getOscTrimValue(getOsc1CoarseTrim(), compOscFineTrim)); DISABLE_PROTECTED_REGISTER_WRITE_MODE; return; } // end of HAL_osc1Comp() function void HAL_osc2Comp(HAL_Handle handle, const int16_t sensorSample) { int16_t compOscFineTrim; HAL_Obj *obj = (HAL_Obj *)handle; ENABLE_PROTECTED_REGISTER_WRITE_MODE; compOscFineTrim = ((sensorSample - getRefTempOffset())*(int32_t)getOsc2FineTrimSlope() + OSC_POSTRIM_OFF + FP_ROUND )/FP_SCALE + getOsc2FineTrimOffset() - OSC_POSTRIM; if(compOscFineTrim > 31) { compOscFineTrim = 31; } else if(compOscFineTrim < -31) { compOscFineTrim = -31; } OSC_setTrim(obj->oscHandle, OSC_Number_2, HAL_getOscTrimValue(getOsc2CoarseTrim(), compOscFineTrim)); DISABLE_PROTECTED_REGISTER_WRITE_MODE; return; } // end of HAL_osc2Comp() function uint16_t HAL_getOscTrimValue(int16_t coarse, int16_t fine) { uint16_t regValue = 0; if(fine < 0) { regValue = ((-fine) | 0x20) << 9; } else { regValue = fine << 9; } if(coarse < 0) { regValue |= ((-coarse) | 0x80); } else { regValue |= coarse; } return regValue; } // end of HAL_getOscTrimValue() function void HAL_AdcOffsetSelfCal(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; uint16_t AdcConvMean; // disable the ADCs ADC_disable(obj->adcHandle); // power up the bandgap circuit ADC_enableBandGap(obj->adcHandle); // set the ADC voltage reference source to internal ADC_setVoltRefSrc(obj->adcHandle,ADC_VoltageRefSrc_Int); // enable the ADC reference buffers ADC_enableRefBuffers(obj->adcHandle); // Set main clock scaling factor (max45MHz clock for the ADC module) ADC_setDivideSelect(obj->adcHandle,ADC_DivideSelect_ClkIn_by_2); // power up the ADCs ADC_powerUp(obj->adcHandle); // enable the ADCs ADC_enable(obj->adcHandle); //Select VREFLO internal connection on B5 ADC_enableVoltRefLoConv(obj->adcHandle); //Select channel B5 for all SOC HAL_AdcCalChanSelect(handle, ADC_SocChanNumber_B5); //Apply artificial offset (+80) to account for a negative offset that may reside in the ADC core ADC_setOffTrim(obj->adcHandle, 80); //Capture ADC conversion on VREFLO AdcConvMean = HAL_AdcCalConversion(handle); //Set offtrim register with new value (i.e remove artical offset (+80) and create a two's compliment of the offset error) ADC_setOffTrim(obj->adcHandle, 80 - AdcConvMean); //Select external ADCIN5 input pin on B5 ADC_disableVoltRefLoConv(obj->adcHandle); return; } // end of HAL_AdcOffsetSelfCal() function void HAL_AdcCalChanSelect(HAL_Handle handle, const ADC_SocChanNumber_e chanNumber) { HAL_Obj *obj = (HAL_Obj *)handle; ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_0,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_1,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_2,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_3,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_4,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_5,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_6,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_7,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_8,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_9,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_10,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_11,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_12,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_13,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_14,chanNumber); ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_15,chanNumber); return; } // end of HAL_AdcCalChanSelect() function uint16_t HAL_AdcCalConversion(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; uint16_t index, SampleSize, Mean; uint32_t Sum; ADC_SocSampleDelay_e ACQPS_Value; index = 0; //initialize index to 0 SampleSize = 256; //set sample size to 256 (**NOTE: Sample size must be multiples of 2^x where is an integer >= 4) Sum = 0; //set sum to 0 Mean = 999; //initialize mean to known value //Set the ADC sample window to the desired value (Sample window = ACQPS + 1) ACQPS_Value = ADC_SocSampleDelay_7_cycles; ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_0,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_1,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_2,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_3,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_4,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_5,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_6,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_7,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_8,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_9,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_10,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_11,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_12,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_13,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_14,ACQPS_Value); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_15,ACQPS_Value); // Enabled ADCINT1 and ADCINT2 ADC_enableInt(obj->adcHandle, ADC_IntNumber_1); ADC_enableInt(obj->adcHandle, ADC_IntNumber_2); // Disable continuous sampling for ADCINT1 and ADCINT2 ADC_setIntMode(obj->adcHandle, ADC_IntNumber_1, ADC_IntMode_EOC); ADC_setIntMode(obj->adcHandle, ADC_IntNumber_2, ADC_IntMode_EOC); //ADCINTs trigger at end of conversion ADC_setIntPulseGenMode(obj->adcHandle, ADC_IntPulseGenMode_Prior); // Setup ADCINT1 and ADCINT2 trigger source ADC_setIntSrc(obj->adcHandle, ADC_IntNumber_1, ADC_IntSrc_EOC6); ADC_setIntSrc(obj->adcHandle, ADC_IntNumber_2, ADC_IntSrc_EOC14); // Setup each SOC's ADCINT trigger source ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_0, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_1, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_2, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_3, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_4, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_5, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_6, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_7, ADC_Int2TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_8, ADC_Int1TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_9, ADC_Int1TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_10, ADC_Int1TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_11, ADC_Int1TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_12, ADC_Int1TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_13, ADC_Int1TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_14, ADC_Int1TriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_15, ADC_Int1TriggersSOC); // Delay before converting ADC channels usDelay(US_TO_CNT(ADC_DELAY_usec)); ADC_setSocFrcWord(obj->adcHandle, 0x00FF); while( index < SampleSize ) { //Wait for ADCINT1 to trigger, then add ADCRESULT0-7 registers to sum while (ADC_getIntFlag(obj->adcHandle, ADC_IntNumber_1) == 0){} //Must clear ADCINT1 flag since INT1CONT = 0 ADC_clearIntFlag(obj->adcHandle, ADC_IntNumber_1); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_0); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_1); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_2); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_3); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_4); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_5); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_6); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_7); //Wait for ADCINT2 to trigger, then add ADCRESULT8-15 registers to sum while (ADC_getIntFlag(obj->adcHandle, ADC_IntNumber_2) == 0){} //Must clear ADCINT2 flag since INT2CONT = 0 ADC_clearIntFlag(obj->adcHandle, ADC_IntNumber_2); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_8); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_9); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_10); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_11); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_12); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_13); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_14); Sum += ADC_readResult(obj->adcHandle, ADC_ResultNumber_15); index+=16; } // end data collection //Disable ADCINT1 and ADCINT2 to STOP the ping-pong sampling ADC_disableInt(obj->adcHandle, ADC_IntNumber_1); ADC_disableInt(obj->adcHandle, ADC_IntNumber_2); //Calculate average ADC sample value Mean = Sum / SampleSize; // Clear start of conversion trigger ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_0, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_1, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_2, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_3, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_4, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_5, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_6, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_7, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_8, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_9, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_10, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_11, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_12, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_13, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_14, ADC_NoIntTriggersSOC); ADC_setupSocTrigSrc(obj->adcHandle, ADC_SocNumber_15, ADC_NoIntTriggersSOC); //return the average return(Mean); } // end of HAL_AdcCalConversion() function void HAL_disableWdog(HAL_Handle halHandle) { HAL_Obj *hal = (HAL_Obj *)halHandle; WDOG_disable(hal->wdogHandle); return; } // end of HAL_disableWdog() function void HAL_disableGlobalInts(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; CPU_disableGlobalInts(obj->cpuHandle); return; } // end of HAL_disableGlobalInts() function void HAL_enableAdcInts(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; // enable the PIE interrupts associated with the ADC interrupts PIE_enableAdcInt(obj->pieHandle,ADC_IntNumber_1); // enable the ADC interrupts ADC_enableInt(obj->adcHandle,ADC_IntNumber_1); // enable the cpu interrupt for ADC interrupts CPU_enableInt(obj->cpuHandle,CPU_IntNumber_10); return; } // end of HAL_enableAdcInts() function void HAL_enableDebugInt(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; CPU_enableDebugInt(obj->cpuHandle); return; } // end of HAL_enableDebugInt() function void HAL_enableGlobalInts(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; CPU_enableGlobalInts(obj->cpuHandle); return; } // end of HAL_enableGlobalInts() function void HAL_enablePwmInt(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; PIE_enablePwmInt(obj->pieHandle,PWM_Number_1); // enable the interrupt PWM_enableInt(obj->pwmHandle[PWM_Number_1]); // enable the cpu interrupt for EPWM1_INT CPU_enableInt(obj->cpuHandle,CPU_IntNumber_3); return; } // end of HAL_enablePwmInt() function void HAL_enableTimer0Int(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; PIE_enableTimer0Int(obj->pieHandle); // enable the interrupt TIMER_enableInt(obj->timerHandle[0]); // enable the cpu interrupt for TINT0 CPU_enableInt(obj->cpuHandle,CPU_IntNumber_1); return; } // end of HAL_enableTimer0Int() function void HAL_setupFaults(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; uint_least8_t cnt; // Configure Trip Mechanism for the Motor control software // -Cycle by cycle trip on CPU halt // -One shot fault trip zone // These trips need to be repeated for EPWM1 ,2 & 3 for(cnt=0;cnt<3;cnt++) { PWM_enableTripZoneSrc(obj->pwmHandle[cnt],PWM_TripZoneSrc_CycleByCycle_TZ6_NOT); PWM_enableTripZoneSrc(obj->pwmHandle[cnt],PWM_TripZoneSrc_OneShot_TZ1_NOT); // What do we want the OST/CBC events to do? // TZA events can force EPWMxA // TZB events can force EPWMxB PWM_setTripZoneState_TZA(obj->pwmHandle[cnt],PWM_TripZoneState_EPWM_Low); PWM_setTripZoneState_TZB(obj->pwmHandle[cnt],PWM_TripZoneState_EPWM_Low); // Clear faults from flip flop GPIO_setLow(obj->gpioHandle,GPIO_Number_9); GPIO_setHigh(obj->gpioHandle,GPIO_Number_9); } return; } // end of HAL_setupFaults() function HAL_Handle HAL_init(void *pMemory,const size_t numBytes) { uint_least8_t cnt; HAL_Handle handle; HAL_Obj *obj; if(numBytes < sizeof(HAL_Obj)) return((HAL_Handle)NULL); // assign the handle handle = (HAL_Handle)pMemory; // assign the object obj = (HAL_Obj *)handle; // initialize the watchdog driver obj->wdogHandle = WDOG_init((void *)WDOG_BASE_ADDR,sizeof(WDOG_Obj)); // disable watchdog HAL_disableWdog(handle); // initialize the ADC obj->adcHandle = ADC_init((void *)ADC_BASE_ADDR,sizeof(ADC_Obj)); // initialize the clock handle obj->clkHandle = CLK_init((void *)CLK_BASE_ADDR,sizeof(CLK_Obj)); // initialize the CPU handle obj->cpuHandle = CPU_init(&cpu,sizeof(cpu)); // initialize the FLASH handle obj->flashHandle = FLASH_init((void *)FLASH_BASE_ADDR,sizeof(FLASH_Obj)); // initialize the GPIO handle obj->gpioHandle = GPIO_init((void *)GPIO_BASE_ADDR,sizeof(GPIO_Obj)); // initialize the current offset estimator handles for(cnt=0;cnt<USER_NUM_CURRENT_SENSORS;cnt++) { obj->offsetHandle_I[cnt] = OFFSET_init(&obj->offset_I[cnt],sizeof(obj->offset_I[cnt])); } // initialize the voltage offset estimator handles for(cnt=0;cnt<USER_NUM_VOLTAGE_SENSORS;cnt++) { obj->offsetHandle_V[cnt] = OFFSET_init(&obj->offset_V[cnt],sizeof(obj->offset_V[cnt])); } // initialize the oscillator handle obj->oscHandle = OSC_init((void *)OSC_BASE_ADDR,sizeof(OSC_Obj)); // initialize the PIE handle obj->pieHandle = PIE_init((void *)PIE_BASE_ADDR,sizeof(PIE_Obj)); // initialize the PLL handle obj->pllHandle = PLL_init((void *)PLL_BASE_ADDR,sizeof(PLL_Obj)); // initialize PWM handles obj->pwmHandle[0] = PWM_init((void *)PWM_ePWM1_BASE_ADDR,sizeof(PWM_Obj)); obj->pwmHandle[1] = PWM_init((void *)PWM_ePWM2_BASE_ADDR,sizeof(PWM_Obj)); obj->pwmHandle[2] = PWM_init((void *)PWM_ePWM3_BASE_ADDR,sizeof(PWM_Obj)); // initialize PWM DAC handles obj->pwmDacHandle[0] = PWMDAC_init((void *)PWM_ePWM6_BASE_ADDR,sizeof(PWM_Obj)); obj->pwmDacHandle[1] = PWMDAC_init((void *)PWM_ePWM5_BASE_ADDR,sizeof(PWM_Obj)); obj->pwmDacHandle[2] = PWMDAC_init((void *)PWM_ePWM4_BASE_ADDR,sizeof(PWM_Obj)); // initialize power handle obj->pwrHandle = PWR_init((void *)PWR_BASE_ADDR,sizeof(PWR_Obj)); // initialize timer handles obj->timerHandle[0] = TIMER_init((void *)TIMER0_BASE_ADDR,sizeof(TIMER_Obj)); obj->timerHandle[1] = TIMER_init((void *)TIMER1_BASE_ADDR,sizeof(TIMER_Obj)); obj->timerHandle[2] = TIMER_init((void *)TIMER2_BASE_ADDR,sizeof(TIMER_Obj)); #ifdef QEP // initialize QEP driver obj->qepHandle[0] = QEP_init((void*)QEP1_BASE_ADDR,sizeof(QEP_Obj)); #endif return(handle); } // end of HAL_init() function void HAL_setParams(HAL_Handle handle,const USER_Params *pUserParams) { uint_least8_t cnt; HAL_Obj *obj = (HAL_Obj *)handle; _iq beta_lp_pu = _IQ(pUserParams->offsetPole_rps/(float_t)pUserParams->ctrlFreq_Hz); HAL_setNumCurrentSensors(handle,pUserParams->numCurrentSensors); HAL_setNumVoltageSensors(handle,pUserParams->numVoltageSensors); for(cnt=0;cnt<HAL_getNumCurrentSensors(handle);cnt++) { HAL_setOffsetBeta_lp_pu(handle,HAL_SensorType_Current,cnt,beta_lp_pu); HAL_setOffsetInitCond(handle,HAL_SensorType_Current,cnt,_IQ(0.0)); HAL_setOffsetValue(handle,HAL_SensorType_Current,cnt,_IQ(0.0)); } for(cnt=0;cnt<HAL_getNumVoltageSensors(handle);cnt++) { HAL_setOffsetBeta_lp_pu(handle,HAL_SensorType_Voltage,cnt,beta_lp_pu); HAL_setOffsetInitCond(handle,HAL_SensorType_Voltage,cnt,_IQ(0.0)); HAL_setOffsetValue(handle,HAL_SensorType_Voltage,cnt,_IQ(0.0)); } // disable global interrupts CPU_disableGlobalInts(obj->cpuHandle); // disable cpu interrupts CPU_disableInts(obj->cpuHandle); // clear cpu interrupt flags CPU_clearIntFlags(obj->cpuHandle); // setup the clocks HAL_setupClks(handle); // Setup the PLL HAL_setupPll(handle,PLL_ClkFreq_90_MHz); // setup the PIE HAL_setupPie(handle); // run the device calibration HAL_cal(handle); // setup the peripheral clocks HAL_setupPeripheralClks(handle); // setup the GPIOs HAL_setupGpios(handle); // setup the flash HAL_setupFlash(handle); // setup the ADCs HAL_setupAdcs(handle); // setup the PWMs HAL_setupPwms(handle, (float_t)pUserParams->systemFreq_MHz, pUserParams->pwmPeriod_usec, USER_NUM_PWM_TICKS_PER_ISR_TICK); #ifdef QEP // setup the QEP HAL_setupQEP(handle,HAL_Qep_QEP1); #endif // setup the PWM DACs HAL_setupPwmDacs(handle); // setup the timers HAL_setupTimers(handle, (float_t)pUserParams->systemFreq_MHz); // setup the timer for estimator HAL_setupEstTimer(handle, (float_t)pUserParams->systemFreq_MHz, USER_EST_FREQ_Hz); // set the default current bias { uint_least8_t cnt; _iq bias = _IQ12mpy(ADC_dataBias,_IQ(pUserParams->current_sf)); for(cnt=0;cnt<HAL_getNumCurrentSensors(handle);cnt++) { HAL_setBias(handle,HAL_SensorType_Current,cnt,bias); } } // set the current scale factor { _iq current_sf = _IQ(pUserParams->current_sf); HAL_setCurrentScaleFactor(handle,current_sf); } // set the default voltage bias { uint_least8_t cnt; _iq bias = _IQ(0.0); for(cnt=0;cnt<HAL_getNumVoltageSensors(handle);cnt++) { HAL_setBias(handle,HAL_SensorType_Voltage,cnt,bias); } } // set the voltage scale factor { _iq voltage_sf = _IQ(pUserParams->voltage_sf); HAL_setVoltageScaleFactor(handle,voltage_sf); } return; } // end of HAL_setParams() function void HAL_setupAdcs(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; // disable the ADCs ADC_disable(obj->adcHandle); // power up the bandgap circuit ADC_enableBandGap(obj->adcHandle); // set the ADC voltage reference source to internal ADC_setVoltRefSrc(obj->adcHandle,ADC_VoltageRefSrc_Int); // enable the ADC reference buffers ADC_enableRefBuffers(obj->adcHandle); // Set main clock scaling factor (max45MHz clock for the ADC module) ADC_setDivideSelect(obj->adcHandle,ADC_DivideSelect_ClkIn_by_2); // power up the ADCs ADC_powerUp(obj->adcHandle); // enable the ADCs ADC_enable(obj->adcHandle); // set the ADC interrupt pulse generation to prior ADC_setIntPulseGenMode(obj->adcHandle,ADC_IntPulseGenMode_Prior); // set the temperature sensor source to external ADC_setTempSensorSrc(obj->adcHandle,ADC_TempSensorSrc_Ext); // configure the interrupt sources ADC_disableInt(obj->adcHandle,ADC_IntNumber_1); ADC_setIntMode(obj->adcHandle,ADC_IntNumber_1,ADC_IntMode_ClearFlag); ADC_setIntSrc(obj->adcHandle,ADC_IntNumber_1,ADC_IntSrc_EOC7); //configure the SOCs for hvkit_rev1p1 // EXT IA-FB ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_0,ADC_SocChanNumber_A1); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_0,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_0,ADC_SocSampleDelay_9_cycles); // EXT IA-FB // Duplicate conversion due to ADC Initial Conversion bug (SPRZ342) ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_1,ADC_SocChanNumber_A1); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_1,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_1,ADC_SocSampleDelay_9_cycles); // EXT IB-FB ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_2,ADC_SocChanNumber_B1); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_2,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_2,ADC_SocSampleDelay_9_cycles); // EXT IC-FB ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_3,ADC_SocChanNumber_A3); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_3,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_3,ADC_SocSampleDelay_9_cycles); // ADC-Vhb1 ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_4,ADC_SocChanNumber_B7); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_4,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_4,ADC_SocSampleDelay_9_cycles); // ADC-Vhb2 ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_5,ADC_SocChanNumber_B6); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_5,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_5,ADC_SocSampleDelay_9_cycles); // ADC-Vhb3 ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_6,ADC_SocChanNumber_B4); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_6,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_6,ADC_SocSampleDelay_9_cycles); // VDCBUS ADC_setSocChanNumber(obj->adcHandle,ADC_SocNumber_7,ADC_SocChanNumber_A7); ADC_setSocTrigSrc(obj->adcHandle,ADC_SocNumber_7,ADC_SocTrigSrc_EPWM1_ADCSOCA); ADC_setSocSampleDelay(obj->adcHandle,ADC_SocNumber_7,ADC_SocSampleDelay_9_cycles); return; } // end of HAL_setupAdcs() function void HAL_setupClks(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; // enable internal oscillator 1 CLK_enableOsc1(obj->clkHandle); // set the oscillator source CLK_setOscSrc(obj->clkHandle,CLK_OscSrc_Internal); // disable the external clock in CLK_disableClkIn(obj->clkHandle); // disable the crystal oscillator CLK_disableCrystalOsc(obj->clkHandle); // disable oscillator 2 CLK_disableOsc2(obj->clkHandle); // set the low speed clock prescaler CLK_setLowSpdPreScaler(obj->clkHandle,CLK_LowSpdPreScaler_SysClkOut_by_1); // set the clock out prescaler CLK_setClkOutPreScaler(obj->clkHandle,CLK_ClkOutPreScaler_SysClkOut_by_1); return; } // end of HAL_setupClks() function void HAL_setupFlash(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; FLASH_enablePipelineMode(obj->flashHandle); FLASH_setNumPagedReadWaitStates(obj->flashHandle,FLASH_NumPagedWaitStates_3); FLASH_setNumRandomReadWaitStates(obj->flashHandle,FLASH_NumRandomWaitStates_3); FLASH_setOtpWaitStates(obj->flashHandle,FLASH_NumOtpWaitStates_5); FLASH_setStandbyWaitCount(obj->flashHandle,FLASH_STANDBY_WAIT_COUNT_DEFAULT); FLASH_setActiveWaitCount(obj->flashHandle,FLASH_ACTIVE_WAIT_COUNT_DEFAULT); return; } // HAL_setupFlash() function void HAL_setupGpios(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; // PWM1 GPIO_setMode(obj->gpioHandle,GPIO_Number_0,GPIO_0_Mode_EPWM1A); // PWM2 GPIO_setMode(obj->gpioHandle,GPIO_Number_1,GPIO_1_Mode_EPWM1B); // PWM3 GPIO_setMode(obj->gpioHandle,GPIO_Number_2,GPIO_2_Mode_EPWM2A); // PWM4 GPIO_setMode(obj->gpioHandle,GPIO_Number_3,GPIO_3_Mode_EPWM2B); // PWM5 GPIO_setMode(obj->gpioHandle,GPIO_Number_4,GPIO_4_Mode_EPWM3A); // PWM6 GPIO_setMode(obj->gpioHandle,GPIO_Number_5,GPIO_5_Mode_EPWM3B); // PWM-DAC4 GPIO_setMode(obj->gpioHandle,GPIO_Number_6,GPIO_6_Mode_EPWM4A); // Input GPIO_setMode(obj->gpioHandle,GPIO_Number_7,GPIO_7_Mode_GeneralPurpose); // PWM-DAC3 GPIO_setMode(obj->gpioHandle,GPIO_Number_8,GPIO_8_Mode_EPWM5A); // CLR-FAULT GPIO_setMode(obj->gpioHandle,GPIO_Number_9,GPIO_9_Mode_GeneralPurpose); GPIO_setHigh(obj->gpioHandle,GPIO_Number_9); GPIO_setDirection(obj->gpioHandle,GPIO_Number_9,GPIO_Direction_Output); // PWM-DAC1 GPIO_setMode(obj->gpioHandle,GPIO_Number_10,GPIO_10_Mode_EPWM6A); // PWM-DAC2 GPIO_setMode(obj->gpioHandle,GPIO_Number_11,GPIO_11_Mode_EPWM6B); // TZ-1 GPIO_setMode(obj->gpioHandle,GPIO_Number_12,GPIO_12_Mode_TZ1_NOT); // HALL-2 GPIO_setMode(obj->gpioHandle,GPIO_Number_13,GPIO_13_Mode_GeneralPurpose); // HALL-3 GPIO_setMode(obj->gpioHandle,GPIO_Number_14,GPIO_14_Mode_GeneralPurpose); // LED2 GPIO_setMode(obj->gpioHandle,GPIO_Number_15,GPIO_15_Mode_GeneralPurpose); // Set Qualification Period for GPIO16-23, 5*2*(1/90MHz) = 0.11us GPIO_setQualificationPeriod(obj->gpioHandle,GPIO_Number_16,5); // SPI-SIMO GPIO_setMode(obj->gpioHandle,GPIO_Number_16,GPIO_16_Mode_GeneralPurpose); // SPI-SOMI GPIO_setMode(obj->gpioHandle,GPIO_Number_17,GPIO_17_Mode_GeneralPurpose); // SPI-CLK GPIO_setMode(obj->gpioHandle,GPIO_Number_18,GPIO_18_Mode_GeneralPurpose); // SPI-STE GPIO_setMode(obj->gpioHandle,GPIO_Number_19,GPIO_19_Mode_GeneralPurpose); #ifdef QEP // EQEPA GPIO_setMode(obj->gpioHandle,GPIO_Number_20,GPIO_20_Mode_EQEP1A); GPIO_setQualification(obj->gpioHandle,GPIO_Number_20,GPIO_Qual_Sample_3); // EQEPB GPIO_setMode(obj->gpioHandle,GPIO_Number_21,GPIO_21_Mode_EQEP1B); GPIO_setQualification(obj->gpioHandle,GPIO_Number_21,GPIO_Qual_Sample_3); // STATUS GPIO_setMode(obj->gpioHandle,GPIO_Number_22,GPIO_22_Mode_GeneralPurpose); // EQEP1I GPIO_setMode(obj->gpioHandle,GPIO_Number_23,GPIO_23_Mode_EQEP1I); GPIO_setQualification(obj->gpioHandle,GPIO_Number_23,GPIO_Qual_Sample_3); #else // EQEPA GPIO_setMode(obj->gpioHandle,GPIO_Number_20,GPIO_20_Mode_GeneralPurpose); // GPIO_setDirection(obj->gpioHandle,GPIO_Number_20,GPIO_Direction_Input); // EQEPB GPIO_setMode(obj->gpioHandle,GPIO_Number_21,GPIO_21_Mode_GeneralPurpose); // GPIO_setDirection(obj->gpioHandle,GPIO_Number_21,GPIO_Direction_Input); // STATUS GPIO_setMode(obj->gpioHandle,GPIO_Number_22,GPIO_22_Mode_GeneralPurpose); // GPIO_setDirection(obj->gpioHandle,GPIO_Number_22,GPIO_Direction_Input); // EQEP1I GPIO_setMode(obj->gpioHandle,GPIO_Number_23,GPIO_23_Mode_GeneralPurpose); // GPIO_setDirection(obj->gpioHandle,GPIO_Number_23,GPIO_Direction_Input); #endif // SPI SIMO B GPIO_setMode(obj->gpioHandle,GPIO_Number_24,GPIO_24_Mode_GeneralPurpose); // SPI SOMI B GPIO_setMode(obj->gpioHandle,GPIO_Number_25,GPIO_25_Mode_GeneralPurpose); // SPI CLK B GPIO_setMode(obj->gpioHandle,GPIO_Number_26,GPIO_26_Mode_GeneralPurpose); // SPI CSn B GPIO_setMode(obj->gpioHandle,GPIO_Number_27,GPIO_27_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_28,GPIO_28_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_29,GPIO_29_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_30,GPIO_30_Mode_GeneralPurpose); // ControlCARD LED2 GPIO_setMode(obj->gpioHandle,GPIO_Number_31,GPIO_31_Mode_GeneralPurpose); GPIO_setLow(obj->gpioHandle,GPIO_Number_31); GPIO_setDirection(obj->gpioHandle,GPIO_Number_31,GPIO_Direction_Output); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_32,GPIO_32_Mode_ADCSOCAO_NOT); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_33,GPIO_33_Mode_GeneralPurpose); // ControlCARD LED3 GPIO_setMode(obj->gpioHandle,GPIO_Number_34,GPIO_34_Mode_GeneralPurpose); GPIO_setLow(obj->gpioHandle,GPIO_Number_34); GPIO_setDirection(obj->gpioHandle,GPIO_Number_34,GPIO_Direction_Output); // JTAG GPIO_setMode(obj->gpioHandle,GPIO_Number_35,GPIO_35_Mode_JTAG_TDI); GPIO_setMode(obj->gpioHandle,GPIO_Number_36,GPIO_36_Mode_JTAG_TMS); GPIO_setMode(obj->gpioHandle,GPIO_Number_37,GPIO_37_Mode_JTAG_TDO); GPIO_setMode(obj->gpioHandle,GPIO_Number_38,GPIO_38_Mode_JTAG_TCK); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_39,GPIO_39_Mode_GeneralPurpose); // CAP1 GPIO_setMode(obj->gpioHandle,GPIO_Number_40,GPIO_40_Mode_GeneralPurpose); // CAP2 GPIO_setMode(obj->gpioHandle,GPIO_Number_41,GPIO_41_Mode_GeneralPurpose); // CAP3 GPIO_setMode(obj->gpioHandle,GPIO_Number_42,GPIO_42_Mode_GeneralPurpose); // DC_CAL GPIO_setMode(obj->gpioHandle,GPIO_Number_43,GPIO_43_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_44,GPIO_44_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_50,GPIO_50_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_51,GPIO_51_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_52,GPIO_52_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_53,GPIO_53_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_54,GPIO_54_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_55,GPIO_55_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_56,GPIO_56_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_57,GPIO_57_Mode_GeneralPurpose); // No Connection GPIO_setMode(obj->gpioHandle,GPIO_Number_58,GPIO_58_Mode_GeneralPurpose); return; } // end of HAL_setupGpios() function void HAL_setupPie(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; PIE_disable(obj->pieHandle); PIE_disableAllInts(obj->pieHandle); PIE_clearAllInts(obj->pieHandle); PIE_clearAllFlags(obj->pieHandle); PIE_setDefaultIntVectorTable(obj->pieHandle); PIE_enable(obj->pieHandle); return; } // end of HAL_setupPie() function void HAL_setupPeripheralClks(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; CLK_enableAdcClock(obj->clkHandle); CLK_enableCompClock(obj->clkHandle,CLK_CompNumber_1); CLK_enableCompClock(obj->clkHandle,CLK_CompNumber_2); CLK_enableCompClock(obj->clkHandle,CLK_CompNumber_3); CLK_enableEcap1Clock(obj->clkHandle); CLK_disableEcanaClock(obj->clkHandle); #ifdef QEP CLK_enableEqep1Clock(obj->clkHandle); CLK_disableEqep2Clock(obj->clkHandle); #endif CLK_enablePwmClock(obj->clkHandle,PWM_Number_1); CLK_enablePwmClock(obj->clkHandle,PWM_Number_2); CLK_enablePwmClock(obj->clkHandle,PWM_Number_3); CLK_enablePwmClock(obj->clkHandle,PWM_Number_4); CLK_enablePwmClock(obj->clkHandle,PWM_Number_5); CLK_enablePwmClock(obj->clkHandle,PWM_Number_6); CLK_enablePwmClock(obj->clkHandle,PWM_Number_7); CLK_disableHrPwmClock(obj->clkHandle); CLK_disableI2cClock(obj->clkHandle); CLK_disableLinAClock(obj->clkHandle); CLK_disableClaClock(obj->clkHandle); CLK_enableSciaClock(obj->clkHandle); CLK_disableSpiaClock(obj->clkHandle); CLK_disableSpibClock(obj->clkHandle); CLK_enableTbClockSync(obj->clkHandle); return; } // end of HAL_setupPeripheralClks() function void HAL_setupPll(HAL_Handle handle,const PLL_ClkFreq_e clkFreq) { HAL_Obj *obj = (HAL_Obj *)handle; // make sure PLL is not running in limp mode if(PLL_getClkStatus(obj->pllHandle) != PLL_ClkStatus_Normal) { // reset the clock detect PLL_resetClkDetect(obj->pllHandle); // ??????? asm(" ESTOP0"); } // Divide Select must be ClkIn/4 before the clock rate can be changed if(PLL_getDivideSelect(obj->pllHandle) != PLL_DivideSelect_ClkIn_by_4) { PLL_setDivideSelect(obj->pllHandle,PLL_DivideSelect_ClkIn_by_4); } if(PLL_getClkFreq(obj->pllHandle) != clkFreq) { // disable the clock detect PLL_disableClkDetect(obj->pllHandle); // set the clock rate PLL_setClkFreq(obj->pllHandle,clkFreq); } // wait until locked while(PLL_getLockStatus(obj->pllHandle) != PLL_LockStatus_Done) {} // enable the clock detect PLL_enableClkDetect(obj->pllHandle); // set divide select to ClkIn/2 to get desired clock rate // NOTE: clock must be locked before setting this register PLL_setDivideSelect(obj->pllHandle,PLL_DivideSelect_ClkIn_by_2); return; } // end of HAL_setupPll() function void HAL_setupPwms(HAL_Handle handle, const float_t systemFreq_MHz, const float_t pwmPeriod_usec, const uint_least16_t numPwmTicksPerIsrTick) { HAL_Obj *obj = (HAL_Obj *)handle; uint16_t halfPeriod_cycles = (uint16_t)(systemFreq_MHz*pwmPeriod_usec) >> 1; uint_least8_t cnt; // turns off the outputs of the EPWM peripherals which will put the power switches // into a high impedance state. PWM_setOneShotTrip(obj->pwmHandle[PWM_Number_1]); PWM_setOneShotTrip(obj->pwmHandle[PWM_Number_2]); PWM_setOneShotTrip(obj->pwmHandle[PWM_Number_3]); // first step to synchronize the pwms CLK_disableTbClockSync(obj->clkHandle); for(cnt=0;cnt<3;cnt++) { // setup the Time-Base Control Register (TBCTL) PWM_setCounterMode(obj->pwmHandle[cnt],PWM_CounterMode_UpDown); PWM_disableCounterLoad(obj->pwmHandle[cnt]); PWM_setPeriodLoad(obj->pwmHandle[cnt],PWM_PeriodLoad_Immediate); PWM_setSyncMode(obj->pwmHandle[cnt],PWM_SyncMode_EPWMxSYNC); PWM_setHighSpeedClkDiv(obj->pwmHandle[cnt],PWM_HspClkDiv_by_1); PWM_setClkDiv(obj->pwmHandle[cnt],PWM_ClkDiv_by_1); PWM_setPhaseDir(obj->pwmHandle[cnt],PWM_PhaseDir_CountUp); PWM_setRunMode(obj->pwmHandle[cnt],PWM_RunMode_FreeRun); // setup the Timer-Based Phase Register (TBPHS) PWM_setPhase(obj->pwmHandle[cnt],0); // setup the Time-Base Counter Register (TBCTR) PWM_setCount(obj->pwmHandle[cnt],0); // setup the Time-Base Period Register (TBPRD) // set to zero initially PWM_setPeriod(obj->pwmHandle[cnt],0); // setup the Counter-Compare Control Register (CMPCTL) PWM_setLoadMode_CmpA(obj->pwmHandle[cnt],PWM_LoadMode_Zero); PWM_setLoadMode_CmpB(obj->pwmHandle[cnt],PWM_LoadMode_Zero); PWM_setShadowMode_CmpA(obj->pwmHandle[cnt],PWM_ShadowMode_Shadow); PWM_setShadowMode_CmpB(obj->pwmHandle[cnt],PWM_ShadowMode_Immediate); // setup the Action-Qualifier Output A Register (AQCTLA) PWM_setActionQual_CntUp_CmpA_PwmA(obj->pwmHandle[cnt],PWM_ActionQual_Set); PWM_setActionQual_CntDown_CmpA_PwmA(obj->pwmHandle[cnt],PWM_ActionQual_Clear); // setup the Dead-Band Generator Control Register (DBCTL) PWM_setDeadBandOutputMode(obj->pwmHandle[cnt],PWM_DeadBandOutputMode_EPWMxA_Rising_EPWMxB_Falling); PWM_setDeadBandPolarity(obj->pwmHandle[cnt],PWM_DeadBandPolarity_EPWMxB_Inverted); // setup the Dead-Band Rising Edge Delay Register (DBRED) PWM_setDeadBandRisingEdgeDelay(obj->pwmHandle[cnt],HAL_PWM_DBRED_CNT); // setup the Dead-Band Falling Edge Delay Register (DBFED) PWM_setDeadBandFallingEdgeDelay(obj->pwmHandle[cnt],HAL_PWM_DBFED_CNT); // setup the PWM-Chopper Control Register (PCCTL) PWM_disableChopping(obj->pwmHandle[cnt]); // setup the Trip Zone Select Register (TZSEL) PWM_disableTripZones(obj->pwmHandle[cnt]); } // setup the Event Trigger Selection Register (ETSEL) PWM_disableInt(obj->pwmHandle[PWM_Number_1]); PWM_setSocAPulseSrc(obj->pwmHandle[PWM_Number_1],PWM_SocPulseSrc_CounterEqualZero); PWM_enableSocAPulse(obj->pwmHandle[PWM_Number_1]); // setup the Event Trigger Prescale Register (ETPS) if(numPwmTicksPerIsrTick == 3) { PWM_setIntPeriod(obj->pwmHandle[PWM_Number_1],PWM_IntPeriod_ThirdEvent); PWM_setSocAPeriod(obj->pwmHandle[PWM_Number_1],PWM_SocPeriod_ThirdEvent); } else if(numPwmTicksPerIsrTick == 2) { PWM_setIntPeriod(obj->pwmHandle[PWM_Number_1],PWM_IntPeriod_SecondEvent); PWM_setSocAPeriod(obj->pwmHandle[PWM_Number_1],PWM_SocPeriod_SecondEvent); } else { PWM_setIntPeriod(obj->pwmHandle[PWM_Number_1],PWM_IntPeriod_FirstEvent); PWM_setSocAPeriod(obj->pwmHandle[PWM_Number_1],PWM_SocPeriod_FirstEvent); } // setup the Event Trigger Clear Register (ETCLR) PWM_clearIntFlag(obj->pwmHandle[PWM_Number_1]); PWM_clearSocAFlag(obj->pwmHandle[PWM_Number_1]); // since the PWM is configured as an up/down counter, the period register is set to one-half // of the desired PWM period PWM_setPeriod(obj->pwmHandle[PWM_Number_1],halfPeriod_cycles); PWM_setPeriod(obj->pwmHandle[PWM_Number_2],halfPeriod_cycles); PWM_setPeriod(obj->pwmHandle[PWM_Number_3],halfPeriod_cycles); // last step to synchronize the pwms CLK_enableTbClockSync(obj->clkHandle); return; } // end of HAL_setupPwms() function #ifdef QEP void HAL_setupQEP(HAL_Handle handle,HAL_QepSelect_e qep) { HAL_Obj *obj = (HAL_Obj *)handle; // hold the counter in reset QEP_reset_counter(obj->qepHandle[qep]); // set the QPOSINIT register QEP_set_posn_init_count(obj->qepHandle[qep], 0); // disable all interrupts QEP_disable_all_interrupts(obj->qepHandle[qep]); // clear the interrupt flags QEP_clear_all_interrupt_flags(obj->qepHandle[qep]); // clear the position counter QEP_clear_posn_counter(obj->qepHandle[qep]); // setup the max position QEP_set_max_posn_count(obj->qepHandle[qep], (4*USER_MOTOR_ENCODER_LINES)-1); // setup the QDECCTL register QEP_set_QEP_source(obj->qepHandle[qep], QEP_Qsrc_Quad_Count_Mode); QEP_disable_sync_out(obj->qepHandle[qep]); QEP_set_swap_quad_inputs(obj->qepHandle[qep], QEP_Swap_Not_Swapped); QEP_disable_gate_index(obj->qepHandle[qep]); QEP_set_ext_clock_rate(obj->qepHandle[qep], QEP_Xcr_2x_Res); QEP_set_A_polarity(obj->qepHandle[qep], QEP_Qap_No_Effect); QEP_set_B_polarity(obj->qepHandle[qep], QEP_Qbp_No_Effect); QEP_set_index_polarity(obj->qepHandle[qep], QEP_Qip_No_Effect); // setup the QEPCTL register QEP_set_emu_control(obj->qepHandle[qep], QEPCTL_Freesoft_Unaffected_Halt); QEP_set_posn_count_reset_mode(obj->qepHandle[qep], QEPCTL_Pcrm_Max_Reset); QEP_set_strobe_event_init(obj->qepHandle[qep], QEPCTL_Sei_Nothing); QEP_set_index_event_init(obj->qepHandle[qep], QEPCTL_Iei_Nothing); QEP_set_index_event_latch(obj->qepHandle[qep], QEPCTL_Iel_Rising_Edge); QEP_set_soft_init(obj->qepHandle[qep], QEPCTL_Swi_Nothing); QEP_disable_unit_timer(obj->qepHandle[qep]); QEP_disable_watchdog(obj->qepHandle[qep]); // setup the QPOSCTL register QEP_disable_posn_compare(obj->qepHandle[qep]); // setup the QCAPCTL register QEP_disable_capture(obj->qepHandle[qep]); // renable the position counter QEP_enable_counter(obj->qepHandle[qep]); return; } #endif void HAL_setupPwmDacs(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; uint16_t halfPeriod_cycles = 512; // 3000->10kHz, 1500->20kHz, 1000-> 30kHz, 500->60kHz uint_least8_t cnt; for(cnt=0;cnt<3;cnt++) { // initialize the Time-Base Control Register (TBCTL) PWMDAC_setCounterMode(obj->pwmDacHandle[cnt],PWM_CounterMode_UpDown); PWMDAC_disableCounterLoad(obj->pwmDacHandle[cnt]); PWMDAC_setPeriodLoad(obj->pwmDacHandle[cnt],PWM_PeriodLoad_Immediate); PWMDAC_setSyncMode(obj->pwmDacHandle[cnt],PWM_SyncMode_EPWMxSYNC); PWMDAC_setHighSpeedClkDiv(obj->pwmDacHandle[cnt],PWM_HspClkDiv_by_1); PWMDAC_setClkDiv(obj->pwmDacHandle[cnt],PWM_ClkDiv_by_1); PWMDAC_setPhaseDir(obj->pwmDacHandle[cnt],PWM_PhaseDir_CountUp); PWMDAC_setRunMode(obj->pwmDacHandle[cnt],PWM_RunMode_FreeRun); // initialize the Timer-Based Phase Register (TBPHS) PWMDAC_setPhase(obj->pwmDacHandle[cnt],0); // setup the Time-Base Counter Register (TBCTR) PWMDAC_setCount(obj->pwmDacHandle[cnt],0); // Initialize the Time-Base Period Register (TBPRD) // set to zero initially PWMDAC_setPeriod(obj->pwmDacHandle[cnt],0); // initialize the Counter-Compare Control Register (CMPCTL) PWMDAC_setLoadMode_CmpA(obj->pwmDacHandle[cnt],PWM_LoadMode_Zero); PWMDAC_setLoadMode_CmpB(obj->pwmDacHandle[cnt],PWM_LoadMode_Zero); PWMDAC_setShadowMode_CmpA(obj->pwmDacHandle[cnt],PWM_ShadowMode_Shadow); PWMDAC_setShadowMode_CmpB(obj->pwmDacHandle[cnt],PWM_ShadowMode_Shadow); // Initialize the Action-Qualifier Output A Register (AQCTLA) PWMDAC_setActionQual_CntUp_CmpA_PwmA(obj->pwmDacHandle[cnt],PWM_ActionQual_Clear); PWMDAC_setActionQual_CntDown_CmpA_PwmA(obj->pwmDacHandle[cnt],PWM_ActionQual_Set); // account for EPWM6B if(cnt == 0) { PWMDAC_setActionQual_CntUp_CmpB_PwmB(obj->pwmDacHandle[cnt],PWM_ActionQual_Clear); PWMDAC_setActionQual_CntDown_CmpB_PwmB(obj->pwmDacHandle[cnt],PWM_ActionQual_Set); } // Initialize the Dead-Band Control Register (DBCTL) PWMDAC_disableDeadBand(obj->pwmDacHandle[cnt]); // Initialize the PWM-Chopper Control Register (PCCTL) PWMDAC_disableChopping(obj->pwmDacHandle[cnt]); // Initialize the Trip-Zone Control Register (TZSEL) PWMDAC_disableTripZones(obj->pwmDacHandle[cnt]); // Initialize the Trip-Zone Control Register (TZCTL) PWMDAC_setTripZoneState_TZA(obj->pwmDacHandle[cnt],PWM_TripZoneState_HighImp); PWMDAC_setTripZoneState_TZB(obj->pwmDacHandle[cnt],PWM_TripZoneState_HighImp); PWMDAC_setTripZoneState_DCAEVT1(obj->pwmDacHandle[cnt],PWM_TripZoneState_HighImp); PWMDAC_setTripZoneState_DCAEVT2(obj->pwmDacHandle[cnt],PWM_TripZoneState_HighImp); PWMDAC_setTripZoneState_DCBEVT1(obj->pwmDacHandle[cnt],PWM_TripZoneState_HighImp); } // since the PWM is configured as an up/down counter, the period register is set to one-half // of the desired PWM period PWMDAC_setPeriod(obj->pwmDacHandle[PWMDAC_Number_1],halfPeriod_cycles); PWMDAC_setPeriod(obj->pwmDacHandle[PWMDAC_Number_2],halfPeriod_cycles); PWMDAC_setPeriod(obj->pwmDacHandle[PWMDAC_Number_3],halfPeriod_cycles); return; } // end of HAL_setupPwmDacs() function void HAL_setupEstTimer(HAL_Handle handle, const float_t systemFreq_MHz, const float_t estFreq_Hz) { HAL_Obj *obj = (HAL_Obj *)handle; uint32_t temp; // // calculate timer period value // temp = ((uint32_t)(systemFreq_MHz *1000000.0 / estFreq_Hz)) - 1; // // use CPU timer 0 for estimator ISR in variable pwm frequency project // TIMER_setDecimationFactor(obj->timerHandle[0],0); TIMER_setEmulationMode(obj->timerHandle[0],TIMER_EmulationMode_RunFree); TIMER_setPeriod(obj->timerHandle[0],temp); TIMER_setPreScaler(obj->timerHandle[0],0); TIMER_reload(obj->timerHandle[0]); return; } // end of HAL_setupEstTimer() function void HAL_setupTimers(HAL_Handle handle,const float_t systemFreq_MHz) { HAL_Obj *obj = (HAL_Obj *)handle; uint32_t timerPeriod_0p5ms = (uint32_t)(systemFreq_MHz * (float_t)500.0) - 1; uint32_t timerPeriod_10ms = (uint32_t)(systemFreq_MHz * (float_t)10000.0) - 1; // use timer 0 for frequency diagnostics TIMER_setDecimationFactor(obj->timerHandle[0],0); TIMER_setEmulationMode(obj->timerHandle[0],TIMER_EmulationMode_RunFree); TIMER_setPeriod(obj->timerHandle[0],timerPeriod_0p5ms); TIMER_setPreScaler(obj->timerHandle[0],0); // use timer 1 for CPU usage diagnostics TIMER_setDecimationFactor(obj->timerHandle[1],0); TIMER_setEmulationMode(obj->timerHandle[1],TIMER_EmulationMode_RunFree); TIMER_setPeriod(obj->timerHandle[1],timerPeriod_10ms); TIMER_setPreScaler(obj->timerHandle[1],0); // use timer 2 for CPU time diagnostics TIMER_setDecimationFactor(obj->timerHandle[2],0); TIMER_setEmulationMode(obj->timerHandle[2],TIMER_EmulationMode_RunFree); TIMER_setPeriod(obj->timerHandle[2],0xFFFFFFFF); TIMER_setPreScaler(obj->timerHandle[2],0); return; } // end of HAL_setupTimers() function void HAL_setDacParameters(HAL_Handle handle, HAL_DacData_t *pDacData) { HAL_Obj *obj = (HAL_Obj *)handle; pDacData->PeriodMax = PWMDAC_getPeriod(obj->pwmDacHandle[PWMDAC_Number_1]); pDacData->offset[0] = _IQ(0.5); pDacData->offset[1] = _IQ(0.5); pDacData->offset[2] = _IQ(0.0); pDacData->offset[3] = _IQ(0.0); pDacData->gain[0] = _IQ(1.0); pDacData->gain[1] = _IQ(1.0); pDacData->gain[2] = _IQ(1.0); pDacData->gain[3] = _IQ(1.0); return; } //end of HAL_setDacParameters() function // end of file
/* --COPYRIGHT--,BSD (lab11a_VariablePWM.c) * Copyright (c) 2015, 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_lab011a.c //! \brief A Feature Rich Example without Controller Module //! //! (C) Copyright 2015, Texas Instruments, Inc. //! \defgroup PROJ_LAB11A PROJ_LAB11A //@{ //! \defgroup PROJ_LAB11A_OVERVIEW Project Overview //! //! A Feature Rich Example without Controller Module //! // ************************************************************************** // the includes // system includes #include <math.h> #include "main.h" #ifdef FLASH #pragma CODE_SECTION(mainISR,"ramfuncs"); #pragma CODE_SECTION(runSetTrigger,"ramfuncs"); #pragma CODE_SECTION(runFieldWeakening,"ramfuncs"); #pragma CODE_SECTION(runCurrentReconstruction,"ramfuncs"); #pragma CODE_SECTION(angleDelayComp,"ramfuncs"); #endif // Include header files used in the main function // ************************************************************************** // the defines // ************************************************************************** // the globals CLARKE_Handle clarkeHandle_I; //!< the handle for the current Clarke transform CLARKE_Obj clarke_I; //!< the current Clarke transform object CLARKE_Handle clarkeHandle_V; //!< the handle for the voltage Clarke transform CLARKE_Obj clarke_V; //!< the voltage Clarke transform object CPU_USAGE_Handle cpu_usageHandle; CPU_USAGE_Obj cpu_usage; EST_Handle estHandle; //!< the handle for the estimator FW_Handle fwHandle; FW_Obj fw; PID_Obj pid[3]; //!< three handles for PID controllers 0 - Speed, 1 - Id, 2 - Iq PID_Handle pidHandle[3]; //!< three objects for PID controllers 0 - Speed, 1 - Id, 2 - Iq uint16_t pidCntSpeed; //!< count variable to decimate the execution of the speed PID controller IPARK_Handle iparkHandle; //!< the handle for the inverse Park transform IPARK_Obj ipark; //!< the inverse Park transform object FILTER_FO_Handle filterHandle[6]; //!< the handles for the 3-current and 3-voltage filters for offset calculation FILTER_FO_Obj filter[6]; //!< the 3-current and 3-voltage filters for offset calculation SVGENCURRENT_Obj svgencurrent; SVGENCURRENT_Handle svgencurrentHandle; SVGEN_Handle svgenHandle; //!< the handle for the space vector generator SVGEN_Obj svgen; //!< the space vector generator object TRAJ_Handle trajHandle_Id; //!< the handle for the id reference trajectory TRAJ_Obj traj_Id; //!< the id reference trajectory object TRAJ_Handle trajHandle_spd; //!< the handle for the speed reference trajectory TRAJ_Obj traj_spd; //!< the speed reference trajectory object #ifdef CSM_ENABLE #pragma DATA_SECTION(halHandle,"rom_accessed_data"); #endif HAL_Handle halHandle; //!< the handle for the hardware abstraction layer (HAL) HAL_PwmData_t gPwmData = {_IQ(0.0), _IQ(0.0), _IQ(0.0)}; //!< contains the three pwm values -1.0 - 0%, 1.0 - 100% HAL_AdcData_t gAdcData; //!< contains three current values, three voltage values and one DC buss value MATH_vec3 gOffsets_I_pu = {_IQ(0.0), _IQ(0.0), _IQ(0.0)}; //!< contains the offsets for the current feedback MATH_vec3 gOffsets_V_pu = {_IQ(0.0), _IQ(0.0), _IQ(0.0)}; //!< contains the offsets for the voltage feedback MATH_vec2 gIdq_ref_pu = {_IQ(0.0), _IQ(0.0)}; //!< contains the Id and Iq references MATH_vec2 gVdq_out_pu = {_IQ(0.0), _IQ(0.0)}; //!< contains the output Vd and Vq from the current controllers MATH_vec2 gIdq_pu = {_IQ(0.0), _IQ(0.0)}; //!< contains the Id and Iq measured values #ifdef CSM_ENABLE #pragma DATA_SECTION(gUserParams,"rom_accessed_data"); #endif USER_Params gUserParams; volatile MOTOR_Vars_t gMotorVars = MOTOR_Vars_INIT; //!< the global motor variables that are defined in main.h and used for display in the debugger's watch window #ifdef FLASH // Used for running BackGround in flash, and ISR in RAM extern uint16_t *RamfuncsLoadStart, *RamfuncsLoadEnd, *RamfuncsRunStart; #ifdef CSM_ENABLE extern uint16_t *econst_start, *econst_end, *econst_ram_load; extern uint16_t *switch_start, *switch_end, *switch_ram_load; #endif #endif MATH_vec3 gIavg = {_IQ(0.0), _IQ(0.0), _IQ(0.0)}; uint16_t gIavg_shift = 1; MATH_vec3 gPwmData_prev = {_IQ(0.0), _IQ(0.0), _IQ(0.0)}; #ifdef DRV8301_SPI // Watch window interface to the 8301 SPI DRV_SPI_8301_Vars_t gDrvSpi8301Vars; #endif #ifdef DRV8305_SPI // Watch window interface to the 8305 SPI DRV_SPI_8305_Vars_t gDrvSpi8305Vars; #endif _iq gFlux_pu_to_Wb_sf; _iq gFlux_pu_to_VpHz_sf; _iq gTorque_Ls_Id_Iq_pu_to_Nm_sf; _iq gTorque_Flux_Iq_pu_to_Nm_sf; _iq gSpeed_krpm_to_pu_sf = _IQ((float_t)USER_MOTOR_NUM_POLE_PAIRS * 1000.0 / (USER_IQ_FULL_SCALE_FREQ_Hz * 60.0)); _iq gSpeed_hz_to_krpm_sf = _IQ(60.0 / (float_t)USER_MOTOR_NUM_POLE_PAIRS / 1000.0); _iq gIs_Max_squared_pu = _IQ((USER_MOTOR_MAX_CURRENT * USER_MOTOR_MAX_CURRENT) / (USER_IQ_FULL_SCALE_CURRENT_A * USER_IQ_FULL_SCALE_CURRENT_A)); float_t gCpuUsagePercentageMin = 0.0; float_t gCpuUsagePercentageAvg = 0.0; float_t gCpuUsagePercentageMax = 0.0; uint32_t gOffsetCalcCount = 0; uint16_t gTrjCnt = 0; volatile bool gFlag_enableRsOnLine = false; volatile bool gFlag_updateRs = false; volatile _iq gRsOnLineFreq_Hz = _IQ(0.2); volatile _iq gRsOnLineId_mag_A = _IQ(0.5); volatile _iq gRsOnLinePole_Hz = _IQ(0.2); _iq angle_pu = _IQ(0.0); _iq speed_pu = _IQ(0.0); MATH_vec2 Iab_pu; MATH_vec2 Vab_pu; MATH_vec2 phasor; // ************************************************************************** // the functions void main(void) { // 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); #ifdef CSM_ENABLE //copy .econst to unsecure RAM if(*econst_end - *econst_start) { memCopy((uint16_t *)&econst_start,(uint16_t *)&econst_end,(uint16_t *)&econst_ram_load); } //copy .switch ot unsecure RAM if(*switch_end - *switch_start) { memCopy((uint16_t *)&switch_start,(uint16_t *)&switch_end,(uint16_t *)&switch_ram_load); } #endif #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 Clarke modules clarkeHandle_I = CLARKE_init(&clarke_I,sizeof(clarke_I)); clarkeHandle_V = CLARKE_init(&clarke_V,sizeof(clarke_V)); // initialize the estimator estHandle = EST_init((void *)USER_EST_HANDLE_ADDRESS, 0x200); // initialize the user parameters USER_setParams(&gUserParams); // set the hardware abstraction layer parameters HAL_setParams(halHandle,&gUserParams); #ifdef FAST_ROM_V1p6 { CTRL_Handle ctrlHandle = CTRL_init((void *)USER_CTRL_HANDLE_ADDRESS, 0x200); CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle; obj->estHandle = estHandle; // initialize the estimator through the controller CTRL_setParams(ctrlHandle,&gUserParams); CTRL_setUserMotorParams(ctrlHandle); CTRL_setupEstIdleState(ctrlHandle); } #else { // initialize the estimator EST_setEstParams(estHandle,&gUserParams); EST_setupEstIdleState(estHandle); } #endif // disable Rs recalculation by default gMotorVars.Flag_enableRsRecalc = true; EST_setFlag_enableRsRecalc(estHandle,false); // configure RsOnLine EST_setFlag_enableRsOnLine(estHandle,gFlag_enableRsOnLine); EST_setFlag_updateRs(estHandle,gFlag_updateRs); EST_setRsOnLineAngleDelta_pu(estHandle,_IQmpy(gRsOnLineFreq_Hz, _IQ(1.0/USER_ISR_FREQ_Hz))); EST_setRsOnLineId_mag_pu(estHandle,_IQmpy(gRsOnLineId_mag_A, _IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A))); // Calculate coefficients for all filters { _iq b0 = _IQmpy(gRsOnLinePole_Hz, _IQ(1.0/USER_ISR_FREQ_Hz)); _iq a1 = b0 - _IQ(1.0); EST_setRsOnLineFilterParams(estHandle,EST_RsOnLineFilterType_Current,b0,a1,_IQ(0.0),b0,a1,_IQ(0.0)); EST_setRsOnLineFilterParams(estHandle,EST_RsOnLineFilterType_Voltage,b0,a1,_IQ(0.0),b0,a1,_IQ(0.0)); } // set the number of current sensors setupClarke_I(clarkeHandle_I,USER_NUM_CURRENT_SENSORS); // set the number of voltage sensors setupClarke_V(clarkeHandle_V,USER_NUM_VOLTAGE_SENSORS); // set the pre-determined current and voltage feeback offset values gOffsets_I_pu.value[0] = _IQ(I_A_offset); gOffsets_I_pu.value[1] = _IQ(I_B_offset); gOffsets_I_pu.value[2] = _IQ(I_C_offset); gOffsets_V_pu.value[0] = _IQ(V_A_offset); gOffsets_V_pu.value[1] = _IQ(V_B_offset); gOffsets_V_pu.value[2] = _IQ(V_C_offset); // initialize the PID controllers { _iq maxCurrent_pu = _IQ(USER_MOTOR_MAX_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A); _iq maxVoltage_pu = _IQ(USER_MAX_VS_MAG_PU * USER_VD_SF); float_t fullScaleCurrent = USER_IQ_FULL_SCALE_CURRENT_A; float_t fullScaleVoltage = USER_IQ_FULL_SCALE_VOLTAGE_V; float_t IsrPeriod_sec = 1.0 / USER_ISR_FREQ_Hz; float_t Ls_d = USER_MOTOR_Ls_d; float_t Ls_q = USER_MOTOR_Ls_q; float_t Rs = USER_MOTOR_Rs; float_t RoverLs_d = Rs/Ls_d; float_t RoverLs_q = Rs/Ls_q; _iq Kp_Id = _IQ((0.25*Ls_d*fullScaleCurrent)/(IsrPeriod_sec*fullScaleVoltage)); _iq Ki_Id = _IQ(RoverLs_d*IsrPeriod_sec); _iq Kp_Iq = _IQ((0.25*Ls_q*fullScaleCurrent)/(IsrPeriod_sec*fullScaleVoltage)); _iq Ki_Iq = _IQ(RoverLs_q*IsrPeriod_sec); pidHandle[0] = PID_init(&pid[0],sizeof(pid[0])); pidHandle[1] = PID_init(&pid[1],sizeof(pid[1])); pidHandle[2] = PID_init(&pid[2],sizeof(pid[2])); PID_setGains(pidHandle[0],_IQ(1.0),_IQ(0.01),_IQ(0.0)); PID_setMinMax(pidHandle[0],-maxCurrent_pu,maxCurrent_pu); PID_setUi(pidHandle[0],_IQ(0.0)); pidCntSpeed = 0; PID_setGains(pidHandle[1],Kp_Id,Ki_Id,_IQ(0.0)); PID_setMinMax(pidHandle[1],-maxVoltage_pu,maxVoltage_pu); PID_setUi(pidHandle[1],_IQ(0.0)); PID_setGains(pidHandle[2],Kp_Iq,Ki_Iq,_IQ(0.0)); PID_setMinMax(pidHandle[2],_IQ(0.0),_IQ(0.0)); PID_setUi(pidHandle[2],_IQ(0.0)); } // initialize the speed reference in kilo RPM where base speed is USER_IQ_FULL_SCALE_FREQ_Hz gMotorVars.SpeedRef_krpm = _IQmpy(_IQ(10.0), gSpeed_hz_to_krpm_sf); // initialize the inverse Park module iparkHandle = IPARK_init(&ipark,sizeof(ipark)); // initialize and configure offsets using filters { uint16_t cnt = 0; _iq b0 = _IQ(gUserParams.offsetPole_rps/(float_t)gUserParams.ctrlFreq_Hz); _iq a1 = (b0 - _IQ(1.0)); _iq b1 = _IQ(0.0); for(cnt=0;cnt<6;cnt++) { filterHandle[cnt] = FILTER_FO_init(&filter[cnt],sizeof(filter[0])); FILTER_FO_setDenCoeffs(filterHandle[cnt],a1); FILTER_FO_setNumCoeffs(filterHandle[cnt],b0,b1); FILTER_FO_setInitialConditions(filterHandle[cnt],_IQ(0.0),_IQ(0.0)); } gMotorVars.Flag_enableOffsetcalc = false; } // initialize the space vector generator module svgenHandle = SVGEN_init(&svgen,sizeof(svgen)); // Initialize and setup the 100% SVM generator svgencurrentHandle = SVGENCURRENT_init(&svgencurrent,sizeof(svgencurrent)); // setup svgen current { float_t minWidth_microseconds = 2.0; uint16_t minWidth_counts = (uint16_t)(minWidth_microseconds * USER_SYSTEM_FREQ_MHz); float_t fdutyLimit = 0.5-(2.0*minWidth_microseconds*USER_PWM_FREQ_kHz*0.001); _iq dutyLimit = _IQ(fdutyLimit); SVGENCURRENT_setMinWidth(svgencurrentHandle, minWidth_counts); SVGENCURRENT_setIgnoreShunt(svgencurrentHandle, use_all); SVGENCURRENT_setMode(svgencurrentHandle,all_phase_measurable); SVGENCURRENT_setVlimit(svgencurrentHandle,dutyLimit); } // set overmodulation to maximum value gMotorVars.OverModulation = _IQ(USER_MAX_VS_MAG_PU); // initialize the speed reference trajectory trajHandle_spd = TRAJ_init(&traj_spd,sizeof(traj_spd)); // configure the speed reference trajectory TRAJ_setTargetValue(trajHandle_spd,_IQ(0.0)); TRAJ_setIntValue(trajHandle_spd,_IQ(0.0)); TRAJ_setMinValue(trajHandle_spd,_IQ(-1.0)); TRAJ_setMaxValue(trajHandle_spd,_IQ(1.0)); TRAJ_setMaxDelta(trajHandle_spd,_IQ(USER_MAX_ACCEL_Hzps / USER_IQ_FULL_SCALE_FREQ_Hz / USER_ISR_FREQ_Hz)); // initialize the Id reference trajectory trajHandle_Id = TRAJ_init(&traj_Id,sizeof(traj_Id)); if(USER_MOTOR_TYPE == MOTOR_Type_Pm) { // configure the Id reference trajectory TRAJ_setTargetValue(trajHandle_Id,_IQ(0.0)); TRAJ_setIntValue(trajHandle_Id,_IQ(0.0)); TRAJ_setMinValue(trajHandle_Id,_IQ(-USER_MOTOR_MAX_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A)); TRAJ_setMaxValue(trajHandle_Id,_IQ(USER_MOTOR_MAX_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A)); TRAJ_setMaxDelta(trajHandle_Id,_IQ(USER_MOTOR_RES_EST_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A / USER_ISR_FREQ_Hz)); // Initialize field weakening fwHandle = FW_init(&fw,sizeof(fw)); FW_setFlag_enableFw(fwHandle, false); // Disable field weakening FW_clearCounter(fwHandle); // Clear field weakening counter FW_setNumIsrTicksPerFwTick(fwHandle, FW_NUM_ISR_TICKS_PER_CTRL_TICK); // Set the number of ISR per field weakening ticks FW_setDeltas(fwHandle, FW_INC_DELTA, FW_DEC_DELTA); // Set the deltas of field weakening FW_setOutput(fwHandle, _IQ(0.0)); // Set initial output of field weakening to zero FW_setMinMax(fwHandle,_IQ(USER_MAX_NEGATIVE_ID_REF_CURRENT_A/USER_IQ_FULL_SCALE_CURRENT_A),_IQ(0.0)); // Set the field weakening controller limits } else { // configure the Id reference trajectory TRAJ_setTargetValue(trajHandle_Id,_IQ(0.0)); TRAJ_setIntValue(trajHandle_Id,_IQ(0.0)); TRAJ_setMinValue(trajHandle_Id,_IQ(0.0)); TRAJ_setMaxValue(trajHandle_Id,_IQ(USER_MOTOR_MAGNETIZING_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A)); TRAJ_setMaxDelta(trajHandle_Id,_IQ(USER_MOTOR_MAGNETIZING_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A / USER_ISR_FREQ_Hz)); } // initialize the CPU usage module cpu_usageHandle = CPU_USAGE_init(&cpu_usage,sizeof(cpu_usage)); CPU_USAGE_setParams(cpu_usageHandle, HAL_getTimerPeriod(halHandle,1), // 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); // enable global interrupts HAL_enableGlobalInts(halHandle); // enable debug interrupts HAL_enableDebugInt(halHandle); // disable the PWM HAL_disablePwm(halHandle); // compute scaling factors for flux and torque calculations gFlux_pu_to_Wb_sf = USER_computeFlux_pu_to_Wb_sf(); gFlux_pu_to_VpHz_sf = USER_computeFlux_pu_to_VpHz_sf(); gTorque_Ls_Id_Iq_pu_to_Nm_sf = USER_computeTorque_Ls_Id_Iq_pu_to_Nm_sf(); gTorque_Flux_Iq_pu_to_Nm_sf = USER_computeTorque_Flux_Iq_pu_to_Nm_sf(); // enable the system by default gMotorVars.Flag_enableSys = true; #ifdef DRV8301_SPI // turn on the DRV8301 if present HAL_enableDrv(halHandle); // initialize the DRV8301 interface HAL_setupDrvSpi(halHandle,&gDrvSpi8301Vars); #endif #ifdef DRV8305_SPI // turn on the DRV8305 if present HAL_enableDrv(halHandle); // initialize the DRV8305 interface HAL_setupDrvSpi(halHandle,&gDrvSpi8305Vars); #endif // Begin the background loop 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) { if(gMotorVars.Flag_Run_Identify) { // disable Rs recalculation EST_setFlag_enableRsRecalc(estHandle,false); // update estimator state EST_updateState(estHandle,0); #ifdef FAST_ROM_V1p6 // call this function to fix 1p6 softwareUpdate1p6(estHandle); #endif // enable the PWM HAL_enablePwm(halHandle); // set trajectory target for speed reference TRAJ_setTargetValue(trajHandle_spd,_IQmpy(gMotorVars.SpeedRef_krpm, gSpeed_krpm_to_pu_sf)); if(USER_MOTOR_TYPE == MOTOR_Type_Pm) { // set trajectory target for Id reference TRAJ_setTargetValue(trajHandle_Id,gIdq_ref_pu.value[0]); } else { if(gMotorVars.Flag_enablePowerWarp) { _iq Id_target_pw_pu = EST_runPowerWarp(estHandle,TRAJ_getIntValue(trajHandle_Id),gIdq_pu.value[1]); TRAJ_setTargetValue(trajHandle_Id,Id_target_pw_pu); TRAJ_setMinValue(trajHandle_Id,_IQ(USER_MOTOR_MAGNETIZING_CURRENT * 0.3 / USER_IQ_FULL_SCALE_CURRENT_A)); TRAJ_setMaxDelta(trajHandle_Id,_IQ(USER_MOTOR_MAGNETIZING_CURRENT * 0.3 / USER_IQ_FULL_SCALE_CURRENT_A / USER_ISR_FREQ_Hz)); } else { // set trajectory target for Id reference TRAJ_setTargetValue(trajHandle_Id,_IQ(USER_MOTOR_MAGNETIZING_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A)); TRAJ_setMinValue(trajHandle_Id,_IQ(0.0)); TRAJ_setMaxDelta(trajHandle_Id,_IQ(USER_MOTOR_MAGNETIZING_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A / USER_ISR_FREQ_Hz)); } } } else if(gMotorVars.Flag_enableRsRecalc) { // set angle to zero EST_setAngle_pu(estHandle,_IQ(0.0)); // enable or disable Rs recalculation EST_setFlag_enableRsRecalc(estHandle,true); // update estimator state EST_updateState(estHandle,0); #ifdef FAST_ROM_V1p6 // call this function to fix 1p6 softwareUpdate1p6(estHandle); #endif // enable the PWM HAL_enablePwm(halHandle); // set trajectory target for speed reference TRAJ_setTargetValue(trajHandle_spd,_IQ(0.0)); // set trajectory target for Id reference TRAJ_setTargetValue(trajHandle_Id,_IQ(USER_MOTOR_RES_EST_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A)); // if done with Rs recalculation, disable flag if(EST_getState(estHandle) == EST_State_OnLine) gMotorVars.Flag_enableRsRecalc = false; } else { // set estimator to Idle EST_setIdle(estHandle); // disable the PWM if(!gMotorVars.Flag_enableOffsetcalc) HAL_disablePwm(halHandle); // clear the speed reference trajectory TRAJ_setTargetValue(trajHandle_spd,_IQ(0.0)); TRAJ_setIntValue(trajHandle_spd,_IQ(0.0)); // clear the Id reference trajectory TRAJ_setTargetValue(trajHandle_Id,_IQ(0.0)); TRAJ_setIntValue(trajHandle_Id,_IQ(0.0)); // configure trajectory Id defaults depending on motor type if(USER_MOTOR_TYPE == MOTOR_Type_Pm) { TRAJ_setMinValue(trajHandle_Id,_IQ(-USER_MOTOR_MAX_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A)); TRAJ_setMaxDelta(trajHandle_Id,_IQ(USER_MOTOR_RES_EST_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A / USER_ISR_FREQ_Hz)); } else { TRAJ_setMinValue(trajHandle_Id,_IQ(0.0)); TRAJ_setMaxDelta(trajHandle_Id,_IQ(USER_MOTOR_MAGNETIZING_CURRENT / USER_IQ_FULL_SCALE_CURRENT_A / USER_ISR_FREQ_Hz)); } // clear integral outputs PID_setUi(pidHandle[0],_IQ(0.0)); PID_setUi(pidHandle[1],_IQ(0.0)); PID_setUi(pidHandle[2],_IQ(0.0)); // clear Id and Iq references gIdq_ref_pu.value[0] = _IQ(0.0); gIdq_ref_pu.value[1] = _IQ(0.0); // disable RsOnLine flags gFlag_enableRsOnLine = false; gFlag_updateRs = false; // disable PowerWarp flag gMotorVars.Flag_enablePowerWarp = false; } // update the global variables updateGlobalVariables(estHandle); // set field weakening enable flag depending on user's input FW_setFlag_enableFw(fwHandle,gMotorVars.Flag_enableFieldWeakening); // set the speed acceleration TRAJ_setMaxDelta(trajHandle_spd,_IQmpy(MAX_ACCEL_KRPMPS_SF,gMotorVars.MaxAccel_krpmps)); // update CPU usage updateCPUusage(); updateRsOnLine(estHandle); // enable/disable the forced angle EST_setFlag_enableForceAngle(estHandle,gMotorVars.Flag_enableForceAngle); #ifdef DRV8301_SPI HAL_writeDrvData(halHandle,&gDrvSpi8301Vars); HAL_readDrvData(halHandle,&gDrvSpi8301Vars); #endif #ifdef DRV8305_SPI HAL_writeDrvData(halHandle,&gDrvSpi8305Vars); HAL_readDrvData(halHandle,&gDrvSpi8305Vars); #endif } // end of while(gFlag_enableSys) loop // disable the PWM HAL_disablePwm(halHandle); gMotorVars.Flag_Run_Identify = false; } // end of for(;;) loop } // end of main() function // // the CPU timer0 interrupt as FAST estimator ISR // interrupt void estISR(void) { HAL_acqTimer0Int(halHandle); // if(gTrjCnt >= gUserParams.numCtrlTicksPerTrajTick) // { // // clear counter // gTrjCnt = 0; // run a trajectory for speed reference, so the reference changes with a ramp instead of a step TRAJ_run(trajHandle_spd); // } // run the estimator EST_run(estHandle, &Iab_pu, &Vab_pu, gAdcData.dcBus, TRAJ_getIntValue(trajHandle_spd)); // generate the motor electrical angle angle_pu = EST_getAngle_pu(estHandle); speed_pu = EST_getFm_pu(estHandle); // get Idq from estimator to avoid sin and cos EST_getIdq_pu(estHandle,&gIdq_pu); // run the appropriate controller if((gMotorVars.Flag_Run_Identify) || (gMotorVars.Flag_enableRsRecalc)) { // when appropriate, run the PID speed controller if((pidCntSpeed++ >= USER_NUM_CTRL_TICKS_PER_SPEED_TICK) && (!gMotorVars.Flag_enableRsRecalc)) { // calculate Id reference squared _iq Id_ref_squared_pu = _IQmpy(PID_getRefValue(pidHandle[1]),PID_getRefValue(pidHandle[1])); // Take into consideration that Iq^2+Id^2 = Is^2 _iq Iq_Max_pu = _IQsqrt(gIs_Max_squared_pu - Id_ref_squared_pu); // clear counter pidCntSpeed = 0; // Set new min and max for the speed controller output PID_setMinMax(pidHandle[0], -Iq_Max_pu, Iq_Max_pu); // run speed controller PID_run_spd(pidHandle[0],TRAJ_getIntValue(trajHandle_spd),speed_pu,&(gIdq_ref_pu.value[1])); } } } //! \brief The main ISR that implements the motor control. interrupt void mainISR(void) { _iq oneOverDcBus; // acknowledge the ADC interrupt HAL_acqAdcInt(halHandle,ADC_IntNumber_1); // convert the ADC data HAL_readAdcDataWithOffsets(halHandle,&gAdcData); // remove offsets gAdcData.I.value[0] = gAdcData.I.value[0] - gOffsets_I_pu.value[0]; gAdcData.I.value[1] = gAdcData.I.value[1] - gOffsets_I_pu.value[1]; gAdcData.I.value[2] = gAdcData.I.value[2] - gOffsets_I_pu.value[2]; gAdcData.V.value[0] = gAdcData.V.value[0] - gOffsets_V_pu.value[0]; gAdcData.V.value[1] = gAdcData.V.value[1] - gOffsets_V_pu.value[1]; gAdcData.V.value[2] = gAdcData.V.value[2] - gOffsets_V_pu.value[2]; // run the current reconstruction algorithm runCurrentReconstruction(); // run Clarke transform on current CLARKE_run(clarkeHandle_I,&gAdcData.I,&Iab_pu); // run Clarke transform on voltage CLARKE_run(clarkeHandle_V,&gAdcData.V,&Vab_pu); // run a trajectory for Id reference, so the reference changes with a ramp instead of a step TRAJ_run(trajHandle_Id); // run the appropriate controller if((gMotorVars.Flag_Run_Identify) || (gMotorVars.Flag_enableRsRecalc)) { _iq refValue; _iq fbackValue; _iq outMax_pu; // get the reference value from the trajectory module refValue = TRAJ_getIntValue(trajHandle_Id) + EST_getRsOnLineId_pu(estHandle); // get the feedback value fbackValue = gIdq_pu.value[0]; // run the Id PID controller PID_run(pidHandle[1],refValue,fbackValue,&(gVdq_out_pu.value[0])); // set Iq reference to zero when doing Rs recalculation if(gMotorVars.Flag_enableRsRecalc) gIdq_ref_pu.value[1] = _IQ(0.0); // get the Iq reference value refValue = gIdq_ref_pu.value[1]; // get the feedback value fbackValue = gIdq_pu.value[1]; // calculate Iq controller limits, and run Iq controller _iq max_vs = _IQmpy(gMotorVars.OverModulation,EST_getDcBus_pu(estHandle)); outMax_pu = _IQsqrt(_IQmpy(max_vs,max_vs) - _IQmpy(gVdq_out_pu.value[0],gVdq_out_pu.value[0])); PID_setMinMax(pidHandle[2],-outMax_pu,outMax_pu); PID_run(pidHandle[2],refValue,fbackValue,&(gVdq_out_pu.value[1])); // compensate angle for PWM delay angle_pu = angleDelayComp(speed_pu, angle_pu); // compute the sin/cos phasor phasor.value[0] = _IQcosPU(angle_pu); phasor.value[1] = _IQsinPU(angle_pu); // set the phasor in the inverse Park transform IPARK_setPhasor(iparkHandle,&phasor); // run the inverse Park module IPARK_run(iparkHandle,&gVdq_out_pu,&Vab_pu); // run the space Vector Generator (SVGEN) module oneOverDcBus = EST_getOneOverDcBus_pu(estHandle); Vab_pu.value[0] = _IQmpy(Vab_pu.value[0],oneOverDcBus); Vab_pu.value[1] = _IQmpy(Vab_pu.value[1],oneOverDcBus); SVGEN_run(svgenHandle,&Vab_pu,&(gPwmData.Tabc)); // run the PWM compensation and current ignore algorithm SVGENCURRENT_compPwmData(svgencurrentHandle,&(gPwmData.Tabc),&gPwmData_prev); // gTrjCnt++; } else if(gMotorVars.Flag_enableOffsetcalc == true) { runOffsetsCalculation(); } else { // disable the PWM HAL_disablePwm(halHandle); // Set the PWMs to 50% duty cycle gPwmData.Tabc.value[0] = _IQ(0.0); gPwmData.Tabc.value[1] = _IQ(0.0); gPwmData.Tabc.value[2] = _IQ(0.0); } // write the PWM compare values HAL_writePwmData(halHandle,&gPwmData); // run function to set next trigger if(!gMotorVars.Flag_enableRsRecalc) runSetTrigger(); // DATALOG_update(datalogHandle); // 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 _iq angleDelayComp(const _iq fm_pu, const _iq angleUncomp_pu) { _iq angleDelta_pu = _IQmpy(fm_pu,_IQ(USER_IQ_FULL_SCALE_FREQ_Hz/(USER_PWM_FREQ_kHz*1000.0))); _iq angleCompFactor = _IQ(1.0 + (float_t)USER_NUM_PWM_TICKS_PER_ISR_TICK * 0.5); _iq angleDeltaComp_pu = _IQmpy(angleDelta_pu, angleCompFactor); uint32_t angleMask = ((uint32_t)0xFFFFFFFF >> (32 - GLOBAL_Q)); _iq angleComp_pu; _iq angleTmp_pu; // increment the angle angleTmp_pu = angleUncomp_pu + angleDeltaComp_pu; // mask the angle for wrap around // note: must account for the sign of the angle angleComp_pu = _IQabs(angleTmp_pu) & angleMask; // account for sign if(angleTmp_pu < _IQ(0.0)) { angleComp_pu = -angleComp_pu; } return(angleComp_pu); } // end of angleDelayComp() function void runCurrentReconstruction(void) { SVGENCURRENT_MeasureShunt_e measurableShuntThisCycle = SVGENCURRENT_getMode(svgencurrentHandle); // run the current reconstruction algorithm SVGENCURRENT_RunRegenCurrent(svgencurrentHandle, (MATH_vec3 *)(gAdcData.I.value)); gIavg.value[0] += (gAdcData.I.value[0] - gIavg.value[0])>>gIavg_shift; gIavg.value[1] += (gAdcData.I.value[1] - gIavg.value[1])>>gIavg_shift; gIavg.value[2] += (gAdcData.I.value[2] - gIavg.value[2])>>gIavg_shift; if(measurableShuntThisCycle > two_phase_measurable) { gAdcData.I.value[0] = gIavg.value[0]; gAdcData.I.value[1] = gIavg.value[1]; gAdcData.I.value[2] = gIavg.value[2]; } return; } // end of runCurrentReconstruction() function void runSetTrigger(void) { SVGENCURRENT_IgnoreShunt_e ignoreShuntNextCycle = SVGENCURRENT_getIgnoreShunt(svgencurrentHandle); SVGENCURRENT_VmidShunt_e midVolShunt = SVGENCURRENT_getVmid(svgencurrentHandle); // Set trigger point in the middle of the low side pulse HAL_setTrigger(halHandle,ignoreShuntNextCycle,midVolShunt); return; } // end of runSetTrigger() function void runFieldWeakening(void) { if(FW_getFlag_enableFw(fwHandle) == true) { FW_incCounter(fwHandle); if(FW_getCounter(fwHandle) > FW_getNumIsrTicksPerFwTick(fwHandle)) { _iq refValue; _iq fbackValue; FW_clearCounter(fwHandle); refValue = gMotorVars.VsRef; fbackValue =_IQmpy(gMotorVars.Vs,EST_getOneOverDcBus_pu(estHandle)); FW_run(fwHandle, refValue, fbackValue, &(gIdq_ref_pu.value[0])); gMotorVars.IdRef_A = _IQmpy(gIdq_ref_pu.value[0], _IQ(USER_IQ_FULL_SCALE_CURRENT_A)); } } else { gIdq_ref_pu.value[0] = _IQmpy(gMotorVars.IdRef_A, _IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A)); } return; } // end of runFieldWeakening() function void runOffsetsCalculation(void) { uint16_t cnt; // enable the PWM HAL_enablePwm(halHandle); for(cnt=0;cnt<3;cnt++) { // Set the PWMs to 50% duty cycle gPwmData.Tabc.value[cnt] = _IQ(0.0); // reset offsets used gOffsets_I_pu.value[cnt] = _IQ(0.0); gOffsets_V_pu.value[cnt] = _IQ(0.0); // run offset estimation FILTER_FO_run(filterHandle[cnt],gAdcData.I.value[cnt]); FILTER_FO_run(filterHandle[cnt+3],gAdcData.V.value[cnt]); } if(gOffsetCalcCount++ >= gUserParams.ctrlWaitTime[CTRL_State_OffLine]) { gMotorVars.Flag_enableOffsetcalc = false; gOffsetCalcCount = 0; for(cnt=0;cnt<3;cnt++) { // get calculated offsets from filter gOffsets_I_pu.value[cnt] = FILTER_FO_get_y1(filterHandle[cnt]); gOffsets_V_pu.value[cnt] = FILTER_FO_get_y1(filterHandle[cnt+3]); // clear filters FILTER_FO_setInitialConditions(filterHandle[cnt],_IQ(0.0),_IQ(0.0)); FILTER_FO_setInitialConditions(filterHandle[cnt+3],_IQ(0.0),_IQ(0.0)); } } return; } // end of runOffsetsCalculation() function void softwareUpdate1p6(EST_Handle handle) { float_t fullScaleInductance = USER_IQ_FULL_SCALE_VOLTAGE_V/(USER_IQ_FULL_SCALE_CURRENT_A*USER_VOLTAGE_FILTER_POLE_rps); float_t Ls_coarse_max = _IQ30toF(EST_getLs_coarse_max_pu(handle)); int_least8_t lShift = ceil(log(USER_MOTOR_Ls_d/(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(USER_MOTOR_Ls_d / L_max); _iq Ls_q_pu = _IQ30(USER_MOTOR_Ls_q / L_max); // store the results EST_setLs_d_pu(handle,Ls_d_pu); EST_setLs_q_pu(handle,Ls_q_pu); EST_setLs_qFmt(handle,Ls_qFmt); return; } // end of softwareUpdate1p6() function //! \brief Setup the Clarke transform for either 2 or 3 sensors. //! \param[in] handle The clarke (CLARKE) handle //! \param[in] numCurrentSensors The number of current sensors void setupClarke_I(CLARKE_Handle handle,const uint_least8_t numCurrentSensors) { _iq alpha_sf,beta_sf; // initialize the Clarke transform module for current if(numCurrentSensors == 3) { alpha_sf = _IQ(MATH_ONE_OVER_THREE); beta_sf = _IQ(MATH_ONE_OVER_SQRT_THREE); } else if(numCurrentSensors == 2) { alpha_sf = _IQ(1.0); beta_sf = _IQ(MATH_ONE_OVER_SQRT_THREE); } else { alpha_sf = _IQ(0.0); beta_sf = _IQ(0.0); } // set the parameters CLARKE_setScaleFactors(handle,alpha_sf,beta_sf); CLARKE_setNumSensors(handle,numCurrentSensors); return; } // end of setupClarke_I() function //! \brief Setup the Clarke transform for either 2 or 3 sensors. //! \param[in] handle The clarke (CLARKE) handle //! \param[in] numVoltageSensors The number of voltage sensors void setupClarke_V(CLARKE_Handle handle,const uint_least8_t numVoltageSensors) { _iq alpha_sf,beta_sf; // initialize the Clarke transform module for voltage if(numVoltageSensors == 3) { alpha_sf = _IQ(MATH_ONE_OVER_THREE); beta_sf = _IQ(MATH_ONE_OVER_SQRT_THREE); } else { alpha_sf = _IQ(0.0); beta_sf = _IQ(0.0); } // set the parameters CLARKE_setScaleFactors(handle,alpha_sf,beta_sf); CLARKE_setNumSensors(handle,numVoltageSensors); return; } // end of setupClarke_V() function //! \brief Update the global variables (gMotorVars). //! \param[in] handle The estimator (EST) handle void updateGlobalVariables(EST_Handle handle) { // get the speed estimate gMotorVars.Speed_krpm = EST_getSpeed_krpm(handle); // get the torque estimate { _iq Flux_pu = EST_getFlux_pu(handle); _iq Id_pu = PID_getFbackValue(pidHandle[1]); _iq Iq_pu = PID_getFbackValue(pidHandle[2]); _iq Ld_minus_Lq_pu = _IQ30toIQ(EST_getLs_d_pu(handle)-EST_getLs_q_pu(handle)); _iq Torque_Flux_Iq_Nm = _IQmpy(_IQmpy(Flux_pu,Iq_pu),gTorque_Flux_Iq_pu_to_Nm_sf); _iq Torque_Ls_Id_Iq_Nm = _IQmpy(_IQmpy(_IQmpy(Ld_minus_Lq_pu,Id_pu),Iq_pu),gTorque_Ls_Id_Iq_pu_to_Nm_sf); _iq Torque_Nm = Torque_Flux_Iq_Nm + Torque_Ls_Id_Iq_Nm; gMotorVars.Torque_Nm = Torque_Nm; } // get the magnetizing current gMotorVars.MagnCurr_A = EST_getIdRated(handle); // get the rotor resistance gMotorVars.Rr_Ohm = EST_getRr_Ohm(handle); // get the stator resistance gMotorVars.Rs_Ohm = EST_getRs_Ohm(handle); // get the online stator resistance gMotorVars.RsOnLine_Ohm = EST_getRsOnLine_Ohm(handle); // get the stator inductance in the direct coordinate direction gMotorVars.Lsd_H = EST_getLs_d_H(handle); // get the stator inductance in the quadrature coordinate direction gMotorVars.Lsq_H = EST_getLs_q_H(handle); // get the flux in V/Hz in floating point gMotorVars.Flux_VpHz = EST_getFlux_VpHz(handle); // get the flux in Wb in fixed point gMotorVars.Flux_Wb = _IQmpy(EST_getFlux_pu(handle),gFlux_pu_to_Wb_sf); // get the estimator state gMotorVars.EstState = EST_getState(handle); // Get the DC buss voltage gMotorVars.VdcBus_kV = _IQmpy(gAdcData.dcBus,_IQ(USER_IQ_FULL_SCALE_VOLTAGE_V/1000.0)); // read Vd and Vq vectors per units gMotorVars.Vd = gVdq_out_pu.value[0]; gMotorVars.Vq = gVdq_out_pu.value[1]; // calculate vector Vs in per units gMotorVars.Vs = _IQsqrt(_IQmpy(gMotorVars.Vd, gMotorVars.Vd) + _IQmpy(gMotorVars.Vq, gMotorVars.Vq)); // read Id and Iq vectors in amps gMotorVars.Id_A = _IQmpy(gIdq_pu.value[0], _IQ(USER_IQ_FULL_SCALE_CURRENT_A)); gMotorVars.Iq_A = _IQmpy(gIdq_pu.value[1], _IQ(USER_IQ_FULL_SCALE_CURRENT_A)); // calculate vector Is in amps gMotorVars.Is_A = _IQsqrt(_IQmpy(gMotorVars.Id_A, gMotorVars.Id_A) + _IQmpy(gMotorVars.Iq_A, gMotorVars.Iq_A)); return; } // end of updateGlobalVariables() function void updateRsOnLine(EST_Handle handle) { // execute Rs OnLine code if(gMotorVars.Flag_Run_Identify == true) { if((EST_getState(handle) == EST_State_OnLine) && (gFlag_enableRsOnLine)) { float_t RsError_Ohm = gMotorVars.RsOnLine_Ohm - gMotorVars.Rs_Ohm; EST_setFlag_enableRsOnLine(handle,true); EST_setRsOnLineId_mag_pu(handle,_IQmpy(gRsOnLineId_mag_A,_IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A))); EST_setRsOnLineAngleDelta_pu(handle,_IQmpy(gRsOnLineFreq_Hz, _IQ(1.0/USER_ISR_FREQ_Hz))); if(abs(RsError_Ohm) < (gMotorVars.Rs_Ohm * 0.05)) { EST_setFlag_updateRs(handle,true); } } else { EST_setRsOnLineId_mag_pu(handle,_IQ(0.0)); EST_setRsOnLineId_pu(handle,_IQ(0.0)); EST_setRsOnLine_pu(handle, EST_getRs_pu(handle)); EST_setFlag_enableRsOnLine(handle,false); EST_setFlag_updateRs(handle,false); EST_setRsOnLine_qFmt(handle,EST_getRs_qFmt(handle)); } } return; } // end of updateRsOnLine() function void updateCPUusage(void) { 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; // 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; return; } // end of updateCPUusage() function //@} //defgroup // end of file
As mentioned above, run all functions in estISR() except HAL_readAdcDataWithOffsets() and HAL_writePwmData(), and disable all of the additional features like over-modulation and Rs online calibration. Make sure that the estISR frequency is set correctly as the USER_ISR_FREQ_Hz.
Hi Yanming Luo,
Thank you for your review.
I need the space vector overmodulation and current reconstruction functions.
Do you mean that the space vector overmodulation and current reconstruction functions should be abandoned if the function of variable PWM frequency has to be implemented for the F28069F DSP along with the estmator library in motorware?
Meanwhile the is12_variable_pwm_frequency lab in MotorControl_SDK enables the space vector overmodulation and current reconstruction functions in implementing the function of variable PWM frequency for the F280049C DSP along with the estmator library in MotorControl_SDK .
Thank you for your guidance.
With regards,
JS Yoo
Just want you can verify if the ISR frequency is right and the estimator parameters are set correctly. Don't recommend that using over-modulation and current reconstruction for variable frequency.
Hi Yanming Luo,
Thank you for your review.
You mean that you do not recommend using over-modulation and current reconstruction for variable frequency.
Is this associated with both F280049C and F28069F?
You know that the is12_variable_pwm_frequency lab in MotorControl_SDK enables the space vector overmodulation and current reconstruction for variable PWM frequency on F280049C.
Thank you for your guidance.
With regards,
JS Yoo
Yes, both although the example project uses over-modulation since the performance is not good.