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.

TMS320F28335: Phase shift between ePWM1x and ePWM5x - waveform is moving in the opposite direction

Part Number: TMS320F28335

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