Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
abcminiuser
PostPosted: Mar 04, 2006 - 06:18 AM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

Freaks,

Another extract from my ButtLoad project. This code, modified from Collin O'Flynn's code, will calibrate the Butterfly's internal 8MHz RC oscilator down to 7372800Hz for very good 115200 baud serial communications. It assumes that a 32768Hz watch crystal is attached to timer 2.

Can be ported easily to other AVR microcontrollers.

Osccal.c
Code:
#include "OSCCal.h"

/* Code taken from Colin Oflynn from AVRFreaks and modified. His code originally used an externally
   divided 32768Hz clock on an external interrupt pin, but I changed that to use the timer 2 async
   mode with an overflow interrupt (clock source is the external 32768Hz crystal on the Butterfly.
   Code will calibrate to 7372800Hz for correct serial transmission at 115200 baud.                 */

volatile static uint16_t ActualCount;

void OSCCAL_Calibrate(void)
{
   uint8_t SREG_Backup;
   uint8_t LoopCount = (0x7F / 2); // Maximum range is 128, and starts from the middle, so 64 is the max number of iterations required
   
   // Make sure all clock division is turned off (8Mhz RC clock)
   CLKPR = (1 << CLKPCE);
   CLKPR = 0;

   // Inital OSCCAL of half its maximum for speed
   OSCCAL = (0x7F / 2);

   // Save the SREG
   SREG_Backup = SREG;
   
   // Disable all timer 1 interrupts
   TIMSK1 = 0;
       
   // Set timer 2 to asyncronous mode (32.768KHz crystal)
   ASSR   = (1 << AS2);
       
   // Timer 2 overflow interrupt enable
   TIMSK2 = (1 << TOIE2);

   // Enable interrupts
   sei();

   // Start both counters with no prescaling
   TCCR1B = (1 << CS10);
   TCCR2A = (1 << CS20);
       
   // Wait until timer 2's external 32.768KHz crystal is stable
   while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB)));
   
   // Clear the timer values
   TCNT1  = 0;
   TCNT2  = 0;
   
   while (LoopCount--)
   {
      // Let it take a few readings (60ms, approx 7 readings)
      _delay_ms(60);
       
      if (ActualCount > (TARGETCOUNT + 5))          // Clock is running too fast
         OSCCAL--;
      else if (ActualCount < (TARGETCOUNT - 5))      // Clock is running too slow
         OSCCAL++;
      else                                          // Clock is just right
         break;
   }
           
   // Disable all timer interrupts
   TIMSK1 = 0;
   TIMSK2 = 0;
   
   // Stop the timers
   TCCR1B = 0x00;
   TCCR2A = 0x00;

   // Turn off timer 2 asynchronous mode
   ASSR  &= ~(1 << AS2);

   // Restore SREG
   SREG = SREG_Backup;
       
   return;
}

ISR(TIMER2_OVF_vect) // Occurs 32768/256 timers per second, or 128Hz
{
   // Stop timer 1 so it can be read
   TCCR1B = 0x00;
   
   // Record timer 1's value
   ActualCount = TCNT1;
        
   // Reset counters and restart timer 1
   TCNT1  = 0;
   TCNT2  = 0;
   TCCR1B = (1 << CS10);
}


Osccal.h
Code:
#ifndef OSCCAL_H
#define OSCCAL_H

// DEFINES:
#define TARGETCOUNT (uint16_t)((7372800 / 128) - 5) // Compile time constant, ((Target Freq / Reference Freq) - 5)

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

// PROTOTYPES:
void OSCCAL_Calibrate(void);

#endif


- Dean Twisted Evil

_________________



Last edited by abcminiuser on Oct 04, 2006 - 11:52 AM; edited 2 times in total
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Apr 05, 2006 - 01:18 PM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

I had a brainwave before.

The problem with my routine above, is that if the internal oscillator cannot be calibrated to within the small tollerance, the routine would loop for the full 64 iterations. During that time the OSCCAL value bounces between the two closest values. Armed with this knowlege, I've added a two-byte array to store the previous two OSCCAL values. On each loop the current value is compared with the one two iterations previous and if it matches, the best value has been found and the loop exits.

