Go Down

Topic: How can I generate 8MHz clock using timers or PWM with my Arduino Leonardo? (Read 3794 times) previous topic - next topic

xRamon

Hi, I'm trying to generate 8MHz clock from the arduino to connect it to an OV7670 camera sensor on XCLK pin. I'm trying to do it using the timer 1, but the maximum frequency I get is approximately 41kHz?
Here is my code:
Code: [Select]

const int led=10;

/*
Input Frequency -> CLK=16MHz

Timer Resolution = (1 / (Input Frequency / Prescale)) = (Prescale / Input Frequency)

Prescaler Value | Resolution at 16MHz
             1 |  62.5nS
             8 |  0.6uS
            64 |  4uS
           256 |  16uS
          1024 |  64uS

Target Timer Count = (1 / (Target Frequency*2)) / (Prescale / Input Frequency) - 1
                  = (Target Period / 2) / Timer Resolution - 1

If: Target Period = 125nsec.  ->  Target frequency = 8MHz
With prescaler = 1
Target Timer Count = (125nS/2)/62.5nS - 1 = 0

*/

#define TMR1 0    //for 8MHz

ISR(TIMER1_COMPA_vect)
{
 digitalWrite(led, digitalRead(led)^1);
};

void setup() {
 pinMode(led, OUTPUT);

//*********************************************************************  
 //TIMER1 (16 bits) in mode CTC
 TCCR1B |= (1 << CS10);  //selecting prescaler 0b001 (Tclk/1)
 TCCR1B &= ~((1<<CS12) | (1<<CS11));    // turn off CS12 and CS11 bits

 TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
 TCCR1A &= ~((1<<WGM11) | (1<<WGM10));  

 OCR1A = TMR1;
 
 TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt

 sei();    //Enable global interrupts
//*********************************************************************
}

void loop(){}


I'm guessing that the instruction in the interrupt routine is taking too long.
Thanks.

AWOL

You're trying to generate an output frequency half the clock frequency of the controller, using an interrupt.
That simply cannot work.

xRamon

And how can I do it then?
Or do you mean that it can not be done?
Can I configure the PWM to get that frequency?

lxguru

looked at http://forum.arduino.cc/index.php/topic,22384.0.html
code that should set pin 3 to 1MHz - it uses timer2 and the normal analogWrite function for pins 3 and 11 won't be available if you do this. This may help.

#define PWMout 3

void setup ()
{
  TCCR2A = 0xB3 ; // fast PWM with programmed TOP val
  TCCR2B = 0x09 ; // divide by 1 prescale
  TCNT2  = 0x00 ;
  OCR2A  = 0x0F ; // TOP = 15, cycles every 16 clocks
  OCR2B  = 0x07 ; // COMP for pin3
  pinMode (PWMout, OUTPUT) ;

  ...
}

xRamon

Well Ixguru thanks for the TIP! I checked out the datasheet and configured the TIMER1 in TOP mode and Toggle mode .
Here I post my code. It works super OK!!!

Code: [Select]

#include <avr/interrupt.h>
#include <avr/io.h>

/*
Input Frequency -> CLK=16MHz

Timer Resolution = (1 / (Input Frequency / Prescale)) = (Prescale / Input Frequency)

Prescaler Value | Resolution at 16MHz
              1 |  62.5nS
              8 |  0.6uS
             64 |  4uS
            256 |  16uS
           1024 |  64uS

Target Timer Count = (1 / (Target Frequency * 2)) / (Prescale / Input Frequency) - 1
                   = (Target Period / 2) / Timer Resolution - 1

If: Target Period = 125nseg.  ->  Target frequency = 8MHz
With prescaler = 1
Target Timer Count = (125nS/2)/62.5nS - 1 = 0
*/

#define TMR1 0    //for 8MHz: TMR1 = 0 , for 10kHz: TMR1 = 799

void setup() {
  // put your setup code here, to run once:
  pinMode(9, OUTPUT);

//********************************************************************* 
  //TIMER1 (16 bits) in mode TOP
  TCCR1B |= (1 << CS10);  //selecting prescaler 0b001 (Tclk/1)
  TCCR1B &= ~((1<<CS12) | (1<<CS11));    // turn off CS12 and CS11 bits

  TCCR1A |= ((1<<WGM11) | (1<<WGM10));  //Configure timer 1 for TOP mode (with TOP = OCR1A)
  TCCR1B |= ((1<<WGM13) | (1<<WGM12));

  TCCR1A |= (1 << COM1A0); // Enable timer 1 Compare Output channel A in toggle mode
  TCCR1A &= ~(1 << COM1A1);
  TCNT1 = 0;
 
  OCR1A = TMR1;
 
//*********************************************************************

}

void loop() {
}

lxguru

Thanks for sharing out your code - spirit of open source :). Basically to use Fast PWM mode, setting TOP value 0. How did you verify you got the desired clock? by using arduinoscope? curious. 

xRamon

I'm using an oscilloscope. That's how i verified the frequency.

Go Up