11 years, 4 months ago.

frequency in PWM output does not change

In the code below, I set a 2-edged PWM output, the duty cycle and frequency of which I want to be able to change in my application. So I set up a bunch of global variables that define the PWM output, and set up a ticker which is meant to change the PWM parameters every so often.

The problem is, I seem to be able to change everything BUT the frequency. Executing the simple code below, the "before" versus "after" has a different duty cycle, but the time period has not changed at all.

/media/uploads/jay_pentair/pwm_before.png

/media/uploads/jay_pentair/pwm_after.png

The code should be simple enough, does anybody see what I'm missing? Any resets maybe?

(comment: cannot use the MBED pwmOut library for other reasons)

Jay

#include "mbed.h"

Ticker pwmChg;

float duty; 
int PWMclock; 
int PWMrate; 
float frequency; 
 
void pwmupdate()
{
    int PWMwidth, PWMhalf, PWMrising, PWMfalling;

    PWMwidth = (duty * PWMrate) / 100;
    PWMhalf = PWMwidth / 2;
    PWMrising = PWMrate - PWMhalf;
    PWMfalling = PWMhalf;
    
    LPC_PWM1->MR3 = PWMrising; // Set rising edge
    LPC_PWM1->MR4 = PWMfalling; // Set falling edge
    
    LPC_PWM1->LER |= 0x18; // Enable PWM Match 3 & 4 latch
}
 
 
int main() 
{
    duty = 50.0;
    frequency = 1000.0;
    
    PWMclock = SystemCoreClock / 4;
    PWMrate = PWMclock / frequency; 
    LPC_PINCON->PINSEL4 |= 0x00000040;                     // Set P2.3 for PWM1.4
    
    LPC_PWM1->MCR |= 0x00000002; // Reset PWM0 on match

    // Set up match registers
    LPC_PWM1->MR0 = PWMrate; // Set MR0 (PWM rate)

    LPC_PWM1->PCR |= 0x00000010; // Select double edge PWM for PWM4

    LPC_PWM1->PCR |= 0x00001000; // Enable PWM4

    LPC_PWM1->TCR |= 0x08; // Enable PWM mode
    LPC_PWM1->TCR |= 0x01; // Enable counter
 
    pwmChg.attach_us(&pwmupdate, 100000);
 
    while (1)
    {
        wait(5);
        
        frequency = 2000.0;
        PWMrate = PWMclock / frequency; 
        LPC_PWM1->MR0 = PWMrate; // Set MR0 (PWM rate)
        
    }
}

My 1st day on mBed hardware/software: Are you allowed by the software to change the frequency with the PWM enabled? Depending on the hardware that can usually cause nasty glitches. Try stopping the PWM and change the frequency. Len Spyker

posted by len spyker 27 Jul 2013

2 Answers

11 years, 4 months ago.

Len Spyker is close to the answer. He is correct that just directly updating it can cause glitches, stopping the PWM and restarting it causes even more glitches though. That's why on the LPC1768 the PWM is buffered: you only write to a buffer register, the buffer register is loaded in the real register when a new PWM cycle starts. However that is only done when the corresponding bit in the LER register is '1', so just as in your update function:

LPC_PWM1->LER |= 0x01;

Jay Zee
poster
11 years, 4 months ago.

Erik: Thanks alot, that did it.

All: what sort of potential problems are you referring to when updating the PWM frequency? For my application, I'm dealing with tens of kHz tops.

And independent of the answer: what's the best solution for implementing pulse frequency modulation? I guess that question extends beyond the mbed framework.

Jay

I guess the best option is simply pretty much what you do, writing directly to the PWM match register. You can do it from an interrupt if you have other code running on the background. But the standard PWM library has some extra code in the frequency update routine that you won't need, so only slows it down.

On unbuffered PWM units you can get some problems with updating the registers. Lets say your match register is equal to 150. The timer is meanwhile at 140, and then you decide to change the match register to 130. Then that cycle no match will occur and you get a glitch. But here the PWM is buffered so it can't happen.

posted by Erik - 29 Jul 2013