To use this code instead of my previous code, replace the contents of OSCCAL.c with this new code, and keep the existing OSCCAL.h.

OSCCAL.c
Code:
#include "OSCCal.h"

/* Code taken from Colin Oflynn from AVRFreaks and modified. His code originally used an externally
   divided 32768Hz clock on an external interrupt pin, but I changed that to use the timer 2 async
   mode with an overflow interrupt (clock source is the external 32768Hz crystal on the Butterfly.
   Code will calibrate to 7372800Hz for correct serial transmission at 115200 baud.                 */

volatile uint16_t ActualCount;

void OSCCAL_Calibrate(void)
{
   uint8_t SREG_Backup;
   uint8_t LoopCount           = (0x7F / 2); // Maximum is 128 and starts from the middle so 64 is the max number of iterations required
   uint8_t PrevOSCCALValues[2] = {};
   
   // Make sure all clock division is turned off (8Mhz RC clock)
   CLKPR = (1 << CLKPCE);
   CLKPR = 0;

   // Inital OSCCAL of half its maximum for speed
   OSCCAL = (0x7F / 2);

   // Save the SREG
   SREG_Backup = SREG;
   
   // Disable all timer 1 interrupts
   TIMSK1 = 0;
       
   // Set timer 2 to asyncronous mode (32.768KHz crystal)
   ASSR   = (1 << AS2);
       
   // Timer 2 overflow interrupt enable
   TIMSK2 = (1 << TOIE2);

   // Enable interrupts
   sei();

   // Start both counters with no prescaling
   TCCR1B = (1 << CS10);
   TCCR2A = (1 << CS20);
       
   // Wait until timer 2's external 32.768KHz crystal is stable
   while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB)));
   
   // Clear the timer values
   TCNT1  = 0;
   TCNT2  = 0;
   
   while (LoopCount--)
   {
      // Let it take a few readings (60ms, approx 2 readings)
      _delay_ms(60);
      
      PrevOSCCALValues[1] = PrevOSCCALValues[0];
      PrevOSCCALValues[0] = OSCCAL;

      if (ActualCount > (TARGETCOUNT + 5))          // Clock is running too fast
         OSCCAL--;
      else if (ActualCount < (TARGETCOUNT - 5))      // Clock is running too slow
         OSCCAL++;
      else                                          // Clock is just right
         break;
         
      // If the OSCCAL cannot calibrate to within the tollerace, the routine will hover around the closest
      // two values for the full 64 iterations. To speed the routine up, the previous two OSCCAL values are
      // saved into an array. If the current value is the same as two iterations ago, the routine is hovering
      // and the loop exits as the OSCCAL is now as close to the target as possible.
      if (OSCCAL == PrevOSCCALValues[1])
         break;
   }
           
   // Disable all timer interrupts
   TIMSK1 = 0;
   TIMSK2 = 0;
   
   // Stop the timers
   TCCR1B = 0x00;
   TCCR2A = 0x00;

   // Turn off timer 2 asynchronous mode
   ASSR  &= ~(1 << AS2);

   // Restore SREG
   SREG = SREG_Backup;
       
   return;
}

ISR(TIMER2_OVF_vect) // Occurs 32768/256 timers per second, or 128Hz
{
   // Stop timer 1 so it can be read
   TCCR1B = 0x00;
   
   // Record timer 1's value
   ActualCount = TCNT1;
        
   // Reset counters and restart timer 1
   TCNT1  = 0;
   TCNT2  = 0;
   TCCR1B = (1 << CS10);
}


- Dean Twisted Evil

_________________

 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
RetroDan
PostPosted: Apr 05, 2006 - 01:37 PM
Resident


Joined: Feb 24, 2006
Posts: 794
Location: http://avr.x.am

I haven't dug into the details of this routine yet, but here's a suggestions off-the-top-of-my-head that will save time and space.

Instead of an array for memory... how about averaging the last two readings and using that instead, then you can scrap the array and everything that goes with it.

