5 MHz clock signal

06 May 2010

I'd like to have precisely 5 MHz clock signal. mbed PWM seems to be able to give 1MHz (with 1 us period). Is there an easy way to do this, instead of buying a 5 MHz crystal oscillator.

10 May 2010 . Edited: 10 May 2010

Assuming you are using an LPC1768, I'm afraid you cannot generate a precisely 5 MHz clock from the PWM. Even if you don't use the current library, and drive the PWM yourself, you are constrained by integers.

The LPC1768 clocks at 96MHz. 96e6 / 5e6 gives 19.2. The PWM block counts off of the system clock, so your period counter would have to be either 19 or 20. 19 gives you a frequency of just over 5.052MHz, and 20 gives you 4.8 MHz. (Note, to get these frequencies, you have to bypass the library).

Assuming that the 5.052andabit is good enough, here's how you get there. I'll use the library object as a starting point, as it does a load of the pin connection setup, enabling the block and all that for us. I'll just go and trample over some of its settings afterwards. I'm going to use pin 21 of the mbed, which is PWM output 6.

The PWM block has a match register 0, which is used as the period counter. Then, each of the PWM outputs (1 through to 6) have their own match counters, which are used to determine when to change the output level. We're using the block in a simple "output high, until match counter matched, then output low" mode. Thus our value of MR0 is going to be 18 (we count from zero, match at 18), and our value of MR6 (if using p21) is going to be 9. These counters are derived from the system clock, through a peripheral clock divider and a prescaler. So what we need to do is:

  • Reset the PWM block
  • Set the peripheral clock divider to /1 (the library sets the prescaler to /1 for us)
  • Load the match registers
  • Tell the block to start at next match
  • Re-start the PWM block

#include "mbed.h"

DigitalOut myled(LED1);
PwmOut fmclck(p21);

int main() {        
    LPC_PWM1->TCR = (1 << 1);               // Reset counter, disable PWM
    LPC_SC->PCLKSEL0 &= ~(0x3 << 12);  
    LPC_SC->PCLKSEL0 |= (1 << 12);          // Set peripheral clock divider to /1, i.e. system clock
    LPC_PWM1->MR0 = 18;                     // Match Register 0 is shared period counter for all PWM1
    LPC_PWM1->MR6 = 9;                      // Pin 21 is PWM output 6, so Match Register 6
    LPC_PWM1->LER |= 1;                     // Start updating at next period start
    LPC_PWM1->TCR = (1 << 0) || (1 << 3);   // Enable counter and PWM

    while(1);
}

13 May 2011

How would this apply to pin 26 and 2MHz?

I have a hard time finding the pattern.

Jesper

14 May 2011

Could you not just change the frequency of one of the peripheral clocks and output it to a pin? I'm not sure if the pin is available as standard, but you could always solder a bit of wire wrap.

Rob

15 May 2011

Sounds reasonable :)

Would you be able to refer me to an example?

Jesper

17 May 2011

Jesper,

A 2.0 MHz clock is even easier than 5.052 MHZ. The default for the mbed cclk is 96 MHz. The default pclk for the PWM block is 1/4 the cclk, or 24 MHz. So, set the PWM channel of your choice to a period of 24.0/2.0 = 12 clocks (set register = 11), and set the output high period for a 50%/50% dutycycle = 12 * 50% = 6 clocks (set register = 5). No need to stop and restart the PWM block.

You can get a nominally exact 5.000 MHz clock if you re-program the CPU's cclk to 100 MHz. There is a prior thread somewhere that discusses how to do that (and re-set the serial clocks, etc.).

You could also use one of the counter-timer channels to generate a clock signal on it's corresponding 'match output' pin. All of the PWM channels have to have the same frequency (5.052 MHz or 2.000 MHz, etc.), but the counter-timers can generate different frequencies from the PWM and from each other. I'm just not sure how using counter-timer channels directly will interfer with the 'timer' library functions (or how to keep them co-operating).

As for connecting one of the pclks to a pin, there is only one pin on the 1768 which has that capability. But, on the mbed, that pin is already used internally in the ethernet chip connections.

17 May 2011

Don't have an example I'm afraid....just have spent too much time reading the user manual. I don't think I'll get a chance to write an example, but maybe someone else on here has had a play with the clocks before? Sorry I can't be more help!

Rob

18 May 2011

I found it a bit confusing working with the user manual.

Then I found this article

http://msys-mv.blogspot.com/2011/01/using-pwm-on-lpc17xx.html

But I could not make it work, partly because I could not figure out what MBED pins map to what LPC1768 pins.

So I ended up just setting up the pwm output pins as usual, and then overwriting the pwm prescaler.

LPC_SC->PCLKSEL0 = ~(0x03 << 12);
LPC_SC->PCLKSEL0 |= 2 << 12;

Its not pretty but it gets the job done.

Thanx for your replies!

Jesper

02 Mar 2012

Hi everyone, Thank you for the explaination. I am not sure what is the V pk-pk for the output signal, can anyone please varify it? Is it TTL 5V logic output at the PWM out pins?

It might seem a bit silly but is this voltage variable?

Furthermore, I am just a beginner and i just bought this mbed microcontroller. I do not have an oscilloscope in handy. Is there a way that i can check the frequecny out on the putty or any other terminal? I see there is a read function in the pwmout. but how would i be able to use it to store the read value into a variable and then print it onto the terminal screen. you help much appreciated.

02 Mar 2012

Hello Muhammad,

I posted some code to test here. It uses printf() to write data on terminal.

http://mbed.org/handbook/PwmOut#c2838

02 Mar 2012

Output levels on all digital pins are 0V or 3V3. The voltage is not variable. You can reduce the output level by using a resistor divider or a variable resistor (potmeter). If you need the mbed to control the voltage level then some form of programmable voltage divider may be used. Higher voltage levels like 5V are possible by using some buffer like a transistor or a TTL gate.

05 Mar 2012

Thank you wim and little llumpu. I tested the code and i had a chance to use a oscilloscope as well. Little llumpu, your code is working. I am a bit confused. I am having difficulty differentiating between led.period_us and led.pulsewidth_us. I am now trying to vary the frequency between 1-30 MHz. according to what i have read, apparently i cannot go higher than 24 Mhz. Although im looking at the datasheet right now, i was wondering if someone could direct me in the right direction. Regards, Arslan

08 Mar 2012

LPC_PWM1->TCR = (1 << 1);

is anyone able to tell me what "->" does in this code?