PWM Phase shift

thanks a lot , can u please help me to shift it not only 90 but can I shift two PWM signlas by 10 degree for example

thanks in advance

dlloyd:
This example uses Stepper Motor Mode of the PWM Controller (no Timer/Counters are used).

Four 25kHz PWM signals:

Pin Phase
34 0°
36 90°
35 180°
37 270°
...

Nice sketch, I checked cabling and did measure with 24MHz logic analyzer.
Reading definition of phase shift, shouldn't it be this?

Channel Pin  Phase
0       34   0°
2       36   270°
1       35   180°
3       37   90°

Hermann.

Nice, works with up to 10.5MHz!

With these changes:

  REG_PWM_CPRD0 = 2;//840;                   //Channel0 Period Register (84mhz/4/3360=25kHz=4µs period)
  REG_PWM_CPRD1 = 2;//840;                   //Channel1 Period Register (84mhz/4/3360=25kHz=4µs period)
  REG_PWM_CDTY0 = 1;//420;                   //Channel0 Duty Cycle Register
  REG_PWM_CDTY1 = 1;//420;                   //Channel1 Duty Cycle Register

Hermann.

can u please help me to shift it not only 90 but can I shift two PWM signlas by 10 degree for example

I cannot tell how to do 10° phase shift on Arduino Due in software.

But I looked into my hardware pool and found a SN74HCU04 hex inverter. I knew that each single logic operation does have some delay. So I just did apply 6 inversions sequentially to channel 3 from above and measured that as channel 4. As can be seen below the signal gets delayed by 40ns. I did use "REG_PWM_CPRD0 = 28;" in the sketch resulting in 1.34μs period. The resulting phase shift is:
360° / (1340 / 40) = 10.75°

So you have to choose some logic gates as in this example and produce the delay needed for 10° phase shift, depending on the frequency you are interested in.

Hermann.


a

I did shorten the 1Y-2A, 2Y-3A, 3Y-4A, 4Y-5A and 5Y-6A connections between the SN74HCU04 hex inverters as much as possible. And I made sure that all paths from measure point to logic analyzer have same length (besides the lengths added by the hex inverter connections).

Now the 270° phase shift signal from Arduino Due (pin 37) is sent to SN74hcu04 1A. Logic analyzer channel 0/1/2/3 do measure 1A, 2A, 3A and 4A, that is 0-3 hex inverters inserted, at 400Msps:

1/2/3 inverters add 3/6/8 or 3/7/8 times 2.5ns delay to channel 0 rising edge (channel 1 and 3 are the inverse of signal on channel 0). This is the best a 400Msps logic analyzer can determine:

Hermann.

I read that electrical signal speed is of the order of speed of light. I bought 250m copper wire to measure the delay with 400Msps logic analyzer. Should be in the range of (1 / 0.5) * 3.3ns/m *250m = 1650ns and 825ns. Today I measured resistance of that wire, showed 89.3Ω. Will do logic analyzer delay measurements tomorrow.

Hermann.

I did the measurements, and I have to say I am a bit surprised on was I saw.

This was the setup (click on any photo below to get it big):

I configured Arduino Due to generate a 2.5KHz PWM frequency, fast enough to get many pulses, and slow enough to not run into potentially high frequency issues. The same signal was measured directly (channel 0) and with a delay by passing through the 250m of copper wire (channel 1). This is the view on successive pulses.

It shows a little delay an falling edge, followed by an additional peak. The rising edge does not show a delay (at that resolution).

So let me start with analyzing the falling edge and the peak, zoomed in here:

The delay on falling edge (2.4μs * 0.6 = 1.44μs) is something I think I can explain. The speed of passing 1m of the copper wire is 1000000/(1.44/250) = 173611111.1m/s or 173,611km/s, slightly less than 60% of speed of light.

The peak occurs 7.44μs after the delayed falling edge. I don't have an explanation, maybe the 250m have some coil effect?