Another idea might be to use a special type of average similar to a moving average.
I think it's called a weighted average. Anyhow it will take into account all reading going back to infinity (theoretically).

You maintain a sort of sum-average. You add in your latest reading and divide it by two, then on next iteration the same, and so-on to infinity. The average takes into account many-many readings and when you hover, it will stablize. You can also adjust the "weight" perhaps you want 3/4 of last and only 1/4 of new reading, etc. When that figure get to within your very tight tollerances, then you know that's about the best your gonna' get so exit.

That way you sort of squeeze an infinite array into a single byte, and the oldest readings are least influential on your decision making and the newest are the most important.

Also, you in some kinda' hurry with this routine? If I'm reading the code correctly, you only allow maximum of 64 iterations for the calibration(?) What if it hasn't "settled" by then?
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
RetroDan
PostPosted: Apr 05, 2006 - 10:47 PM
Resident


Joined: Feb 24, 2006
Posts: 794
Location: http://avr.x.am

This is from another thread, but directly relates to this conversation:

alejmrm wrote:
Hey guys,

If this helps, I have the C version of OSCCAL_retrocal(), but right now I am in the office so allow me 8 hours to return home, and I will post the OSCAL_minical (function that is small from retroDan tutorial and still readable for human beings) and the OSCCAL_retrocal(function that is even small but not readable for normal mortals)... and the functions takes the same space as the asm... I am using gcc... so I think is really to go in any project that use the win-avr gcc compiler...
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Apr 06, 2006 - 04:47 AM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

Yes, a hurry. My version uses timer two which is overflowing at a rate of 128Hz. I've altered the code so that the delay inside the loop is 14ms, or about two readings (erronously put as 60ms=2 readings in the code). Since the code waits for timer 2 to stabalise, and takes two readings for each loop to ensure that the OSCCAL has taken effect this should work fine. OSCCAL starts from 64 in my code, so the 64 iterations should allow it to reach both extreame ends of the scale without falling off.

My new code means that the next version of ButtLoad should calibrate in under a second worse-case-scenario.

- Dean Twisted Evil

_________________

 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
RetroDan
PostPosted: Apr 06, 2006 - 05:24 AM
Resident


Joined: Feb 24, 2006
Posts: 794
Location: http://avr.x.am

If you're concerned about doing it FAST, how about, instead of incrementing/decrementing by only one, you calculate the error by subtracting the actual-count from target and adjusting OSSCAL accordingly.

Should be able to "Nail It" SuperFast.

Have you worked-out how much one step in OSCCAL will theoretically change Oscillator?
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Apr 06, 2006 - 05:30 AM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

Nope, havn't done that. Every AVR's OSCCAL will change the frequency slightly differently, which is most likely why the Atmel engineers chose the same method as I'm using above (decrement/increment by one). Calibration doesn't need to be absolutly instant, but the quicker the better. If the calibration time with the new code turns out to be short enough, i'm going to place it into the UART enable code in ButtLoad so that each time the AVRISP mode (and other UART-reliant modes) is entered the OSCCAL is recalibrated.

- Dean Twisted Evil

_________________

 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Koshchi
PostPosted: Apr 06, 2006 - 07:45 AM
Raving lunatic


Joined: Nov 17, 2004
Posts: 9102
Location: Vancouver, BC

Quote:
Calibration doesn't need to be absolutly instant, but the quicker the better.

Dean, have you looked at my successive approximation code in the "Shrinking OSCCAL" thread? It calibrates in 7 iterations and doesn't have the bouncing problems. As I stated in one of the posts, it can end up 1 off, but that can easily be corrected with another six lines of code (in assembly). If you need it done in C, I'm working on the translation now.

_________________
Regards,
Steve A.

The Board helps those that help themselves.
wylfwt?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 06, 2006 - 07:51 AM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

I just went back and had a look at your routine, Steve. Neato - calibration in under 0.01 secs! Sign me up for the C translation when it's done. I'd be very interested in using your code (plus any modifications I make to it) in ButtLoad, will that be a problem?

- Dean Twisted Evil

_________________

 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Koshchi
PostPosted: Apr 06, 2006 - 07:59 AM
Raving lunatic


