This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Hardware PWM - vary the frequency

I'm using a Philips P89C668 at 16MHz in 6-clock mode. I've got a piezo (with internal driver) on P1.3 (CEX0). I'd like to switch to a speaker and output PWM to get different tones. However, I can't find any good examples on how to vary the period (frequency). I've read the Intel PCA cookbook and their one example shows how to set it at the maximum frequency, but not how to vary it or how to use other PCA sources for PWM. I don't need to vary duty cycle. Here's the PCA init:

CMOD = 0x02;    // OSC/2 (6-clk mode)
CCAPM0 = 0x42;  // Mod0 in 8-bit PWM
CCAP0H = 0x80;  // set 50% duty cycle
CCAP0L = 0x00;  // set 50% duty cycle
CH = 0x00;
CL = 0x00;
CR = 1;         // turn it on

There don't appear to be any prescalers involved, so then am I stuck with a fixed output frequency? Would it help to change the PCA source to Timer0? If so, what other registers are involved and in what ways? The P89C668 datasheet is light on the details. Any help would be appreciated...

  • The reason it's hard to do this with a PWM is that what you're looking for isn't PWM. It's PFM or pulse frequency modulation. As you have discerned, you need to select a variable-frequency source (e.g. timer0) for the PCA clock input rather than a fixed frequency.

    From that point, varying the frequency will consist of just changing the Timer0 reload value to get a different rollover frequency on it and you'll change the output frequency of your PWM.

    (Note that the PWM might still be useful to you. Depending on how you hook things up, the PWM duty cycle might well vary the volume of your output tone)

  • Sorry... I didn't realize you had asked for registers, etc. before I posted my answer. Here's an example of how to change the frequency based on your code.

    CMOD = 0x04;    //T0 overflow as PCA CLK
    CCAPM0 = 0x42;
    CCAP0H = 0x80;
    CCAP0L = 0x00;
    CH = 0x00;
    CL = 0x00;
    
    TMOD &= 0xF0;
    TMOD |= 0x02;    //Set T0 to 8-bit timer
    TH0 = 0x80;      //Half frequency
    TL0 = 0x00;
    TR0 = 1;         //T0 Run
    

    Here's a pretty important point though: You had previously selected Osc/2 as the input to your PCA clock. T0, has Osc/12 as its input (or I guess Osc/6 in your 6-clocker). This means that even at its maximum rollover rate, the output frequency will be 3-times lower than what you can achieve by using the fixed prescaler for the PCA input. Dpending on what you're trying to achieve, this might be too low altogether.

    Hope some of that helps.

  • Ahh, you're right. Not sure why that didn't occur to me...

    Anyway, let's say I wanted to set the PWM output to 50 Hz at 50% for a servo. Could I even do that in this case?

  • Pete,

    That depends quite a bit on your clock frequency. You've clearly already figured out how to make a 50% duty-cycle waveform from the PWM. That doesn't need to change. What you need to change is the PCA input frequency. Here's an example:

    Let's assume you have a 29.4912MHz crystal (a commonly-used value for the 33MHz standard 8XC51 variants due to baud rates, etc.). I'll also assume you're in 12-clock mode since I don't feel like breaking out the datasheet for a 6-clocker to make sure I'm not losing any nuances.

    The input to the T0 when it's configured as a timer is Osc/12 or 2.4576MHz. Assuming I keep T0 configured as an 8-bit auto-reloading timer as I mentioned above, the minimum rollover frequency would be (2.4576e6 / 255), which is about 9.6kHz. So, leaving things as we had them above, this is the MINIMUM PCA input frequency you could get. The way the PCA PWM modules work is that the PCA counter ticks up from 0 to 255. When it's less than the value in CCAPXL, the output is at one state, and when it's equal to or greater, the output is in the other state. This means that the actual frequency coming out of the PWM for this PCA input would be

    (2.4576e6 /255 /255) = 37Hz

    So if for some reason you wanted exactly 50Hz (which isn't such a necessity for just running an R/C servo and in fact might be too fast), you'd calculate the number of T0 clock ticks per rollover as:

    (2.4576e6 /255 / x) = 50 ===> x = ~193

    This would give a T0 reload value (to be placed in TH0) of 256 - 193 = 63

    Again... I hope some of that helps. Trust me... once you do this the first time, it will all become much clearer. Also, Erik's advice to take another look at the PCA cookbook is a seriously good one. Things like this will almost surely be in there.