Firmware for increased Ice Tube Clock accuracy
Moderators: adafruit_support_bill, adafruit

Firmware for increased Ice Tube Clock accuracy

by fat16lib on Sun Sep 20, 2009 11:22 am

Here is a suggestion for increasing the accuracy of the Ice Tube Clock with no hardware mods.

I know the hardware types are busy with gps, wwvb, internet and other hardware mods but here is a simple way to add a calibration factor.

Low cost quartz watches like my $20 Casio are rated at ± 15 seconds/month. I have built RTCs with a crystal like the one in the Ice Tube Clock that are accurate to less than one second per day so it should be possible to improve the accuracy of the Ice Tube Clock.

The idea is to shorten or lengthen the first second of each hour. This will allow the rate of the clock to be adjusted in units of 24/256 or about 0.1 second per day.

This mod has not been tested on the Ice Tube Clock since my daughter won’t let me touch her clock so there may be bugs.

Here is the mod that I tested on a 168 Arduino simulator.
Code: Select all | TOGGLE FULL SIZE
  // use a calculator for this calculation
  // if losing time
  // cal_factor = - (<seconds lost per day>*256)/24;
  // if gaining time
  // cal_factor = (<seconds gained per day>*256)/24;
  //
  int8_t cal_factor = <set it to the above result here>; 
  if (cal_factor < 0) {
    // clock slow - shorten first second of hour
    TCNT2 += -cal_factor + 1;
  }
  else if (cal_factor > 0) {
    // clock fast - lengthen first second of hour
    uint8_t tmp = TCNT2;
    while ((TCNT2 - tmp) < cal_factor);
    TCNT2 = tmp;
  }


The mod needs to be inserted in this block where the hour rolls over:
Code: Select all | TOGGLE FULL SIZE
   // an hour...
  if (time_m >= 60) {
    time_m = 0;
    time_h++;
    // lets write the time to the EEPROM
    eeprom_write_byte((uint8_t *)EE_HOUR, time_h);
    eeprom_write_byte((uint8_t *)EE_MIN, time_m);
  }

It would be nice if someone would write a menu to set cal_factor.

Here is a chart of measured results on the Arduino test setup for -50 < cal_factor < 50.
calFactor.jpg
calFactor.jpg (30.16 KiB) Viewed 6091 times
fat16lib
 
Posts: 593
Joined: Wed Dec 24, 2008 1:54 pm

Re: Firmware for increased Ice Tube Clock accuracy

by ki4mmm on Sun Sep 20, 2009 4:05 pm

I just flashed your mod to my clock, and will watch and see what happens - "only time will tell" :) Nevertheless, it took me a couple of hours of troubleshooting before I could flash mine. Maybe this is common knowledge, or documented somewhere that I could not find, or maybe I don't know what I am talking about, but the tube has to be removed for the programmer to see the MCU. At least two of the ISP pins (MOSI & SCK) are used to drive the display. Either way, I gained a magnitude of experience with avrdude flags, and Lady Ada's Makefile. It was while looking at the schematic that it hit me. Someone please tell me if this isn't the case.
ki4mmm
 
Posts: 19
Joined: Sun Aug 16, 2009 7:05 am

Re: Firmware for increased Ice Tube Clock accuracy

by adafruit on Sun Sep 20, 2009 4:31 pm

yes it seems that for many programmers the tube must be removed. Thats why its not soldered directly in
User avatar
adafruit
 
Posts: 11708
Joined: Thu Apr 06, 2006 4:21 pm
Location: nyc

Re: Firmware for increased Ice Tube Clock accuracy

by ki4mmm on Sun Sep 20, 2009 4:45 pm

Lady Ada, I'm guessing that your programmer works with the tube in? Amongst my troubleshooting-Googling, I saw enough to indicate that not all (similar USB) programmers are the same (including comments of yours on the tutorials). I am using the Pololu avrispv2 (because I got it with a 3pi robot package), but I will eventually get yours as well. It sure would be nice to leave the programmer attached while tweaking it.
ki4mmm
 
Posts: 19
Joined: Sun Aug 16, 2009 7:05 am

Re: Firmware for increased Ice Tube Clock accuracy

by adafruit on Sun Sep 20, 2009 6:39 pm

we havent found any that work with the tube in (yet)
User avatar
adafruit
 
Posts: 11708
Joined: Thu Apr 06, 2006 4:21 pm
Location: nyc

Re: Firmware for increased Ice Tube Clock accuracy

by ki4mmm on Thu Sep 24, 2009 8:11 pm

I'll start by saying....., It works! I've been playing with this for the past several days, and I will admit that I don't know what is going on. I tried cheating for the first couple of days, thinking that the following two lines were all that I needed (i.e, since my clock was slow, why use the 'fast clock' code):

int8_t cal_factor = 28;
TCNT2 += -cal_factor + 1;

I tried different variants of the sign (+/-) on the cal factor, but in every case, my clock added one second every hour?? It finally occurred to me to just try the whole block of code, which I inserted yesterday evening. Tonight, I don't notice any significant difference from the atomic clock I am using for a reference.

In summary, I would say that my clock is more accurate than my finger at hitting the 'set' button. Thanks fat16lib!!
ki4mmm
 
Posts: 19
Joined: Sun Aug 16, 2009 7:05 am

Re: Firmware for increased Ice Tube Clock accuracy

by fat16lib on Sat Sep 26, 2009 9:56 am

ki4mmm,

Adding just the clock slow part should have worked. I was afraid my instructions and code would not be clear.

For your clock, which is slow, the single line
Code: Select all | TOGGLE FULL SIZE
TCNT2 += 29;

Should have worked.

If the sign was wrong on cal_factor, the result would be to add 229 to TCNT2 since it is uint8_t. This would cause the clock to gain about 0.9 seconds per hour.

Thanks for reporting your results. I am curious to see how stable the clock can be. Most 32k crystals have an inverted parabolic temperature curve with zero coefficient at 25°C.

The clock should be very stable if the crystal is between 20°C and 30°C (68°F to 86°F). Outside that range, a temperature sensor near the crystal has been used to calculate a calibration factor in some RTCs that I have seen.

Once again I am interested in how accurate the unmodified clock can be. I know GPS Synchronization Clocks can be accurate to better than a microsecond but they are not works of art like the ITC.
fat16lib
 
Posts: 593
Joined: Wed Dec 24, 2008 1:54 pm

Re: Firmware for increased Ice Tube Clock accuracy

by ki4mmm on Sat Sep 26, 2009 4:33 pm

I guess I am still a little confused on the math. In the complete code, I interpret your reference to "-cal_factor" as a negative number i.e., the negative sign in front of it. It seams that incrementing (+=) TCNT2 by a negative number is that same as subtracting cal_factor. Of course, I wondered why not just use decrement (-=). I also don't understand where "229" is coming from?

I'm not complaining or criticizing, but just trying to understand something that is probably pretty obvious. I had already spent some time over at AVRFreaks.com trying learn more about timers, but those discussions were a bit over my head at this time.

Anyway, my clock is now ~1/2 second fast, so I'm not done tinkering yet, and will try the one-liner on my next tweak. Thanks for all!!
ki4mmm
 
Posts: 19
Joined: Sun Aug 16, 2009 7:05 am

Re: Firmware for increased Ice Tube Clock accuracy

by Len17 on Sat Sep 26, 2009 9:33 pm

ki4mmm wrote:I guess I am still a little confused on the math.

I think all the minus signs are just there to confuse you. :)

When you tried this:
Code: Select all | TOGGLE FULL SIZE
int8_t cal_factor = 28;
TCNT2 += -cal_factor + 1;

you got cal_factor wrong. If the clock is slow, the calculation is this:
Code: Select all | TOGGLE FULL SIZE
  // if losing time
  // cal_factor = - (<seconds lost per day>*256)/24;

so cal_factor should be -28 not 28. That makes the whole thing equivalent to this:
Code: Select all | TOGGLE FULL SIZE
TCNT2 += 29;

(as fat16lib said above)
User avatar
Len17
 
Posts: 393
Joined: Sat Mar 14, 2009 7:20 pm

Re: Firmware for increased Ice Tube Clock accuracy

by DigiSage on Mon Nov 09, 2009 4:52 pm

Just FYI, I've been using this mod in my own firmware and with a calibration of -35, and I've achieved less than 1 second drift over a period of 10 days. Pretty awesome!
User avatar
DigiSage
 
Posts: 20
Joined: Tue Sep 29, 2009 6:11 pm
Location: San Diego, CA

Re: Firmware for increased Ice Tube Clock accuracy

by mike31416 on Tue Nov 10, 2009 8:35 am

Same here. I am using -35 also (add 35 to TCNT2) and have about 1 second loss over two weeks.
User avatar
mike31416
 
Posts: 126
Joined: Wed Aug 26, 2009 12:06 pm

Re: Firmware for increased Ice Tube Clock accuracy

by jsgf on Fri Nov 13, 2009 12:56 pm

