Loading...
Pages: 1 2 3 [4] 5   Go Down
Author Topic: Can't find old topic on clock compensation  (Read 1227 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Melbourne, Australia
Offline Offline
Shannon Member
*****
Karma: 218
Posts: 13896
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

== not =.

But no, not at all. You don't have to use interrupts.

http://www.gammon.com.au/forum/?id=11504

I just hooked this up and tested it:

Code:
const byte OUTPUT_PIN = 3;  // Timer 2 "B" output: OC2B  (chip pin 5)

const byte n = 31;  // tick every 32 cycles

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

  ASSR = _BV (AS2);    // asynchronous input from chip pins 9 and 10 (XTAL1 and XTAL2)
   
  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2A on compare
  TCCR2B = _BV (WGM22) | _BV (CS20);         // fast PWM, no prescaler
  OCR2A =  n;                             
  OCR2B = ((n + 1) / 2) - 1;           // 50% duty cycle
  }  // end of setup

void loop() { }

No interrupts, no digitalWrite.

I set the chip to run off the internal 8 MHz oscillator and shoved a 32.768 KHz crystal between pins  9 and 10. And it works! 1.024 KHz output, as expected:

Code:
1 / (32 * (1 / 32768)) = 1024
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 35
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Neat! Works for me too. But this is only for crystal testing, right? The long-term goal, after all, is to tick a counter for the clock.
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 43
Posts: 2502
"We're a proud service of the Lost Electricity Reclamation Agency"
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Using the code below, I'm getting right about 20ppm error with an inexpensive crystal from Tayda just stuck in the breadboard. Pics of the setup and my homebrew frequency counter here.

Code:
//configure timer 2 for external 32768Hz crystal.
//toggles OC2A at f/2 = 16384Hz.

void setup(void)
{
    pinMode(11, OUTPUT);                  //OC2A/MOSI
    TCCR2B = 0;                           //stop the timer
    TCCR2A = 0;                   
    TIMSK2 = 0;                           //no interrupts
    TIFR2 = 0;
    ASSR = _BV(AS2);                      //Timer/Counter2 clocked from external crystal
    TCCR2A = _BV(COM2A0) | _BV(WGM21);    //Toggle OC2A on compare match, CTC mode
    TCCR2B = _BV(CS20);                   //no prescaling
    OCR2A = 0;                            //top count, matches on every cycle, so toggles OC2A at f/2
    TCNT2 = 0;                            //zero the counter
    while (ASSR & (_BV(TCN2UB) | _BV(TCR2AUB) | _BV(TCR2BUB)));    //wait for the registers to be updated   
}

void loop(void)
{
}
Logged

Get the infamous "One Million Ohms" board at tINDIE.com: http://tinyurl.com/BuyMohms

Offline Offline
Newbie
*
Karma: 0
Posts: 35
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hoo boy! Quite the setup you've got there.

Well, curiosity kills the chip. I have discovered that bending the pins three times is one time too many, and now I have a perfectly working µC with no XTAL/TOSC pins. Maybe I'll see if I can come up with some non-time-critical project sometime. I'll try out your code when the new ones arrive!
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 43
Posts: 2502
"We're a proud service of the Lost Electricity Reclamation Agency"
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, curiosity kills the chip. I have discovered that bending the pins three times is one time too many, and now I have a perfectly working µC with no XTAL/TOSC pins. Maybe I'll see if I can come up with some non-time-critical project sometime. I'll try out your code when the new ones arrive!

We mourn the passing of your AVR smiley-cry
Logged

Get the infamous "One Million Ohms" board at tINDIE.com: http://tinyurl.com/BuyMohms

Global Moderator
Melbourne, Australia
Offline Offline
Shannon Member
*****
Karma: 218
Posts: 13896
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Neat! Works for me too. But this is only for crystal testing, right? The long-term goal, after all, is to tick a counter for the clock.

How often? Every second?
Logged


Global Moderator
Melbourne, Australia
Offline Offline
Shannon Member
*****
Karma: 218
Posts: 13896
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you change the prescaler then it toggles every 500 mS giving a frequency of 1 Hz.

