Go Down

Topic: Can't find old topic on clock compensation (Read 4 times) previous topic - next topic

Nick Gammon

#60
Feb 01, 2013, 06:19 am Last Edit: Feb 01, 2013, 06:25 am by Nick Gammon Reason: 1
Just to prove it to myself, I made this amended sketch:

Code: [Select]

#include <avr/sleep.h>
#include <avr/power.h>

const byte tick = 3;

// interrupt on Timer 2 compare "A" completion - does nothing
EMPTY_INTERRUPT (TIMER2_COMPA_vect);

void setup()
{
 pinMode (tick, OUTPUT);
 
 // clock input to timer 2 from XTAL1/XTAL2
 ASSR = _BV (AS2);  

 // set up timer 2 to count up to 32 * 1024  (32768)
 TCCR2A = _BV (WGM21);                             // CTC
 TCCR2B = _BV (CS20) | _BV (CS21) | _BV (CS22);    // Prescaler of 1024                                  
 OCR2A =  31;              // count to 32 (zero-relative)                  

 // enable timer interrupts
 TIMSK2 |= _BV (OCIE2A);
 
 // disable ADC
 ADCSRA = 0;  
 
 // turn off everything we can
 power_adc_disable ();
 power_spi_disable();
 power_twi_disable();
 power_timer0_disable();
 power_timer1_disable();
 power_usart0_disable();
 
 // full power-down doesn't respond to Timer 2
 set_sleep_mode (SLEEP_MODE_PWR_SAVE);  

 // get ready ...
 sleep_enable();
 
 }  // end of setup

void loop()
 {

 // turn off brown-out enable in software
 MCUCR = _BV (BODS) | _BV (BODSE);
 MCUCR = _BV (BODS);
 
 // sleep, finally!
 sleep_cpu ();  

 // we awoke! pulse the clock hand
 digitalWrite (tick, ! digitalRead (tick));
 
 }  // end of loop


With the 32.768 KHz crystal the LED (on pin 3 toggles every second). Now as this is under software control, you could do anything you want in the main loop, instead of the digitalWrite (eg. update a display).

The current consumption, when the LED is not lit, was 1.46 uA, which is pretty low.

(edit) And 1.1 uA at 3.3V power supply.
http://www.gammon.com.au/electronics

randomizer


Just to prove it to myself, I made this amended sketch:


Okay, I am seriously upset/confused right now.

When I use your code (with the EMPTY_INTERRUPT), changing the value of OCR2A changes the frequency of the blinking. As expected.

If I change EMPTY_INTERRUPT to an ISR, move the digitalWrite up into the ISR, and comment out all the sleepy-stuff, changing OCR2A has no effect at all. Zip. Nada. Using the exact same TCCR2A/B values. The frequency is always the base frequency of the prescaler, as if OCR2A is 0.

What am I not seeing here?

Nick Gammon

Post the amended sketch, don't just describe it.
http://www.gammon.com.au/electronics

randomizer

Code: [Select]


#include <avr/sleep.h>
#include <avr/power.h>

const byte tick = 11;

// interrupt on Timer 2 compare "A" completion - does nothing
ISR(TIMER2_COMPA_vect) {
  digitalWrite (tick, ! digitalRead (tick));
}

void setup()
{
  pinMode (tick, OUTPUT);
 
  // clock input to timer 2 from XTAL1/XTAL2
  ASSR = _BV (AS2); 

  // set up timer 2 to count up to 32 * 1024  (32768)
  TCCR2A = _BV (WGM21);                             // CTC
  TCCR2B = _BV (CS20) | _BV (CS21) | _BV (CS22);    // Prescaler of 1024                                 
  OCR2A =  15;              // count to 32 (zero-relative)                 

  // enable timer interrupts
  TIMSK2 |= _BV (OCIE2A);
/* 
  // disable ADC
  ADCSRA = 0; 
 
  // turn off everything we can
  power_adc_disable ();
  power_spi_disable();
  power_twi_disable();
  power_timer0_disable();
  power_timer1_disable();
  power_usart0_disable();
 
  // full power-down doesn't respond to Timer 2
  set_sleep_mode (SLEEP_MODE_PWR_SAVE); 
 
  // get ready ...
  sleep_enable();
  */
  }  // end of setup

void loop()
  {
/*
  // turn off brown-out enable in software
  MCUCR = _BV (BODS) | _BV (BODSE);
  MCUCR = _BV (BODS);
 
  // sleep, finally!
  sleep_cpu (); 

  // we awoke! pulse the clock hand
  digitalWrite (tick, ! digitalRead (tick));
  */
  }  // end of loop


Always blinks at 15.99 Hz, regardless of ACR2A.
Thanks!

Nick Gammon

To save fetching out the board with the extra crystal, I tried on my Uno this slight variation:

Code: [Select]

const byte tick = 11;

// interrupt on Timer 2 compare "A" completion
ISR(TIMER2_COMPA_vect)
 {
 digitalWrite (tick, ! digitalRead (tick));
 }

void setup()
{
 pinMode (tick, OUTPUT);
 
 // clock input to timer 2 from XTAL1/XTAL2
 ASSR = _BV (AS2);  

 // set up timer 2 to count up to 32 * 1024  (32768)
 TCCR2A = _BV (WGM21);                             // CTC
 TCCR2B = _BV (CS20) | _BV (CS21) | _BV (CS22);    // Prescaler of 1024                                  
 OCR2A =  63;              // count to 64 (zero-relative)                  

 // enable timer interrupts
 TIMSK2 |= _BV (OCIE2A);
 }  // end of setup

void loop() { }


This gave a frequency of 122 Hz as predicted by the theory:

Code: [Select]
1 / (1/16e6 * 1024 * 64) / 2 = 122.0703125

You divide by 2 because it takes two pulses to complete one cycle. Changing OCR2A changed the frequency.
http://www.gammon.com.au/electronics

randomizer

I've still got the problem. Changing the prescaler changes the frequency; changing OCR2A changes absolutely nothing. I guess there's something screwy inside the chip, and I'll just work around that in my code.

Nick Gammon

Are you measuring the right pin?

Sometimes I found that where the OCR2A line was affected thing. Try moving that line earlier up.
http://www.gammon.com.au/electronics

randomizer

Well! I tried moving the OCR2A line up; nothing changed. I added the TCCR2A = 0 and TCCR2B = 0 lines at the top and it works! Which is strange, because in other non-working sketches I've tried it hasn't worked. Must've been a combination of that and moving the OCR2A line.

Nick Gammon

Adding those lines stops the timer. I think in some modes the OCR2A changes are buffered, so it makes some sense to stop it first.
http://www.gammon.com.au/electronics

Go Up