Here I zoomed into the rising edge to get timings at 2.5ns resolution of 400Msps logic analyzer:

A delay of only 5ns for 250m would correspond to 167 times the speed of light, and Einstein showed that this is not possible. Here the copper cable coil effect must be the cause.

Copper cable, at least in coil form, is not good for getting signal delay and therefore phase shift. I will cut 1m from copper wire and see whether delay is linear (should give a delay like 1.44/250 = 5.76ns).

Explanations for the peak following the delayed falling edge and the super minimal delay for 250m copper wire on rising edge are appreciated.

Going thru that big coil of wire is going to have an impact on the signal integrity.
Try looking at the signal with an oscilloscope and see what it looks like.

CrossRoads:
Try looking at the signal with an oscilloscope and see what it looks like.

I do have several logic analyzers up to 400Msps.
But I only have a SMO DSO150 (toy) oscilloscope that can do 2.250Ksps which is unusable for delays in nanosecond range.

CrossRoads:
Going thru that big coil of wire is going to have an impact on the signal integrity.

I eliminated the coil issue in cutting a 10m coper wire first and laying that in a big loop in room without any crossing. Later I did cut the 10m into pieces of 7m and 3m.

This is the falling edge, still 2μs jitter after the "real" delayed falling edge:

Zooming in on delayed falling edge shows 42.5ns delay:

Zooing in on the delayed rising edge shows 40ns delay (there is no jitter after delayed rising edge).

These are the measurements I did:

length [m] rising [ns] falling [ns]
10 40 42.5
7 27.5 30
3 10 12.5

Signal speed in my copper cable is therefore between 240,000km/s and 250,000km/s (80%-83% of speed of light):

$ bc -ql
1000000/(40/10)
250000.00000000000000000000
1000000/(42.5/10)
235294.11764705882352941176
1000000/(27.5/7)
254545.45454545454545510082
1000000/(30/7)
233333.33333333333333364444
1000000/(10/3)
300000.00000000000000030000
1000000/(12.5/3)
240000.00000000000000038400

The jitter after delayed falling edge makes just copper wire unusable for producing (PWM frequency) phase shift.

The jitter after delayed falling edge makes just copper wire unusable for producing (PWM frequency) phase shift.

Nice work!

Possibly some of the jitter (±11.9ns) is because the PWM channels aren't synchronized. The Due's PWMC has registers for synchronizing the PWM channels but I haven't tried them. Maybe there's some examples somewhere.

Also I think there would be an inductive component in the spool (coil) of wire ... probably creating some ringing on the signal, hence more jitter and measurement error.

The Due's PWMC has registers for synchronizing the PWM channels...

To synchronize the PWM controller channels you just need to set the PWM Sync Channels Mode register (REG_PWM_SCM) for the given channels:

REG_PWM_SCM |= PWM_SCM_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
               PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;

