Generating a 4Mhz square wave/clock for the ATMEGA644P

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I am trying to generate a 4Mhz FAST PWM square wave from the ATMEGA644P that runs at 8Mhz off the internal RC clock.  Is that possible?  I have searched the entire site but haven't found some near my requirement.

 

Below is my code so far, but that does not seem to do it.  Basically, I am trying to get the fast PWM signal out from the OC0B pin (pin 5, PB4) of the ATMEGA644.  Thanks for any tip!

 

void setup4MhzClk() {

  TCNT0 = 0;

  // In the next line of code, we:
  // 1. Set the compare output mode to OC0B on compare match.  To achieve this,
  //    we set bits COM0B1 to high.
  // 2. Set the waveform generation mode to fast PWM (mode 3 in datasheet).
  //    To achieve this, we set bits WGM01 and WGM00 to high.
  TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);

  // In the next line of code, we:
  // 1. Set the waveform generation mode to fast PWM mode 7 et counter on
  //    OCRA value instead of the default 255. To achieve this, we set bit
  //    WGM02 to high.
  // 2. Set the prescaler divisor to 1, so that our counter will be fed with
  //    the clock's full frequency (8MHz). To achieve this, we only need to
  //    set CS00 to high.
  TCCR0B = _BV(WGM02) | _BV(CS00);

  // Half of the freq => 4Mhz.  Top value for our counter to hit before
  // resetting.
  OCR0A = 127;

  // 50% duty cycle
  OCR0B = 63;
}

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If it needs to be a true PWM (that is, varying duty cycle), then no, you cannot from a Mega644. You need something that has a clock, significantly higher than 4MHZ, that the timer can run from. Why not? 1 8MHz clock, logic high, 1 8MHz clock, logic low, thats a 4MHz square wave, no way to do PWM. And, to make a signal, the generator has to be in a loop; no way to do a single-clock set pin, single-clock clear pin, and then loop. Even that absolute minimum will be at least 3 clock cycles, maybe 4 in assembler.

 

XMega chips have a PLL clock multiplier. There are also a few Mega or Tiny chips that have this capability. But not M644.

 

In your setup, the fequency will be 8MHz (8MHz FCPU and 1x prescaler) divided by 128 (from OCR1A). Nowhere close to 4MHz.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Tue. Jul 9, 2019 - 02:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:

If it needs to be a true PWM (that is, varying duty cycle), then no, you cannot from a Mega644. You need something that has a clock, significantly higher than 4MHZ, that the timer can run from. Why not? 1 8MHz clock, logic high, 1 8MHz clock, logic low, thats a 4MHz square wave, no way to do PWM. And, to make a signal, the generator has to be in a loop; no way to do a single-clock set pin, single-clock clear pin, and then loop. Even that absolute minimum will be at least 3 clock cycles, maybe 4 in assembler.

 

XMega chips have a PLL clock multiplier. There are also a few Mega or Tiny chips that have this capability. But not M644.

 

In your setup, the fequency will be 8MHz (8MHz FCPU and 1x prescaler) divided by 128 (from OCR1A). Nowhere close to 4MHz.

 

Jim

 

I don't need to vary duty cycle.  Just a nice 4Mhz square wave at 50% duty cycle.  Not sure what loop you are referring to, but the code I posted is just function, which basically attempts to setup a free running 4Mhz square wave.  There is main() that will loop forever.

 

In the worst case, I'll just run the 644 with 4Mhz external crystal and use the CLKOUT pin to have 4Mhz square wave output.  But, I am running it as 8Mhz via the internal RC oscillator.

Last Edited: Tue. Jul 9, 2019 - 02:23 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

unebonnevie wrote:

I am trying to generate a 4Mhz FAST PWM square wave from the ATMEGA644P that runs at 8Mhz off the internal RC clock.  Is that possible?  I have searched the entire site but haven't found some near my requirement.

That will depend on the PWM block, for this to work, you would need

*SysCLK /1 clock feed into PWM

*PwmPeriod counter set very low, so every 2nd clock reloads.

*PwmCompare value you may need to experiment with, as there could be a Min/Max delay on the compare output. You want this to set on one sysclk and clear on the next.

 

It may be pushing things, but you could approach from below with (say) a 1MHz try of /8 and 50% setpoint, then when you have 50% output, you can work where to move to go faster.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

It sounds like you have an 8MHz clock and want to

generate a 4MHz output.  For this, you do not need

PWM. Set up a timer to run at full speed in Clear

Timer on Compare match (CTC) mode and set the

TOP value to 0. Configure one of the compare match

registers to 0 and its corresponding pin to toggle on

match.

 

The counter will not actually count since it is constantly

resetting to zero, but this will cause the output pin to

toggle continuously at half the clock rate, producing a

square wave of half the clock frequency.

 

--Mike

 

EDIT: toggles at clock rate, not half

 

