maelli01 74 Posted June 4, 2014 Share Posted June 4, 2014 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 Quote Link to post Share on other sites
roadrunner84 466 Posted June 4, 2014 Share Posted June 4, 2014 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. maelli01 1 Quote Link to post Share on other sites
spirilis 1,265 Posted June 4, 2014 Share Posted June 4, 2014 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 maelli01 1 Quote Link to post Share on other sites
maelli01 74 Posted June 4, 2014 Author Share Posted June 4, 2014 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? Quote Link to post Share on other sites
spirilis 1,265 Posted June 4, 2014 Share Posted June 4, 2014 I thought Arduino had the same problem but I could be mistaken. Sounds like you tested on the Uno anyhow. Quote Link to post Share on other sites
maelli01 74 Posted June 4, 2014 Author Share Posted June 4, 2014 here is the Arduino Uno, same script, pin 3 (the one with 480Hz, some pins have different frequency...) definitely no problem there Quote Link to post Share on other sites
roadrunner84 466 Posted June 4, 2014 Share Posted June 4, 2014 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 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. Quote Link to post Share on other sites
spirilis 1,265 Posted June 4, 2014 Share Posted June 4, 2014 @@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 maelli01 1 Quote Link to post Share on other sites
maelli01 74 Posted June 4, 2014 Author Share Posted June 4, 2014 works a treat! glitches are gone (tried to trigger on "longer than allowed pulses", none present) thanks alot! Quote Link to post Share on other sites
maelli01 74 Posted June 4, 2014 Author Share Posted June 4, 2014 now I can do fun things with PWM 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... manhdan, jsolarski, roadrunner84 and 1 other 4 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.