Then activate channel 0, (in synchronous mode there's no need to specify channels 1-7), using the PWM enable register (PWM_ENA):

REG_PWM_ENA = PWM_ENA_CHID0;           // Enable the PWM channels, (only need to set channel 0 for synchronous mode)

Finally, after loading the duty cycle update registers (REG_PWM_CDTYUPDx), trigger an update by setting Update Unlock bit (UPDULOCK) the PWM Sync Channels Update Control Register (REG_PWM_SCUC):

REG_PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period

It's also possible to set the PWM controller to automatically update the duty cycle every timer cycle, (rather than using the trigger above), by setting the UPDM: Synchronous Channels Update Mode bitfield in the PWM Sync Channels Mode register (REG_PWM_SCM) to MODE 1.

Here's an example:

// Enable synchronous, centre-aligned, 14-bit resolution PWM at 2kHz on 8 channels
void setup() {
  // PWM set-up on pins DAC1, A8, A9, A10, D9, D8, D7 and D6 for channels 0 through to 8 respectively
  REG_PMC_PCER1 |= PMC_PCER1_PID36;                                               // Enable PWM 
  REG_PIOB_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16;     // Set the port B PWM pins to peripheral type B
  REG_PIOC_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;     // Set the port C PWM pins to peripheral type B
  REG_PIOB_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;          // Set the port B PWM pins to outputs
  REG_PIOC_PDR |= PIO_PDR_P24 | PIO_PDR_P23 | PIO_PDR_P22 | PIO_PDR_P21;          // Set the port C PWM pins to outputs
  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);                                // Set the PWM clock A rate to 84MHz (84MHz/1)
  REG_PWM_SCM |= PWM_SCM_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4 |  // Set the PWM channels as synchronous
                 PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;  
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)                      // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CMR = PWM_CMR_CALG | PWM_CMR_CPRE_CLKA;    // Enable centre aligned PWM and set the clock source as CLKA
    PWM->PWM_CH_NUM[i].PWM_CPRD = 21000;                              // Set the PWM period register 84MHz/(2*2kHz)=21000;
  } 
  REG_PWM_ENA = PWM_ENA_CHID0;           // Enable the PWM channels, (only need to set channel 0 for synchronous mode)
  for (uint8_t i = 0; i < PWMCH_NUM_NUMBER; i++)                      // Loop for each PWM channel (8 in total)
  {
    PWM->PWM_CH_NUM[i].PWM_CDTYUPD = 10500;                           // Set the PWM duty cycle to 50% (21000/2=10500)
  } 
  REG_PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
}

void loop() {}

I am not sure why you are talking on PWM channel synchronization.
Please see this zoomin into my previous setup photo.
The whole measurements were done for only one PWM signal (pin34).
Logic analyzer channel 0 measured the signal directly, channel 1 after passing through the 250m copper cable:

Also I think there would be an inductive component in the spool (coil) of wire ... probably creating some ringing on the signal, hence more jitter and measurement error.

As I said, I did the measurements for 10m, 7m and 3m without coil effect.
I used the living room to lay the 10m cable in one big loop without any crossings, so no coil effects.

Can someone give the full code for arduino uno of 3 phase pwm with 120 degree phase shift?

... code for arduino uno ...

You post in this thread in Arduino Due forum, the answer is for Arduino Due.

The above software phase shift solution only allows for 0°/90°/180°/270" phase shift.

But I found a solution based on the code provided by MartinL (because for the 0°/90°/180°/270" phase shift code duty settings don't work, always 50%). Find below my sketch, the numbering of the channels is interesting at least. I found out by try and error starting with MartinL's code.

I did create synchronized PWM on pins D9/D8/D7 (logic analyzer channels 0/1/2):

Below sketch demonstrates as an example how to phase shift PWM signal with 60% duty by 120°.

The shifted PWM signal needs to start at 120° = 33.3% of the PWM signal.
It has to end at 33.33% + 60% = 93.33%.

The trick I use is to generate two signals (channel 1 and channel 2), that when combined by XOR gate result in the 120° phase shifted signal:

The only logic IC I currently have at home is a DIP-14 INVERTER one, so I cannot demonstrate now.
I just ordered five DIP-14 2-input XOR for 2.18$ (as well 10 DIP-14 2-input NOR/NAND/INVERTER).

Hermann.

// Enable synchronous, 14-bit resolution PWM on 3 channels
void setup() {
  // PWM set-up on pins D9, D8 and D7 
  REG_PMC_PCER1 |= PMC_PCER1_PID36;                              // Enable PWM 

  REG_PIOC_ABSR |= PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;   // Set the port C PWM pins to peripheral type B
  REG_PIOC_PDR  |= PIO_PDR_P23  | PIO_PDR_P22  | PIO_PDR_P21;    // Set the port C PWM pins to outputs
  
  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);               // Set the PWM clock A rate to 84MHz (84MHz/1)
  
  REG_PWM_SCM |= PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4;  // Set the PWM channels as synchronous

  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[0].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[1].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[2].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  REG_PWM_ENA = PWM_ENA_CHID0;                                   // Enable the PWM channels, (only need to set channel 0 for synchronous mode)

  PWM->PWM_CH_NUM[0].PWM_CDTYUPD = 0;                            // ?!?!?
  PWM->PWM_CH_NUM[4].PWM_CDTYUPD = 12600;                        // Set the PWM duty cycle to 60%            (21000*0.6=12600)
  PWM->PWM_CH_NUM[5].PWM_CDTYUPD = 7000;                         // Set the PWM duty cycle to 120°=33.33%    (21000/3=7000)
  PWM->PWM_CH_NUM[6].PWM_CDTYUPD = 19600;                        // Set the PWM duty cycle to 33%+60%=93.33% (12600+7000=19600)

  REG_PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
}

void loop() {}

I did not want to wait for the 74HC86 logic XOR to arrive.
The Due does nothing after configuring PWM in setup() of previous sketch.
So why not let Due read channel 1 and channel 2, compute the xor value and set channel 3 signal?

First you can see here that below sketch does work, channel 3 is 120° phase shifted channel 0 signal:

Ardunio Due does not allow pins to be configured for INPUT and OUTPUT at the same time.
Setting a PIN for INPUT does disable the PWM signal configured for it.
What I did is to duplicate D8/D7 (channel 1/2) to D6/D5 and use D4 for channel 3, click for details:

This is the diff to previous sketch:

$ diff sketch_feb22d.ino sketch_feb24a.ino 
0a1,6
> // C.24/C.25/C.26 = D6/D5/D4
> Pio *p = digitalPinToPort(4);
> uint32_t b4 = digitalPinToBitMask(4);
> uint32_t b5 = digitalPinToBitMask(5);
> uint32_t b6 = digitalPinToBitMask(6);
> 
29a36,39
> 
>   pinMode(4, OUTPUT);
>   pinMode(5, INPUT);
>   pinMode(6, INPUT);
32c42,53
< void loop() {}
---
> void loop() {
>   for(;;) {
>     uint32_t v;
>     v = p->PIO_PDSR;
>     
>     if (bool(v & b6) ^ bool(v & b5)) {
>       p->PIO_SODR = b4;
>     } else {
>       p->PIO_CODR = b4;
>     }
>   }
> }
$

Some global variable definitions, configuring pins 4-6 for INPUT/OUTPUT, and a loop computing the signal xor value. I used direct port access to minimize the timing footprint of the endless loop's body.

Zooming into raising edge of channel 3 shows a delay of 375ns:

Zooming into falling edge of channel 3 shows a delay of 0.4μs:

The difference with 74HC86 logic XOR woud be a delay of only 7-9ns according the datasheets.

Hermann.

https://stamm-wilbrandt.de/en/forum/sketch_feb24a.ino

can u help me for the arduino uno or arduino Mega 2560 coding to create the 3 pwm waveform ?

Sorry, I fried my only Mega, cannot help on that.

I bought a CD74HCT86E XOR IC at an electronics store.

The overall picture is the same as in previous posting:

Rising edge of 120° phase shifted signal (channel 3) is only 22.5ns delayed:

Falling edge of 120° phase shifted signal is only 22.5ns delayed:

Hermann.

OK, this is it finally, 3 PWM signals phase shifted 0°/120°/240°:

The 240° phase shift has to start at 66.66% of PWM cycle (14000).
And it has to end at 66.66%+60%=126.66% or 26.66% in next cycle (5600).

Since the 240° phase shifted signal has to be low where the 120° one is high (wrt its two generating PWM signals), the XNOR function is needed instead of XOR. I just added NOT chip SN74HCU04N to invert the computed XOR value. The added NOT adds 5ns delay to rising edge and 10ns to falling edge, resulting in 27.5ns/32.5ns delaus for the whole 240° phase shifted signal. This should be acceptable for much higher frequencies than the 4KHz PWM frequency used in this sample.

This is the wiring used matching sketch below:

