Jump to content
43oh

PWM glitches, Analog Write


Recommended Posts

Hi,

Playing around with AnalogWrite and my scope:

This little script toggles between two duty cycles:

const int analogOutPin = 9;

void setup() {
  pinMode (analogOutPin,OUTPUT);
}

void loop() {
  analogWrite(analogOutPin, 100);
  delay(15);
  analogWrite(analogOutPin, 150);
  delay(15);
  }  

 

below is how this looks on the scope, blue direct, yellow with a simple

R-C lowpass.

 

 

every now and then, when changing duty cycle, I get an extra-long pulse.

I am using the G2553 on the launchpad, with xtal.

I have seen on this forum that calling AnalogWrite when NOT changing the duty cycle should be avoided.

But I DO sometimes want to change the duty cycle  ;-)

 

Tried the same on an Arduino Uno, no problem there, smooth transitions.

 

any suggestions?

 

maelli01

post-37272-0-64988100-1401869918_thumb.png

Link to post
Share on other sites

The problem that occurs is intrinsic to the way the PWM (timer) behaves.

The timer is counting from 0 up to TACCR0 (Timer A capture / compare register 0), then it resets to 0 and starts again.

In the mean while TACCR1 and TACCR2 monitor the value of the counter and set or clear certain flags when they are equal to the counter value.

Now imagine this counter to be counting up:

0, 1, 2... 98, 99, 100, 101, 102... 253, 254, 0, 1....

Now every so much time you change TACCR1 by means of analogWrite(). This will be fine if you change from 100 to 150, the flags will be updated 50 counts later.

If however you change from 150 to 100 just as the counter is in between 100 and 150 you got a problem:

the capture/compare unit will not trigger at 100, nor at 150. Instead, the counter will roll over to 0 again, and the next time it hits 100 again, just then it will trigger the capture/compare unit.

 

The only real solution is to define a well behaved system for this exception. Here are some suggestions:

- After the delay(15) set a flag, then have an interrupt trigger on the roll over of the counter. When the rollover occurs and the flag is set, update analogWrite().

- After the delay(15) wait for the output to drop to low value, then update with analogWrite().

- Instead of delay(15), count a number of timer rollovers, then your update will always be close to the point where the counter is 0.

Link to post
Share on other sites

Was just wondering why it works so easily on the AVR.

 

Had a look at the AVR datasheet:

could it be that Arduino uses "phase correct PWM mode" where the counter counts

"up-down-up...." instead of "up, then reset, up...." ?

 

The MSP430 timer does not have such a mode?

Link to post
Share on other sites

Was just wondering why it works so easily on the AVR.

 

Had a look at the AVR datasheet:

could it be that Arduino uses "phase correct PWM mode" where the counter counts

"up-down-up...." instead of "up, then reset, up...." ?

 

The MSP430 timer does not have such a mode?

Actually, the MSP430 does have a up/down mode. but it's not used for PWM, probably because it's a bunch more complex to use.

 

There's a patch in the works to get Energia to do this right but it's not quite committed due to some details to work out with interrupts. It uses IRQs in conjunction with the timers to "double buffer" any pwm updates.

 

Sent from my Galaxy Note II with Tapatalk 4

Which is identical to my either of my first two suggestions :rolleyes:

 

Was just wondering why it works so easily on the AVR.

 

Had a look at the AVR datasheet:

could it be that Arduino uses "phase correct PWM mode" where the counter counts

"up-down-up...." instead of "up, then reset, up...." ?

 

The MSP430 timer does not have such a mode?

Actually, the MSP430 does have an up/down mode, but it's not used for the PWM. I think the same problem would occur then.

Link to post
Share on other sites

@@maelli01 - If you'd like to test my variation of the analogWrite stuff, pop this file into your energia-0101E0012\hardware\msp430\cores\msp430 directory:

https://raw.githubusercontent.com/energia/Energia/af7236c9f45992cfc5780f172a165fede5bae2a9/hardware/msp430/cores/msp430/wiring_analog.c

It replaces "wiring_analog.c"

 

If you happen to be using the F5529 LaunchPad with this too, please also grab this:

https://raw.githubusercontent.com/energia/Energia/af7236c9f45992cfc5780f172a165fede5bae2a9/hardware/msp430/variants/launchpad_f5529/pins_energia.h

and put it in energia-0101E0012\hardware\msp430\variants\launchpad_f5529 - it replaces pins_energia.h

Link to post
Share on other sites

now I can do fun things with PWM :smile:

 

feed a 1kHz sine wave into Pin2, go through this shortish sketch:

void setup() {analogFrequency(20000);}
void loop()  {analogWrite(9,analogRead(2)/4);}

look at the signal on pin 9, blue trace, low pass filtered yellow trace.

 

 

With the new library: nice 1kHz PWMded sinewave on a 20Khz carrier!

With the old library: garbage.

 

 

the loop() runs with 6.8kHz, should be fast enough for very low quality audio

stuff...

post-37272-0-05933000-1401909301_thumb.png

post-37272-0-39036500-1401910061_thumb.png

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...