Go Down

Topic: Long term stability of internal RC oscillator (Read 3812 times) previous topic - next topic

westfw

Note that while the "internal 8MHz RC Oscillator" is "high accuracy" and able to be calibrated via the OSCCAL register, that is NOT true of the 128kHz watchdog oscillator.  I haven't measured anything on an ATmega328p, but on an ATtiny11 (which uses a similar (?) watchdog oscillator as THE internal clock (nominally 1MHz)), I can tell you that the frequency varies dramatically and visibly (on a blinking-LED-like program) depending on supply voltage; perhaps 60% going from 3V to 5V...

MrMark

Note that while the "internal 8MHz RC Oscillator" is "high accuracy" and able to be calibrated via the OSCCAL register, that is NOT true of the 128kHz watchdog oscillator.  I haven't measured anything on an ATmega328p, but on an ATtiny11 (which uses a similar (?) watchdog oscillator as THE internal clock (nominally 1MHz)), I can tell you that the frequency varies dramatically and visibly (on a blinking-LED-like program) depending on supply voltage; perhaps 60% going from 3V to 5V...
Figure 1-2 in this application note shows the 8 MHz sensitivity to supply voltage for an Atmega8: Atmel-2555-Internal-RC-Oscillator-Calibration-for-tinyAVR-and-megaAVR-Devices_ApplicationNote_AVR053.pdf  It's on the order of 10% but certainly significant.  It indicates the full range temperature sensitivity is of similar magnitude.  This doesn't directly address the question of what happens under moderately well controlled voltage and temperature, but improving four orders of magnitude seems really unlikely.

Mixe

