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:
Hello,
I have a question about the configuration of HRPWM for TMS320F28P650DK9.
We are trying to control the MEP of HRPWM in a kind of "hybrid" mode: chosen a frequency value (about 200kHz), below that frequency we need to control the MEP of HRPWM in phase shift mode, above that frequency we need to control the MEP of HRPWM in period mode. We need to switch from phase shift mode to period mode without stopping the PWM.
My questions are:
1 - It's possible to implement the behaviour I described above? And if so, is there a guide or an example about peripheral configuration?
2 - I cannot find any examples in C2000Ware on the configuration of phase shift control mode and deadband for HRPWM. Can you suggest where to look?
Thank you in advance,
Simone
Hi Simone,
The expert is currently out of office today due to US holiday. Please expect a delay in response.
Best Regards,
Aishwarya
1 - It's possible to implement the behaviour I described above? And if so, is there a guide or an example about peripheral configuration?
It is possible to use both TBPRDHR and TBPHSHR and control both in your different modes.
We have examples on updating TBPRD:TBPRDHR. We do not have currently an example of TBPHSHR but we have a guide in our TRM to enable this.
Step 6 outlines what is needed to have TBPHSHR enabled.
2 - I cannot find any examples in C2000Ware on the configuration of phase shift control mode and deadband for HRPWM. Can you suggest where to look?
To configure this, you should have dead band counter running at 2* TBCLK rate, configure the load mode for DBRED/FEDHR to be load on counter zero or period. Please take note of this limitation below. If you're in up-down count mode you should be fine.
Here is a simple example show casing TBPHSHR below using HRPWM ex 3 as the starter code:
//############################################################################# // // FILE: hrpwm_ex3_prdupdown_sfo.c // // TITLE: HRPWM Period Control. // //! \addtogroup driver_example_list //! <h1>HRPWM Period Control</h1> //! //! 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. //! //! \b External \b Connections \n //! - Monitor ePWM1/2/3/4 A/B pins on an oscilloscope. // //############################################################################# // // // // C2000Ware v5.03.00.00 // // Copyright (C) 2024 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 "clocktree.h" #include "board.h" #include "sfo_v8.h" // // Defines // #define EPWM_TIMER_TBPRD 20UL #define LAST_EPWM_INDEX_FOR_EXAMPLE 5 #define MIN_HRPWM_PRD_PERCENT 0.2 #define EPWM_TIMER_TBPRD 20 // // Globals // float32_t periodFine = MIN_HRPWM_PRD_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. uint32_t count = 0; uint8_t phaseHR = 0; uint16_t phase = 0; volatile uint32_t ePWM[] = {0, myEPWM1_BASE, myEPWM2_BASE}; extern volatile uint32_t gHrpwmCal_base; // // Function Prototypes // void error(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(); // // We are only required to calibrate HRPWMCAL1 as we using EPWMs between 1-8. // // gHrpwmCal_base = HRPWMCAL1_BASE; // gHrpwmCal_base = HRPWMCAL2_BASE; // gHrpwmCal_base = HRPWMCAL3_BASE; // // 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_TBCLKSYNC); // // Initialize EPWM GPIOs and change XBAR inputs from using GPIO0 // Board_init(); EPWM_enableOneShotSync(myEPWM2_BASE); // // Enable sync and clock to PWM // SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); // // Enable Global Interrupt (INTM) and realtime interrupt (DBGM) // EINT; ERTM; for(;;) { // // Sweep DutyFine // for(phaseHR = 0; phaseHR < 256; phaseHR += 1) { DEVICE_DELAY_US(1000); // // Update TBPHSHR going through all MEP steps // with auto conversion on // HRPWM_setHiResPhaseShiftOnly(ePWM[2], phaseHR); // // 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. } } } void INT_myEPWM1_ISR(void) { count++; if(count == 100000){ // // Move TBPHS by 1 // EPWM_setPhaseShift(ePWM[2], phase); count = 0; phase += 1; if(phase == 20) { phase = 0; } EPWM_startOneShotSync(myEPWM2_BASE); } EPWM_clearEventTriggerInterruptFlag(myEPWM1_BASE); Interrupt_clearACKGroup(INT_myEPWM1_INTERRUPT_ACK_GROUP); } // // error - Halt debugger when called // void error (void) { ESTOP0; // Stop here and handle error }
/** * These arguments were used when this file was generated. They will be automatically applied on subsequent loads * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments. * @cliArgs --device "F28P65x" --package "256ZEJ" --part "F28P65x_256ZEJ" --context "CPU1" --product "C2000WARE@5.03.00.00" * @versions {"tool":"1.20.0+3587"} */ /** * Import the modules used in this configuration. */ const epwm = scripting.addModule("/driverlib/epwm.js", {}, false); const epwm1 = epwm.addInstance(); const epwm2 = epwm.addInstance(); const inputxbar = scripting.addModule("/driverlib/inputxbar.js", {}, false); const inputxbar1 = inputxbar.addInstance(); const inputxbar_input = scripting.addModule("/driverlib/inputxbar_input.js"); const inputxbar_input1 = inputxbar_input.addInstance(); const inputxbar_input2 = inputxbar_input.addInstance(); /** * Write custom configuration values to the imported modules. */ const divider8 = system.clockTree["EPWMCLKDIV"]; divider8.divideValue = 1; epwm1.$name = "myEPWM1"; epwm1.epwmTimebase_hsClockDiv = "EPWM_HSCLOCK_DIVIDER_1"; epwm1.epwmTimebase_period = 20; epwm1.epwmCounterCompare_cmpA = 10; epwm1.epwmCounterCompare_cmpB = 10; epwm1.epwmTimebase_counterMode = "EPWM_COUNTER_MODE_UP_DOWN"; epwm1.epwmActionQualifier_EPWM_AQ_OUTPUT_A_ON_TIMEBASE_DOWN_CMPA = "EPWM_AQ_OUTPUT_LOW"; epwm1.epwmActionQualifier_EPWM_AQ_OUTPUT_B_ON_TIMEBASE_UP_CMPB = "EPWM_AQ_OUTPUT_HIGH"; epwm1.epwmActionQualifier_EPWM_AQ_OUTPUT_B_ON_TIMEBASE_DOWN_CMPB = "EPWM_AQ_OUTPUT_LOW"; epwm1.hrpwm_enable = true; epwm1.hrpwm_autoConv = true; epwm1.hrpwm_edgeModeA = "HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE"; epwm1.hrpwm_edgeModeB = "HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE"; epwm1.hrpwm_HRLoadB = "HRPWM_LOAD_ON_CNTR_ZERO_PERIOD"; epwm1.hrpwm_HRLoadA = "HRPWM_LOAD_ON_CNTR_ZERO_PERIOD"; epwm1.hrpwm_periodEnable = true; epwm1.epwmCounterCompare_shadowLoadModeCMPB = "EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD"; epwm1.epwmCounterCompare_shadowLoadModeCMPA = "EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD"; epwm1.epwmActionQualifier_EPWM_AQ_OUTPUT_A_ON_TIMEBASE_UP_CMPA = "EPWM_AQ_OUTPUT_HIGH"; epwm1.epwmTimebase_forceSyncPulse = true; epwm1.epwmEventTrigger_enableInterrupt = true; epwm1.epwmEventTrigger_registerInterrupts = true; epwm1.epwmEventTrigger_interruptSource = "EPWM_INT_TBCTR_ZERO"; epwm1.epwmTimebase_syncInPulseSource = "EPWM_SYNC_IN_PULSE_SRC_DISABLE"; epwm1.epwmTimebase_syncOutPulseMode = ["EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO"]; epwm1.epwmEventTrigger_interruptEventCount = "15"; epwm1.epwm.$assign = "EPWM1"; epwm1.epwm.epwm_aPin.$assign = "GPIO0"; epwm1.epwm.epwm_bPin.$assign = "GPIO1"; epwm1.epwmInt.enableInterrupt = true; epwm2.$name = "myEPWM2"; epwm2.epwmTimebase_hsClockDiv = "EPWM_HSCLOCK_DIVIDER_1"; epwm2.epwmTimebase_period = 20; epwm2.epwmCounterCompare_cmpA = 10; epwm2.epwmCounterCompare_cmpB = 10; epwm2.epwmTimebase_counterMode = "EPWM_COUNTER_MODE_UP_DOWN"; epwm2.epwmActionQualifier_EPWM_AQ_OUTPUT_A_ON_TIMEBASE_DOWN_CMPA = "EPWM_AQ_OUTPUT_LOW"; epwm2.epwmActionQualifier_EPWM_AQ_OUTPUT_B_ON_TIMEBASE_UP_CMPB = "EPWM_AQ_OUTPUT_HIGH"; epwm2.epwmActionQualifier_EPWM_AQ_OUTPUT_B_ON_TIMEBASE_DOWN_CMPB = "EPWM_AQ_OUTPUT_LOW"; epwm2.hrpwm_enable = true; epwm2.hrpwm_autoConv = true; epwm2.hrpwm_edgeModeA = "HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE"; epwm2.hrpwm_edgeModeB = "HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE"; epwm2.hrpwm_HRLoadB = "HRPWM_LOAD_ON_CNTR_ZERO_PERIOD"; epwm2.hrpwm_HRLoadA = "HRPWM_LOAD_ON_CNTR_ZERO_PERIOD"; epwm2.hrpwm_periodEnable = true; epwm2.epwmCounterCompare_shadowLoadModeCMPB = "EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD"; epwm2.epwmCounterCompare_shadowLoadModeCMPA = "EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD"; epwm2.epwmActionQualifier_EPWM_AQ_OUTPUT_A_ON_TIMEBASE_UP_CMPA = "EPWM_AQ_OUTPUT_HIGH"; epwm2.epwmTimebase_forceSyncPulse = true; epwm2.epwmTimebase_phaseEnable = true; epwm2.epwmTimebase_phaseShift = 1; epwm2.epwmTimebase_counterModeAfterSync = "EPWM_COUNT_MODE_UP_AFTER_SYNC"; epwm2.epwm.$assign = "EPWM2"; epwm2.epwm.epwm_aPin.$assign = "GPIO2"; epwm2.epwm.epwm_bPin.$assign = "GPIO3"; inputxbar1.$name = "myINPUTXBAR5"; inputxbar_input1.$name = "myINPUTXBARINPUT0"; inputxbar_input1.inputxbarInput = "XBAR_INPUT5"; inputxbar_input1.inputxbarGpio = "GPIO40"; inputxbar_input2.$name = "myINPUTXBARINPUT1"; inputxbar_input2.inputxbarInput = "XBAR_INPUT6"; inputxbar_input2.inputxbarGpio = "GPIO40";
Hi,
thank you for your answer. I just have one last question about TBPHSHR.
In TRM I read that I need to use TRREM register instead of TBPHSHR for phase shift (22.20.2.35 TBPHS Register, pag. 3967):
Can I use the following thread as guideline or for TMS320F28P650DK something is different?