Phase shift PWM signals

Is it possible to phase shift two PWM signals 90 degrees, without using delays?

I had thought about this a few days ago, in some context that might sound very idiotic,

But i think, if we have 2 separate microcontrollers, or arduinos, communicating through serial or through some other interface like I2C,
we can have a phase shift between the PWM signals.

I havent actually tried doing this, and i just think this might work. It might also sound idiotic, but i am kinda new here.

Regards

I havent actually tried doing this, and i just think this might work

No way can you make that work.

As the PWM is based on the timers if you take two timers and set them to run at the same frequency then it might be possible. However setting the initial offset could be tricky.

1 Like

I succeed. In datasheet: .
Set two PWM signals:

  • First PWM channel CALG = 0 (left aligned) with freqA (running on CLKA)
  • Second PWM channel CALG =1 (center aligned) with freqB (running on CLKB)

The center aligned period is twice as long as the left aligned. If we take freqB = freqA *2 we get a phase shift of 90 degrees. Note: This works a duty cycle of 50% only ( I use it to generate encoder pulses).

The SAM also has a PWM engine that will (I think) produce synced waveforms out of phase. As I understand it any PWMLx and PWMHx pair will do this but it's not supported by the Arduino libraries so you'll have to cut your own driver code.


Rob

Note: This works a duty cycle of 50% only ( I use it to generate encoder pulses).

Yes it is easy to do things when you do not do them correctly or only approximate what is being asked for.

I need not only 2 PWM phase shifted but 3 PWM signals 120 phase shifted to each other.. how can i adapt it ?

Psudeo code for 90deg shift

Start up:
  Select Timer0 Source
  N = counts per half cycle
  Timer0 = 0;
  Timer0 Max = (180 * N) -1;
  Timer0 CompareA = (90 * N) -1;
  Timer0 Set Interupts= { CompareA, Max }
  Set Pin A Low;
  Set Pin B Low;
  Start Timer0;

Interrupt:
  If(Interrupt == CompareA) Toggle Pin A;
  If(Interrupt == Max) Toggle Pin B; Set Timer0 = 0;
  Clear Interrupt;

Psudeo Code for 3Phase:

Start up:
  Select Timer0 Source
  N = counts per half cycle
  Timer0 = 0;
  Timer0 Max = (360 * N) -1;
  Timer0 CompareA = (120 * N) -1;
  Timer0 CompareB = (240 * N) -1;
  Timer0 Set Interupts= { CompareA, CompareB, Max }
  Set Pin A Low;
  Set Pin B Low;
  Set Pin C Low;
  Start Timer0;

Interrupt:
  If(Interrupt == CompareA) Toggle Pin A;
  If(Interrupt == CompareB) Toggle Pin B;
  If(Interrupt == Max) Toggle Pin C; Set Timer0 = 0;
  Clear Interrupt;

You can access either through a timer library, or directly through the NVIC and setting registers directly

Edit: I forgot to add that this is only for a 50% Duty Cycle. It takes 2 timers with 4 interrupts to do the PWM otherwise...
I can modify code if requested, but I think it's self explanatory to how to change the code.

Phase shifting PWM outputs is entirely possible. You can even get high resolution phase control, especially when generating low frequencies. I also think the PWM engine with its complementary pairs is best suited and probably required for this type of application.

Its possible to use just one sine data array, then the index you use for each signal will determine the phase shift. I've experimented with the PWM engine and was able to get 0.01 degree phase control resolution for a specific 3-phase power application. The sine data array only needs to be one quadrant (90 deg) in order to create the full cycle of required data points. The rate of incrementing the index determines the filtered sine output frequency. For 3 PWM output pairs (A,B,C) shifted by 120 degrees, the index values would be i, i+12000, i+24000.

Another application requirement might have 1 degree phase control using one array with 360 data points.
In this case, the index values would be i, i+120, i+240. Care needs to be taken to never read past the array size and to cycle back when i+shift >359.

Anyone interested in using the PWM engine (PWMH/PWML), this is the code I used to initialize the PWM and clock but it would need to be customized/cleaned up to suit your own application:

//Configure PWM channels 0,1,2,3 (PWML0,PWMH0,PWML1,PWMH1,PWML2,PWMH2,PWML3,PWMH3), (port C.2,C.3,C.4,C.5,C.6,C.7,C.8,C.9), (pins P34,P35,P36,P37,P38,P39,P40,P41)
 REG_PIOC_PDR = 0x3FC;  //B1111111100, PIO Disable Register
 REG_PIOC_ABSR = REG_PIOC_ABSR | 0x3FCu; //B1111111100, Peripheral AB Select Register

 REG_PMC_PCER1 = REG_PMC_PCER1 | 16; //Peripheral Clock Enable Register 1 (activate clock for PWM, id36, bit5 of PMC_PCSR1)
 REG_PWM_ENA = REG_PWM_SR | B1111; //PWM Enable Register | PWM Status Register (activate channels 0,1,2,3)

 REG_PWM_CMR0 = 0x10000; //Channel Mode Register: Dead Time Enable DTE=1
 REG_PWM_CMR1 = 0x10000; //Channel Mode Register: Dead Time Enable DTE=1
 REG_PWM_CMR2 = 0x10000; //Channel Mode Register: Dead Time Enable DTE=1
 REG_PWM_CMR3 = 0x10000; //Channel Mode Register: Dead Time Enable DTE=1
 REG_PWM_DT0 = 0xA800A8; //PWM Channel Dead Time Register (168=2us for outputs PWML0,PWMH0)  
 REG_PWM_DT1 = 0xA800A8; //PWM Channel Dead Time Register (168=2us for outputs PWML1,PWMH1)
 REG_PWM_DT2 = 0xA800A8; //PWM Channel Dead Time Register (168=2us for outputs PWML2,PWMH2)  
 REG_PWM_DT3 = 0xA800A8; //PWM Channel Dead Time Register (168=2us for outputs PWML3,PWMH3)

 REG_PWM_CPRD0 = 5600; //1/5600 resolution for VoltsA (84mhz/5600=15khz=66.667us period)
 REG_PWM_CPRD1 = 5600; //1/5600 resolution for VoltsB (84mhz/5600=15khz=66.667us period)
 REG_PWM_CPRD2 = 65535; //16 bit resolution for VoltsA DC Power Supply amplitude (84mhz/65535=1.281khz=780.64us period)
 REG_PWM_CPRD3 = 65535; //16 bit resolution for VoltsB DC Power Supply amplitude (84mhz/65535=1.281khz=780.64us period)

//configure sine clock
 REG_PMC_PCER0 = REG_PMC_PCER0 | 0x80000000; //Peripheral Clock Enable Register 1 (activate clock for TC4, id31, bit31` of PMC_PCSR0)
 TC_Configure(/* clock */TC1,/* channel */1, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK3); //TIMER_CLOCK3 = MCK/32 = 2,625,000 Hz

Thanks for your reply

I cant get it work at ma Arduino Due board. Is ist compatible to Arduino Due

Another question how can I can get the phase shift 120 degree not 90?

@
dlloyd or mlosuper Can you please post the entire code you made ?

Thanks in Advance

Complete code for phase shift of 0°, 90°, 180° and 270° can be found here:
http://forum.arduino.cc/index.php?topic=291435.msg3096824#msg3096824

And yes, its for Arduino Due only, as can be seen by "84MHz" in code comment of post #8 in this thread.

I have not seen anything on phase shift 120°, not sure whether that is even possible with Arduino Due.