chipKIT® Development Platform

Inspired by Arduino™

analogWrite (PWM) issues

Created Tue, 05 Jul 2011 07:51:11 +0000 by mirifica


mirifica

Tue, 05 Jul 2011 07:51:11 +0000

Dear all, we are experiencing problems porting a PWM application from Arduino 2009 to ChipKit Uno32 (mpide-0022-chipkit-win-20110619.zip).

working original code @ Arduino 2009

void setup() {
}
void loop() {
  analogWrite(6, 100);
}

Result on pin6 @ Arduino 2009: PWM signal (right) Result on pin6 @ chipKit Uno32: steady high level (wrong!)

working workaround code A) @ chipKit Uno32

void setup() {
  analogWrite(6, 100);
}
void loop() {
}

working workaround code B) @ chipKit Uno32

void setup() {
}
void loop() {
  analogWrite(6, 100);
  delay(1000);
}

These workaround are not viable solutions in our applications. Would it be possible to improve the chipKit PWM library at least at Arduino quality standard (indeed not very high either)?


ex2939

Tue, 05 Jul 2011 11:54:15 +0000

I'm having the same problem. I'm using the Max 32 and I can't get any pulse on the PWM just a constant voltage of 2.5V.


davec

Sat, 09 Jul 2011 00:09:37 +0000

I can see why this happens, the PWM implementation in wiring_analog.c re-opens Timer2 and resets the Output Compare being used for the pin on every call to analogWrite(), so if analogWrite() is being called rapidly in a loop the OC never gets the chance to fire, so there is no PWM. Even if it's called less often, the PWM will still "glitch" on every analogWrite() call because it will reset the PWM, probably part-way through a cycle. Every PWM pin will glitch because it's the same timer for all of them.

The AVR equivalent sets up the timers in wiring.c init() and just remaps them to the right pin in analogWrite(). Is it possible to do this for PIC32?


CNCaddict

Thu, 14 Jul 2011 02:01:14 +0000

Thanks to hackaday drum synthesizer code I managed to get the fade example working. Looks like you need a pin with OC on it..OC1, OC2, etc.

/* Fade

This example shows how to fade an LED on pin 9 using the analogWrite() function.

This example code is in the public domain.

*/ int brightness = 1; // how bright the LED is int fadeAmount = 1; // how many points to fade the LED by

void setup() { // declare pin 3 to be an output: pinMode(3, OUTPUT);

// Open Timer2, 1:1 w/2048 tick interval (for 11-bit PWM) OpenTimer2(T2_ON | T2_PS_1_1,2048); OpenOC1(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0,0); }

void loop() { // set the brightness of pin 3: SetDCOC1PWM(brightness);

// change the brightness for next time through the loop: brightness = brightness + fadeAmount;

// reverse the direction of the fading at the ends of the fade: if (brightness == 1 || brightness == 2047) // wait for 5 milliseconds to see the dimming effect delay(5); }


GeneApperson

Fri, 05 Aug 2011 20:52:37 +0000

The current implementation of analogWrite has a problem when successive calls are made too quickly. The PWM waveform generated has a period of about 2ms (i.e. ~500Hz). If successive calls are made with less than 2ms between them you are actually calling analogWrite faster than the frequency of the generated waveform. The fact that it fails in this case is a bug, but I have found experimentally, if there is ~10ms or more delay between successive calls, it works pretty well.

I think I know how to fix it, but this is a work around in the interim.

Gene Apperson Digilent


slayer1991

Sun, 27 Nov 2011 04:37:16 +0000

Hello, I want to use pwm to control a lm 3914 bar graph. Of course, it would be easy if analogWrite would work. How can I do it otherwise?


majenko

Sat, 03 Dec 2011 12:13:38 +0000

The proper way to deal with the PWM would be to only update the duty cycle when the timer triggers an interrupt to say it is at the end of the duty period.

However, that's not how the chipKITâ„¢ implementation does it.

For now you will have to insert a delay between successive calls. It doesn't make sense to change the duty cycle faster than the period of the duty anyway.


GeneApperson

Tue, 13 Dec 2011 16:55:14 +0000

The proper way to deal with the PWM would be to only update the duty cycle when the timer triggers an interrupt to say it is at the end of the duty period. However, that's not how the chipKITâ„¢ implementation does it. For now you will have to insert a delay between successive calls. It doesn't make sense to change the duty cycle faster than the period of the duty anyway.

The fix for the PWM bug was checked into the github repository on Aug 7. It should be working correctly on any build done after that.

There are no interrupts involved in doing PWM output on either PIC32 or AVR devices. On the PIC32 the timer is programmed to reset when the value in the period register is reached. This sets the PWM frequency. The output compare sets the pin high when the timer resets and sets the pin low when the value in the compare register is reached, thus setting the duty cycle. It works similarly on AVR devices, but the details are different.

In this case, the bug was that the code was reinitializing the timer each time that analogWrite was called. The result being that if calls to analogWrite were made more frequently than the period of the timer (about 490hz), the counter never counted up to the value in the compare register of the output compare unit.

The fix was to keep track of whether or not the timer had already been initialized, and only initialize it when analogWrite is called and there are no PWM outputs active.

Gene Apperson Digilent