Joined: Nov 17, 2004
Posts: 9102
Location: Vancouver, BC

Quote:
will that be a problem?

Not a problem at all. I'd be honored! I should have the C code for you tomorrow. I'd do it now, but it's bedtime.

_________________
Regards,
Steve A.

The Board helps those that help themselves.
wylfwt?
 
 View user's profile Send private message  
Reply with quote Back to top
K5HJ
PostPosted: Apr 06, 2006 - 07:26 PM
Rookie


Joined: May 15, 2004
Posts: 37


Later devices, such as the tiny2313 have a warning in the data sheet that says:

Quote:
Avoid changing the calibration value in large steps when calibrating the calibrated internal RC Oscillator to ensure stable operation of the MCU. A variation in frequency of more than 2% from one cycle to the next can lead to unpredictable behavior. Changes in OSCCAL-register should not exceed 0x20 for each calibration.

I wonder if this could also apply to the M169?

Randy Ott
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 07, 2006 - 08:05 AM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

Hmmm, very good Randy. I knew there must have been a reason for the Atmel engineer's decision to use single stepping on the OSCCAL calibration! I believe I have read that also, but i'll have to go and check to see if it's in the M169 datasheet.

- Dean Twisted Evil

_________________

 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Koshchi
PostPosted: Apr 07, 2006 - 08:50 AM
Raving lunatic


Joined: Nov 17, 2004
Posts: 9102
Location: Vancouver, BC

Here's my successive approximation routine:
Code:
/*****************************************************************************
*
*   Function name : OSCCAL_sa
*
*   Returns :       None
*
*   Parameters :    None
*
*   Purpose :       Calibrate the internal OSCCAL byte, using successive
*               approximation and the external 32,768 kHz crystal as reference
*
*****************************************************************************/
void OSCCAL_sa()
{
   unsigned char mask = 0x40;
   unsigned char tempH;
    unsigned char tempL;
   unsigned char tempC;
   
   CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
                        // set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
   CLKPR = (1<<CLKPS1) | (1<<CLKPS0);
   
    TIMSK2 = 0;             //disable OCIE2A and TOIE2
   
    ASSR = (1<<AS2);        //select asynchronous operation of timer2 (32,768kHz)
   
    OCR2A = 218;            // set timer2 compare value. This creates a target count of 0x1A00
   
   TIMSK0 = 0;             // delete any interrupt sources
   
   TCCR1B = (1<<CS10);     // start timer1 with no prescaling
    TCCR2A = (1<<CS20);     // start timer2 with no prescaling
   TIFR2 = 0xFF;   // delete TIFR2 flags
   
    Delay(1000);    // wait for external crystal to stabilise
   
   cli(); // disable global interrupt
   
   tempC = 0;
   
   while(mask)   //As long as we have a bit to mask in...
   {
      tempC |= mask;   // OR the mask in
      OSCCAL = tempC;
      TIFR2 = 0xFF;   // delete TIFR1 flags       
      TCNT2 = 0;      // clear timer2 counter
      
      while (ASSR & (1<<TCN2UB));   //Wait for timer 2 to update
      
      TCNT1H = 0;     // clear timer1 counter
      TCNT1L = 0;
   
       while ( !(TIFR2 & (1<<OCF2A)) );   // wait for timer2 compareflag
   
      // read out the timer1 counter value
      tempL = TCNT1L;
      tempH = TCNT1H;

      if (tempH >= 0x1A)
      {
         tempC -= mask;   // too high, so remove the mask bit
       }
      mask >>= 1;      // Shift the mask
   }

   //The second to last reading may have actually been closer
   if (tempH < 0x1A)
   {   
      if (tempL < 0xD8)
      {
         tempC++;   //The last reading was below 0x1AD8, so one step up is closer
      }
   }
   else
   {
      if (tempL < 0x28)
      {
         // The last reading was over 0x1A00, so the last bit was removed,
         // but since the count was below 0x1A28, the previous reading was closer,
         // so put the bit back
         tempC++;
      }
   }
   OSCCAL = tempC;

   sei(); // __enable_interrupt();  // enable global interrupt
}


