November 08, 2024, 01:48:03 PM

Maple RTClock accuracy

Started by tfcroft4, September 17, 2012, 12:40:45 PM

Previous topic - Next topic

tfcroft4

I have implemented the MapleRTC code on my new board using the Maple IDE. I am finding that the time accuracy using the LSE crystal is poor. :( Gaining 10 seconds in a day. Searches on the web suggest that the 32khz crystal should have its can grounded and the circuit diagram also shows that. On my board I don't think the crystal can is grounded.
Can you advise how best to proceed?

Thanks
Ted

olimex

grounding will not help much, the problem with these 32kHz crystals is the temperature frequency drift, unless you put this crystal in temperature chamber with constant temperature there will be always frequency shift, another approach is to take the characteristics and to measure the ambient temperature and do frequency compensation

tfcroft4

Thanks for the reply. A consistent 10 seconds gain in time is in the order of 120 ppm. The board under test is sitting in a temperature stable room at 24C.

I have built a number of systems using DS1307 RTC chips driven by 32khz crystals and most reamain accurate to +- 2 secs a day.

Is the Olimexino boards likely to give anything approaching this accuracy?

STM documents give a potential calibration range of 1 - 127 ppm for the RTC counter - as this board is already at that extreme I not sure that there is enough calibration available to bring the RTC into an acceptable accuracy.

What is the spec of the crystal on the board? Are there more accurate HW alternatives before using SW to compensate?

Thanks


olimex

the crystal we use is DT206 32768Hz, +-20ppm, 6 pf, -10+60C

tfcroft4

Thanks for the crystal spec. Am I correct in thinking that if the crystal is +- 20ppm with -10 +60 C range. One would expect 0 - 20ppm around the mean temperature of 25C ?

TF

olimex

I'm not sure about this , this is just the manufacturer specs which I copy

tfcroft4

I would like to have a reasonably accurate battery backed RTC within my system. The STM32 MCU has this capability but does depend on the HW setup.

Do you think my experience is typical of this board design or a one off??

Thanks again for your help.


tfcroft4

The problem is not as bad as I thought but does need some work.

The ST Application note  AN2604 describes how to slow down / calibrate the LSE ( 32khz) crystal input used for the RTC. http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/APPLICATION_NOTE/CD00167326.pdf

Note that the calibration works by removing 'ticks' every 2^20 ticks ( about 32 seconds) so helps in long term accuracy but would impare using the RTC for accurate short term timing. In the latter case then the HSE clocked timers would be a better source.

I have added a calibration function to the RTC code I am using and am testing values. I think this may have to be done on a case by case basis if there is variation between individual boards.

I hope this helps others.

tfcroft4

#8
An update.

I now have the RTC generating an fairly accurate 1 sec interrupt from the LSE crystal (32khz). I have had to adjust both the RTC calibration and Pre Scaler values. This has been a bit of trial and error although I feel that one ought to be able to calculate the values.

Currently running with a RTC Pre Scaler of 32770 and Calibration value of 35.

Without wider tests I don't know if this is specific to my board or a more general value.

So could we now go for a temperature compensation too by reading the temperature?

manitou

I've been experimenting with 32khz RTC on maple (via breadboard).  I enabled the 512hz output of the RTC to measure frequency offset of crystal.  I tried writing values in the calibration register, but that didn't seem to have any effect.  Can you share the code you used for setting calibration and prescaler for the RTC.

Here are some results for various MCU's and RTC's using an NTP host to measure frequency offset (measured ppm)  ...


  processor    oscillator      spec    measured(ppm)
  avr 328p    16Mhz resonator  0.5%     -1330        uno
              16MHz resonator  0.5%     -1422        breadboard 328p
              16MHz crystal    50ppm    -42          breadboard 328p
  avr 328p    11Mhz crystal     ?       -23          3.74v batteries
  avr 328p    11Mhz crystal     ?       -16          5v
  avr 128     14Mhz             ?       1738         no schematic, resonator?

  DUE         12MHz*x crystal    ?
  maple       8MHz*9 crystal    ?        -5
  propeller   5Mhz*16 crystal   ?        -40         board1 (quickstart)
  propeller   5Mhz*16 crystal   ?        -98         board2 (quickstart)
 
  ds1307 RTC  32khz            20ppm    23           external "watch" crystal
  ds3132 RTC  32khz             2ppm     1           chronodot TCXO i2c
  ds3134 RTC  32khz             2ppm     1           TCXO SPI

  maple RTC   32khz            20ppm     -41         breadboard 512hz ticks

  avr 328p RC  8Mhz             1%       2100         OSCCAL units 3000 ppm
  avr 328p RC  8Mhz             1%       2700         OSCCAL units 5000 ppm

  beagle      24MHz*x                    -5          ntp drift
  raspberry   19MHz*x                   -16          ntp drift
  dell desk                             -26          ntp drift
  dell laptop                           -14          ntp drift



manitou

The 512hz output (maple pin 21) from the 32k cyrstal will not be affected by the calibration or prescale, so that's why I wasn't "seeing" any change.  I need to measure the RTC pps change.  Changing the prescale for the 32khz cyrstal will be in units of 30ppm and the calibration register can slow things from 1 to 120 ppm.  Your 32770/43 combination "slows" your crystal by about 103 ppm -- looks like you could have done that with just the calibration register.

i'm still interested in a code snippet of manipulating bits/counters for RTC control ...

manitou

I found this RTC library did what I needed on a maple. 
  https://github.com/bubulindo/MapleRTC
I was able calibrate my 32khz crystal from -35ppm to -4ppm by using the prescaler via

   RTClock rt (RTCSEL_LSE,0x7ffe);

and I could adjust the LSI clock from -20000ppm to 100ppm in a similar fashion.

tfcroft4

This is a quick cut and paste from longer code - I hope this helps.

I link in bkp.h and RTCClock from leaflabs with an edit as below.

The main loop can send or display time when displaytime == true;



// this is a quick cut and paste and will probably not compile
// TFCROFT4

#include <bkp.h>


int milliseconds;

#define CALIBRATE 35
#define PRESCALER 32770

//instantiate a RTC use the low speed external crystal
// if CALIBRATE or PRESCALER are defined then use the defined values

#ifdef PRESCALER
RTClock rt(RTCSEL_LSE, PRESCALER);
#else
RTClock rt(RTCSEL_LSE);
#endif

//
void newSecond () {
    milliseconds = 0;
    togglePin(3);
}

void mySysTickHandler(){
    milliseconds++;
    if (milliseconds == 500)  digitalWrite(3, LOW);
    if (milliseconds == 1000) milliseconds = 0;

    } // ms sound count back

}