I just added drift correction to my firmware. I took a slightly different approach. Rather than tweaking TCNT, I switched TC2 into CTC mode (clear on compare), set the divider to clock it at 128Hz, and set OCR2A to a nominal value of 128. The result is that counter goes up to match OCR2A, automatically zeros itself and raises an interrupt, so the drift correction can be set by setting OCR2A to 128±drift. The adjustment is too coarse to do to every second, but doing the correction every hour allows up to ±1 sec/hour drifts to be adjusted (though I've limited the correction to ±0.5 sec/hour).

Because the divider is at 256 rather than 128, the drift correction numbers are going to be half the size (twice as coarse); I don't know if this is going to make a difference in practice.

The patch is pretty simple (taken from my git tree, with the UI parts removed):

Code: Select all | TOGGLE FULL SIZE
diff --git a/iv.c b/iv.c
index 1a33cfa..ade474d 100644
--- a/iv.c
+++ b/iv.c
@@ -37,6 +37,10 @@ THE SOFTWARE.
 
 static uint8_t region = REGION_US;
 static uint8_t secondmode = SEC_FULL;
+
+/* Drift correction applied each hour */
+static int8_t drift = 0;
+
 /*
  * Barrier to force compiler to make sure memory is up-to-date.  This
  * is preferable to using "volatile" because we can just resync with
@@ -761,7 +765,7 @@ static void set_brite(void)
  * crystal.  It leaves interrupts disabled so it can never itself be
  * interrupted.
  */
-SIGNAL (TIMER2_OVF_vect) {
+SIGNAL (TIMER2_COMPA_vect) {
   struct timedate td;
   CLKPR = _BV(CLKPCE);  //MEME
   CLKPR = 0;
@@ -770,6 +774,13 @@ SIGNAL (TIMER2_OVF_vect) {
 
   if (!suspend_update) {
     increment_time(&td);
+
+    /* Apply drift correction on the first second of each hour */
+    if (td.time.m == 0 && td.time.s == 0)
+      OCR2A = 128 + drift;
+    else
+      OCR2A = 128;
+
     timedate = td;
   }
 
@@ -1526,6 +1576,12 @@ static void display_date(uint8_t style)
 
 /**************************** RTC & ALARM *****************************/
 static void clock_init(void) {
+  drift = eeprom_read_byte((uint8_t *)EE_HOUR);
+  if (drift > DRIFT_MAX || drift < -DRIFT_MIN) {
+    drift = 0;
+    eeprom_write_byte((uint8_t *)EE_DRIFT, drift);
+  }
+
   // we store the time in EEPROM when switching from power modes so its
   // reasonable to start with whats in memory
   timedate.time.h = eeprom_read_byte((uint8_t *)EE_HOUR) % 24;
@@ -1551,14 +1607,28 @@ static void clock_init(void) {
 
   restored = 1;
 
+  /*
+   * Input is a (nominal) 32khz crystal.  Set:
+   * - divider to 256
+   * - mode to CTC
+   * - comparitor to 128
+   *
+   * This will increment the counter at (nominally) 128Hz.  When it
+   * compares to OCR2A it will reset the counter to 0 and raise an
+   * interrupt so we can increment seconds.
+   *
+   * To correct drift we can adjust the comparitor to 128 +/-
+   * correction.
+   */
   // Turn on the RTC by selecting the external 32khz crystal
-  // 32.768 / 128 = 256 which is exactly an 8-bit timer overflow
   ASSR |= _BV(AS2); // use crystal
-  TCCR2B = _BV(CS22) | _BV(CS20); // div by 128
-  // We will overflow once a second, and call an interrupt
+
+  OCR2A = 128;         /* +/- drift correction */
+  TCCR2A = _BV(WGM21);
+  TCCR2B = _BV(WGM22) | _BV(CS22) | _BV(CS21);
 
   // enable interrupt
-  TIMSK2 = _BV(TOIE2);
+  TIMSK2 = _BV(OCIE1A);
 
   // enable all interrupts!
   sei();
diff --git a/iv.h b/iv.h
index 868fdb6..3ae72bd 100644
--- a/iv.h
+++ b/iv.h
@@ -83,6 +83,10 @@ THE SOFTWARE.
 #define EE_EVENINGHR 15
 #define EE_DAYBRITE 16
 #define EE_NIGHTBRITE 17
+#define EE_DRIFT 18
+
+#define DRIFT_MIN   (-64)
+#define DRIFT_MAX   (64)
 
 void delay(uint16_t delay);
 
Advanced IceTubeClock Firmware download Source Git Wiki
jsgf
 
Posts: 61
Joined: Mon Oct 26, 2009 1:21 am

Re: Firmware for increased Ice Tube Clock accuracy

by mike31416 on Fri Nov 13, 2009 2:23 pm

Should this be:

+ drift = eeprom_read_byte((uint8_t *)EE_DRIFT);

instead of:

+ drift = eeprom_read_byte((uint8_t *)EE_HOUR);

???

Mike
User avatar
mike31416
 
Posts: 126
Joined: Wed Aug 26, 2009 12:06 pm

Re: Firmware for increased Ice Tube Clock accuracy

by jsgf on Fri Nov 13, 2009 7:08 pm

mike31416 wrote:Should this be:

+ drift = eeprom_read_byte((uint8_t *)EE_DRIFT);


Yes indeed. That shows an embarrassing lack of testing :oops:.
Advanced IceTubeClock Firmware download Source Git Wiki
jsgf
 
Posts: 61
Joined: Mon Oct 26, 2009 1:21 am

Re: Firmware for increased Ice Tube Clock accuracy

by DigiSage on Fri Nov 13, 2009 8:35 pm

Also, shouldn't it be "int8_t" instead of "uint8_t"? (i assume drift could be negative...)
User avatar
DigiSage
 
Posts: 20
Joined: Tue Sep 29, 2009 6:11 pm
Location: San Diego, CA