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
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
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
the crystal we use is DT206 32768Hz, +-20ppm, 6 pf, -10+60C
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
I'm not sure about this , this is just the manufacturer specs which I copy
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.
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 (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.
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?
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
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 ...
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.
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();
}