Re: Firmware for increased Ice Tube Clock accuracy

by jsgf on Fri Nov 13, 2009 10:18 pm

DigiSage wrote:Also, shouldn't it be "int8_t" instead of "uint8_t"? (i assume drift could be negative...)

No. eeprom_read_byte() is defined to take a uint8_t * as an argument; it gets implicitly cast to signed when it gets assigned to "drift". The actual bitpattern of the number won't be affected, so it doesn't lose its sign in the process.
Advanced IceTubeClock Firmware download Source Git Wiki
Posts: 61
Joined: Mon Oct 26, 2009 12:21 am

Re: Firmware for increased Ice Tube Clock accuracy

by Troubadix on Tue Nov 17, 2009 1:06 am

Might be a stupid question: But what's the max. (negative) value of the cal factor? the fat16lib-mod.
Looks like my code slows it down a bit much.
User avatar
Posts: 18
Joined: Fri Oct 09, 2009 12:09 pm

Re: Firmware for increased Ice Tube Clock accuracy

by fat16lib on Tue Nov 17, 2009 8:11 am

cal_factor is int8_t so it's range is:

-128 <= cal_factor <= 127
Posts: 591
Joined: Wed Dec 24, 2008 12:54 pm

Re: Firmware for increased Ice Tube Clock accuracy

by Troubadix on Tue Nov 17, 2009 3:27 pm

Thank you!
User avatar
Posts: 18
Joined: Fri Oct 09, 2009 12:09 pm

Re: Firmware for increased Ice Tube Clock accuracy

by Len17 on Sat Nov 21, 2009 11:51 pm

I finally got around to adding this mod to my firmware and calibrating it. It seems spot on so far. Thanks, fat16lib.
User avatar
Posts: 393
Joined: Sat Mar 14, 2009 6:20 pm

Re: Firmware for increased Ice Tube Clock accuracy

by jarchie on Wed Jan 16, 2013 7:07 pm

I've gotten a couple questions regarding my fully-automatic drift correction in my firmware, so I thought it would be worth posting a description here. I hope the method will be useful to other clock hackers.

Instead of adjusting the duration of the first second each hour, the clock makes a 1/128 second adjustment at regular intervals. The code defines two global variables: int16_t drift_adjust specifies how often an adjustment is to be made and uint16_t drift_adjust_timer stores the number of seconds until the next adjustment. The absolute value of drift_adjust is the time between adjustments in seconds. If drift_adjust is positive, the clock is slow; if negative, fast.

This implementation has two advantages: First, the maximum adjustment per second is 1/128 seconds, so no second is noticeably longer or shorter in duration. Second, this method has improved accuracy. For a typical crystal drift of 35ppm, adjusting every abs(drift_adjust) seconds allows a higher resolution--0.2ppm versus with 2 ppm for the once-per-hour method. And with a drift of 2ppm, typical of a temperature compensated crystal oscillator, the adjustment resolution for this method is 0.0005 ppm.

The drift_adjust variable is also updated automatically when the user changes the time, so there is no need to adjust any drift correction constant. After a new time is entered, the clock determines if it is running fast or slow based on the difference between the old and new time. The system uses three global variables:

Code: Select all
int32_t drift_total_seconds;  // seconds since time last set
int32_t drift_delta_seconds;  // seconds between new and old times
uint16_t drift_delay_timer;   // seconds until updating drift adjustment

(1) Every second, drift_total_seconds is incremented by 1.

(2) When initially setting the time after reset, both drift_total_seconds and drift_delta_seconds are set to zero.

(3) When changing the current time, the clock calculates the difference between the old time and the new time in seconds, and adds the difference to drift_delta_seconds. Thus, the current drift in ppm is 1,000,000 * drift_delta_seconds / drift_total_seconds. Because a user might have set an incorrect time by mistake, the clock does not immediately update drift_adjust. Instead, a delay timer, drift_delay_timer, is set to 600 (ten minutes). Therefore, when users incorrectly set the time, they may correct the mistake within ten minutes, and the new drift correction will be estimated correctly.

(4) If nonzero, drift_delay_timer is decremented by one each second. If the value of drift_delay_timer is zero after the decrement, the clock attempts to determine a new drift correction:

If abs(drift_delta_seconds) is less than 15, no drift correction is recorded and the values of drift_delta_seconds and drift_total_seconds are preserved. This somewhat odd behavior prevents a drift adjustment value from being estimated if a user accidently enters the "set time" menu and presses "set" three times to exit.

If abs(drift_delta_seconds) is more than 1200 seconds--20 minutes--no new drift adjustment is calculated and the values of drift_delta_seconds and drift_total_seconds are set to zero. This behavior prevents the drift adjustment from being erroneously estimated when the clock changes timezones or is set to a wildly incorrect time.

Next, a new drift correction, new_adj, is estimated by

Code: Select all
// subtract effect of current drift adjustment, if any
if(drift_adjust) {
    int32_t adj_sec = (drift_total_seconds / drift_adjust) >> 7;
    drift_total_seconds -= adj_sec;
    drift_delta_seconds += adj_sec;

// calculate new drift adjustment
new_adj = (drift_total_seconds / drift_delta_seconds) >> 7;

If abs(new_adj) is at least 39 (under ~200ppm drift), new_adj is likely a reasonable drift adjustment and is saved in an EEPROM array as a potential value for drift_adjust.

(5) The EEPROM contains calculated values for new_adj corresponding to previous time changes (up to seven). The drift adjustment actually used by the clock--drift_adjust--is the median of the previously computed new_adj values in EEPROM. Note that the median must be computed in reciprocal space, so the median of -12, 8, and 15 would be 15 because -1/12 < 1/15 < 1/8. Also note that the median is robust to outliers, so occasionally setting an incorrect time doesn't mess things up.

For more specifics, see the implementation in the time_autodrift(void) function in time.c of my xmas-icetube firmware:
--John <>
Posts: 325
Joined: Sun Jun 24, 2012 1:16 pm
Location: Santa Cruz, California, United States