Code:
const byte OUTPUT_PIN = 3;  // Timer 2 "B" output: OC2B

const byte n = 31; 

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

  ASSR = _BV (AS2); 
   
  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2A on compare
  TCCR2B = _BV (WGM22) | _BV (CS20) | _BV (CS21) | _BV (CS22);         // fast PWM, prescaler of 1024
  OCR2A =  n;                                 
  OCR2B = ((n + 1) / 2) - 1;                 // 50% duty cycle
 
  }  // end of setup

void loop() { }

Maths:

Code:
1 / (32 * (1 / 32768)) / 1024 = 1
Logged


Global Moderator
Melbourne, Australia
Offline Offline
Shannon Member
*****
Karma: 218
Posts: 13896
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Using the code below, I'm getting right about 20ppm error  ...

I'm not sure if I have the maths right here. I measured (with the prescaler of 1) a frequency of 1023.943 Hz when I was expecting 1024 Hz. Now I make that as 55.66 ppm error. Someone want to check that?

Code:
(1024 - 1023.943)/1024 * 1e6 = 55.664062500016
Logged


Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 43
Posts: 2502
"We're a proud service of the Lost Electricity Reclamation Agency"
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Using the code below, I'm getting right about 20ppm error  ...

I'm not sure if I have the maths right here. I measured (with the prescaler of 1) a frequency of 1023.943 Hz when I was expecting 1024 Hz. Now I make that as 55.66 ppm error. Someone want to check that?

Code:
(1024 - 1023.943)/1024 * 1e6 = 55.664062500016

Yep, that's how I'd do it.
Logged

Get the infamous "One Million Ohms" board at tINDIE.com: http://tinyurl.com/BuyMohms

Offline Offline
Newbie
*
Karma: 0
Posts: 35
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you change the prescaler then it toggles every 500 mS giving a frequency of 1 Hz.
Right, but it's still toggling an output pin, not clicking something, right? I could set up some code to monitor that pin and second++ every tick or two ticks or whatever, but why would I do that when I have the ISR? Besides, eventually I want to sleep the chip and have the ISR wake it every second (or five seconds). Not sure if that's going to happen, but it's the goal.
Logged

Offline Offline
Edison Member
*
Karma: 114
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
why would I do that when I have the ISR? Besides, eventually I want to sleep the chip and have the ISR wake it every second (or five seconds). Not sure if that's going to happen, but it's the goal.


Advance a counter / time struct in the isr.

To wake it up, you need to have an isr on the LF oscillator.
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 43
Posts: 2502
"We're a proud service of the Lost Electricity Reclamation Agency"
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you change the prescaler then it toggles every 500 mS giving a frequency of 1 Hz.
Right, but it's still toggling an output pin, not clicking something, right? I could set up some code to monitor that pin and second++ every tick or two ticks or whatever, but why would I do that when I have the ISR? Besides, eventually I want to sleep the chip and have the ISR wake it every second (or five seconds). Not sure if that's going to happen, but it's the goal.

Completely possible. Power Save mode sleeps most of the µC but keeps Timer2 running, so it can generate an interrupt that wakes the system. Code from the link I posted earlier below. I must have measured the current, but I don't remember. Datasheet says Power Save mode should only require around a microamp or two (with brownout detector disabled).

Timer setup:

Code:
   TIMSK2 = 0;                        //stop timer2 interrupts while we set up
    ASSR = _BV(AS2);                   //Timer/Counter2 clocked from external crystal
    TCCR2A = 0;                        //override arduino settings, ensure WGM mode 0 (normal mode)
    TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);    //prescaler clk/1024 -- TCNT2 will overflow once every 8 seconds
    TCNT2 = 0;                         //start the timer at zero
    while (ASSR & (_BV(TCN2UB) | _BV(TCR2AUB) | _BV(TCR2BUB))) {}    //wait for the registers to be updated    
    TIFR2 = _BV(OCF2B) | _BV(OCF2A) | _BV(TOV2);                     //clear the interrupt flags
    TIMSK2 = _BV(TOIE2);               //enable interrupt on overflow

The ISR does the time keeping, it is the RTC:

Code:
ISR(TIMER2_OVF_vect)
{
    if ((tm.Second += 8) > 59) {
        tm.Second = tm.Second % 60;
        if (++tm.Minute > 59) {
            tm.Minute = 0;
            if(++tm.Hour > 23) {
                tm.Hour = 0;
                if(++tm.Day > (((tm.Month == 2) && isLeap(tm.Year)) ? monthDays[tm.Month] + 1 : monthDays[tm.Month]) ) {
                    tm.Day = 1;
                    if(++tm.Month > 12) {
                        tm.Month = 1;
                        ++tm.Year;
                    }
                }
            }
        }
    }                
}

Sleep function:

Code:
void goToSleep()
{
    byte adcsra, mcucr1, mcucr2;

    //Cannot re-enter sleep mode within one TOSC cycle. This provides the needed delay.
    OCR2A = 0;                        //write to OCR2A, we're not using it, but no matter
    while (ASSR & _BV(OCR2AUB)) {}    //wait for OCR2A to be updated  

    sleep_enable();
    set_sleep_mode(SLEEP_MODE_PWR_SAVE);
    adcsra = ADCSRA;                  //save the ADC Control and Status Register A
    ADCSRA = 0;                       //disable ADC
    ATOMIC_BLOCK(ATOMIC_FORCEON) {    //ATOMIC_FORCEON ensures interrupts are enabled so we can wake up again
        mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
        mcucr2 = mcucr1 & ~_BV(BODSE);
        MCUCR = mcucr1;               //timed sequence
        MCUCR = mcucr2;               //BODS stays active for 3 cycles, sleep instruction must be executed while it's active
    }
    sleep_cpu();                      //go to sleep
                                      //wake up here
    sleep_disable();
    ADCSRA = adcsra;                  //restore ADCSRA
}
Logged

Get the infamous "One Million Ohms" board at tINDIE.com: http://tinyurl.com/BuyMohms

Global Moderator
Melbourne, Australia
Offline Offline
Shannon Member
*****
Karma: 218
Posts: 13896
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Right, but it's still toggling an output pin, not clicking something, right?

What do you mean by "clicking something"? If the clicking thing is on the output pin, it will click, right?

However I agree, if you want it to sleep, an ISR would be the way to go. However it doesn't have to do anything. Your main loop could look like:


Code:
void loop ()
  {
  go_to_sleep ();
  click_clock_hands ();
  }

Given that the timer wakes you up, all the ISR has to do is exist to achieve that.
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 35
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What do you mean by "clicking something"? If the clicking thing is on the output pin, it will click, right?
Sorry, I'm not being clear. I'm working with a tweaked version of Daniel Andrade's binary clock (direct link to code), so the "click" I was talking about was setting the seconds (minutes, half-seconds, eight-seconds, whatever) counter ahead by one. Not a physical click like the second hand on a watch.

Basically, the code keeps track of hours and minutes (and seconds, though it doesn't display them). Then it strips HH:MM into H, H, M, M and figures out which LEDs to turn on based on that. So the chip needs to be awake to set/check the seconds and change the LEDs, and also if the hour/minute-set buttons are pushed (which I'll use an external interrupt for).

Code:
void loop ()
  {
  go_to_sleep ();
  click_clock_hands ();
  }
If I'm reading this right, that makes the chip 1) go to sleep until the interrupt fires, 2) tick the time, and 3) repeat, yes?
Logged

Global Moderator
Melbourne, Australia
Offline Offline
Shannon Member
*****
Karma: 218
Posts: 13896
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Basically, the code keeps track of hours and minutes (and seconds, though it doesn't display them). Then it strips HH:MM into H, H, M, M and figures out which LEDs to turn on based on that. So the chip needs to be awake to set/check the seconds and change the LEDs, and also if the hour/minute-set buttons are pushed (which I'll use an external interrupt for).

That's all achievable, although if you have glowing LEDs there isn't that much point going to sleep to save power.

Quote
If I'm reading this right, that makes the chip 1) go to sleep until the interrupt fires, 2) tick the time, and 3) repeat, yes?

That's right.
Logged


Pages: 1 2 3 [4] 5   Go Up
Print
 
Jump to: