Pages: [1]   Go Down
Author Topic: Phase shift PWM signals  (Read 2166 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 639
Posts: 34725
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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).


Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 130
Posts: 8620
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 639
Posts: 34725
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Mt. Laguna Obs.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Psudeo code for 90deg shift
Code:
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:
Code:
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.
« Last Edit: March 12, 2014, 03:54:35 pm by mlosuper » Logged

Canada
Offline Offline
Sr. Member
****
Karma: 14
Posts: 450
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:

Code:
//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
Logged

Disclaimer: I sometimes implement the infinite monkey theorem when composing a reply.

Offline Offline
Full Member
***
Karma: 1
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: March 12, 2014, 05:00:45 pm by so3ody » Logged

Pages: [1]   Go Up
Jump to: