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.
Hello,
I am using the TMS320F28335 DSP to control the phaseshift between two PWM modules (i.e. ePWM1A and ePWM5A). To my understanding according to the datasheet (page 28), I set up my PWM modules such that all PWM modules are synchronized to the ePWM1 module.
What I noted is, that an increasing value in the phaseshift register moves the waveform of the PWM module. However, the direction the waveform is moved is opposite to what I actually want :D
In particular, increasing the phaseshift for ePWM5A yields a move in the waveform to the left with respect to ePWM1A. In other words, an increasing value in the TBPHS register leads to a waveforms shifted to the left with respect to the fixed ePWM1A channel. Below you'll find my code and I did some screenshots of the waveforms for two different phaseshift values to clarify my concern. I would like to achieve the opposite behavior, i.e. an increased value in the TBPHS register moves the waveform to right with respect to ePWM1A.
Do you maybe see where my misunderstanding / wrong C implementation is? Thank you for your help.
#include "DSP28x_Project.h" #include "DCL.h" void InitialADC(); void InitePWM1(); void InitePWM2(); void InitePWM5(); void InitePWM6(); __interrupt void ADC_isr(); __interrupt void TZ_isr(); // Flash functionality extern Uint16 RamfuncsLoadStart; extern Uint16 RamfuncsLoadEnd; extern Uint16 RamfuncsRunStart; Uint16 phaseshift; Uint16 phaseshift1; volatile int32 dummy; volatile Uint16 ConversionCount; volatile float32 Voltage1[256]; volatile float32 Current[256]; void main(void) { // Initialize PLL, Watchdog, enable peripheral clocks InitSysCtrl(); // Used to program to flash MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart); // Initialize ePWM and TZ InitEPwmGpio(); InitTzGpio(); // Initialize PIE control registers InitPieCtrl(); IER = 0x0000; IFR = 0x0000; // Initialize PIE vector table to default ISR InitPieVectTable(); // Remap the ISR function to the PIE vector table EALLOW; PieVectTable.ADCINT = &ADC_isr; PieVectTable.EPWM1_TZINT = &TZ_isr; EDIS; // First step of setting up the ADC sampling rate EALLOW; SysCtrlRegs.HISPCP.all = 3; // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz EDIS; // Synchronization already done in the InitSysCtrl() function --> Ask the TI support to verify /* EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Enable time base clock synchronization with SYSCLKOUT from DSP EDIS; */ InitFlash(); dummy = 0; // Initialize the ADC InitAdc(); phaseshift1 = 4; // Compensating a ca. 15ns delay between ePWM1 and ePWM6 InitialADC(); // Set up the ADC for voltage and current measurement EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; EDIS; InitePWM1(); InitePWM2(); InitePWM5(); InitePWM6(); EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; EDIS; /* * Set GPIO4 as output to measure execution time within ISR */ EALLOW; // Set GPIO10 as a GPIO - already done in InitGpio() GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 0; // Set GPIO10 as an output GpioCtrlRegs.GPADIR.bit.GPIO4 = 1; EDIS; PieCtrlRegs.PIEIER1.bit.INTx6 = 1; // Group 1, bit 6 for ADC PieCtrlRegs.PIEIER2.bit.INTx1 = 1; // Group 2, bit 1 for ePWM1_TZ IER |= M_INT1; // Sets the interrupt enable bit of group 1 IER |= M_INT2; // Sets the interrupt enable bit of group 3 EINT; // Enable global interrupts INTM for(;;) { } } __interrupt void ADC_isr(void) { Voltage1[ConversionCount] = AdcRegs.ADCRESULT0 >>4; // Read value from ADCINA5 Current[ConversionCount] = AdcRegs.ADCRESULT1 >>4; // Read value from ADCINB5 EPwm5Regs.TBPHS.half.TBPHS = dummy; // ePWM5 and ePWM6 will have phaseshift EPwm6Regs.TBPHS.half.TBPHS = phaseshift1; // Compensate ca. 16ns delay of ePWM6 // If 256 conversions have been logged, start over if(ConversionCount == 255) { ConversionCount = 0; } else { ConversionCount++; } // Re-initialize for next ADC AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reset SEQ1 AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // Clears the interrupt flag bit PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE } void InitialADC(void) { // Configure ADC AdcRegs.ADCTRL3.bit.ADCCLKPS = 1; // Set the ADC sampling rate: 25MHz/(2*1+1) = 8.3MHz AdcRegs.ADCTRL1.bit.ACQ_PS = 0; // AdcRegs.ADCTRL1.bit.SEQ_CASC = 0; // Cascaded mode AdcRegs.ADCTRL1.bit.CONT_RUN = 0; // Start-stop mode AdcRegs.ADCTRL3.bit.SMODE_SEL = 1; // Simultaneous sampling mode AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1; // ePWM starts SOCA trigger AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 0; // One conversion AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 5; // ADCINA5 and ADCINB5 AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // Interrupt request enabled } void InitePWM1(void) { // Enable SOCA for ADC measurements EPwm1Regs.ETSEL.bit.SOCAEN = 1; // Enable SOCA EPwm1Regs.ETSEL.bit.SOCASEL = 4; // Generate SOCA pulse at 50% duty cycle EPwm1Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event EPwm1Regs.TBPRD = 1499; // Set the PWM period time EPwm1Regs.CMPA.half.CMPA = (1499+1)/2; EPwm1Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Up count mode EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // Slave module EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync down-stream module EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0; // Set time base clock to SYSCLKOUT EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.LOADAMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm1Regs.CMPCTL.bit.LOADBMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // Sets pin when CTR=PRD EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clears pin when CTR=COMPA EPwm1Regs.DBCTL.bit.IN_MODE = 0; // ePWMxA source for falling and rising edge EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // DB full enable EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active high complementary EPwm1Regs.DBRED = DT; EPwm1Regs.DBFED = DT; } void InitePWM2(void) { EPwm2Regs.TBPRD = 1499; // Set the PWM period time EPwm2Regs.CMPA.half.CMPA = (1499+1)/2; EPwm2Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Up count mode EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Slave module EPwm2Regs.TBCTL.bit.PRDLD = TB_SHADOW; EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync down-stream module EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0; // Set time base clock to SYSCLKOUT EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; EPwm2Regs.CMPCTL.bit.LOADAMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm2Regs.CMPCTL.bit.LOADBMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm2Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Clears pin when CTR=PRD EPwm2Regs.AQCTLA.bit.CAU = AQ_SET; // Sets pin when CTR=COMPA EALLOW; EPwm2Regs.TZSEL.bit.OSHT3 = 1; // Enable TZ3 EPwm2Regs.TZCTL.bit.TZA = 2; // Clear ePWM2A on TZ event EPwm2Regs.TZCTL.bit.TZB = 2; // Clear ePWM2B on TZ event EDIS; EPwm2Regs.DBCTL.bit.IN_MODE = 0; // ePWMxA source for falling and rising edge EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // DB full enable EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active high complementary EPwm2Regs.DBRED = DT; EPwm2Regs.DBFED = DT; } void InitePWM5(void) { EPwm5Regs.TBPRD = 1499; // Set the PWM period time EPwm5Regs.CMPA.half.CMPA = (1499+1)/2; EPwm5Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero EPwm5Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Up count mode EPwm5Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Master module EPwm5Regs.TBCTL.bit.PRDLD = TB_SHADOW; EPwm5Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync down-stream module EPwm5Regs.TBCTL.bit.HSPCLKDIV = 0; // Set time base clock to SYSCLKOUT EPwm5Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm5Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; EPwm5Regs.CMPCTL.bit.LOADAMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm5Regs.CMPCTL.bit.LOADBMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm5Regs.AQCTLA.bit.ZRO = AQ_SET; // Sets pin when CTR=PRD EPwm5Regs.AQCTLA.bit.CAU = AQ_CLEAR; // Clears pin when CTR=COMPA EALLOW; EPwm5Regs.TZSEL.bit.OSHT3 = 1; // Enable TZ3 EPwm5Regs.TZCTL.bit.TZA = 2; // Clear ePWM5A on TZ event EPwm5Regs.TZCTL.bit.TZB = 2; // Clear ePWM5B on TZ event EDIS; EPwm5Regs.DBCTL.bit.IN_MODE = 0; // ePWMxA source for falling and rising edge EPwm5Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // DB full enable EPwm5Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active high complementary EPwm5Regs.DBRED = DT; EPwm5Regs.DBFED = DT; } void InitePWM6(void) { EPwm6Regs.TBPRD = 1499; // Set the PWM period time EPwm6Regs.CMPA.half.CMPA = (1499+1)/2; EPwm6Regs.TBPHS.half.TBPHS = 0; // Set Phase register to zero EPwm6Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // Up count mode EPwm6Regs.TBCTL.bit.PHSEN = TB_ENABLE; // Slave module EPwm6Regs.TBCTL.bit.PRDLD = TB_SHADOW; EPwm6Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // Sync down-stream module EPwm6Regs.TBCTL.bit.HSPCLKDIV = 0; // Set time base clock to SYSCLKOUT EPwm6Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm6Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; EPwm6Regs.CMPCTL.bit.LOADAMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm6Regs.CMPCTL.bit.LOADBMODE = 0; // Loads on either CTR=0 or CTR=PRD EPwm6Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // Clears pin when CTR=PRD EPwm6Regs.AQCTLA.bit.CAU = AQ_SET; // Sets pin when CTR=COMPA EALLOW; EPwm6Regs.TZSEL.bit.OSHT3 = 1; // Enable TZ3 EPwm6Regs.TZCTL.bit.TZA = 2; // Clear ePWM6A on TZ event EPwm6Regs.TZCTL.bit.TZB = 2; // Clear ePWM6B on TZ event EDIS; EPwm6Regs.DBCTL.bit.IN_MODE = 0; // ePWMxA source for falling and rising edge EPwm6Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // DB full enable EPwm6Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active low complementary EPwm6Regs.DBRED = DT; EPwm6Regs.DBFED = DT; }
EDIT: 3/22/17 This post is unhelpful, and can be ignored
Alexander,
My first suggestion is to ensure 100% sure that you don't have your scope probes reversed.
Secondly, how are you updating TBPHS? Can you read the ePWM5 TBPHS and make sure this value was correctly written?
How have you configured ePWM5's SYNCISEL ?
Regards,
Cody
Hi Cody,
thank you for your answer. I looked into your suggestions.
1. The scope probes are not reversed. Yellow waveform corresponds to the probe that is connected to the ePWM1A pin on the uC. Magenta waveform corresponds to the probe that is connected to the ePWM5A pin on the uC. I just double checked the configuration and can confirm that the probes are not reversed.
2. I am updating my calculated TBPHS value in the ADC_ISR where I execute my PI controller that calculates my TBPHS value. In particular, I am updating my TBPHS value at a 100kHz rate.
3. I do not see an option where I can actively configure/set/clear the SYNCISEL bit on any of the PWM modules. What I have done, however, is to configure the SYNCOSEL for ePWM1 to be on CTR_ZERO. The following modules are then configured as SYNCOSEL = TB_SYNC_IN. The logic is adapted from this figure, and I believe this is what you were asking me, right?:
Looking at the corresponding waveforms for this module, I can see that the slave is also ahead of time of the Master, which is exactly what my measurements are about.
So to speak, my measurements are actually confirming the principle in Figure 58, aren't they? A positive value in the TBPHS register yields the slave module to be shifted to the left. A quote from your reference:
"Figure 58 shows the associated timing waveforms for this configuration. Here, TBPRD = 600 for both master and slave. For the slave, TBPHS = 200 (i.e., 200/600 X 360° = 120°). Whenever the master generates a SyncIn pulse (CTR = PRD), the value of TBPHS = 200 is loaded into the slave TBCTR register so the slave time-base is always leading the master's time-base by 120°."
Bottom line, my measurements match the principles from your datasheet, and I simply had a misunderstanding in the beginning. Correct?
BR,
Alexander
Alex,
I was wrong; I have no idea what I was thinking.
The device is working as expected. Anytime a sync pulse occurs PWM5 will be “advanced” by the value in TBPHS. The TBCTR will be loaded with TBPHS anytime that a sync pulse happens (ePWM1’s TBCTR = 0), of course that means that ePWM5 (TBCTR = TBPHS at time of sync) should ‘lead’ ePWM1 (TBCTR = 0 at time of sync).
Additionally, I was referring to “EPWMxSYNCI” as “SYNCISEL”; I assume I was tired yesterday. The point is the sync in pulse to an ePWM module will be ignored if TBCTL.PHSEN is not set. You aren’t having this issue because you are able to adjust the phase between ePWM 1 and ePWM5.
Regards,
Cody
Thank you, Cody. Then I had a misunderstanding in first place, and learned something new about the F28335 again.
One final question, though:
If I wanted to operate a bi-directional DC/DC converter, where the phase shift can be both positive and negative (according to the current/power flow direction), how would that be properly adapted into the phaseshift register?
My solution as for now is to load a positive OR a negative (depending on the current flow) value into TBPHS (for instance TBPHS= -50).
As an example:
TBPHS = 0 -> Both PWM modules have 0 phaseshift
TBPHS = 50 -> ePWM5 (slave) is leading ePWM1 (master) as we discussed in this thread.
TBPHS = -50 -> ePWM5 (slave) is lagging ePWM1 (master)
That solution works fine, and I get the waveforms as I want. However, I was (for some reason) not expecting the TBPHS register to accept negative values. (Probably because my brain is still dominated by duty cycles 0%...100%).
Could you maybe elaborate on that, the TBPHS register accepts negative values as well? I cannot really find the answer to that in the datasheet.
Thank you,
Alexander,
You can adjust the phase by writing only positive values. Let’s say you were using a PWM with a Period of 1000, with a 50% duty cycle. If you write a value 1-499 then the slave will lead, and if you write a value from 501-999 then the slave will lag. Leading and lagging isn’t always the best way to think about it, in my mind the best way to cause a signal to lag is to write (Period-PhaseShift) for example if you wanted to lag by 50 counts and you period was 1000; 1000-50= 950 will give you the desired result.
The reason it will accept negative values is more a question of basic signed integers…-50 as a signed integer is(1111 1111 1100 1110), if you put that value in an “up counter” then it will count 50 times and then overflow to(0000 0000 0000 0000) thus causing a lag.
Be careful, writing negative values only works as long as your sign extension extends up to or past the length of the TBCTR, and the negative values is less than (2^n)-1(n being the length of TBCTR in bits). This device has a TPCTR of 16 bits so anytime you use a 16 bit signed integer or larger you should be OK because of sign extension of negative numbers.
If this is still confusing look up how signed negative numbers are represented in binary, as well as why sign extension is required. Then I can help you answer some questions you may still have.
I hope this helps!!!
Regards,
Cody