Tool/software: Code Composer Studio
Hi everyone,
I'm trying to make a home function based on proj_lab13f,so i wrote the code for that in proj_lab13f.c file, there are no problems with the compilation but the program does nothing.
This is part of the code, i also add the file.
#include <math.h> #include "main_position_2mtr.h" /*--------- INICIO Headers y variables globales ----*/ interrupt void QEP_Index_ISR(void); short gIndexOcurre = 0; #include "spa_c.h" double azi = 0, zen = 0; spa_data spa; //declare the SPA structure int result; float min, sec; int f_err = 0; char *azi_zeni; double angAz, angZen; double ang_azi_Actual = 0; double ang_zen_Actual = 0; double ang_azi_establecer = 0; double ang_zen_establecer = 0; double ang_azi_mrev = 0.0; //_iq24 double ang_zen_mrev = 0.0; double late = 20.6242738798, lon = -100.3663814068, ele = 1829; /*--------- FIN Headers y variables globales ----*/ #ifdef FLASH #pragma CODE_SECTION(motor1_ISR,"ramfuncs"); #pragma CODE_SECTION(motor2_ISR,"ramfuncs"); #endif // Include header files used in the main function // ************************************************************************** // the defines // ************************************************************************** // the globals CLARKE_Handle clarkeHandle_I[2]; //!< the handle for the current Clarke //!< transform CLARKE_Obj clarke_I[2]; //!< the current Clarke transform object PARK_Handle parkHandle[2]; //!< the handle for the current Parke //!< transform PARK_Obj park[2]; //!< the current Parke transform object CLARKE_Handle clarkeHandle_V[2]; //!< the handle for the voltage Clarke //!< transform CLARKE_Obj clarke_V[2]; //!< the voltage Clarke transform object EST_Handle estHandle[2]; //!< the handle for the estimator PID_Obj pid[2][3]; //!< three objects for PID controllers //!< 0 - Speed, 1 - Id, 2 - Iq PID_Handle pidHandle[2][3]; //!< three handles for PID controllers //!< 0 - Speed, 1 - Id, 2 - Iq uint16_t stCntPosition[2]; //!< count variable to decimate the execution //!< of SpinTAC Position Control IPARK_Handle iparkHandle[2]; //!< the handle for the inverse Park //!< transform IPARK_Obj ipark[2]; //!< the inverse Park transform object SVGEN_Handle svgenHandle[2]; //!< the handle for the space vector generator SVGEN_Obj svgen[2]; //!< the space vector generator object ENC_Handle encHandle[2]; //!< the handle for the encoder ENC_Obj enc[2]; //!< the encoder object SLIP_Handle slipHandle[2]; //!< the handle for the slip compensator SLIP_Obj slip[2]; //!< the slip compensator object HAL_Handle halHandle; //!< the handle for the hardware abstraction //!< layer for common CPU setup HAL_Obj hal; //!< the hardware abstraction layer object ANGLE_COMP_Handle angleCompHandle[2]; //!< the handle for the angle compensation ANGLE_COMP_Obj angleComp[2]; //!< the angle compensation object HAL_Handle_mtr halHandleMtr[2]; //!< the handle for the hardware abstraction //!< layer specific to the motor board. HAL_Obj_mtr halMtr[2]; //!< the hardware abstraction layer object //!< specific to the motor board. HAL_PwmData_t gPwmData[2] = {{_IQ(0.0),_IQ(0.0),_IQ(0.0)}, //!< contains the {_IQ(0.0),_IQ(0.0),_IQ(0.0)}}; //!< pwm values for each phase. //!< -1.0 is 0%, 1.0 is 100% HAL_AdcData_t gAdcData[2]; //!< contains three current values, three //!< voltage values and one DC buss value MATH_vec3 gOffsets_I_pu[2] = {{_IQ(0.0),_IQ(0.0),_IQ(0.0)}, //!< contains {_IQ(0.0),_IQ(0.0),_IQ(0.0)}}; //!< the offsets for the current feedback MATH_vec3 gOffsets_V_pu[2] = {{_IQ(0.0),_IQ(0.0),_IQ(0.0)}, //!< contains {_IQ(0.0),_IQ(0.0),_IQ(0.0)}}; //!< the offsets for the voltage feedback MATH_vec2 gIdq_ref_pu[2] = {{_IQ(0.0),_IQ(0.0)}, //!< contains the Id and {_IQ(0.0),_IQ(0.0)}}; //!< Iq references MATH_vec2 gVdq_out_pu[2] = {{_IQ(0.0),_IQ(0.0)}, //!< contains the output {_IQ(0.0),_IQ(0.0)}}; //!< Vd and Vq from the current controllers MATH_vec2 gIdq_pu[2] = {{_IQ(0.0),_IQ(0.0)}, //!< contains the Id and Iq {_IQ(0.0),_IQ(0.0)}}; //!< measured values FILTER_FO_Handle filterHandle[2][6]; //!< the handles for the 3-current and 3-voltage filters for offset calculation FILTER_FO_Obj filter[2][6]; //!< the 3-current and 3-voltage filters for offset calculation uint32_t gOffsetCalcCount[2] = {0,0}; USER_Params gUserParams[2]; uint32_t gAlignCount[2] = {0,0}; ST_Obj st_obj[2]; //!< the SpinTAC objects ST_Handle stHandle[2]; //!< the handles for the SpinTAC objects volatile MOTOR_Vars_t gMotorVars[2] = {MOTOR_Vars_INIT_Mtr1,MOTOR_Vars_INIT_Mtr2}; //!< 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; #endif #ifdef DRV8301_SPI // Watch window interface to the 8301 SPI DRV_SPI_8301_Vars_t gDrvSpi8301Vars[2]; #endif #ifdef DRV8305_SPI // Watch window interface to the 8305 SPI DRV_SPI_8305_Vars_t gDrvSpi8305Vars[2]; #endif _iq gFlux_pu_to_Wb_sf[2]; _iq gFlux_pu_to_VpHz_sf[2]; _iq gTorque_Ls_Id_Iq_pu_to_Nm_sf[2]; _iq gTorque_Flux_Iq_pu_to_Nm_sf[2]; _iq gSpeed_krpm_to_pu_sf[2]; _iq gSpeed_pu_to_krpm_sf[2]; _iq gSpeed_hz_to_krpm_sf[2]; _iq gCurrent_A_to_pu_sf[2]; // ************************************************************************** // 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); #endif // initialize the Hardware Abstraction Layer (HAL) // halHandle will be used throughout the code to interface with the HAL // (set parameters, get and set functions, etc) halHandle is required since // this is how all objects are interfaced, and it allows interface with // multiple objects by simply passing a different handle. The use of // handles is explained in this document: // C:/ti/motorware/motorware_1_01_00_1x/docs/motorware_coding_standards.pdf halHandle = HAL_init(&hal,sizeof(hal)); // initialize the user parameters // This function initializes all values of structure gUserParams with // values defined in user.h. The values in gUserParams will be then used by // the hardware abstraction layer (HAL) to configure peripherals such as // PWM, ADC, interrupts, etc. USER_setParamsMtr1(&gUserParams[HAL_MTR1]); USER_setParamsMtr2(&gUserParams[HAL_MTR2]); // set the hardware abstraction layer parameters // This function initializes all peripherals through a Hardware Abstraction // Layer (HAL). It uses all values stored in gUserParams. HAL_setParams(halHandle,&gUserParams[HAL_MTR1]); // initialize the estimator estHandle[HAL_MTR1] = EST_init((void *)USER_EST_HANDLE_ADDRESS,0x200); estHandle[HAL_MTR2] = EST_init((void *)USER_EST_HANDLE_ADDRESS_1,0x200); { uint_least8_t mtrNum; for(mtrNum=HAL_MTR1;mtrNum<=HAL_MTR2;mtrNum++) { // initialize the individual motor hal files halHandleMtr[mtrNum] = HAL_init_mtr(&halMtr[mtrNum],sizeof(halMtr[mtrNum]),(HAL_MtrSelect_e)mtrNum); // Setup each motor board to its specific setting HAL_setParamsMtr(halHandleMtr[mtrNum],halHandle,&gUserParams[mtrNum]); { // These function calls are used to initialize the estimator with ROM // function calls. It needs the specific address where the controller // object is declared by the ROM code. CTRL_Handle ctrlHandle = CTRL_init((void *)USER_CTRL_HANDLE_ADDRESS,0x200); CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle; // this sets the estimator handle (part of the controller object) to // the same value initialized above by the EST_init() function call. // This is done so the next function implemented in ROM, can // successfully initialize the estimator as part of the controller // object. obj->estHandle = estHandle[mtrNum]; // initialize the estimator through the controller. These three // function calls are needed for the F2806xF/M implementation of // InstaSPIN. CTRL_setParams(ctrlHandle,&gUserParams[mtrNum]); CTRL_setUserMotorParams(ctrlHandle); CTRL_setupEstIdleState(ctrlHandle); } //Compensates for the delay introduced //from the time when the system inputs are sampled to when the PWM //voltages are applied to the motor windings. angleCompHandle[mtrNum] = ANGLE_COMP_init(&angleComp[mtrNum],sizeof(angleComp[mtrNum])); ANGLE_COMP_setParams(angleCompHandle[mtrNum], gUserParams[mtrNum].iqFullScaleFreq_Hz, gUserParams[mtrNum].pwmPeriod_usec, gUserParams[mtrNum].numPwmTicksPerIsrTick); // initialize the Clarke modules // Clarke handle initialization for current signals clarkeHandle_I[mtrNum] = CLARKE_init(&clarke_I[mtrNum],sizeof(clarke_I[mtrNum])); // Clarke handle initialization for voltage signals clarkeHandle_V[mtrNum] = CLARKE_init(&clarke_V[mtrNum],sizeof(clarke_V[mtrNum])); // Park handle initialization for current signals parkHandle[mtrNum] = PARK_init(&park[mtrNum],sizeof(park[mtrNum])); // compute scaling factors for flux and torque calculations gFlux_pu_to_Wb_sf[mtrNum] = USER_computeFlux_pu_to_Wb_sf(&gUserParams[mtrNum]); gFlux_pu_to_VpHz_sf[mtrNum] = USER_computeFlux_pu_to_VpHz_sf(&gUserParams[mtrNum]); gTorque_Ls_Id_Iq_pu_to_Nm_sf[mtrNum] = USER_computeTorque_Ls_Id_Iq_pu_to_Nm_sf(&gUserParams[mtrNum]); gTorque_Flux_Iq_pu_to_Nm_sf[mtrNum] = USER_computeTorque_Flux_Iq_pu_to_Nm_sf(&gUserParams[mtrNum]); gSpeed_krpm_to_pu_sf[mtrNum] = _IQ((float_t)gUserParams[mtrNum].motor_numPolePairs * 1000.0 / (gUserParams[mtrNum].iqFullScaleFreq_Hz * 60.0)); //// 0.26666666666666666666666666666667 gSpeed_pu_to_krpm_sf[mtrNum] = _IQ((gUserParams[mtrNum].iqFullScaleFreq_Hz * 60.0) / ((float_t)gUserParams[mtrNum].motor_numPolePairs * 1000.0)); gSpeed_hz_to_krpm_sf[mtrNum] = _IQ(60.0 / (float_t)gUserParams[mtrNum].motor_numPolePairs / 1000.0); gCurrent_A_to_pu_sf[mtrNum] = _IQ(1.0 / gUserParams[mtrNum].iqFullScaleCurrent_A); // disable Rs recalculation EST_setFlag_enableRsRecalc(estHandle[mtrNum],false); // set the number of current sensors setupClarke_I(clarkeHandle_I[mtrNum],gUserParams[mtrNum].numCurrentSensors); // set the number of voltage sensors setupClarke_V(clarkeHandle_V[mtrNum],gUserParams[mtrNum].numVoltageSensors); // initialize the PID controllers pidSetup((HAL_MtrSelect_e)mtrNum); // initialize the inverse Park module iparkHandle[mtrNum] = IPARK_init(&ipark[mtrNum],sizeof(ipark[mtrNum])); // initialize the space vector generator module svgenHandle[mtrNum] = SVGEN_init(&svgen[mtrNum],sizeof(svgen[mtrNum])); // initialize and configure offsets using filters { uint16_t cnt = 0; _iq b0 = _IQ(gUserParams[mtrNum].offsetPole_rps/(float_t)gUserParams[mtrNum].ctrlFreq_Hz); _iq a1 = (b0 - _IQ(1.0)); _iq b1 = _IQ(0.0); for(cnt=0;cnt<6;cnt++) { filterHandle[mtrNum][cnt] = FILTER_FO_init(&filter[mtrNum][cnt],sizeof(filter[mtrNum][0])); FILTER_FO_setDenCoeffs(filterHandle[mtrNum][cnt],a1); FILTER_FO_setNumCoeffs(filterHandle[mtrNum][cnt],b0,b1); FILTER_FO_setInitialConditions(filterHandle[mtrNum][cnt],_IQ(0.0),_IQ(0.0)); } gMotorVars[mtrNum].Flag_enableOffsetcalc = false; } // initialize the encoder module encHandle[mtrNum] = ENC_init(&enc[mtrNum],sizeof(enc[mtrNum])); // initialize the slip compensation module slipHandle[mtrNum] = SLIP_init(&slip[mtrNum],sizeof(slip[mtrNum])); // setup the SLIP module SLIP_setup(slipHandle[mtrNum], _IQ(gUserParams[mtrNum].ctrlPeriod_sec)); // setup faults HAL_setupFaults(halHandleMtr[mtrNum]); // initialize the SpinTAC Components stHandle[mtrNum] = ST_init(&st_obj[mtrNum], sizeof(st_obj[mtrNum])); } // End of for loop } // setup the encoder module ENC_setup(encHandle[HAL_MTR1], 1, USER_MOTOR_NUM_POLE_PAIRS, USER_MOTOR_ENCODER_LINES, 0, USER_IQ_FULL_SCALE_FREQ_Hz, USER_ISR_FREQ_Hz, 8000.0); ENC_setup(encHandle[HAL_MTR2], 1, USER_MOTOR_NUM_POLE_PAIRS_2, USER_MOTOR_ENCODER_LINES_2, 0, USER_IQ_FULL_SCALE_FREQ_Hz_2, USER_ISR_FREQ_Hz_2, 8000.0); /// M C >>>>>>>>>>>>> HAL_Obj_mtr *obj_mtr = (HAL_Obj_mtr *)halHandle; HAL_Obj *obj = (HAL_Obj *)halHandle; obj_mtr = (HAL_Obj_mtr *)halHandle; // QEP_Obj *qep = (QEP_Obj *)obj_mtr->qepHandle; QEP_clear_all_interrupt_flags(obj_mtr->qepHandle); // Limpiar todas las banderas de interrupci�n QEP_disable_all_interrupts(obj_mtr->qepHandle); // Deshabilitar todas las interrupciones PIE_enableInt( obj->pieHandle, PIE_GroupNumber_5, PIE_InterruptSource_EQEP1 ); //Grupo 5 donde se encuentra la interrupcion de EQEP1 QEP_enable_interrupt(obj_mtr->qepHandle, QEINT_Iel); //Habilitar el bit de interrupci�n correspondiente al pulso de Index CPU_enableInt(obj->cpuHandle,CPU_IntNumber_5); //Habilitar el grupo 5 en las interrupciones de la CPU /// M C >>>>>>>>>>>>> // setup the SpinTAC Components ST_setupPosConv_mtr1(stHandle[HAL_MTR1]); ST_setupPosConv_mtr2(stHandle[HAL_MTR2]); ST_setupPosCtl_mtr1(stHandle[HAL_MTR1]); ST_setupPosMove_mtr1(stHandle[HAL_MTR1]); ST_setupPosCtl_mtr2(stHandle[HAL_MTR2]); ST_setupPosMove_mtr2(stHandle[HAL_MTR2]); // set the pre-determined current and voltage feeback offset values gOffsets_I_pu[HAL_MTR1].value[0] = _IQ(I_A_offset); gOffsets_I_pu[HAL_MTR1].value[1] = _IQ(I_B_offset); gOffsets_I_pu[HAL_MTR1].value[2] = _IQ(I_C_offset); gOffsets_V_pu[HAL_MTR1].value[0] = _IQ(V_A_offset); gOffsets_V_pu[HAL_MTR1].value[1] = _IQ(V_B_offset); gOffsets_V_pu[HAL_MTR1].value[2] = _IQ(V_C_offset); gOffsets_I_pu[HAL_MTR2].value[0] = _IQ(I_A_offset_2); gOffsets_I_pu[HAL_MTR2].value[1] = _IQ(I_B_offset_2); gOffsets_I_pu[HAL_MTR2].value[2] = _IQ(I_C_offset_2); gOffsets_V_pu[HAL_MTR2].value[0] = _IQ(V_A_offset_2); gOffsets_V_pu[HAL_MTR2].value[1] = _IQ(V_B_offset_2); gOffsets_V_pu[HAL_MTR2].value[2] = _IQ(V_C_offset_2); // initialize the interrupt vector table HAL_initIntVectorTable(halHandle); //>>>> Configuracion de la interrupcion del index <<<<<<<<<<<<// PIE_Obj *pie = (PIE_Obj *)obj->pieHandle; ENABLE_PROTECTED_REGISTER_WRITE_MODE; pie->EQEP1_INT = &QEP_Index_ISR; DISABLE_PROTECTED_REGISTER_WRITE_MODE; //>>>> Configuracion de la interrupcion del index <<<<<<<<<<<<// // enable the ADC interrupts HAL_enableAdcInts(halHandle); // enable global interrupts HAL_enableGlobalInts(halHandle); // enable debug interrupts HAL_enableDebugInt(halHandle); // disable the PWM HAL_disablePwm(halHandleMtr[HAL_MTR1]); HAL_disablePwm(halHandleMtr[HAL_MTR2]); // initialize SpinTAC Velocity Control watch window variables gMotorVars[HAL_MTR1].SpinTAC.PosCtlBw_radps = STPOSCTL_getBandwidth_radps(st_obj[HAL_MTR1].posCtlHandle); gMotorVars[HAL_MTR2].SpinTAC.PosCtlBw_radps = STPOSCTL_getBandwidth_radps(st_obj[HAL_MTR2].posCtlHandle); // initialize the watch window with maximum and minimum Iq reference gMotorVars[HAL_MTR1].SpinTAC.PosCtlOutputMax_A = _IQmpy(STPOSCTL_getOutputMaximum(st_obj[HAL_MTR1].posCtlHandle), _IQ(gUserParams[HAL_MTR1].iqFullScaleCurrent_A)); gMotorVars[HAL_MTR1].SpinTAC.PosCtlOutputMin_A = _IQmpy(STPOSCTL_getOutputMinimum(st_obj[HAL_MTR1].posCtlHandle), _IQ(gUserParams[HAL_MTR1].iqFullScaleCurrent_A)); gMotorVars[HAL_MTR2].SpinTAC.PosCtlOutputMax_A = _IQmpy(STPOSCTL_getOutputMaximum(st_obj[HAL_MTR2].posCtlHandle), _IQ(gUserParams[HAL_MTR2].iqFullScaleCurrent_A)); gMotorVars[HAL_MTR2].SpinTAC.PosCtlOutputMin_A = _IQmpy(STPOSCTL_getOutputMinimum(st_obj[HAL_MTR2].posCtlHandle), _IQ(gUserParams[HAL_MTR2].iqFullScaleCurrent_A)); // enable the system by default gMotorVars[HAL_MTR1].Flag_enableSys = true; #ifdef DRV8301_SPI // turn on the DRV8301 if present HAL_enableDrv(halHandleMtr[HAL_MTR1]); HAL_enableDrv(halHandleMtr[HAL_MTR2]); // initialize the DRV8301 interface HAL_setupDrvSpi(halHandleMtr[HAL_MTR1],&gDrvSpi8301Vars[HAL_MTR1]); HAL_setupDrvSpi(halHandleMtr[HAL_MTR2],&gDrvSpi8301Vars[HAL_MTR2]); #endif #ifdef DRV8305_SPI // turn on the DRV8305 if present HAL_enableDrv(halHandleMtr[HAL_MTR1]); HAL_enableDrv(halHandleMtr[HAL_MTR2]); // initialize the DRV8305 interface HAL_setupDrvSpi(halHandleMtr[HAL_MTR1],&gDrvSpi8305Vars[HAL_MTR1]); HAL_setupDrvSpi(halHandleMtr[HAL_MTR2],&gDrvSpi8305Vars[HAL_MTR2]); #endif spa.year = 2003; spa.month = 10; spa.day = 17; spa.hour = 12; spa.minute = 30; spa.second = 30; spa.timezone = -7.0; spa.delta_ut1 = 0; spa.delta_t = 67; spa.longitude = -105.1786; spa.latitude = 39.742476; spa.elevation = 1830.14; spa.pressure = 820; spa.temperature = 11; spa.slope = 30; spa.azm_rotation = -10; spa.atmos_refract = 0.5667; spa.function = SPA_ALL; // Begin the background loop for(;;) { // Waiting for enable system flag to be set // Motor 1 Flag_enableSys is the master control. while(!(gMotorVars[HAL_MTR1].Flag_enableSys)); // loop while the enable system flag is true // Motor 1 Flag_enableSys is the master control. while(gMotorVars[HAL_MTR1].Flag_enableSys) { uint_least8_t mtrNum = HAL_MTR1; // >>> INICIO Se le pasan los parametros al algoritmo y se obtienen los �ngulos <<< // spa_algorithm(late,lon, ele); result = spa_calculate(&spa); if (result == 0) //check for SPA errors { //display the results inside the SPA structure // printf("Julian Day: %.6f\n",spa.jd); // printf("L: %.6e degrees\n",spa.l); // printf("B: %.6e degrees\n",spa.b); // printf("R: %.6f AU\n",spa.r); // printf("H: %.6f degrees\n",spa.h); // printf("Delta Psi: %.6e degrees\n",spa.del_psi); // printf("Delta Epsilon: %.6e degrees\n",spa.del_epsilon); // printf("Epsilon: %.6f degrees\n",spa.epsilon); // printf("Zenith: %.6f degrees\n",spa.zenith); // printf("Azimuth: %.6f degrees\n",spa.azimuth); // printf("Incidence: %.6f degrees\n",spa.incidence); azi = spa.azimuth; zen = spa.zenith; min = 60.0*(spa.sunrise - (int)(spa.sunrise)); sec = 60.0*(min - (int)min); // printf("Sunrise: %02d:%02d:%02d Local Time\n", (int)(spa.sunrise), (int)min, (int)sec); min = 60.0*(spa.sunset - (int)(spa.sunset)); sec = 60.0*(min - (int)min); // printf("Sunset: %02d:%02d:%02d Local Time\n", (int)(spa.sunset), (int)min, (int)sec); } else f_err = 1; // printf("SPA Error Code: %d\n", result); angAz = spa.azimuth; angZen = spa.zenith; ang_azi_establecer = (angAz - ang_azi_Actual); ang_zen_establecer = (angZen - ang_zen_Actual); ang_azi_mrev = ang_azi_establecer/360; ang_zen_mrev = ang_zen_establecer/360; ang_azi_Actual = angAz; ang_zen_Actual = angZen; // gMotorVars[HAL_MTR1].PosStepInt_MRev = 0; // gMotorVars[HAL_MTR1].PosStepFrac_MRev = _IQ24(ang_azi_mrev); gMotorVars[HAL_MTR1].RunPositionProfile = true; // gMotorVars[HAL_MTR2].PosStepInt_MRev = 0; // gMotorVars[HAL_MTR2].PosStepFrac_MRev = _IQ24(ang_zen_mrev); gMotorVars[HAL_MTR2].RunPositionProfile = true; // >>> FIN Se le pasan los parametros al algoritmo y se obtienen los �ngulos <<< for(mtrNum=HAL_MTR1;mtrNum<=HAL_MTR2;mtrNum++) { // If Flag_enableSys is set AND Flag_Run_Identify is set THEN // enable PWMs and set the speed reference if(gMotorVars[mtrNum].Flag_Run_Identify) { // update estimator state EST_updateState(estHandle[mtrNum],0); #ifdef FAST_ROM_V1p6 // call this function to fix 1p6. This is only used for // F2806xF/M implementation of InstaSPIN (version 1.6 of // ROM), since the inductance calculation is not done // correctly in ROM, so this function fixes that ROM bug. softwareUpdate1p6(estHandle[mtrNum],&gUserParams[mtrNum]); #endif // enable the PWM HAL_enablePwm(halHandleMtr[mtrNum]); // enable SpinTAC Velocity Control STPOSCTL_setEnable(st_obj[mtrNum].posCtlHandle, true); // provide bandwidth setting to SpinTAC Velocity Control STPOSCTL_setBandwidth_radps(st_obj[mtrNum].posCtlHandle, gMotorVars[mtrNum].SpinTAC.PosCtlBw_radps); // provide output maximum and minimum setting to SpinTAC Velocity Control STPOSCTL_setOutputMaximums(st_obj[mtrNum].posCtlHandle, _IQmpy(gMotorVars[mtrNum].SpinTAC.PosCtlOutputMax_A, gCurrent_A_to_pu_sf[mtrNum]), _IQmpy(gMotorVars[mtrNum].SpinTAC.PosCtlOutputMin_A, gCurrent_A_to_pu_sf[mtrNum])); } else // Flag_enableSys is set AND Flag_Run_Identify is not set { // set estimator to Idle EST_setIdle(estHandle[mtrNum]); // disable the PWM HAL_disablePwm(halHandleMtr[mtrNum]); // clear integrator outputs PID_setUi(pidHandle[mtrNum][0],_IQ(0.0)); PID_setUi(pidHandle[mtrNum][1],_IQ(0.0)); PID_setUi(pidHandle[mtrNum][2],_IQ(0.0)); // clear Id and Iq references gIdq_ref_pu[mtrNum].value[0] = _IQ(0.0); gIdq_ref_pu[mtrNum].value[1] = _IQ(0.0); // place SpinTAC Velocity Control into reset STPOSCTL_setEnable(st_obj[mtrNum].posCtlHandle, false); // If motor is not running, feed the position feedback into SpinTAC Position Move STPOSMOVE_setPositionStart_mrev(st_obj[mtrNum].posMoveHandle, STPOSCONV_getPosition_mrev(st_obj[mtrNum].posConvHandle)); } // update the global variables updateGlobalVariables(estHandle[mtrNum], mtrNum); // enable/disable the forced angle EST_setFlag_enableForceAngle(estHandle[mtrNum], gMotorVars[mtrNum].Flag_enableForceAngle); #ifdef DRV8301_SPI HAL_writeDrvData(halHandleMtr[mtrNum],&gDrvSpi8301Vars[mtrNum]); HAL_readDrvData(halHandleMtr[mtrNum],&gDrvSpi8301Vars[mtrNum]); #endif #ifdef DRV8305_SPI HAL_writeDrvData(halHandleMtr[mtrNum],&gDrvSpi8305Vars[mtrNum]); HAL_readDrvData(halHandleMtr[mtrNum],&gDrvSpi8305Vars[mtrNum]); #endif } // end of for loop } // end of while(gFlag_enableSys) loop // disable the PWM HAL_disablePwm(halHandleMtr[HAL_MTR1]); HAL_disablePwm(halHandleMtr[HAL_MTR2]); gMotorVars[HAL_MTR1].Flag_Run_Identify = false; gMotorVars[HAL_MTR2].Flag_Run_Identify = false; } // end of for(;;) loop } // end of main() function //! \brief The main ISR that implements the motor control. interrupt void motor1_ISR(void) { // Declaration of local variables static _iq angle_pu = _IQ(0.0); _iq speed_pu = _IQ(0.0); _iq oneOverDcBus; MATH_vec2 Iab_pu; MATH_vec2 Vab_pu; MATH_vec2 phasor; HAL_setGpioHigh(halHandle,GPIO_Number_12); // acknowledge the ADC interrupt HAL_acqAdcInt(halHandle,ADC_IntNumber_1); // convert the ADC data HAL_readAdcDataWithOffsets(halHandle,halHandleMtr[HAL_MTR1],&gAdcData[HAL_MTR1]); // remove offsets gAdcData[HAL_MTR1].I.value[0] = gAdcData[HAL_MTR1].I.value[0] - gOffsets_I_pu[HAL_MTR1].value[0]; gAdcData[HAL_MTR1].I.value[1] = gAdcData[HAL_MTR1].I.value[1] - gOffsets_I_pu[HAL_MTR1].value[1]; gAdcData[HAL_MTR1].I.value[2] = gAdcData[HAL_MTR1].I.value[2] - gOffsets_I_pu[HAL_MTR1].value[2]; gAdcData[HAL_MTR1].V.value[0] = gAdcData[HAL_MTR1].V.value[0] - gOffsets_V_pu[HAL_MTR1].value[0]; gAdcData[HAL_MTR1].V.value[1] = gAdcData[HAL_MTR1].V.value[1] - gOffsets_V_pu[HAL_MTR1].value[1]; gAdcData[HAL_MTR1].V.value[2] = gAdcData[HAL_MTR1].V.value[2] - gOffsets_V_pu[HAL_MTR1].value[2]; // run Clarke transform on current. Three values are passed, two values // are returned. CLARKE_run(clarkeHandle_I[HAL_MTR1],&gAdcData[HAL_MTR1].I,&Iab_pu); // compute the sine and cosine phasor values which are part of the // Park transform calculations. Once these values are computed, // they are copied into the PARK module, which then uses them to // transform the voltages from Alpha/Beta to DQ reference frames. phasor.value[0] = _IQcosPU(angle_pu); phasor.value[1] = _IQsinPU(angle_pu); // set the phasor in the Park transform PARK_setPhasor(parkHandle[HAL_MTR1],&phasor); // Run the Park module. This converts the current vector from // stationary frame values to synchronous frame values. PARK_run(parkHandle[HAL_MTR1],&Iab_pu,&gIdq_pu[HAL_MTR1]); // compute the electrical angle ENC_calcElecAngle(encHandle[HAL_MTR1], HAL_getQepPosnCounts(halHandleMtr[HAL_MTR1])); if(stCntPosition[HAL_MTR1] >= gUserParams[HAL_MTR1].numCtrlTicksPerSpeedTick) { // Calculate the feedback position, this must always be ran in order to ensure there are no jumps ST_runPosConv(stHandle[HAL_MTR1], encHandle[HAL_MTR1], slipHandle[HAL_MTR1], &gIdq_pu[HAL_MTR1], gUserParams[HAL_MTR1].motor_type); } // run the appropriate controller if(gMotorVars[HAL_MTR1].Flag_Run_Identify) { // Declaration of local variables. _iq refValue; _iq fbackValue; _iq outMax_pu; // check if the motor should be forced into encoder slignment if(gMotorVars[HAL_MTR1].Flag_enableAlignment == false) { gMotorVars[HAL_MTR1].MaxVel_krpm = _IQ(3); gMotorVars[HAL_MTR1].MaxAccel_krpmps = _IQ(65); gMotorVars[HAL_MTR1].MaxDecel_krpmps = _IQ(65); gMotorVars[HAL_MTR1].MaxJrk_krpmps2 = _IQ20(350); // when appropriate, run SpinTAC Position Control // This mechanism provides the decimation for the speed loop. if(stCntPosition[HAL_MTR1] >= gUserParams[HAL_MTR1].numCtrlTicksPerSpeedTick) { // Reset the Position execution counter. stCntPosition[HAL_MTR1] = 0; if((STPOSMOVE_getStatus(st_obj[HAL_MTR1].posMoveHandle) == ST_MOVE_IDLE) && (gMotorVars[HAL_MTR1].RunPositionProfile == true)) { // Get the configuration for SpinTAC Position Move STPOSMOVE_setCurveType(st_obj[HAL_MTR1].posMoveHandle, gMotorVars[HAL_MTR1].SpinTAC.PosMoveCurveType); STPOSMOVE_setPositionStep_mrev(st_obj[HAL_MTR1].posMoveHandle, gMotorVars[HAL_MTR1].PosStepInt_MRev,gMotorVars[HAL_MTR1].PosStepFrac_MRev); STPOSMOVE_setVelocityLimit(st_obj[HAL_MTR1].posMoveHandle, _IQmpy(gMotorVars[HAL_MTR1].MaxVel_krpm, gSpeed_krpm_to_pu_sf[HAL_MTR1])); STPOSMOVE_setAccelerationLimit(st_obj[HAL_MTR1].posMoveHandle, _IQmpy(gMotorVars[HAL_MTR1].MaxAccel_krpmps, gSpeed_krpm_to_pu_sf[HAL_MTR1])); STPOSMOVE_setDecelerationLimit(st_obj[HAL_MTR1].posMoveHandle, _IQmpy(gMotorVars[HAL_MTR1].MaxDecel_krpmps, gSpeed_krpm_to_pu_sf[HAL_MTR1])); STPOSMOVE_setJerkLimit(st_obj[HAL_MTR1].posMoveHandle, _IQ20mpy(gMotorVars[HAL_MTR1].MaxJrk_krpmps2, _IQtoIQ20(gSpeed_krpm_to_pu_sf[HAL_MTR1]))); // Enable the SpinTAC Position Profile Generator STPOSMOVE_setEnable(st_obj[HAL_MTR1].posMoveHandle, true); // clear the position step command gMotorVars[HAL_MTR1].PosStepInt_MRev = 0; gMotorVars[HAL_MTR1].PosStepFrac_MRev = 0; gMotorVars[HAL_MTR1].RunPositionProfile = false; } // The next instruction executes SpinTAC Velocity Move // This is the speed profile generation STPOSMOVE_run(st_obj[HAL_MTR1].posMoveHandle); // The next instruction executes SpinTAC Position Control and places // its output in Idq_ref_pu.value[1], which is the input reference // value for the q-axis current controller. gIdq_ref_pu[HAL_MTR1].value[1] = ST_runPosCtl(stHandle[HAL_MTR1]); } else { // increment counter stCntPosition[HAL_MTR1]++; } // generate the motor electrical angle if(gUserParams[HAL_MTR1].motor_type == MOTOR_Type_Induction) { // update the electrical angle for the SLIP module SLIP_setElectricalAngle(slipHandle[HAL_MTR1], ENC_getElecAngle(encHandle[HAL_MTR1])); // compute the amount of slip SLIP_run(slipHandle[HAL_MTR1]); // set magnetic angle angle_pu = SLIP_getMagneticAngle(slipHandle[HAL_MTR1]); } else { angle_pu = ENC_getElecAngle(encHandle[HAL_MTR1]); } speed_pu = STPOSCONV_getVelocity(st_obj[HAL_MTR1].posConvHandle); } else { // the alignment procedure is in effect // force motor angle and speed to 0 angle_pu = _IQ(0.0); speed_pu = _IQ(0.0); // set D-axis current to Rs estimation current gIdq_ref_pu[HAL_MTR1].value[0] = _IQ(USER_MOTOR_RES_EST_CURRENT/USER_IQ_FULL_SCALE_CURRENT_A); // set Q-axis current to 0 gIdq_ref_pu[HAL_MTR1].value[1] = _IQ(0.0); // save encoder reading when forcing motor into alignment if(gUserParams[HAL_MTR1].motor_type == MOTOR_Type_Pm) { ENC_setZeroOffset(encHandle[HAL_MTR1], (uint32_t)(HAL_getQepPosnMaximum(halHandleMtr[HAL_MTR1]) - HAL_getQepPosnCounts(halHandleMtr[HAL_MTR1]))); } // if alignment counter exceeds threshold, exit alignment if(gAlignCount[HAL_MTR1]++ >= gUserParams[HAL_MTR1].ctrlWaitTime[CTRL_State_OffLine]) { gMotorVars[HAL_MTR1].Flag_enableAlignment = false; gAlignCount[HAL_MTR1] = 0; gIdq_ref_pu[HAL_MTR1].value[0] = _IQ(0.0); } } // Get the reference value for the d-axis current controller. refValue = gIdq_ref_pu[HAL_MTR1].value[0]; // Get the actual value of Id fbackValue = gIdq_pu[HAL_MTR1].value[0]; // The next instruction executes the PI current controller for the // d axis and places its output in Vdq_pu.value[0], which is the // control voltage along the d-axis (Vd) PID_run(pidHandle[HAL_MTR1][1],refValue,fbackValue,&(gVdq_out_pu[HAL_MTR1].value[0])); // get the Iq reference value refValue = gIdq_ref_pu[HAL_MTR1].value[1]; // get the actual value of Iq fbackValue = gIdq_pu[HAL_MTR1].value[1]; // The voltage limits on the output of the q-axis current controller // are dynamic, and are dependent on the output voltage from the d-axis // current controller. In other words, the d-axis current controller // gets first dibs on the available voltage, and the q-axis current // controller gets what's left over. That is why the d-axis current // controller executes first. The next instruction calculates the // maximum limits for this voltage as: // Vq_min_max = +/- sqrt(Vbus^2 - Vd^2) outMax_pu = _IQsqrt(_IQ(USER_MAX_VS_MAG_PU * USER_MAX_VS_MAG_PU) - _IQmpy(gVdq_out_pu[HAL_MTR1].value[0],gVdq_out_pu[HAL_MTR1].value[0])); // Set the limits to +/- outMax_pu PID_setMinMax(pidHandle[HAL_MTR1][2],-outMax_pu,outMax_pu); // The next instruction executes the PI current controller for the // q axis and places its output in Vdq_pu.value[1], which is the // control voltage vector along the q-axis (Vq) PID_run(pidHandle[HAL_MTR1][2],refValue,fbackValue,&(gVdq_out_pu[HAL_MTR1].value[1])); // The voltage vector is now calculated and ready to be applied to the // motor in the form of three PWM signals. However, even though the // voltages may be supplied to the PWM module now, they won't be // applied to the motor until the next PWM cycle. By this point, the // motor will have moved away from the angle that the voltage vector // was calculated for, by an amount which is proportional to the // sampling frequency and the speed of the motor. For steady-state // speeds, we can calculate this angle delay and compensate for it. ANGLE_COMP_run(angleCompHandle[HAL_MTR1],speed_pu,angle_pu); angle_pu = ANGLE_COMP_getAngleComp_pu(angleCompHandle[HAL_MTR1]); // compute the sine and cosine phasor values which are part of the inverse // Park transform calculations. Once these values are computed, // they are copied into the IPARK module, which then uses them to // transform the voltages from DQ to Alpha/Beta reference frames. phasor.value[0] = _IQcosPU(angle_pu); phasor.value[1] = _IQsinPU(angle_pu); // set the phasor in the inverse Park transform IPARK_setPhasor(iparkHandle[HAL_MTR1],&phasor); // Run the inverse Park module. This converts the voltage vector from // synchronous frame values to stationary frame values. IPARK_run(iparkHandle[HAL_MTR1],&gVdq_out_pu[HAL_MTR1],&Vab_pu); // These 3 statements compensate for variations in the DC bus by adjusting the // PWM duty cycle. The goal is to achieve the same volt-second product // regardless of the DC bus value. To do this, we must divide the desired voltage // values by the DC bus value. Or...it is easier to multiply by 1/(DC bus value). oneOverDcBus = _IQdiv(_IQ(1.0), gAdcData[HAL_MTR1].dcBus);//EST_getOneOverDcBus_pu(estHandle[HAL_MTR1]); Vab_pu.value[0] = _IQmpy(Vab_pu.value[0],oneOverDcBus); Vab_pu.value[1] = _IQmpy(Vab_pu.value[1],oneOverDcBus); // Now run the space vector generator (SVGEN) module. // There is no need to do an inverse CLARKE transform, as this is // handled in the SVGEN_run function. SVGEN_run(svgenHandle[HAL_MTR1],&Vab_pu,&(gPwmData[HAL_MTR1].Tabc)); } else if(gMotorVars[HAL_MTR1].Flag_enableOffsetcalc == true) { runOffsetsCalculation(HAL_MTR1); } else // gMotorVars.Flag_Run_Identify = 0 { // disable the PWM HAL_disablePwm(halHandleMtr[HAL_MTR1]); // Set the PWMs to 50% duty cycle gPwmData[HAL_MTR1].Tabc.value[0] = _IQ(0.0); gPwmData[HAL_MTR1].Tabc.value[1] = _IQ(0.0); gPwmData[HAL_MTR1].Tabc.value[2] = _IQ(0.0); } // write to the PWM compare registers, and then we are done! HAL_writePwmData(halHandleMtr[HAL_MTR1],&gPwmData[HAL_MTR1]); HAL_setGpioLow(halHandle,GPIO_Number_12); return; } // end of motor1_ISR() function interrupt void motor2_ISR(void) { // Declaration of local variables static _iq angle_pu = _IQ(0.0); _iq speed_pu = _IQ(0.0); _iq oneOverDcBus; MATH_vec2 Iab_pu; MATH_vec2 Vab_pu; MATH_vec2 phasor; HAL_setGpioHigh(halHandle,GPIO_Number_20); // acknowledge the ADC interrupt HAL_acqAdcInt(halHandle,ADC_IntNumber_2); // convert the ADC data HAL_readAdcDataWithOffsets(halHandle,halHandleMtr[HAL_MTR2],&gAdcData[HAL_MTR2]); // remove offsets gAdcData[HAL_MTR2].I.value[0] = gAdcData[HAL_MTR2].I.value[0] - gOffsets_I_pu[HAL_MTR2].value[0]; gAdcData[HAL_MTR2].I.value[1] = gAdcData[HAL_MTR2].I.value[1] - gOffsets_I_pu[HAL_MTR2].value[1]; gAdcData[HAL_MTR2].I.value[2] = gAdcData[HAL_MTR2].I.value[2] - gOffsets_I_pu[HAL_MTR2].value[2]; gAdcData[HAL_MTR2].V.value[0] = gAdcData[HAL_MTR2].V.value[0] - gOffsets_V_pu[HAL_MTR2].value[0]; gAdcData[HAL_MTR2].V.value[1] = gAdcData[HAL_MTR2].V.value[1] - gOffsets_V_pu[HAL_MTR2].value[1]; gAdcData[HAL_MTR2].V.value[2] = gAdcData[HAL_MTR2].V.value[2] - gOffsets_V_pu[HAL_MTR2].value[2]; // run Clarke transform on current. Three values are passed, two values // are returned. CLARKE_run(clarkeHandle_I[HAL_MTR2],&gAdcData[HAL_MTR2].I,&Iab_pu); // compute the sine and cosine phasor values which are part of the // Park transform calculations. Once these values are computed, // they are copied into the PARK module, which then uses them to // transform the voltages from Alpha/Beta to DQ reference frames. phasor.value[0] = _IQcosPU(angle_pu); phasor.value[1] = _IQsinPU(angle_pu); // set the phasor in the Park transform PARK_setPhasor(parkHandle[HAL_MTR2],&phasor); // Run the Park module. This converts the current vector from // stationary frame values to synchronous frame values. PARK_run(parkHandle[HAL_MTR2],&Iab_pu,&gIdq_pu[HAL_MTR2]); // compute the electrical angle ENC_calcElecAngle(encHandle[HAL_MTR2], HAL_getQepPosnCounts(halHandleMtr[HAL_MTR2])); if(stCntPosition[HAL_MTR2] >= gUserParams[HAL_MTR2].numCtrlTicksPerSpeedTick) { // Calculate the feedback position, this must always be ran in order to ensure there are no jumps ST_runPosConv(stHandle[HAL_MTR2], encHandle[HAL_MTR2], slipHandle[HAL_MTR2], &gIdq_pu[HAL_MTR2], gUserParams[HAL_MTR2].motor_type); } // run the appropriate controller if(gMotorVars[HAL_MTR2].Flag_Run_Identify) { // Declaration of local variables. _iq refValue; _iq fbackValue; _iq outMax_pu; // check if the motor should be forced into encoder slignment if(gMotorVars[HAL_MTR2].Flag_enableAlignment == false) { gMotorVars[HAL_MTR2].MaxVel_krpm = _IQ(3); gMotorVars[HAL_MTR2].MaxAccel_krpmps = _IQ(65); gMotorVars[HAL_MTR2].MaxDecel_krpmps = _IQ(65); gMotorVars[HAL_MTR2].MaxJrk_krpmps2 = _IQ20(350); // when appropriate, run SpinTAC Position Control // This mechanism provides the decimation for the speed loop. if(stCntPosition[HAL_MTR2] >= gUserParams[HAL_MTR2].numCtrlTicksPerSpeedTick) { // Reset the Position execution counter. stCntPosition[HAL_MTR2] = 0; if((STPOSMOVE_getStatus(st_obj[HAL_MTR2].posMoveHandle) == ST_MOVE_IDLE) && (gMotorVars[HAL_MTR2].RunPositionProfile == true)) { // Get the configuration for SpinTAC Position Move STPOSMOVE_setCurveType(st_obj[HAL_MTR2].posMoveHandle, gMotorVars[HAL_MTR2].SpinTAC.PosMoveCurveType); STPOSMOVE_setPositionStep_mrev(st_obj[HAL_MTR2].posMoveHandle, gMotorVars[HAL_MTR2].PosStepInt_MRev, gMotorVars[HAL_MTR2].PosStepFrac_MRev); STPOSMOVE_setVelocityLimit(st_obj[HAL_MTR2].posMoveHandle, _IQmpy(gMotorVars[HAL_MTR2].MaxVel_krpm, gSpeed_krpm_to_pu_sf[HAL_MTR2])); STPOSMOVE_setAccelerationLimit(st_obj[HAL_MTR2].posMoveHandle, _IQmpy(gMotorVars[HAL_MTR2].MaxAccel_krpmps, gSpeed_krpm_to_pu_sf[HAL_MTR2])); STPOSMOVE_setDecelerationLimit(st_obj[HAL_MTR2].posMoveHandle, _IQmpy(gMotorVars[HAL_MTR2].MaxDecel_krpmps, gSpeed_krpm_to_pu_sf[HAL_MTR2])); STPOSMOVE_setJerkLimit(st_obj[HAL_MTR2].posMoveHandle, _IQ20mpy(gMotorVars[HAL_MTR2].MaxJrk_krpmps2, _IQtoIQ20(gSpeed_krpm_to_pu_sf[HAL_MTR2]))); // Enable the SpinTAC Position Profile Generator STPOSMOVE_setEnable(st_obj[HAL_MTR2].posMoveHandle, true); // clear the position step command gMotorVars[HAL_MTR2].PosStepInt_MRev = 0; gMotorVars[HAL_MTR2].PosStepFrac_MRev = 0; gMotorVars[HAL_MTR2].RunPositionProfile = false; } // The next instruction executes SpinTAC Velocity Move // This is the speed profile generation STPOSMOVE_run(st_obj[HAL_MTR2].posMoveHandle); // The next instruction executes SpinTAC Position Control and places // its output in Idq_ref_pu.value[1], which is the input reference // value for the q-axis current controller. gIdq_ref_pu[HAL_MTR2].value[1] = ST_runPosCtl(stHandle[HAL_MTR2]); } else { // increment counter stCntPosition[HAL_MTR2]++; } // generate the motor electrical angle if(gUserParams[HAL_MTR2].motor_type == MOTOR_Type_Induction) { // update the electrical angle for the SLIP module SLIP_setElectricalAngle(slipHandle[HAL_MTR2], ENC_getElecAngle(encHandle[HAL_MTR2])); // compute the amount of slip SLIP_run(slipHandle[HAL_MTR2]); // set magnetic angle angle_pu = SLIP_getMagneticAngle(slipHandle[HAL_MTR2]); } else { angle_pu = ENC_getElecAngle(encHandle[HAL_MTR2]); } speed_pu = STPOSCONV_getVelocity(st_obj[HAL_MTR2].posConvHandle); } else { // the alignment procedure is in effect // force motor angle and speed to 0 angle_pu = _IQ(0.0); speed_pu = _IQ(0.0); // set D-axis current to Rs estimation current gIdq_ref_pu[HAL_MTR2].value[0] = _IQ(USER_MOTOR_RES_EST_CURRENT_2/USER_IQ_FULL_SCALE_CURRENT_A_2); // set Q-axis current to 0 gIdq_ref_pu[HAL_MTR2].value[1] = _IQ(0.0); // save encoder reading when forcing motor into alignment if(gUserParams[HAL_MTR2].motor_type == MOTOR_Type_Pm) { ENC_setZeroOffset(encHandle[HAL_MTR2], (uint32_t)(HAL_getQepPosnMaximum(halHandleMtr[HAL_MTR2]) - HAL_getQepPosnCounts(halHandleMtr[HAL_MTR2]))); } // if alignment counter exceeds threshold, exit alignment if(gAlignCount[HAL_MTR2]++ >= gUserParams[HAL_MTR2].ctrlWaitTime[CTRL_State_OffLine]) { gMotorVars[HAL_MTR2].Flag_enableAlignment = false; gAlignCount[HAL_MTR2] = 0; gIdq_ref_pu[HAL_MTR2].value[0] = _IQ(0.0); } } // Get the reference value for the d-axis current controller. refValue = gIdq_ref_pu[HAL_MTR2].value[0]; // Get the actual value of Id fbackValue = gIdq_pu[HAL_MTR2].value[0]; // The next instruction executes the PI current controller for the // d axis and places its output in Vdq_pu.value[0], which is the // control voltage along the d-axis (Vd) PID_run(pidHandle[HAL_MTR2][1],refValue,fbackValue,&(gVdq_out_pu[HAL_MTR2].value[0])); // get the Iq reference value refValue = gIdq_ref_pu[HAL_MTR2].value[1]; // get the actual value of Iq fbackValue = gIdq_pu[HAL_MTR2].value[1]; // The voltage limits on the output of the q-axis current controller // are dynamic, and are dependent on the output voltage from the d-axis // current controller. In other words, the d-axis current controller // gets first dibs on the available voltage, and the q-axis current // controller gets what's left over. That is why the d-axis current // controller executes first. The next instruction calculates the // maximum limits for this voltage as: // Vq_min_max = +/- sqrt(Vbus^2 - Vd^2) outMax_pu = _IQsqrt(_IQ(USER_MAX_VS_MAG_PU_2 * USER_MAX_VS_MAG_PU_2) - _IQmpy(gVdq_out_pu[HAL_MTR2].value[0],gVdq_out_pu[HAL_MTR2].value[0])); // Set the limits to +/- outMax_pu PID_setMinMax(pidHandle[HAL_MTR2][2],-outMax_pu,outMax_pu); // The next instruction executes the PI current controller for the // q axis and places its output in Vdq_pu.value[1], which is the // control voltage vector along the q-axis (Vq) PID_run(pidHandle[HAL_MTR2][2],refValue,fbackValue,&(gVdq_out_pu[HAL_MTR2].value[1])); // The voltage vector is now calculated and ready to be applied to the // motor in the form of three PWM signals. However, even though the // voltages may be supplied to the PWM module now, they won't be // applied to the motor until the next PWM cycle. By this point, the // motor will have moved away from the angle that the voltage vector // was calculated for, by an amount which is proportional to the // sampling frequency and the speed of the motor. For steady-state // speeds, we can calculate this angle delay and compensate for it. ANGLE_COMP_run(angleCompHandle[HAL_MTR2],speed_pu,angle_pu); angle_pu = ANGLE_COMP_getAngleComp_pu(angleCompHandle[HAL_MTR2]); // compute the sine and cosine phasor values which are part of the inverse // Park transform calculations. Once these values are computed, // they are copied into the IPARK module, which then uses them to // transform the voltages from DQ to Alpha/Beta reference frames. phasor.value[0] = _IQcosPU(angle_pu); phasor.value[1] = _IQsinPU(angle_pu); // set the phasor in the inverse Park transform IPARK_setPhasor(iparkHandle[HAL_MTR2],&phasor); // Run the inverse Park module. This converts the voltage vector from // synchronous frame values to stationary frame values. IPARK_run(iparkHandle[HAL_MTR2],&gVdq_out_pu[HAL_MTR2],&Vab_pu); // These 3 statements compensate for variations in the DC bus by adjusting the // PWM duty cycle. The goal is to achieve the same volt-second product // regardless of the DC bus value. To do this, we must divide the desired voltage // values by the DC bus value. Or...it is easier to multiply by 1/(DC bus value). oneOverDcBus = _IQdiv(_IQ(1.0), gAdcData[HAL_MTR2].dcBus); Vab_pu.value[0] = _IQmpy(Vab_pu.value[0],oneOverDcBus); Vab_pu.value[1] = _IQmpy(Vab_pu.value[1],oneOverDcBus); // Now run the space vector generator (SVGEN) module. // There is no need to do an inverse CLARKE transform, as this is // handled in the SVGEN_run function. SVGEN_run(svgenHandle[HAL_MTR2],&Vab_pu,&(gPwmData[HAL_MTR2].Tabc)); } else if(gMotorVars[HAL_MTR2].Flag_enableOffsetcalc == true) { runOffsetsCalculation(HAL_MTR2); } else // gMotorVars.Flag_Run_Identify = 0 { // disable the PWM HAL_disablePwm(halHandleMtr[HAL_MTR2]); // Set the PWMs to 50% duty cycle gPwmData[HAL_MTR2].Tabc.value[0] = _IQ(0.0); gPwmData[HAL_MTR2].Tabc.value[1] = _IQ(0.0); gPwmData[HAL_MTR2].Tabc.value[2] = _IQ(0.0); } // write to the PWM compare registers, and then we are done! HAL_writePwmData(halHandleMtr[HAL_MTR2],&gPwmData[HAL_MTR2]); HAL_setGpioLow(halHandle,GPIO_Number_20); return; } // end of motor2_ISR() function void pidSetup(HAL_MtrSelect_e mtrNum) { // This equation uses the scaled maximum voltage vector, which is // already in per units, hence there is no need to include the #define // for USER_IQ_FULL_SCALE_VOLTAGE_V _iq maxVoltage_pu = _IQ(gUserParams[mtrNum].maxVsMag_pu * gUserParams[mtrNum].voltage_sf); float_t fullScaleCurrent = gUserParams[mtrNum].iqFullScaleCurrent_A; float_t fullScaleVoltage = gUserParams[mtrNum].iqFullScaleVoltage_V; float_t IsrPeriod_sec = 1.0e-6 * gUserParams[mtrNum].pwmPeriod_usec * gUserParams[mtrNum].numPwmTicksPerIsrTick; float_t Ls_d = gUserParams[mtrNum].motor_Ls_d; float_t Ls_q = gUserParams[mtrNum].motor_Ls_q; float_t Rs = gUserParams[mtrNum].motor_Rs; // This lab assumes that motor parameters are known, and it does not // perform motor ID, so the R/L parameters are known and defined in // user.h float_t RoverLs_d = Rs / Ls_d; float_t RoverLs_q = Rs / Ls_q; // For the current controller, Kp = Ls*bandwidth(rad/sec) But in order // to be used, it must be converted to per unit values by multiplying // by fullScaleCurrent and then dividing by fullScaleVoltage. From the // statement below, we see that the bandwidth in rad/sec is equal to // 0.25/IsrPeriod_sec, which is equal to USER_ISR_FREQ_HZ/4. This means // that by setting Kp as described below, the bandwidth in Hz is // USER_ISR_FREQ_HZ/(8*pi). _iq Kp_Id = _IQ((0.25 * Ls_d * fullScaleCurrent) / (IsrPeriod_sec * fullScaleVoltage)); // In order to achieve pole/zero cancellation (which reduces the // closed-loop transfer function from a second-order system to a // first-order system), Ki must equal Rs/Ls. Since the output of the // Ki gain stage is integrated by a DIGITAL integrator, the integrator // input must be scaled by 1/IsrPeriod_sec. That's just the way // digital integrators work. But, since IsrPeriod_sec is a constant, // we can save an additional multiplication operation by lumping this // term with the Ki value. _iq Ki_Id = _IQ(RoverLs_d * IsrPeriod_sec); // Now do the same thing for Kp for the q-axis current controller. // If the motor is not an IPM motor, Ld and Lq are the same, which // means that Kp_Iq = Kp_Id _iq Kp_Iq = _IQ((0.25 * Ls_q * fullScaleCurrent) / (IsrPeriod_sec * fullScaleVoltage)); // Do the same thing for Ki for the q-axis current controller. If the // motor is not an IPM motor, Ld and Lq are the same, which means that // Ki_Iq = Ki_Id. _iq Ki_Iq = _IQ(RoverLs_q * IsrPeriod_sec); // There are two PI controllers; two current // controllers. Each PI controller has two coefficients; Kp and Ki. // So you have a total of four coefficients that must be defined. // This is for the Id current controller pidHandle[mtrNum][1] = PID_init(&pid[mtrNum][1],sizeof(pid[mtrNum][1])); // This is for the Iq current controller pidHandle[mtrNum][2] = PID_init(&pid[mtrNum][2],sizeof(pid[mtrNum][2])); stCntPosition[mtrNum] = 0; // Set the counter for decimating the speed // controller to 0 // The following instructions load the parameters for the d-axis // current controller. // P term = Kp_Id, I term = Ki_Id, D term = 0 PID_setGains(pidHandle[mtrNum][1],Kp_Id,Ki_Id,_IQ(0.0)); // Largest negative voltage = -maxVoltage_pu, largest positive // voltage = maxVoltage_pu PID_setMinMax(pidHandle[mtrNum][1],-maxVoltage_pu,maxVoltage_pu); // Set the initial condition value for the integrator output to 0 PID_setUi(pidHandle[mtrNum][1],_IQ(0.0)); // The following instructions load the parameters for the q-axis // current controller. // P term = Kp_Iq, I term = Ki_Iq, D term = 0 PID_setGains(pidHandle[mtrNum][2],Kp_Iq,Ki_Iq,_IQ(0.0)); // The largest negative voltage = 0 and the largest positive // voltage = 0. But these limits are updated every single ISR before // actually executing the Iq controller. The limits depend on how much // voltage is left over after the Id controller executes. So having an // initial value of 0 does not affect Iq current controller execution. PID_setMinMax(pidHandle[mtrNum][2],_IQ(0.0),_IQ(0.0)); // Set the initial condition value for the integrator output to 0 PID_setUi(pidHandle[mtrNum][2],_IQ(0.0)); } void runOffsetsCalculation(HAL_MtrSelect_e mtrNum) { uint16_t cnt; // enable the PWM HAL_enablePwm(halHandleMtr[mtrNum]); for(cnt=0;cnt<3;cnt++) { // Set the PWMs to 50% duty cycle gPwmData[mtrNum].Tabc.value[cnt] = _IQ(0.0); // reset offsets used gOffsets_I_pu[mtrNum].value[cnt] = _IQ(0.0); gOffsets_V_pu[mtrNum].value[cnt] = _IQ(0.0); // run offset estimation FILTER_FO_run(filterHandle[mtrNum][cnt],gAdcData[mtrNum].I.value[cnt]); FILTER_FO_run(filterHandle[mtrNum][cnt+3],gAdcData[mtrNum].V.value[cnt]); } if(gOffsetCalcCount[mtrNum]++ >= gUserParams[mtrNum].ctrlWaitTime[CTRL_State_OffLine]) { gMotorVars[mtrNum].Flag_enableOffsetcalc = false; gOffsetCalcCount[mtrNum] = 0; for(cnt=0;cnt<3;cnt++) { // get calculated offsets from filter gOffsets_I_pu[mtrNum].value[cnt] = FILTER_FO_get_y1(filterHandle[mtrNum][cnt]); gOffsets_V_pu[mtrNum].value[cnt] = FILTER_FO_get_y1(filterHandle[mtrNum][cnt+3]); // clear filters FILTER_FO_setInitialConditions(filterHandle[mtrNum][cnt],_IQ(0.0),_IQ(0.0)); FILTER_FO_setInitialConditions(filterHandle[mtrNum][cnt+3],_IQ(0.0),_IQ(0.0)); } } return; } // end of runOffsetsCalculation() function //! \brief Call this function to fix 1p6. This is only used for F2806xF/M //! \brief implementation of InstaSPIN (version 1.6 of ROM) since the //! \brief inductance calculation is not done correctly in ROM, so this //! \brief function fixes that ROM bug. void softwareUpdate1p6(EST_Handle handle,USER_Params *pUserParams) { float_t iqFullScaleVoltage_V = pUserParams->iqFullScaleVoltage_V; float_t iqFullScaleCurrent_A = pUserParams->iqFullScaleCurrent_A; float_t voltageFilterPole_rps = pUserParams->voltageFilterPole_rps; float_t motorLs_d = pUserParams->motor_Ls_d; float_t motorLs_q = pUserParams->motor_Ls_q; float_t fullScaleInductance = iqFullScaleVoltage_V / (iqFullScaleCurrent_A * voltageFilterPole_rps); float_t Ls_coarse_max = _IQ30toF(EST_getLs_coarse_max_pu(handle)); int_least8_t lShift = ceil(log(motorLs_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(motorLs_d / L_max); _iq Ls_q_pu = _IQ30(motorLs_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); } // In other words, the only acceptable number of voltage sensors is three. // 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, const uint_least8_t mtrNum) { uint32_t profile_mticks, profile_ticks; // get the speed estimate gMotorVars[mtrNum].Speed_krpm = _IQmpy(STPOSCONV_getVelocityFiltered(st_obj[mtrNum].posConvHandle), gSpeed_pu_to_krpm_sf[mtrNum]); // Get the DC buss voltage gMotorVars[mtrNum].VdcBus_kV = _IQmpy(gAdcData[mtrNum].dcBus, _IQ(gUserParams[mtrNum].iqFullScaleVoltage_V / 1000.0)); // read Vd and Vq vectors per units gMotorVars[mtrNum].Vd = gVdq_out_pu[mtrNum].value[0]; gMotorVars[mtrNum].Vq = gVdq_out_pu[mtrNum].value[1]; // calculate vector Vs in per units: (Vs = sqrt(Vd^2 + Vq^2)) gMotorVars[mtrNum].Vs = _IQsqrt(_IQmpy(gMotorVars[mtrNum].Vd,gMotorVars[mtrNum].Vd) + _IQmpy(gMotorVars[mtrNum].Vq,gMotorVars[mtrNum].Vq)); // read Id and Iq vectors in amps gMotorVars[mtrNum].Id_A = _IQmpy(gIdq_pu[mtrNum].value[0], _IQ(gUserParams[mtrNum].iqFullScaleCurrent_A)); gMotorVars[mtrNum].Iq_A = _IQmpy(gIdq_pu[mtrNum].value[1], _IQ(gUserParams[mtrNum].iqFullScaleCurrent_A)); // calculate vector Is in amps: (Is_A = sqrt(Id_A^2 + Iq_A^2)) gMotorVars[mtrNum].Is_A = _IQsqrt(_IQmpy(gMotorVars[mtrNum].Id_A,gMotorVars[mtrNum].Id_A) + _IQmpy(gMotorVars[mtrNum].Iq_A,gMotorVars[mtrNum].Iq_A)); // gets the Position Controller status gMotorVars[mtrNum].SpinTAC.PosCtlStatus = STPOSCTL_getStatus(st_obj[mtrNum].posCtlHandle); // get the inertia setting gMotorVars[mtrNum].SpinTAC.InertiaEstimate_Aperkrpm = _IQmpy(STPOSCTL_getInertia(st_obj[mtrNum].posCtlHandle), _IQ(((float_t)gUserParams[mtrNum].motor_numPolePairs / (0.001 * 60.0 * gUserParams[mtrNum].iqFullScaleFreq_Hz)) * gUserParams[mtrNum].iqFullScaleCurrent_A)); // get the friction setting gMotorVars[mtrNum].SpinTAC.FrictionEstimate_Aperkrpm = _IQmpy(STPOSCTL_getFriction(st_obj[mtrNum].posCtlHandle), _IQ(((float_t)gUserParams[mtrNum].motor_numPolePairs / (0.001 * 60.0 * gUserParams[mtrNum].iqFullScaleFreq_Hz)) * gUserParams[mtrNum].iqFullScaleCurrent_A)); // get the Position Controller error gMotorVars[mtrNum].SpinTAC.PosCtlErrorID = STPOSCTL_getErrorID(st_obj[mtrNum].posCtlHandle); // get the Position Move status gMotorVars[mtrNum].SpinTAC.PosMoveStatus = STPOSMOVE_getStatus(st_obj[mtrNum].posMoveHandle); // get the Position Move profile time STPOSMOVE_getProfileTime_tick(st_obj[mtrNum].posMoveHandle, &profile_mticks, &profile_ticks); gMotorVars[mtrNum].SpinTAC.PosMoveTime_mticks = profile_mticks; gMotorVars[mtrNum].SpinTAC.PosMoveTime_ticks = profile_ticks; // get the Position Move error gMotorVars[mtrNum].SpinTAC.PosMoveErrorID = STPOSMOVE_getErrorID(st_obj[mtrNum].posMoveHandle); // get the Position Converter error gMotorVars[mtrNum].SpinTAC.PosConvErrorID = STPOSCONV_getErrorID(st_obj[mtrNum].posConvHandle); return; } // end of updateGlobalVariables() function void ST_runPosConv(ST_Handle handle, ENC_Handle encHandle, SLIP_Handle slipHandle, MATH_vec2 *Idq_pu, MOTOR_Type_e motorType) { ST_Obj *stObj = (ST_Obj *)handle; // get the electrical angle from the ENC module STPOSCONV_setElecAngle_erev(stObj->posConvHandle, ENC_getElecAngle(encHandle)); if(motorType == MOTOR_Type_Induction) { // The CurrentVector feedback is only needed for ACIM // get the vector of the direct/quadrature current input vector values from CTRL STPOSCONV_setCurrentVector(stObj->posConvHandle, Idq_pu); } // run the SpinTAC Position Converter STPOSCONV_run(stObj->posConvHandle); if(motorType == MOTOR_Type_Induction) { // The Slip Velocity is only needed for ACIM // update the slip velocity in electrical angle per second, Q24 SLIP_setSlipVelocity(slipHandle, STPOSCONV_getSlipVelocity(stObj->posConvHandle)); } } _iq ST_runPosCtl(ST_Handle handle) { _iq iqReference; ST_Obj *stObj = (ST_Obj *)handle; // provide the updated references to the SpinTAC Position Control STPOSCTL_setPositionReference_mrev(stObj->posCtlHandle, STPOSMOVE_getPositionReference_mrev(stObj->posMoveHandle)); STPOSCTL_setVelocityReference(stObj->posCtlHandle, STPOSMOVE_getVelocityReference(stObj->posMoveHandle)); STPOSCTL_setAccelerationReference(stObj->posCtlHandle, STPOSMOVE_getAccelerationReference(stObj->posMoveHandle)); // provide the feedback to the SpinTAC Position Control STPOSCTL_setPositionFeedback_mrev(stObj->posCtlHandle, STPOSCONV_getPosition_mrev(stObj->posConvHandle)); // Run SpinTAC Position Control STPOSCTL_run(stObj->posCtlHandle); // Provide SpinTAC Position Control Torque Output to the FOC iqReference = STPOSCTL_getTorqueReference(stObj->posCtlHandle); return iqReference; } interrupt void QEP_Index_ISR(void) // Funci�n que se encarga de llevar a cero grados los rotores { HAL_Obj_mtr *obj_mtr = (HAL_Obj_mtr *)halHandle; HAL_Obj *obj = (HAL_Obj *)halHandle; // QEP_Obj *qep = (QEP_Obj *)obj_mtr->qepHandle; // Limpiar el "interrupt flag" QEP_clear_interrupt_flag(obj_mtr->qepHandle, QEINT_Iel); // Acknowledge interrupt from PIE group 5 PIE_clearInt(obj->pieHandle,PIE_GroupNumber_5); gIndexOcurre++; return; }
interrupt void QEP_Index_ISR(void); short gIndexOcurre = 0; //counter of interruptions void main(void) { // setup the encoder module ENC_setup(encHandle[HAL_MTR1], 1, USER_MOTOR_NUM_POLE_PAIRS, USER_MOTOR_ENCODER_LINES, 0, USER_IQ_FULL_SCALE_FREQ_Hz, USER_ISR_FREQ_Hz, 8000.0); ENC_setup(encHandle[HAL_MTR2], 1, USER_MOTOR_NUM_POLE_PAIRS_2, USER_MOTOR_ENCODER_LINES_2, 0, USER_IQ_FULL_SCALE_FREQ_Hz_2, USER_ISR_FREQ_Hz_2, 8000.0); /// M C >>>>>>>>>>>>> HAL_Obj_mtr *obj_mtr = (HAL_Obj_mtr *)halHandle; HAL_Obj *obj = (HAL_Obj *)halHandle; obj_mtr = (HAL_Obj_mtr *)halHandle; // QEP_Obj *qep = (QEP_Obj *)obj_mtr->qepHandle; QEP_clear_all_interrupt_flags(obj_mtr->qepHandle); // Limpiar todas las banderas de interrupción QEP_disable_all_interrupts(obj_mtr->qepHandle); // Deshabilitar todas las interrupciones PIE_enableInt( obj->pieHandle, PIE_GroupNumber_5, PIE_InterruptSource_EQEP1 ); //Grupo 5 donde se encuentra la interrupcion de EQEP1 QEP_enable_interrupt(obj_mtr->qepHandle, QEINT_Iel); //Habilitar el bit de interrupción correspondiente al pulso de Index CPU_enableInt(obj->cpuHandle,CPU_IntNumber_5); //Habilitar el grupo 5 en las interrupciones de la CPU /// M C >>>>>>>>>>>>> //>>>> Configuracion de la interrupcion del index <<<<<<<<<<<<// PIE_Obj *pie = (PIE_Obj *)obj->pieHandle; ENABLE_PROTECTED_REGISTER_WRITE_MODE; pie->EQEP1_INT = &QEP_Index_ISR; DISABLE_PROTECTED_REGISTER_WRITE_MODE; //>>>> Configuracion de la interrupcion del index <<<<<<<<<<<<// // enable the ADC interrupts HAL_enableAdcInts(halHandle); // enable global interrupts HAL_enableGlobalInts(halHandle); // enable debug interrupts HAL_enableDebugInt(halHandle); // disable the PWM HAL_disablePwm(halHandleMtr[HAL_MTR1]); HAL_disablePwm(halHandleMtr[HAL_MTR2]); }
interrupt void QEP_Index_ISR(void) //Interruption function at the end of the file { HAL_Obj_mtr *obj_mtr = (HAL_Obj_mtr *)halHandle; HAL_Obj *obj = (HAL_Obj *)halHandle; // QEP_Obj *qep = (QEP_Obj *)obj_mtr->qepHandle; // Limpiar el "interrupt flag" QEP_clear_interrupt_flag(obj_mtr->qepHandle, QEINT_Iel); // Acknowledge interrupt from PIE group 5 PIE_clearInt(obj->pieHandle,PIE_GroupNumber_5); gIndexOcurre++; return; }