Funny, I'm designing a test circuit for this very purpose right now. I'm testing the reliability of the watchdog RC oscillator in power down mode, both for longer periods of time and 24 hours for the ATtiny10 (extremely small, 1 kb mc, not programmable by the arduino IDE yet. But it's awesome). The setup is:

An ATtiny10 powered by one single CR2032 battery, running a code that puts it into sleep mode for 24 hours in 8 second intervals. When it wakes up, it fires of a pulse through one of its IO-pins. The pulse triggers an interrupt on an ESP8266 connected to an RTC. It logs the time, calculates the interval and resets the ATtiny10. It also runs a server that dispays the list of intervals to incoming connections.
I will also test longer intervals and one running code.

Right now I have some problems getting the voltage provided by the ATtiny's IO pin to successfully provoke an interrupt on the  ESP. The level is too low to be read as a pin change. If anyone has any idea how to change the level needed I would be very grateful! And naturally post my findings here.


CrossRoads

What level is needed?
Buffer the signal with cd74HC4050, powered from the ESP8266 Vcc supply. Output will then be low and  high that is compatible with ESC8266.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Mixe

I think 3V is the trigger level, but the datasheet for ESP is not as detailed and extensive as those for AVR:s, so I reach that figure by trial and error. If anyone knows how to find out for sure, I'm all ears.

And thank you so much for the tip! I will check out the cd74HC4050 immediately.

Smajdalf

I don't exactly understand how HC4050 is supposed to do the level shifting. Probably easiest way is transistor in common emitter configuration.

Smajdalf

#21
May 06, 2017, 06:17 pm Last Edit: Jul 04, 2017, 06:44 pm by Smajdalf
After some problems I have first results:


I recorded number of "16 ms" overflows of both WDT and Timer0 for one minute. On the graph are "moving sum" (like moving average without averaging) of 200 minutes - IIRC the blue line is Timer0 and orange is WDT. Data are from not full day experiment. I was monitoring voltage and it dropped at end of the experiment for some reason. I will collect the data for much longer time (at least one week) with monitoring of temperature and voltage and make some decent statistical analysis. I wonder what will be result.

EDIT: I was a bit busy lately so I let my experiment run much longer than expected. Due to a bug in SPI settings no data were recorded :-( It should be fixed now...

Smajdalf

#22
Jul 24, 2017, 06:06 pm Last Edit: Jul 24, 2017, 08:37 pm by Smajdalf
I got some data from about 14 days. Both WDT and main oscillator have about the same variations. Sadly it depends on temperature so much it is possible to determine temperature variations between night and day indoors hidden in my table drawer and so it is not possible to use it to some good time keeping without callibration to temperature. On the other hand this be exploited somehow: main oscillator frequency increases with increasing temperature while WDT oscillator slows down and so differences may be measured even without better time reference. It is interesting the frequency oscillations are more sensitive than internal temperature sensor. Here is graph from my experiment. If someone is interested in the raw data I can share them but I think everything important is in the graph.

EDIT: the picture was too large and was not included. There it is:


zoomx


Smajdalf

Can you share your sketch?
I can but it was not intended to be shared so I don't know how much you will understand. Also it was written and compiled it Atmel Studio 7 for standalone Atmega328p. Data were saved to 1Mb SPI EEPROM, I read them back by simple sketch in Arduino. That sketch is so messy I won't share it ;-)
Code: [Select]

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#define WREN  6 //write enable
#define WRDI  4 //write disable
#define RDSR  5 //read status register
#define WRSR  1 //write status register
#define READ  3
#define WRITE 2
#define PE 0b01000010
#define BP1 3
#define BP0 2
#define WEL 1
#define WIP 0
#define StartPin (1<<PB0) //pin 14
#define LivingPin (1<<PB6) //pin 9
#define SSPin (1<<PB2) //pin 16
//pin 4 is for external interrupt
#define DefaultADCSRA ((1<<ADEN)+(1<<ADPS2)+(1<<ADPS1))
#define TempADMUX ((1<<REFS1)+(1<<REFS0)+(1<<MUX3))
#define VADMUX ((1<<REFS0)+(1<<MUX3)+(1<<MUX2)+(1<<MUX1))

#define SavingTime 60*5 //seconds; currently 5 minutes -> overflow in about 37 days
#define maxPointer 6*21-3 //just to be sure
#define DataBufferLength 128

volatile unsigned int WDT_overflows, counter_overflows, seconds;
unsigned int dataToSave[DataBufferLength], minTemp=-1, maxTemp=0, minV=-1, maxV=0, pageAddress=0;
uint8_t timeToSave, dataPointer, readV;

static void sendToMemory();
static void selectMemory();
static void deselectMemory();
static void toggleLiving() {PINB=LivingPin;} //Pin 9 next to GND

ISR(WDT_vect) {
WDT_overflows++;
}

ISR(TIMER0_COMPA_vect) {
counter_overflows++;
}

ISR(INT0_vect) {
seconds++;
toggleLiving();
}

static void debugLED() {
PORTB|=1<<PB1;
}

int main(void) {
deselectMemory();
DDRB=SSPin+(1<<PB5)+(1<<PB3);
PORTB|=StartPin|LivingPin;
SPCR = (1 << SPE) + (1 << MSTR);
SPSR = (1 << SPI2X); //Set double speed
while (PINB&StartPin) {} //Waiting for pressing of button
EIMSK = 1; //enable INT0
EICRA = 2; // falling edge on INT0 generates interrupt
wdt_reset();
WDTCSR=(1<<WDCE)+(1<<WDE);
WDTCSR=(1<<WDIE); //about 16ms interrupt
OCR0A=127;
TCCR0A=1<<WGM01; //CTC mode
TCCR0B=(1<<CS02)+(1<<CS00); //Prescaler 1024
TIMSK0=(1<<OCIE0A); //Enable interrupt
ADCSRA=DefaultADCSRA; //Enable ADC with prescaler 64
TCCR2B=7; //Prescaler 1024
while(1) {
cli();
if (seconds>=SavingTime) {
seconds=0;
dataToSave[dataPointer++]=WDT_overflows;
WDT_overflows=0;
dataToSave[dataPointer++]=counter_overflows;
counter_overflows=0;
dataToSave[dataPointer++]=minTemp;
minTemp=-1;
dataToSave[dataPointer++]=maxTemp;
maxTemp=0;
dataToSave[dataPointer++]=minV;
minV=-1;
dataToSave[dataPointer++]=maxV;
maxV=0;
if (timeToSave) {
debugLED();
}
}
sei();
if ((dataPointer>maxPointer)&&(!(timeToSave))) {
timeToSave=2;
dataPointer=0;
selectMemory();
SPDR=WREN;
}
if ((SPSR&(1<<SPIF))&&(timeToSave)) {
sendToMemory();
}
if (TIFR2&(1<<TOV2)) {
TIFR2|=(1<<TOV2);
ADCSRA=DefaultADCSRA+(1<<ADSC);
}
if (ADCSRA&(1<<ADIF)) {
ADCSRA=DefaultADCSRA+(1<<ADIF);
unsigned int result = ADCW;
if (!(readV)) {
ADMUX=VADMUX;
readV=1;
if (result>maxTemp) {
maxTemp=result;
}
if (result<minTemp) {
minTemp=result;
}
}
else {
if (readV++>8) {
readV=0;
ADMUX=TempADMUX;
}
if (result>maxV) {
maxV=result;
}
if (result<minV) {
minV=result;
}
}
}
}
}

static void deselectMemory() {
PORTB|=SSPin;
}

static void selectMemory() {
PORTB&=~SSPin;
}

static void sendToMemory() {
if (timeToSave==1) { //writing into EEPROM LSB
SPDR=dataToSave[dataPointer];
timeToSave=4;
}
else if (timeToSave==4) {//writing into EEPROM MSB
SPDR=dataToSave[dataPointer]>>8;
if (dataPointer<(DataBufferLength-1)) { //write next byte
dataPointer++;
timeToSave=1;
}
else {
timeToSave=5;//finish writing
dataPointer=0;
}
}
else if (timeToSave==2) { //only WREN was send
deselectMemory();
timeToSave=3;
}
else if (timeToSave==3) {
selectMemory();
SPDR=WRITE;
timeToSave=6; //need to send address
}
else if (timeToSave==5) { //end writing page
deselectMemory(); //deselect EEPROM
timeToSave=0;
PORTC=(pageAddress>>3);  //2^9 pages; to fit to 6 bit PORTC
pageAddress++;
}
else if (timeToSave==6) {
SPDR=pageAddress>>8;
timeToSave=7;
}
else if (timeToSave==7) {
SPDR=pageAddress;
timeToSave=8;
}
else if (timeToSave==8) {
SPDR=0;
timeToSave=1;
}
}


zoomx

Thanks!
You choosed to save on a SPI memory because is faster than a serial print or than using an SD, right?

Smajdalf

I used SPI because it is easier to use than SD card (less SW, works on 5V). I did not use serial print because it was standalone chip without USB <-> TTL and because it run for about 2 weeks - I don't have computer that would run so long. I turn computer off before I go sleep/leave for long.

MrMark

#27
Jul 24, 2017, 10:19 pm Last Edit: Jul 24, 2017, 10:19 pm by MrMark
Could you post the WDT and Oscillator data without normalizing the scale as in post #21?  The absolute magnitude of variation is not clear from the graph of #22.

What do you use at the reference time base (INT0)?

Smajdalf

#28
Jul 24, 2017, 10:37 pm Last Edit: Jul 24, 2017, 10:39 pm by Smajdalf
Reference was PPS signal from DS3231. I think best reasonably available reference. Here are graphs for the oscillators and raw data.


westfw

So the main osillator varies over a range of about 100/18000?  About 0.5%?  That's not too bad.
That they have opposite response to temperature changes is ... interesting!

Go Up