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.
Tool/software: Code Composer Studio
Hi,
I am trying to use a symmetric HRPWM (up/down) and I have modified the HRPWM_PrdUpDown_SFO_V8.c example to test it.
The example seams to run fine, but there are some circumstances in which the duty cycle "jumps" and then goes "back". This nonlinear behavior can be founded for example at 50% (by setting DutyFine=16383 and then changing the value to 16384 and finally 16385). At duty =16384 the PWM jumps and then at duty=16385 goes back.
Is this behavior normal? Is the PWM correctly configured for this purpose (symmetrical pwm)?
Thank you,
//########################################################################### // // FILE: HRPWM_Duty_SFO_V8.c // // TITLE: F2837xD Device HRPWM SFO V8 High-Resolution Period // (Up-Down Count) example // // ASSUMPTIONS: // // $Boot_Table: // // $End_Boot_Table // //! \addtogroup cpu01_example_list //! <h1> HRPWM SFO Test (hrpwm_duty_sfo_v8)</h1> //! This program requires the F2837xD header files, which include //! the following files required for this example: //! SFO_V8.h and SFO_TI_Build_V8_FPU.lib //! //! Monitor ePWM1-ePWM8 A/B pins on an oscilloscope. //! DESCRIPTION: //! //! This example modifies the MEP control registers to show edge displacement //! for high-resolution period with ePWM in Up-Down count mode //! due to the HRPWM control extension of the respective ePWM module. //! //! This example calls the following TI's MEP Scale Factor Optimizer (SFO) //! software library V8 functions: //! //! //! \b int \b SFO(); \n //! updates MEP_ScaleFactor dynamically when HRPWM is in use //! updates HRMSTEP register (exists only in EPwm1Regs register space) //! with MEP_ScaleFactor value //! - returns 2 if error: MEP_ScaleFactor is greater than maximum value of 255 //! (Auto-conversion may not function properly under this condition) //! - returns 1 when complete for the specified channel //! - returns 0 if not complete for the specified channel //! //! This example is intended to explain the HRPWM capabilities. The code can be //! optimized for code efficiency. Refer to TI's Digital power application //! examples and TI Digital Power Supply software libraries for details. //! //! All ePWM1 -7 all channels will have fine //! edge movement due to the HRPWM logic //! //! ======================================================================= //! NOTE: For more information on using the SFO software library, see the //! F2837xD High-Resolution Pulse Width Modulator (HRPWM) Reference Guide //! ======================================================================= //! //! To load and run this example: //! -# **!!IMPORTANT!!** - in SFO_V8.h, set PWM_CH to the max number of //! HRPWM channels plus one. For example, for the F2837xD, the //! maximum number of HRPWM channels is 8. 8+1=9, so set //! #define PWM_CH 9 in SFO_V8.h. (Default is 8) //! -# Run this example at maximum SYSCLKOUT //! -# Activate Real time mode //! -# Run the code //! -# Watch ePWM A / B channel waveforms on a Oscilloscope //! -# In the watch window: //! Set the variable UpdateFine = 1 to observe the ePWMxA & ePWMxB output //! with HRPWM capabilities (default) //! Observe the period/frequency of the waveform changes in fine MEP steps //! -# In the watch window: //! Change the variable UpdateFine to 0, to observe the //! ePWMxA & ePWMxB output without HRPWM capabilities //! Observe the period/frequency of the waveform changes in coarse SYSCLKOUT cycle steps. // //########################################################################### // $TI Release: F2837xD Support Library v190 $ // $Release Date: Mon Feb 1 16:51:57 CST 2016 $ // $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated - // http://www.ti.com/ ALL RIGHTS RESERVED $ //########################################################################### #include "F28x_Project.h" // Device Headerfile and Examples Include File #include "SFO_V8.h" #define PWM_CH 9 // # of PWM channels #define STATUS_SUCCESS 1 #define STATUS_FAIL 0 #define AUTOCONVERT 1 // 1 = Turn auto-conversion ON, 0 = Turn auto-conversion OFF // Declare your function prototypes here //--------------------------------------------------------------- void HRPWM_Config(int); void error(void); // General System variables - useful for debug Uint16 UpdateFine, DutyFine, status, CMPA_reg_val, CMPAHR_reg_val, CMPB_reg_val, CMPBHR_reg_val; int Updatedir=1; int counter=0; int timeS=2500; //==================================================================== // The following declarations are required in order to use the SFO // library functions: // int MEP_ScaleFactor; // Global variable used by the SFO library // Result can be used for all HRPWM channels // This variable is also copied to HRMSTEP // register by SFO() function. // Array of pointers to EPwm register structures: // *ePWM[0] is defined as dummy value not used in the example volatile struct EPWM_REGS *ePWM[PWM_CH] = { &EPwm1Regs, &EPwm1Regs, &EPwm2Regs, &EPwm3Regs, &EPwm4Regs, &EPwm5Regs, &EPwm6Regs, &EPwm7Regs, &EPwm8Regs}; void main(void) { // Local variables int i; Uint32 temp, temp1; EALLOW; // Step 1. Initialize System Control for Control and Analog Subsystems // Enable Peripheral Clocks // This example function is found in the F2837xD_SysCtrl.c file. InitSysCtrl(); EDIS; // Step 2. Initialize GPIO: // This example function is found in the F2837xD_Gpio.c file and // illustrates how to set the GPIO to it's default state. // InitGpio(); // Skipped for this example InitEPwmGpio(); // EPWM1A EPWM1B through EPWM9 DINT; // Disable CPU interrupts // Initialize PIE control registers to their default state. // The default state is all PIE interrupts disabled and flags // are cleared. // This function is found in the F2837xD_PieCtrl.c file. InitPieCtrl(); // Disable CPU interrupts and clear all CPU interrupt flags: EALLOW; IER = 0x0000; IFR = 0x0000; // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // This will populate the entire table, even if the interrupt // is not used in this example. This is useful for debug purposes. // The shell ISR routines are found in F2837xD_DefaultIsr.c. // This function is found in F2837xD_PieVect.c. InitPieVectTable(); // For this example, only initialize the ePWM // Step 5. User specific code, enable interrupts: UpdateFine = 1; DutyFine = 0; status = SFO_INCOMPLETE; // Enable global Interrupts and higher priority real-time debug events: EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM // Calling SFO() updates the HRMSTEP register with calibrated MEP_ScaleFactor. // HRMSTEP must be populated with a scale factor value prior to enabling // high resolution period control. while (status== SFO_INCOMPLETE){ // Call until complete status = SFO(); if (status == SFO_ERROR) { error(); // SFO function returns 2 if an error occurs & # of MEP steps/coarse step } // exceeds maximum of 255. } //==================================================================== // ePWM and HRPWM register initialization //==================================================================== EALLOW; HRPWM_Config(1000); // ePWMx target for(;;) { // Sweep DutyFine as a Q15 number from 0.2 - 0.999 for(;;)//DutyFine = 0x2300; DutyFine < 0x7000; DutyFine++) { if(UpdateFine) { /* all below calculation apply for CMPB as well // CMPA_reg_val , CMPA_reg_val is calculated as a Q0. // Since DutyFine is a Q15 number, and the period is Q0 // the product is Q15. So to store as a Q0, we shift right // 15 bits. CMPA_reg_val = ((long)DutyFine * EPwm1Regs.TBPRD)>>15; // This next step is to obtain the remainder which was // truncated during our 15 bit shift above. // compute the whole value, and then subtract CMPA_reg_val // shifted LEFT 15 bits: temp = ((long)DutyFine * EPwm1Regs.TBPRD) ; temp = temp - ((long)CMPA_reg_val<<15); ** If auto-conversion is disabled, the following step can be skipped. // If autoconversion is enabled, the SFO function will write // the MEP_ScaleFactor to the HRMSTEP register and the hardware // will automatically scale the remainder in the CMPAHR register // by the MEP_ScaleFactor. // Because the remainder calculated above (temp) is in Q15 format, // it must be shifted left by 1 to convert to Q16 format for the // hardware to properly convert. CMPAHR_reg_val = temp<<1; ** If auto-conversion is enabled, the following step is performed automatically in hardware and can be skipped // This obtains the MEP count in digits, from // 0,1, .... MEP_Scalefactor. // 0x0080 (0.5 in Q8) is converted to 0.5 in Q15 by shifting left 7. // This is added to fractional duty*MEP_SF product in order to round // the decimal portion of the product up to the next integer if the decimal // portion is >=0.5. // //Once again since this is Q15 // convert to Q0 by shifting: CMPAHR_reg_val = (temp*MEP_ScaleFactor+(0x0080<<7))>>15; ** If auto-conversion is enabled, the following step is performed automatically in hardware and can be skipped // Now the lower 8 bits contain the MEP count. // Since the MEP count needs to be in the upper 8 bits of // the 16 bit CMPAHR register, shift left by 8. CMPAHR_reg_val = CMPAHR_reg_val << 8; ** If auto-conversion is enabled, the following step is performed automatically in hardware and can be skipped // Add the offset and rounding CMPAHR_reg_val += 0x0080; // Write the values to the registers as one 32-bit or two 16-bits EPwm1Regs.CMPA.bit.CMPA = CMPA_reg_val; EPwm1Regs.CMPA.bit.CMPAHR = CMPAHR_reg_val; */ // All the above operations may be condensed into // the following form: // EPWM1 calculations for(i=1;i<PWM_CH;i++) { CMPA_reg_val = ((long)DutyFine * (*ePWM[i]).TBPRD)>>15; CMPB_reg_val = ((long)DutyFine * (*ePWM[i]).TBPRD)>>15; temp = ((long)DutyFine * (*ePWM[i]).TBPRD) ; temp1 = ((long)DutyFine * (*ePWM[i]).TBPRD) ; temp = temp - ((long)CMPA_reg_val<<15); temp1 = temp1 - ((long)CMPB_reg_val<<15); #if (AUTOCONVERT) CMPAHR_reg_val = temp<<1; // convert to Q16 CMPBHR_reg_val = temp<<1; // convert to Q16 #else CMPAHR_reg_val = ((temp*MEP_ScaleFactor)+(0x0080<<7))>>15; CMPAHR_reg_val = CMPAHR_reg_val << 8; CMPBHR_reg_val = ((temp1*MEP_ScaleFactor)+(0x0080<<7))>>15; CMPBHR_reg_val = CMPBHR_reg_val << 8; #endif // Example for a 32 bit write to CMPA:CMPAHR (*ePWM[i]).CMPA.all = ((long)CMPA_reg_val)<<16 | CMPAHR_reg_val; // loses lower 8-bits // Example for a 32 bit write to CMPB:CMPBHR (*ePWM[i]).CMPB.all = ((long)CMPB_reg_val)<<16 | CMPBHR_reg_val; // loses lower 8-bits } } else { // CMPA_reg_val is calculated as a Q0. // Since DutyFine is a Q15 number, and the period is Q0 // the product is Q15. So to store as a Q0, we shift right // 15 bits. for(i=1;i<PWM_CH;i++) { (*ePWM[i]).CMPA.bit.CMPA = ((long)DutyFine * (*ePWM[i]).TBPRD>>15); (*ePWM[i]).CMPB.bit.CMPB = ((long)DutyFine * (*ePWM[i]).TBPRD>>15); } } // Call the scale factor optimizer lib function SFO() // periodically to track for any change due to temp/voltage. // This function generates MEP_ScaleFactor by running the // MEP calibration module in the HRPWM logic. This scale // factor can be used for all HRPWM channels. The SFO() // function also updates the HRMSTEP register with the // scale factor value. status = SFO(); // in background, MEP calibration module continuously updates MEP_ScaleFactor if (status == SFO_ERROR) { error(); // SFO function returns 2 if an error occurs & # of MEP steps/coarse step } // exceeds maximum of 255. counter++; if(counter>timeS){ counter=0; DutyFine=DutyFine+Updatedir; if(DutyFine>32768){Updatedir=-1;} if(DutyFine==0){Updatedir=1;} } } // end DutyFine for loop } // end infinite for loop } // end main //============================================================= // FUNCTION: HRPWM_Config // DESCRIPTION: Configures all ePWM channels and sets up HRPWM // on ePWMxA / ePWMxB channels // // PARAMETERS: period - desired PWM period in TBCLK counts // RETURN: N/A //============================================================= /* void HRPWM_Config(period) { Uint16 j; // ePWM channel register configuration with HRPWM // ePWMxA / ePWMxB toggle low/high with MEP control on Rising edge CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0; for (j=1;j<PWM_CH;j++) { (*ePWM[j]).TBCTL.bit.PRDLD = TB_SHADOW; // set Immediate load (*ePWM[j]).TBPRD = (period-1)/2; // PWM frequency = 1 / period (*ePWM[j]).CMPA.bit.CMPA = period / 2; // set duty 50% initially (*ePWM[j]).CMPA.bit.CMPAHR = (1 << 8); // initialize HRPWM extension (*ePWM[j]).CMPB.bit.CMPB = period / 2; // set duty 50% initially (*ePWM[j]).CMPB.all |= (1 << 8); // initialize HRPWM extension (*ePWM[j]).TBPHS.all = 0; (*ePWM[j]).TBCTR = 0; (*ePWM[j]).TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; (*ePWM[j]).TBCTL.bit.PHSEN = TB_DISABLE; (*ePWM[j]).TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; (*ePWM[j]).TBCTL.bit.HSPCLKDIV = TB_DIV1; (*ePWM[j]).TBCTL.bit.CLKDIV = TB_DIV1; (*ePWM[j]).TBCTL.bit.FREE_SOFT = 11; (*ePWM[j]).CMPCTL.bit.LOADAMODE = CC_CTR_ZERO_PRD; (*ePWM[j]).CMPCTL.bit.LOADBMODE = CC_CTR_ZERO_PRD; (*ePWM[j]).CMPCTL.bit.SHDWAMODE = CC_SHADOW; (*ePWM[j]).CMPCTL.bit.SHDWBMODE = CC_SHADOW; (*ePWM[j]).AQCTLA.all=0x090; (*ePWM[j]).AQCTLB.all=0x900; (*ePWM[j]).DBCTL.all = 0b101011 ; (*ePWM[j]).DBRED.all = 20; (*ePWM[j]).DBFED.all = 20; // // Write to PWM1 GLDCTL2 will result in simultaneous write to PWM2 GLDCTL2 // (*ePWM[j]).DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; (*ePWM[j]).DBCTL.bit.POLSEL = DB_ACTV_HIC; (*ePWM[j]).DBCTL.bit.IN_MODE = DBA_ALL; (*ePWM[j]).DBCTL.bit.SHDWDBREDMODE = 1; (*ePWM[j]).DBCTL.bit.SHDWDBFEDMODE = 1; (*ePWM[j]).DBCTL.bit.LOADREDMODE = 0; // Load on Counter == 0 (*ePWM[j]).DBCTL.bit.LOADFEDMODE = 0; // Load on Counter == 0 (*ePWM[j]).DBCTL.bit.HALFCYCLE = 1; //(*ePWM[j]).DBCTL.all = 0b101011 ; (*ePWM[j]).DBRED.bit.DBRED = 20*2; (*ePWM[j]).DBFED.bit.DBFED = 20*2; (*ePWM[j]).DBREDHR.bit.DBREDHR = 0x0; (*ePWM[j]).DBFEDHR.bit.DBFEDHR = 0x0; (*ePWM[j]).HRCNFG2.bit.EDGMODEDB = HR_BEP; // DBREDHR and DBFEDHR (*ePWM[j]).HRCNFG2.bit.CTLMODEDBRED = 0; // Load on ZRO (*ePWM[j]).HRCNFG2.bit.CTLMODEDBFED = 0; // Load on ZRO (*ePWM[j]).DBREDHR.bit.DBREDHR = (0 << 9); EALLOW; (*ePWM[j]).HRCNFG.all = 0x0; (*ePWM[j]).HRCNFG.bit.EDGMODE = HR_BEP; // MEP control on falling edge (*ePWM[j]).HRCNFG.bit.CTLMODE = HR_CMP; (*ePWM[j]).HRCNFG.bit.HRLOAD = HR_CTR_ZERO_PRD; (*ePWM[j]).HRCNFG.bit.EDGMODEB = HR_BEP; // MEP control on falling edge (*ePWM[j]).HRCNFG.bit.CTLMODEB = HR_CMP; (*ePWM[j]).HRCNFG.bit.HRLOADB = HR_CTR_ZERO_PRD; #if (AUTOCONVERT) (*ePWM[j]).HRCNFG.bit.AUTOCONV = 1; // Enable auto-conversion logic #endif (*ePWM[j]).HRPCTL.bit.TBPHSHRLOADE=0; (*ePWM[j]).TBCTL.bit.PHSEN=0; (*ePWM[j]).HRPCTL.bit.HRPE = 1; // Turn off high-resolution period control. //(*ePWM[1]).TBCTL.bit.SYNCOSEL=1; //(*ePWM[j]).TBCTL.bit.SWFSYNC=1; } CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; EDIS; } */ void HRPWM_Config(period) { Uint16 j; // ePWM channel register configuration with HRPWM // ePWMxA / ePWMxB toggle low/high with MEP control on Rising edge for (j=1;j<PWM_CH;j++) { (*ePWM[j]).TBCTL.bit.PRDLD = TB_SHADOW; // set Immediate load (*ePWM[j]).TBPRD = period-1; // PWM frequency = 1 / period (*ePWM[j]).CMPA.bit.CMPA = period / 2; // set duty 50% initially (*ePWM[j]).CMPA.bit.CMPAHR = (1 << 8); // initialize HRPWM extension (*ePWM[j]).CMPB.bit.CMPB = period / 2; // set duty 50% initially (*ePWM[j]).CMPB.all |= (1 << 8); // initialize HRPWM extension (*ePWM[j]).TBPHS.all = 0; (*ePWM[j]).TBCTR = 0; (*ePWM[j]).TBCTL.bit.CTRMODE = TB_COUNT_UP; (*ePWM[j]).TBCTL.bit.PHSEN = TB_DISABLE; (*ePWM[j]).TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; (*ePWM[j]).TBCTL.bit.HSPCLKDIV = TB_DIV1; (*ePWM[j]).TBCTL.bit.CLKDIV = TB_DIV1; (*ePWM[j]).TBCTL.bit.FREE_SOFT = 11; (*ePWM[j]).CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; (*ePWM[j]).CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; (*ePWM[j]).CMPCTL.bit.SHDWAMODE = CC_SHADOW; (*ePWM[j]).CMPCTL.bit.SHDWBMODE = CC_SHADOW; (*ePWM[j]).AQCTLA.bit.ZRO = AQ_SET; // PWM toggle high/low (*ePWM[j]).AQCTLA.bit.CAU = AQ_CLEAR; (*ePWM[j]).AQCTLB.bit.ZRO = AQ_SET; (*ePWM[j]).AQCTLB.bit.CBU = AQ_CLEAR; EALLOW; (*ePWM[j]).HRCNFG.all = 0x0; (*ePWM[j]).HRCNFG.bit.EDGMODE = HR_FEP; // MEP control on falling edge (*ePWM[j]).HRCNFG.bit.CTLMODE = HR_CMP; (*ePWM[j]).HRCNFG.bit.HRLOAD = HR_CTR_ZERO; (*ePWM[j]).HRCNFG.bit.EDGMODEB = HR_FEP; // MEP control on falling edge (*ePWM[j]).HRCNFG.bit.CTLMODEB = HR_CMP; (*ePWM[j]).HRCNFG.bit.HRLOADB = HR_CTR_ZERO; #if (AUTOCONVERT) (*ePWM[j]).HRCNFG.bit.AUTOCONV = 1; // Enable auto-conversion logic #endif (*ePWM[j]).HRPCTL.bit.HRPE = 0; // Turn off high-resolution period control. EDIS; } } void error (void) { ESTOP0; // Stop here and handle error } // No more
No most likely you are using values that are larger than the MAX number of delay elements specified by the sfo.
Take a look at this:
//############################################################################# // $Copyright: // Copyright (C) 2013-2019 Texas Instruments Incorporated - http://www.ti.com/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the // distribution. // // Neither the name of Texas Instruments Incorporated nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // $ //############################################################################# // // Included Files // #include "driverlib.h" #include "device.h" #include "SFO_V8.h" #define EPWM_TIMER_TBPRD 100UL #define MIN_HRPWM_DUTY_PERCENT 4.0/((float32_t)EPWM_TIMER_TBPRD)*100.0 // // Defines // #define LAST_EPWM_INDEX_FOR_EXAMPLE 5 // // Globals // float32_t dutyFine = MIN_HRPWM_DUTY_PERCENT; uint16_t status; int MEP_ScaleFactor; // Global variable used by the SFO library // Result can be used for all HRPWM channels // This variable is also copied to HRMSTEP // register by SFO() function. volatile uint32_t ePWM[(PWM_CH + 1)] = {0, EPWM1_BASE, EPWM2_BASE, EPWM3_BASE, EPWM4_BASE}; // // Function Prototypes // void initHRPWM(uint32_t period); void initEPWMGpio(void); void error(void); //__interrupt void epwm1ISR(void); //__interrupt void epwm2ISR(void); //__interrupt void epwm3ISR(void); //__interrupt void epwm4ISR(void); // // Main // void main(void) { uint16_t i = 0; // // Initialize device clock and peripherals // Device_init(); // // Disable pin locks and enable internal pull ups. // Device_initGPIO(); // // Initialize PIE and clear PIE registers. Disables CPU interrupts. // Interrupt_initModule(); // // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // Interrupt_initVectorTable(); // // Assign the interrupt service routines to ePWM interrupts // //Interrupt_register(INT_EPWM1, &epwm1ISR); //Interrupt_register(INT_EPWM2, &epwm2ISR); //Interrupt_register(INT_EPWM3, &epwm3ISR); //Interrupt_register(INT_EPWM4, &epwm4ISR); initEPWMGpio(); // // CHANGE XBAR inputs from using GPIO0 // if EPWM SYNCIN is enabled, EXTSYNCIN1 and EXTSYNCIN2 will use // GPIO0 (which is the output of EPWM1). // Pick and unused GPIO // XBAR_setInputPin(XBAR_INPUT5, 50); XBAR_setInputPin(XBAR_INPUT6, 50); // // Calling SFO() updates the HRMSTEP register with calibrated MEP_ScaleFactor. // HRMSTEP must be populated with a scale factor value prior to enabling // high resolution period control. // while(status == SFO_INCOMPLETE) { status = SFO(); if(status == SFO_ERROR) { error(); // SFO function returns 2 if an error occurs & # of MEP } // steps/coarse step exceeds maximum of 255. } // // Disable sync(Freeze clock to PWM as well) // SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_GTBCLKSYNC); SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); initHRPWM(EPWM_TIMER_TBPRD); // // Enable sync and clock to PWM // SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); // Enable ePWM interrupts // //Interrupt_enable(INT_EPWM1); //Interrupt_enable(INT_EPWM2); //Interrupt_enable(INT_EPWM3); //Interrupt_enable(INT_EPWM4); // // Enable Global Interrupt (INTM) and realtime interrupt (DBGM) // EINT; ERTM; for(;;) { // // Sweep DutyFine // for(dutyFine = MIN_HRPWM_DUTY_PERCENT; dutyFine < 99.9; dutyFine += 0.01) { DEVICE_DELAY_US(1000); for(i=1; i<LAST_EPWM_INDEX_FOR_EXAMPLE; i++) { float32_t count = (dutyFine * (float32_t)(EPWM_TIMER_TBPRD << 8))/100; uint32_t compCount = (count); HRPWM_setCounterCompareValue(ePWM[i], HRPWM_COUNTER_COMPARE_A, compCount); HRPWM_setCounterCompareValue(ePWM[i], HRPWM_COUNTER_COMPARE_B, compCount); } // // Call the scale factor optimizer lib function SFO() // periodically to track for any change due to temp/voltage. // This function generates MEP_ScaleFactor by running the // MEP calibration module in the HRPWM logic. This scale // factor can be used for all HRPWM channels. The SFO() // function also updates the HRMSTEP register with the // scale factor value. // status = SFO(); // in background, MEP calibration module // continuously updates MEP_ScaleFactor if (status == SFO_ERROR) { error(); // SFO function returns 2 if an error occurs & # // of MEP steps/coarse step } // exceeds maximum of 255. } } } // // epwm1ISR - ePWM 1 ISR // //__interrupt void epwm1ISR(void) //{ // EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE); // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3); //} // // epwm2ISR - ePWM 2 ISR // //__interrupt void epwm2ISR(void) //{ // EPWM_clearEventTriggerInterruptFlag(EPWM2_BASE); // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3); //} // // epwm3ISR - ePWM 3 ISR // //__interrupt void epwm3ISR(void) //{ // EPWM_clearEventTriggerInterruptFlag(EPWM3_BASE); // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3); //} // // epwm4ISR - ePWM 4 ISR // //__interrupt void epwm4ISR(void) //{ // EPWM_clearEventTriggerInterruptFlag(EPWM4_BASE); // Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3); //} void initEPWMGpio(void) { // // Configure GPIO0/1 as ePWM1A/1B pins respectively // GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_0_EPWM1A); GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_1_EPWM1B); // // Configure GPIO2/3 as ePWM2A/2B pins respectively // GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_2_EPWM2A); GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_3_EPWM2B); // // Configure GPIO4/5 as ePWM3A/3B pins respectively // GPIO_setPadConfig(4, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_4_EPWM3A); GPIO_setPadConfig(5, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_5_EPWM3B); // // Configure GPIO6/7 as ePWM4A/4B pins respectively // GPIO_setPadConfig(6, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_6_EPWM4A); GPIO_setPadConfig(7, GPIO_PIN_TYPE_STD); GPIO_setPinConfig(GPIO_7_EPWM4B); } void initHRPWM(uint32_t period) { uint16_t j; // // ePWM channel register configuration with HRPWM // ePWMxA / ePWMxB toggle low/high with MEP control on Rising edge // for (j=1;j<LAST_EPWM_INDEX_FOR_EXAMPLE;j++) { EPWM_setEmulationMode(ePWM[j], EPWM_EMULATION_FREE_RUN); // // Set-up TBCLK // EPWM_setTimeBasePeriod(ePWM[j], period-1); EPWM_setPhaseShift(ePWM[j], 0U); EPWM_setTimeBaseCounter(ePWM[j], 0U); // // set duty 50% initially // HRPWM_setCounterCompareValue(ePWM[j], HRPWM_COUNTER_COMPARE_A, (period/2 << 8)); HRPWM_setCounterCompareValue(ePWM[j], HRPWM_COUNTER_COMPARE_B, (period/2 << 8)); // // Set up counter mode // EPWM_setTimeBaseCounterMode(ePWM[j], EPWM_COUNTER_MODE_UP); EPWM_disablePhaseShiftLoad(ePWM[j]); EPWM_setClockPrescaler(ePWM[j], EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1); EPWM_setSyncOutPulseMode(ePWM[j], EPWM_SYNC_OUT_PULSE_DISABLED); // // Set up shadowing // EPWM_setCounterCompareShadowLoadMode(ePWM[j], EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO); EPWM_setCounterCompareShadowLoadMode(ePWM[j], EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO); // // Set actions // EPWM_setActionQualifierAction(ePWM[j], EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); EPWM_setActionQualifierAction(ePWM[j], EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); EPWM_setActionQualifierAction(ePWM[j], EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA); EPWM_setActionQualifierAction(ePWM[j], EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB); HRPWM_setMEPEdgeSelect(ePWM[j], HRPWM_CHANNEL_A, HRPWM_MEP_CTRL_FALLING_EDGE); HRPWM_setMEPControlMode(ePWM[j], HRPWM_CHANNEL_A, HRPWM_MEP_DUTY_PERIOD_CTRL); HRPWM_setCounterCompareShadowLoadEvent(ePWM[j], HRPWM_CHANNEL_A, HRPWM_LOAD_ON_CNTR_ZERO); HRPWM_setMEPEdgeSelect(ePWM[j], HRPWM_CHANNEL_B, HRPWM_MEP_CTRL_FALLING_EDGE); HRPWM_setMEPControlMode(ePWM[j], HRPWM_CHANNEL_B, HRPWM_MEP_DUTY_PERIOD_CTRL); HRPWM_setCounterCompareShadowLoadEvent(ePWM[j], HRPWM_CHANNEL_B, HRPWM_LOAD_ON_CNTR_ZERO); HRPWM_enableAutoConversion(ePWM[j]); // // Turn off high-resolution period control. // HRPWM_disablePeriodControl(ePWM[j]); HRPWM_disablePhaseShiftLoad(ePWM[j]); // // Interrupt where we will change the Compare Values // Select INT on Time base counter zero event, // Enable INT, generate INT on 1st event // //EPWM_setInterruptSource(ePWM[j], EPWM_INT_TBCTR_ZERO); //EPWM_enableInterrupt(ePWM[j]); //EPWM_setInterruptEventCount(ePWM[j], 1U); } } // // error - Halt debugger when called // void error (void) { ESTOP0; // Stop here and handle error }
Thank you for your reply. Can you provide some documentation regarding this MAX number of delays of SFO? Did you found anything wrong with the example that I provided? Could you send the entire project so I could test it myself?
Thank you.
To test the project just use a Driverlib example project and replace main.c with the one i provided.
http://dev.ti.com/tirex/explore/node?node=ANitrqhsIFh2iKi74mDV8g__gYkahfz__LATEST
Also for how many delays can be used, it depends on whether you have autoconvert enabled or not. When it is enabled, you can look at HRMSTEP register after your SFO function has completed.