void setup() {
    Serial1.begin(9600);
    Serial1.println("RTC application.");
    pinMode(BOARD_LED_PIN, OUTPUT);
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);
    // Maple Seconds interrupt Hook from RTC
    rt.attachSecondsInterrupt(&newSecond);
    // Maple systick interrupt hook - internal ms tick
    systick_attach_callback(&mySysTickHandler);
    // initialise the backup domain
    rtc_bkp_init();
    // get config data from backup storage
    config_data_init();
   
}// end of setup


/**
* @brief  initialse backup domain
* checks for magic number which is lost if backup power goes down
* @param  None
* @retval None
*/
void rtc_bkp_init(){
    uint32 csr;
    /** Initialize backup interface.  */
    bkp_init();
    /** Test for magic number in BKP data.  */
    {
        Serial1.println("Read reset flags");
        // Flag Register in RCC CSR
        csr = RCC_BASE->CSR;
        Serial1.println(csr,2);
        /* Check if the Software reset flag flag is set Bit 28 */
        if (bitRead(csr,RCC_CSR_SFTRSTF_BIT) == RESET)  { 
            Serial1.println("Software Reset occurred....");   
        }
        /* Check if the Power On Reset flag is set Bit 27 */
        if (bitRead(csr,RCC_CSR_PORRSTF_BIT) == RESET) { 
            Serial1.println("Power On Reset occurred....");   
        }
        /* Check if the Pin Reset flag is set bit 26 */
        if (bitRead(csr,RCC_CSR_PINRSTF_BIT) == RESET) { 
            Serial1.println("External Reset occurred....");   
        }
    }
    Serial1.println("Read Magic Number");
    // decimal value of 0xA545 is 42405
    Serial1.println(bkp_read(BKP_MAGIC));
    if (bkp_read(BKP_MAGIC) != 0xA5A5)
    {
        /* Backup data register value is not correct or not yet programmed (when
         the first time the program is executed) */
        Serial1.println("RTC not yet configured....");

        /* Adjust time by values entered by the user on the hyperterminal */
        /* Change the current time */
        rt.setTime(Time_Init());

        my_bkp_write(BKP_MAGIC, 0xA5A5);


    }
# ifdef CALIBRATE
    Serial1.print("Defined Calibration value ");
    Serial1.println(CALIBRATE);
    // Flag Register in RCC CSR
    csr = BKP_BASE->RTCCR;
    Serial1.println(csr,2);
    //mask lower bits
    csr &= 0x7F;
    Serial1.print("Current calibration value: ");
    Serial1.println(csr,2);
    // Set Calibration value for RTC in backup domain
    rt.SetRTCCalibrationValue(CALIBRATE);
    Serial1.print("New calibration value: ");
    // Flag Register in RCC CSR
    csr = BKP_BASE->RTCCR;
    Serial1.println(csr,2);
    //mask lower bits
    csr &= 0x7F;
    Serial1.println(csr);
#endif
}

// add this to RTC library

// TF Write calibration value to backup domain
// this number of ticks are 'lost' every 2^20 clock tick so approximates to lost ticks ppm
void RTClock::SetRTCCalibrationValue(uint8 calibration_value){
rtc_set_calibration(calibration_value);
}

// Added by TF so standard now() in Time code can work
time_t RTClock::now() {
return rtc_get_count();
}