channel 0: D9
channel 1: 1Y(CD74HCT86E) 
channel 2: 2Y(SN74HCU04N)  

Due--CD74HCT86E
---------------
D8--1A
D7--1B
A9--2A
A8--2B

CD74HCT86E--SN74HCU04N
----------------------
2Y--2A

And this is the sketch with additional 14000/5600 settings for A8/A9:

// Enable synchronous, 14-bit resolution PWM on 3 channels
void setup() {
  // PWM set-up on pins D9, D8 and D7 
  REG_PMC_PCER1 |= PMC_PCER1_PID36;                              // Enable PWM 

  REG_PIOB_ABSR |= PIO_ABSR_P19 | PIO_ABSR_P18 | PIO_ABSR_P17 | PIO_ABSR_P16; 
  REG_PIOC_ABSR |= PIO_ABSR_P24 | PIO_ABSR_P23 | PIO_ABSR_P22 | PIO_ABSR_P21;   // Set the port C PWM pins to peripheral type B
  REG_PIOB_PDR |= PIO_PDR_P19 | PIO_PDR_P18 | PIO_PDR_P17 | PIO_PDR_P16;
  REG_PIOC_PDR  |= PIO_PDR_P24  | PIO_PDR_P23  | PIO_PDR_P22  | PIO_PDR_P21;    // Set the port C PWM pins to outputs
  
  REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);               // Set the PWM clock A rate to 84MHz (84MHz/1)
  
  REG_PWM_SCM |= PWM_SCM_SYNC7 | PWM_SCM_SYNC6 | PWM_SCM_SYNC5 | PWM_SCM_SYNC4  // Set the PWM channels as synchronous
                 | PWM_SCM_SYNC3 | PWM_SCM_SYNC2 | PWM_SCM_SYNC1 | PWM_SCM_SYNC0;
  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[0].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[1].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[2].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[2].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[3].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[3].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[4].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[4].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[5].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[5].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[6].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[6].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  PWM->PWM_CH_NUM[7].PWM_CMR = PWM_CMR_CPRE_CLKA;                // Enable centre aligned PWM and set the clock source as CLKA
  PWM->PWM_CH_NUM[7].PWM_CPRD = 21000;                           // Set the PWM period register 84MHz/(2*2kHz)=21000;

  REG_PWM_ENA = PWM_ENA_CHID0;                                   // Enable the PWM channels, (only need to set channel 0 for synchronous mode)

  PWM->PWM_CH_NUM[0].PWM_CDTYUPD = 0;                            // ?!?!?
  PWM->PWM_CH_NUM[1].PWM_CDTYUPD = 14000;  //A8                          
  PWM->PWM_CH_NUM[2].PWM_CDTYUPD = 5600;   //A9                         

  PWM->PWM_CH_NUM[4].PWM_CDTYUPD = 12600;                        // D9 Set the PWM duty cycle to 60%            (21000*0.6=12600)
  PWM->PWM_CH_NUM[5].PWM_CDTYUPD = 7000;                         // D8 Set the PWM duty cycle to 120°=33.33%    (21000/3=7000)
  PWM->PWM_CH_NUM[6].PWM_CDTYUPD = 19600;                        // D7 Set the PWM duty cycle to 33%+60%=93.33% (12600+7000=19600)

  REG_PWM_SCUC = PWM_SCUC_UPDULOCK;      // Set the update unlock bit to trigger an update at the end of the next PWM period
}

void loop() {}

Summary:
For Due the described method shows how to generate 120° phase shifted PWM signal. More it shows how to do any phase shift with any pulsewidth. Cost is 2 PWM lines on Due and 1 XOR/XNOR gate per phase shifted signal.

Hermann.

I used PWM library to generate 4 PWM signals of desired frequency(60hz)and 1phase.The problem is i am not able to give a phase shift to the PWM.and i need a phase shift of 90 degree. can you please help me to shift it with these particulars ?thanks a lot