The sa in the name could stand for successive approximation, but it's really my initials Wink

The section after the loop is recovering the last bit. If smaller size is required and less accuracy is needed, this could be left out. The line:
Code:
while (ASSR & (1<<TCN2UB));   //Wait for timer 2 to update

could also be left out as well, but without it the routine gives an answer consistently one step lower than with it. It is not included in the original Atmel routine, but I believe that they compensated for this by using a target count higher than what it theoretically should be.

The note on large changes in the OSCCAL is interesting. My routine just squeaks in. The change from the first pass to the second pass is 0x20. All others are smaller. In my testing I am getting virtually the same value no matter what routine I use, so I think that it is safe.

_________________
Regards,
Steve A.

The Board helps those that help themselves.
wylfwt?
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Dec 07, 2006 - 04:44 AM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

I modified my routine a while ago, removing the need for the ISRs. This is extremely fast and gives great results. Unlike my original routine, each calibration cycle lasts for one reading check, rather than 7:

OSCCAL.c
Code:
#include "OSCCal.h"

void OSCCAL_Calibrate(void)
{
   uint8_t LoopCount = (0x7F / 2); // Maximum range is 128, and starts from the middle, so 64 is the max number of iterations required

   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
   {
      // Make sure all clock division is turned off (8MHz RC clock)
      CLKPR  = (1 << CLKPCE);
      CLKPR  = 0x00;
   
      // Inital OSCCAL of half its maximum
      OSCCAL = (0x7F / 2);
      
      // Disable timer interrupts
      TIMSK1 = 0;
      TIMSK2 = 0;
         
      // Set timer 2 to asyncronous mode (32.768KHz crystal)
      ASSR   = (1 << AS2);
   
      // Ensure timer 1 control register A is cleared
      TCCR1A = 0;
   
      // Start both counters with no prescaling
      TCCR1B = (1 << CS10);
      TCCR2A = (1 << CS20);
         
      // Wait until timer 2's external 32.768KHz crystal is stable
      while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB)));
      
      // Clear the timer values
      TCNT1  = 0;
      TCNT2  = 0;
   
      while (LoopCount--)
      {
         // Wait until timer 2 overflows
         while (!(TIFR2 & (1 << TOV2)));
      
         // Stop timer 1 so it can be read
         TCCR1B = 0x00;
         
         // Check timer value against ideal constant
         if (TCNT1 > OSCCAL_TARGETCOUNT)      // Clock is running too fast
           OSCCAL--;
         else if (TCNT1 < OSCCAL_TARGETCOUNT) // Clock is running too slow
           OSCCAL++;
         
         // Clear timer 2 overflow flag
         TIFR2 |= (1 << TOV2);
   
         // Restart timer 1
         TCCR1B = (1 << CS10);
   
         // Reset counters
         TCNT1  = 0;
         TCNT2  = 0;
      }
   
      // Stop the timers
      TCCR1B = 0x00;
      TCCR2A = 0x00;
   
      // Turn off timer 2 asynchronous mode
      ASSR  &= ~(1 << AS2);
   }   
   END_ATOMIC_BLOCK
   
   return;
}


OSCCAL.h
Code:
#ifndef OSCCAL_H
#define OSCCAL_H

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

   // CODE DEFINES:
   #define ATOMIC_BLOCK(exitmode)   { exitmode cli();
   #define END_ATOMIC_BLOCK         }
   
   #define ATOMIC_RESTORESTATE      inline void __irestore(uint8_t *s) { SREG = *s; }         \
                                    uint8_t __isave __attribute__((__cleanup__(__irestore))) = SREG;
   #define ATOMIC_ASSUMEON          inline void __irestore(uint8_t *s) { sei(); *s = 0; }     \
                                    uint8_t __isave __attribute__((__cleanup__(__irestore))) = 0;

   // CONFIG DEFINES:
   #define OSCCAL_TARGETCOUNT         (uint16_t)(F_CPU / (32768 / 256)) // (Target Freq / Reference Freq)   
   
   // PROTOTYPES:
   void OSCCAL_Calibrate(void);
   