Last Edited: Tue. Jul 9, 2019 - 02:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another option is simply to set the CKOUT fuse then pass the CKO signal into a binary dividing TTL to halve the 8MHz to 4MHz.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Another option is simply to set the CKOUT fuse then pass the CKO signal into a binary dividing TTL to halve the 8MHz to 4MHz.

Or, if the app can live with it, divide the system clock by two via CLKPR.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-mike wrote:

It sounds like you have an 8MHz clock and want to

generate a 4MHz output.  For this, you do not need

PWM. Set up a timer to run at full speed in Clear

Timer on Compare match (CTC) mode and set the

TOP value to 0. Configure one of the compare match

registers to 0 and its corresponding pin to toggle on

match.

 

The counter will not actually count since it is constantly

resetting to zero, but this will cause the output pin to

toggle continuously at half the clock rate, producing a

square wave of half the clock frequency.

 

--Mike

 

EDIT: toggles at clock rate, not half

 

 

 

I like this proposal.  Trying this out and got the below.  See scope image attached.  Very good.  At 4.03Mhz!  0.3Mhz extra.  Probably I can set OCR0B to 1 to get rid of the extra 0.03Mhz.  Thank you! AVR-MIKE!  However, the waveform is not that squared.  Will that affect much?  What can I do to make the wave more squared?  A capacitor?

 

Btw, I want 0C0B ouput and I had to set the flag WGM01 to enable CTC mode, but that flag, per the datasheet, has OCRA as the TOP value NOT OCR0B!!!  That's one confusion I hope someone can clear for me, because right now the below code works due to OCR0A being zero by default????

_BV(WGM01)

//
// Use CTC with toggling.
// OC0B (Timer/Counter 0 Output Compare Match B Output)
// Set the below registers
// =======================
// 1) In TCCR0A:
//    -set COM0B0 1 Toggle OC0B on Compare Match
// 2) In TCCR0B:
//    -CS00 (no pre-scaling)
// 3) OCR0B sets to 0.  The counter will not actually count since it is constantly
//    resetting to zero, but this will cause the output pin to toggle continuously
//    at the clock rate, producing a square wave of half the clock frequency.
//
void setup4MhzClk() {

  TCNT0 = 0;

  TCCR0A = _BV(COM0B0) | _BV(WGM01);
  TCCR0B = _BV(CS00);
  OCR0B = 0;
}

Attachment(s): 

Last Edited: Wed. Jul 10, 2019 - 08:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:

Or, if the app can live with it, divide the system clock by two via CLKPR

 

Not familiar with the CLKPR option.  Found the post  https://www.avrfreaks.net/forum/programming-clkpr .  Please elaborate more if anything else needed.  Thanks!

Last Edited: Tue. Jul 9, 2019 - 02:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

unebonnevie wrote:
Not familiar with the CLKPR option.  Found the post  https://www.avrfreaks.net/forum/programming-clkpr .  Please elaborate more if anything else needed.  Thanks!
It's right there in the datasheet!

 

However, rather than fuss with tickling SFR in just the right way (e.g. ensuring that timing requirements are met, handling device-to-device idiosyncrasies, etc.), it's best to let a proven library do the work:

https://www.nongnu.org/avr-libc/user-manual/group__avr__power.html

clock_prescale_set     (     clock_div_t      x    )     

 

Set the clock prescaler register select bits, selecting a system clock division setting. This function is inlined, even if compiler optimizations are disabled.

 

The type of x is clock_div_t.

 

Note
    For device with XTAL Divide Control Register (XDIV), x can actually range from 1 to 129. Thus, one does not need to use clock_div_t type as argument.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The nice thing about a divider is it will give you "exactly" 50% duty, regardless of the input duty cycle  (neglecting any slight variations, and time responses). 

So you could feed in 8 MHz at 27.13% duty & a divider provides 4 MHz at 50% duty.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

The nice thing about a divider is it will give you "exactly" 50% duty, regardless of the input duty cycle  (neglecting any slight variations, and time responses). 

So you could feed in 8 MHz at 27.13% duty & a divider provides 4 MHz at 50% duty.

 

Sorry a little densed...

 

27.13% duty cycle means the top counter set at around 69.  Then divides by 2 from 8Mhz to achieve 4Mhz, then the top counter is around 38?

Last Edited: Wed. Jul 10, 2019 - 07:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, you DO NOT need to try to generate such an asymmetrical square wave. It was just an example. Using a JK or RS flipflop CAN (if properly connected) count down by 2 and the result will be almost perfectly symmetrical. The only asymmetry will be from mis-matched delay times in the two halves of the flip-flop. So, that should be no more than a few nanoseconds with 74HC logic.

 

Actually, you would not even need to use an internal timer. Just set the CKOUT fuse and connect the flipflop clock input to the clock out pin. You may also need to connect Q and !Q flipflop outputs to control inputs to get the divide by 2. That depends on the kind of flipflop used.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Wed. Jul 10, 2019 - 08:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

unebonnevie wrote:

At 4.03Mhz!  0.3Mhz extra.  Probably I can set OCR0B to 1 to get rid of the extra 0.03Mhz.

 

Your clock is probably running at 8.06 MHz.  This can

be adjusted by modifying the value in the OSCCAL

register.

 

Quote:

However, the waveform is not that squared.  Will that affect much?  What can I do to make the wave more squared?  A capacitor?

 

From looking at your attached picture, it appears there

is a bit of capacitance already on the output.  Adding

more capacitance would make it even less square.

 

Quote:

Btw, I want 0C0B ouput and I had to set the flag WGM01 to enable CTC mode, but that flag, per the datasheet, has OCRA as the TOP value NOT OCR0B!!!  That's one confusion I hope someone can clear for me, because right now the below code works due to OCR0A being zero by default????

 

You have it configured correctly.

 

The counter will count from zero to the TOP value which

is OCR0A.  Since OCR0A is zero, the counter will never

increase TCNT0 to a number larger than zero.  OCR0B

is also zero, so it always matches TCNT0.  Every time

there is a match (which is always), the COM0B bits say

to toggle the OC0B output pin.

 

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-mike wrote:

unebonnevie wrote:

At 4.03Mhz!  0.3Mhz extra.  Probably I can set OCR0B to 1 to get rid of the extra 0.03Mhz.

 

Your clock is probably running at 8.06 MHz.  This can

be adjusted by modifying the value in the OSCCAL

register.

 

Quote:

However, the waveform is not that squared.  Will that affect much?  What can I do to make the wave more squared?  A capacitor?

 

From looking at your attached picture, it appears there

is a bit of capacitance already on the output.  Adding

more capacitance would make it even less square.

 

Quote:

Btw, I want 0C0B ouput and I had to set the flag WGM01 to enable CTC mode, but that flag, per the datasheet, has OCRA as the TOP value NOT OCR0B!!!  That's one confusion I hope someone can clear for me, because right now the below code works due to OCR0A being zero by default????

 

You have it configured correctly.

 

The counter will count from zero to the TOP value which

is OCR0A.  Since OCR0A is zero, the counter will never

increase TCNT0 to a number larger than zero.  OCR0B

is also zero, so it always matches TCNT0.  Every time

there is a match (which is always), the COM0B bits say

to toggle the OC0B output pin.

 

--Mike

 

 

Thanks, Mike!  I did a bit more measurements on the scope, and, given the current configuration of the code, I see 4.01Mhz at times but never more than 4.03Mhz.  I won't mess with the OSCCAL register for now.  The datasheet says factory calibration for the 8Mhz RC oscillator is with +/- 10% variance.

 

>OCR0Bis also zero, so it always matches TCNT0.  Every time there is a match (which is always), the COM0B bits say to toggle the OC0B output pin.

 

So, for the above I MUST set BOTH OCR0A and 0CR0B to zero?  I was lucky that OCR0A is zero by default!

 

It turns out that setting OCR0B alone to 1 to attempt to get rid of the extra 0.03Mhz causes output of 4Mhz not to work at all!  I get no signal, because it needs to be done to OCR0A as well!  Setting OCR0A & OCR0B to 1, the output gets knocked down to 2.000xxxMhz.  That makes sense.

 

I experimented with different OSCCAL values a bit, and below is what I saw on my scope.  I'll probably go with 0x65, which gives OC0B very close to 4Mhz.

 

// 0x70 gives 4.31Mhz output!
// 0x6B gives 4.1666Mhz
// 0x66 gives 4.01-4.02Mhz
// 0x65 gives 3.989Mhz
// 0x01 gives 2.20Mhz
// Factory OSCCAL value gives 4.017Mhz output.

 

 

Thanks again!

Last Edited: Thu. Jul 11, 2019 - 06:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Vpp = 52.8 V  !!?!?!?

Is this just a case of using a 1:1 probe and the scope thinks it's 10:1 (or a 10:1 and the scope thinks it's 100:1)?

If it really is 52.8V then I would first look at your amplifier circuit for the source of rounding of the corners.

Letting the smoke out since 1978

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

digitalDan wrote:

Vpp = 52.8 V  !!?!?!?

Is this just a case of using a 1:1 probe and the scope thinks it's 10:1 (or a 10:1 and the scope thinks it's 100:1)?

If it really is 52.8V then I would first look at your amplifier circuit for the source of rounding of the corners.

 

My scope's scaling for the grid is not properly set.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

unebonnevie wrote:

I experimented with different OSCCAL values a bit, and below is what I saw on my scope.  I'll probably go with 0x65, which gives OC0B very close to 4Mhz.

 

Every chip is different, so if you are making more than

one of your project, you'll have to calibrate OSCCAL for

each one.

 

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And, there IS a temperature coefficient and a supply voltage coefficient. You seem to be after "ultimate" accuracy but you simply won't get it with the internal RC oscillator in an AVR!

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net