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
Hello,
I am using the deadband module in halfcycle mode to delay the edges of a signal which has symmetric duty control (in up-down count mode). The pulses are centered around the CTR=PRD event (with a TBPRD value of 166), therefore the rising edge occurs before CTR=PRD and the falling edge occurs after CTR=PRD. The ePWM clock is set to 200MHz, since on the F28388 device the ePWM (Type 4) modules support operation at this frequency.
For most values of DBRED and CMPA:CMPAHR the waveforms are perfectly fine. However as I increase DBRED there is a threshold above which the rising edge is delayed in a different manner depending on the value of CMPAHR. I am not 100% certain but this threshold seems to depend on the value of CMPA and I think the anomaly arises as soon as the deadband module tries to delay the rising edge beyond the CTR=PRD event.
Here is an oscilloscope screenshot:
I assume one possible explanation would be along the lines of the deadband module not being "aware" of the internal shadow CMPA buffers used by the HRPWM module in HRPE mode. But maybe it's just a mistake in my configuration. In any case the scenario where the duty cycle is so small that it becomes close to the dead-time is not very likely in my application, but I just wanted to make sure I'm not missing something important.
Kind regards,
Pierre
Hi,
You say you may run at 200MHz, but when reading the SPRS880D document there is stated on page 61:
f(EPWM) Frequency, EPWMCLK(2) 100 MHz (Note 2)
f(HRPWM) Frequency, HRPWMCLK 60 100 MHz
Note 2: For SYSCLK above 100 MHz, the EPWMCLK must be half of SYSCLK.
So, you can never operate the PWM above 100MHz.
Best regards
You can use epwm upto 200MHz in this device. I will review the rest of your requests.
Nima,
I isolated the issue in a very small CCS project. It should be easier for you to reproduce the issue using this as a starting point.
Kind Regards,
Pierre
Hi Nima,
Since it has been nearly two weeks I was wondering if some progress has been made on this issue.
Would it help if I tried to reproduce the issue on a different device such as F28379?
Regards,
Pierre
Pierre,
Sorry for the delay! I have a new Peripheral releasing at the end of the month and we have been extremely busy with that effort. If you can reproduce the issue on an F28379D device, that would be EXTREMELY helpful!
I will try to work with your CCS project. Thank you for providing that!
Nima
Hello Nima,
Firstly, please find attached another CCS Project which seems to show the same issue when running on a F28379D ControlCard.
Secondly I noticed something odd. In many examples from C2000Ware (but not every one of them!) there is the following operation during the configuration of the HRPWM:
(*ePWM[j]).CMPA.bit.CMPAHR = (1 << 8); // initialize HRPWM extension
I cannot remember seeing any information regarding this operation in the datasheets or TRMs of the F28x devices. Where does it come from, what does it do and is it mandatory?
Kind regards,
Pierre
Nima,
I was wondering whether this issue is being investigated, since it's been a month.
Best regards,
Pierre
Pierre,
Yes. We are working on this.
Remember the new peripheral I mentioned before that was being released, the CLB. well that is now released in the latest C2000WARE. Please check this out and send me a private message with your thoughts on it. Based on your previous posts, I think the CLB is something you will find VERY useful!
In the mean time, we are working to see what exactly is causing that!
Nima
With regards to this, YES this IS mandatory, it is done in the examples to show it initialize to a value. and that it needs to be shifted by 8.
The value of CMPAHR=0 is not the same as DISABLING the HRPWM module. The delay from the HRPWM internal logic is still applied to the ePWM output signal.
In the diagram you sent Pierre,
The last two green rising edges, are they apart by the delay that CMPAHR=1 would introduce based on the SFO step size?
Nima
Hello Nima,
I'm not sure whether you mean (CMPAHR = 1 micro-step) or (CMPAHR = 1 TBCLK).
Assuming it is the former it seems that when transitioning between two non-zero values of CMPAHR the shift is correct, but when CMPAHR=0 then the edge moves back by approximately a whole TBCLK cycle (the screenshot is at 10ns/div and the edge is shifted by half a div i.e 5ns which is the TBCLK period).
Have you been able to reproduce the anomaly on your board?
Pierre
Yes, I was able to reproduce this, I'm trying to figure out if this is expected behavior, or a violation of a specific mode, or it is a new issue.
Nima
Pierre,
I see the issue, however the code you sent me for F28379D launchpad, changes RED but in the signal I view on the scope it changes the falling edge of the signal by pulling it closer to PRD. Is this what you meant to do with the sample code?
Nima
Okay I changed some settings in your code and here is what I found and the explanations I got from other ePWM experts.
The code you sent what changed to this:
#include "F28x_Project.h" #include "SFO_V8.h" int ePWM, MEP_ScaleFactor; void HRPWM1_Config(int); void main(void) { InitSysCtrl(); __eallow(); ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV = 1; __edis(); __eallow(); CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0; CpuSysRegs.PCLKCR0.bit.GTBCLKSYNC = 0; __edis(); /* * Configure ePWM2 to generate edges on CTR=ZRO and CTR=PRD. * High-resolution edge placement is not enabled on ePWM2. */ EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1; EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; EPwm2Regs.TBCTL.bit.FREE_SOFT = 2; EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE; EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR; EPwm2Regs.AQCTLA.bit.PRD = AQ_SET; EPwm2Regs.TBPRD = 20; /* * Configure ePWM1 for symmetric high-resolution duty control. */ EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO_PRD; EPwm1Regs.AQCTL.bit.SHDWAQAMODE = 1; EPwm1Regs.AQCTL.bit.LDAQAMODE = 0; EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; EPwm1Regs.TBPRD = 20; EPwm1Regs.CMPA.bit.CMPA = 10; EPwm1Regs.CMPA.bit.CMPAHR = 0; EPwm1Regs.DBCTL.bit.HALFCYCLE = 1; EPwm1Regs.DBCTL.bit.IN_MODE = DBA_RED_DBB_FED; EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; EPwm1Regs.DBRED.bit.DBRED = 4; __eallow(); EPwm1Regs.HRCNFG.bit.EDGMODE = HR_BEP; EPwm1Regs.HRCNFG.bit.CTLMODE = HR_CMP; EPwm1Regs.HRCNFG.bit.HRLOAD = HR_CTR_ZERO_PRD; EPwm1Regs.HRCNFG.bit.AUTOCONV = 1; EPwm1Regs.HRPCTL.bit.HRPE = 1; EPwm1Regs.HRPCTL.bit.TBPHSHRLOADE = 1; __edis(); __eallow(); CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; __edis(); EPwm1Regs.TBCTL.bit.SWFSYNC = 1; while (SFO() == SFO_INCOMPLETE); /* Prevent ePWM1 from resynchronizing on its own output */ EPwm1Regs.TBCTL.bit.PHSEN = 0; InitEPwm1Gpio(); InitEPwm2Gpio(); for(;;) { /* Starting position */ EPwm1Regs.CMPA.bit.CMPAHR = 0x0000; EPwm1Regs.DBRED.bit.DBRED = 0; ESTOP0; EPwm1Regs.CMPA.bit.CMPAHR = 0x0000; EPwm1Regs.DBRED.bit.DBRED = 22; ESTOP0; /* By adding 1 MEP step the edge shoud move by a tiny amount */ EPwm1Regs.CMPA.bit.CMPAHR = 0x0100; EPwm1Regs.DBRED.bit.DBRED = 22; ESTOP0; /* By adding 2 to DBRED the edge is delayed by 1 cycle */ EPwm1Regs.CMPA.bit.CMPAHR = 0x0100; EPwm1Regs.DBRED.bit.DBRED = 26; ESTOP0; /* * By removing 1 MEP step the edge shoud move by a tiny amount * but we can see it moving much more than expected. */ EPwm1Regs.CMPA.bit.CMPAHR = 0x0000; EPwm1Regs.DBRED.bit.DBRED = 26; ESTOP0; } }
1. When you delay the Rising edge passed the PRD in the first step everything is fine!
2. When you enable the HRPWM by writing a 1, it shifts ONLY the falling edge. Past the PRD event, the HR module seems to only effect the falling edge! This is expected since the rising edge HR portion didnt take affect since the deadband module was active!
3. With HR enabled, moving RED to 26, seems to only delay the rising edge more! this is as expected.
4. Disabling the HR and keeping the DBRED the same, seems to shift everything to the left, towards the PRD by 1 Cycle. This is what I do not have an answer for yet!
Marking this answer yellow while I investigate the rest so other users with the same issue read this answer.
Nima
Hello Nima,
Are you certain the RED changes the falling edge of the signal? On my setup only the rising edge changes, as shown on the scope picture where the falling edges of the green signal in the rightmost division are all superposed.
I will check again on my setup as soon as I can.
Cheers,
Pierre
Pierre,
Actually the rising edge was moving. The settings on my oscilloscope was changed.
Nima
Nima Eskandari said:With regards to this, YES this IS mandatory, it is done in the examples to show it initialize to a value. and that it needs to be shifted by 8.
Nima, sorry I just noticed that you said it is mandatory.
Nima Eskandari said:The value of CMPAHR=0 is not the same as DISABLING the HRPWM module. The delay from the HRPWM internal logic is still applied to the ePWM output signal.
I'm not following. What are the consequences of this delay from the HRPWM internal logic for the output signal? I mean, my goal when I use the HRPWM module is to have consistent behaviour accross all values of CMPAHR so I hope that I don't need to consider CMPAHR=0 as a special value with different behaviour.
Kind regards,
Pierre
Same as 3.
Akshaya Jain Can you confirm my comments above?
Nima Eskandari said:It does work, but the set of accepted values are from 0x1 and up. Using the value 0 for the HR section will not give you the correct ePWM frequency that you assume. That is becuase the 0x0 value in the HR portion does not mean your PWM calculation is the same as if you had your HRMODE disabled.
Sorry I don't get it. Every single document about the HRPWM I've come accross basically says that CMPAHR value = (number of MEP steps) << 8. So what you are saying is that this is true except in the case where I want zero MEP steps?
For example the formulas in chapter 26.15.1.5.2 Scaling Considerations explicitely show how the value of CMPAHR should be based on frac(PWMDuty*PWMPeriod). Do you mean that this formula is actually wrong if PWMDuty*PWMPeriod happens to be an integer without a fractional part?
Nima Eskandari said:I can add an extra note to make sure users dont assume HRMODE=DISABLED is the same as CMPxHR=0
I can't wrap my head around this. Obviously I don't assume HR mode is disabled, why would I want to disable in the middle of my application? I enable it once and for all during peripheral initialization, then my control loop gives me a floating point duty which I convert then write to CMPA:CMPAHR as an integer value, as described in the docs. What does the HR mode have to do with this?
Best Regards,
Pierre
Let me try coding this up and checking the behavior again. I read some contradicting document.
Pierre,
I tested this. Enabling HRMODE even when CMPAHR is set to 0 WILL add a delay in ps (approximately 1 MEP step).
Here is my code below. It does not change anything and as long as your okay with only a 200ps change when enabling the HR, everything else should work as expected.
// // 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; dutyFine = 50.0; 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); } for(;;) { // // 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 }
Hi Nima,
I would like to run this code, could you please send it as a CCS project?
Thanks & Regards,
Pierre
Pierre,
Please import this project: http://dev.ti.com/tirex/explore/node?node=AGQH5zZ6qpYvuEiMHzgF8A__gYkahfz__LATEST
and replace the main file with the content above.
And add the two driverlib SFO libs:
C2000Ware_2_01_00_00\libraries\calibration\hrpwm\f2837xd\lib\SFO_v8_fpu_lib_build_c28_driverlib.lib
C2000Ware_2_01_00_00\libraries\calibration\hrpwm\f2837xd\lib\SFO_v8_fpu_lib_build_c28_driverlib_eabi.lib
to the project.