#endif


- Dean Twisted Evil

_________________

 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Dalo
PostPosted: Nov 09, 2007 - 11:55 PM
Newbie


Joined: Jun 20, 2006
Posts: 13


Code:
// Clear the timer values
      TCNT1  = 0;
      TCNT2  = 0;
      while (LoopCount--)
      {  // Wait until timer 2 overflows
         while (!(TIFR2 & (1 << TOV2)));

bette
Code:
// Clear the timer values
      while (LoopCount--)
      {  // Wait until timer 2 overflows
[b]      TCNT1  = 0;
      TCNT2  = 0;
[/b]         while (!(TIFR2 & (1 << TOV2)));


and #define OSCCAL_TARGETCOUNT (uint16_t)(F_CPU / (32768 / 256)) +2 // (Target Freq / Reference Freq)
 
 View user's profile Send private message  
Reply with quote Back to top
Dalo
PostPosted: Nov 09, 2007 - 11:57 PM
Newbie


Joined: Jun 20, 2006
Posts: 13


if (TCNT1 > OSCCAL_TARGETCOUNT) // Clock is running too fast
OSCCAL--;
else if (TCNT1 < OSCCAL_TARGETCOUNT) // Clock is running too slow
OSCCAL++;
else LoopCount = 0;
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Nov 11, 2007 - 07:38 AM
Moderator


Joined: Jan 23, 2004
Posts: 6964
Location: Melbourne, Victoria, Australia

Thank's Dalo, very clever. However, I think there's a slight problem with that - shifting the OSCCAL_TARGETCOUNT by two makes no difference apart from adding a slight error to the final calibrated value. If what you want to do is to add a little window which is deemed a "correct" calibrated value, you need to add the offset to one, and subtract from the other:

Code:
         if (TCNT1 > (OSCCAL_TARGETCOUNT + OSCCAL_TOLLERANCE))      // Clock is running too fast
           OSCCAL--;
         else if (TCNT1 < (OSCCAL_TARGETCOUNT - OSCCAL_TOLLERANCE)) // Clock is running too slow
           OSCCAL++;
         else                                                       // Clock within tollerance
           LoopCount = 0;


- Dean Twisted Evil

_________________

 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
morgman
PostPosted: Dec 14, 2007 - 01:35 PM
Newbie


Joined: Oct 19, 2007
Posts: 11


All, I've been struggling with RTC on my 90USB1287 as I've mentioned in another thread... I ordered my watch crystal and I'm currently playing with a RTC on Timer 2 running async... I think all of the code you mentioned will be very useful, but I'm confused over exactly how to connect the watch crystal. The 90USB1287 "talks" about connecting a watch crystal between TOSC1 & 2, but it references a page in the docs that shows the crystal connected between XTAL1&2 with a couple small 6pf caps...
So far I haven't been able to get much to work.
If I could get a clear answer on exactly where to hook the watch crystal and how that would help immensely... especially given this thread on the calibration.
 
 View user's profile Send private message  
Reply with quote Back to top
morgman
PostPosted: Dec 14, 2007 - 07:33 PM
Newbie


Joined: Oct 19, 2007
Posts: 11


figured it out...
This may be specific to me... I decided that the 32.768 watch crystal needed to be connected to the 90usb1287 via the TOSC1/2 directly with no caps. This was based on Collin O'Flynn's "Why you need a clock source" pdf... although the files link for the document is broken on AVF Freaks.
The tricky part for me was using the 90USB1287 on a STK525 mounted to the STK500.
As it turns out the PE4/5 pins (TOSC1/2) aren't broken out on the STK500/STK525...
I was hooking my crystal to the wrong pins altogether...
Now lucky for me the board had solder pads for these pins accessible and I ended up soldering my crystal directly to the board...
Once I did that and tweaked my software I was off and running.
Hope this helps someone else... took me long enough to figure it out.
Now that I have this Asyc watch crystal based RTC, I can calibrate my internal oscillator ah la AVR055, and I should have a stable RTC!
I'm running a test over the weekend to see how accurate this setup is. I'll report next week.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits