Mega168 RC oscillator inaccuracy

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a batch of boards using the ATmega168V-10AU flat pack chip, running at 3 volts and 8MHz (nominal) using the internal calibrated RC oscillator. According to the data sheet, the RC oscillator is pre-calibrated to as close as possible to the nominal frequency at 3 volts and temperature 25C (my room is actually at 23C), but I'm finding typical inaccuracies of 2% or more, usually on the slow side, requiring the calibration register to be incremented or decremented by 4 or more.

Several of these boards have had CPUs replaced in the belief that their USARTs were faulty, but so many were failing that I decided to look for a different cause - and this cause seems to be the clock inaccuracy. An asynchronous serial data clock really needs to be accurate to within 1%. 2% is OK if the signal is really clean. Anything much above this can cause serious data loss (and at 5% data loss is virtually guaranteed).

Does anyone know why these chips are not performing to spec, and just how far out we can expect this inaccuracy to be? Are the chips being calibrated correctly but drifting in storage, or is there an error in the calibration itself? Is the calibration likely to drift much over the life of the chip, and if so, by how much?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I thought the factory calibration was for 5V, not 3V3, I therefore wouldn't be surprised if it were a bit no the slow side at 3V3. Also are you actually using a programmer to read the 8MHz factory calibration value from the signature bytes, store it into an EEPROM location and then having your code pick up this value at system start and load it into OSCCAL? The default loaded into OSCCAL otherwise is the 1MHz value I think.

What I've done to try and combat worries about this and on the basis that the ONLY accurate timing I need in my system is the UART is to route the inbound RxD signal also to the INT0 pin and then I have some code that responds to the first inbound traffic on the UART and not only measures (unsing INT0) the width of the start bit to set OSCCAL for an accurate value but also can auto baud detect. So I just start the PC terminal at any baud 2400, 9600, 38400, 115200 and hit enter a couple of times and the AVR is switched to a calibrated rate (using UBRR and then OSCCAL adjustments) to accurately communicate with the PC. The only thing the PC user has to get right is the 8,n,1 and remember to transmit a character or two at the start.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I thought the factory calibration was for 5V, not 3V3, I therefore wouldn't be surprised if it were a bit no the slow side at 3V3. Also are you actually using a programmer to read the 8MHz factory calibration value from the signature bytes, store it into an EEPROM location and then having your code pick up this value at system start and load it into OSCCAL? The default loaded into OSCCAL otherwise is the 1MHz value I think.

What I've done to try and combat worries about this and on the basis that the ONLY accurate timing I need in my system is the UART is to route the inbound RxD signal also to the INT0 pin and then I have some code that responds to the first inbound traffic on the UART and not only measures (unsing INT0) the width of the start bit to set OSCCAL for an accurate value but also can auto baud detect. So I just start the PC terminal at any baud 2400, 9600, 38400, 115200 and hit enter a couple of times and the AVR is switched to a calibrated rate (using UBRR and then OSCCAL adjustments) to accurately communicate with the PC. The only thing the PC user has to get right is the 8,n,1 and remember to transmit a character or two at the start.


From page 31 of the Mega168 data sheet (rev. F):-
Quote:
The calibrated internal RC oscillatos by default provides an 8.0MHz clock. The frequency is nominal value at 3V and 25C.

I already had a routine to calibrate the oscillator from the 32KHz crystal and make small adjustments (+/-1) once an hour or so to compensate for temperature variation (there units have to operate outside in all seasons). I've now changed it to calibrate once a minute and adjust by up to +/-10, and that seems OK.

In this case, fortunately, the UART is only used during debugging and production testing, so a few percent drift in the field is not critical. It might not always be that way, though - if Atmel say it is pre-calibrated to the nearest value to nominal, I wouldn't expect to have to adjust by 4 or more on startup..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want reliable UART comms, then you need to calibrate the internal oscillator against an accurate clock source at least once per session (where supply voltage & temperature stay reasonably constant). I'll state that pretty much as a postulate.

--Since you are hooked to "something" during debugging & production testing, you could inject a signal from the test setup, or even autoboad timing a few bit widths during synchronization.

--Consider calibrating to 7.3728MHz or 3.6864MHz from the nominal 8 or 4 MHz clock values. Since these are magic numbers, small drifts are tolerated nicely.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

timbierman wrote:
clawson wrote:
I thought the factory calibration was for 5V, not 3V3,

From page 31 of the Mega168 data sheet (rev. F):-
Quote:
The calibrated internal RC oscillatos by default provides an 8.0MHz clock. The frequency is nominal value at 3V and 25C.


Ah, my bad, I should have checked the Mega168 datasheet specifically, for the Mega16 that I'm using:
Quote:
The Calibrated Internal RC Oscillator provides a fixed 1.0, 2.0, 4.0, or 8.0 MHz clock. All frequencies are nominal values at 5V and 25°C.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
If you want reliable UART comms, then you need to calibrate the internal oscillator against an accurate clock source at least once per session (where supply voltage & temperature stay reasonably constant). I'll state that pretty much as a postulate.

--Since you are hooked to "something" during debugging & production testing, you could inject a signal from the test setup, or even autoboad timing a few bit widths during synchronization.

--Consider calibrating to 7.3728MHz or 3.6864MHz from the nominal 8 or 4 MHz clock values. Since these are magic numbers, small drifts are tolerated nicely.


I think I agree. Whatever the data sheet says, the base accuracy is not good enough for serial comms.

I don't need to inject a timing signal during testing because the 32K crystal provides that. I have a spare output pin toggling high and low once a second - originally an LED on the breadboard version to tell me the program was running - so I can time that with the test rig to see how accurate the calibration is.

I considered going down to 7.3728MHz, but that would need rather a lot of re-thinking of timing in other parts of the program, and it might be too slow for a time-critical part that has to interrupt every 10 microseconds. As it is, 8MHz gives me the baud rate I need to within 1%, which is fine as long as the base rate is OK. If I needed greater accuracy I could use 7.9872MHz, which gives accurate baud rates up to 76800.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

uh, What accuracy are you expecting? Chapter 7.6.1 says OSCCAL is automatically loaded with the value given by the factory, providing 8.0 MHz. But read Chapter 6.1; it's only within 10%. Each increment of OSCCAL 6:0 will produce steps of 2% or less, so you can further tune it within 2%.

It appears from Figure 28-40 that 15C change will result in 1% frequency change. It appears from Figure 28-42 that voltage variation between 2V5 and 5V is not a significant factor.

It would seem to me that the RC oscillator is adequate only if you calibrate it to an outside source.

And none of these figures are given in the 'guaranteed' charts, only in the 'typical'.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mneary wrote:
uh, What accuracy are you expecting? Chapter 7.6.1 says OSCCAL is automatically loaded with the value given by the factory, providing 8.0 MHz. But read Chapter 6.1; it's only within 10%. Each increment of OSCCAL 6:0 will produce steps of 2% or less, so you can further tune it within 2%.

It appears from Figure 28-40 that 15C change will result in 1% frequency change. It appears from Figure 28-42 that voltage variation between 2V5 and 5V is not a significant factor.

It would seem to me that the RC oscillator is adequate only if you calibrate it to an outside source.

And none of these figures are given in the 'guaranteed' charts, only in the 'typical'.


We must have a different data sheet as on mine it's chapter 7.6.

You are right that the base value is +/-10%, but the calibration is intended to make it more accurate than that. One step of the OSCCAL register actually adjusts it by about 0.5%, so maybe the quoted value of 2% is just the accuracy they bother with when pre-calibrating it.

Maybe they speed up the production process by only calibrating to an accuracy sufficient to make the EEPROM writes reliable. In any case, 2% is usable for serial data (just), but it;s clear that some of the chips are further out than this. I'll know better when I get some of the failed boards back to test properly.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've got two production designs that use internal oscillator plus 32k crystal ("regular" crystal would be about the same size and cost, but starts up too slowly from Power Dowm when a wakeup event occurs).

We use /2 prescaler, and my "target" frequency is 3.6864MHz. It continually auto-tunes when awake (running off external power) and the Timer2 is running. The UART speed is 57600. We have no problems with this arrangement with hundreds of production units. Frankly, though the OSCCAL value is loaded the app ignores this, and starts with a value that gives close to 3.6864MHz on a batch of pre-production units. Many units end up pretty close to that value; some are quite a bit lower; some quite a bit higher. I've "watched" the auto-tune process and things do drift and change, especially when hit with a blast of freeze mist or heat gun. But the UART comms never miss a beat. I've never actually checked a bit time with precision to see how close we are to nominal.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
I've got two production designs that use internal oscillator plus 32k crystal ("regular" crystal would be about the same size and cost, but starts up too slowly from Power Dowm when a wakeup event occurs).

We use /2 prescaler, and my "target" frequency is 3.6864MHz. It continually auto-tunes when awake (running off external power) and the Timer2 is running. The UART speed is 57600. We have no problems with this arrangement with hundreds of production units. Frankly, though the OSCCAL value is loaded the app ignores this, and starts with a value that gives close to 3.6864MHz on a batch of pre-production units. Many units end up pretty close to that value; some are quite a bit lower; some quite a bit higher. I've "watched" the auto-tune process and things do drift and change, especially when hit with a blast of freeze mist or heat gun. But the UART comms never miss a beat. I've never actually checked a bit time with precision to see how close we are to nominal.


Looks like I've now got a reasonable algorithm to calibrate it against the 32K crystal in 4-8 milliseconds without having to turn interrupts off. I have timer 1 counting microseconds (x8 prescaler) and timer 2 on the async counter set to interrupt once a second. If the clock is 8MHz, timer 2 should increment once every 3906 timer 1 cycles or so, and the amount to adjust OSCCAL by is roughly one increment or decrement for every 0.55% error. To get this I multiply the error by 12 and take the top 8 bits of the result, which is close enough. If an interrupt occurs, as indicated by the timer 1 reading incrementing by more than about 5 between the loops before and after timer 2 increments, then I just start the process again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I run the process continually when the app is not on battery power. Will you have the watch crystal running all the time?

I'm sure that it take MUCH less than 4ms. There is only one 16-bit divide and a few other instructions.

Be sure to add some hysteresis so you don't jump one side to another when you are close. Also, I don't worry about stepping directly to the "right" value; otherwise ping-ponging can occur.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
I run the process continually when the app is not on battery power. Will you have the watch crystal running all the time?

I'm sure that it take MUCH less than 4ms. There is only one 16-bit divide and a few other instructions.

Be sure to add some hysteresis so you don't jump one side to another when you are close. Also, I don't worry about stepping directly to the "right" value; otherwise ping-ponging can occur.


The watch crystal is running all the time. In fact, it and the watchdog are the only things that run all the time (total current about 12 microamps).

It doesn't take 4ms of solid processing. Tha actual calculation takes only a few microseconds, but I need to be in a tight loop for 4ms (plus up to 4ms more st the start waiting for the first timer 2 increment) in order to catch the timer tick exactly as it happens.

Actually, there is a faster method using the busy flags in the ASSR register to time a single cycle of the 32K crystal, but I need to work on that one a bit more to make it reliable.

Hysteresis doesn't seem to be a problem. Occasionally the OSCCAL value will toggle between two adjacent values, but only if those two values are more or less equally close to the right one. If anything, this makes the long-term accuracy even better, though as the CPU is in power save mode 99.9% of the time this is not really an issue.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wrote the incorrect chapter. You're right, it's 7.6. I have the revision f data sheet, which I downloaded a few minutes ago from Atmel.com. The errata says that this chapter was "updated" in revision e and then again in f.

"During reset, hardware loads the calibration byte into the OSCCAL Register and thereby automatically calibrates the RC oscillator. At 3V and 25C this calibration gives a frequency of 8 MHz +/- 10%." "The oscillator can be calibrated to any frequency in the range 7.3 - 8.1 MHz within +/- 2% accuracy...."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

, but I need to be in a tight loop for 4ms (plus up to 4ms more st the start waiting for the first timer 2 increment) in order to catch the timer tick exactly as it happens.

I don't worry about it (catching anything exactly). I have timer2 interrupting every 500ms (just because it was convenient). Then I set a flag for the main loop--one instruction ISR.

I have the luxury of using 16-bit Timer1, and expect about 7200 ticks in 500ms. (nominal 3.6864MHz with /256 prescaler). I only do an adjustment when I am at least 36 ticks away from 7200-- 2.5ms out of 500, or 1/2 percent.

I stop the Timer1, grab the counts, clear TCNT1, and restart the timer. Yes, I have some jiggle from repetition to repetition, but most of it cancels out by doing everything in the same spot in the main loop.

I "invented" my own sequence, without examining Butterfly or other similar code.

I do not keep the 32k running during power-down, so I throw away the first repetition when awakening to let the crystal stabilize. Not a problem if you never stop it; definitely a problem if you do since the milliseconds of warmup causes a jump.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Assuming a couple of fairly major things I happen to have in my application (like a regulated voltage supply and access to a calibrated temperature sensor) it seems like it should be fairly possible to use the internal temperature sensor to adjust for frequency drift. Has anyone tried this? I might give it a shot. In a UART situation it seems like if you were still off you could auto-baud a little (or possible just increase OSCCAL - looking at the typical graphs) after detecting a few failed packets

Any thoughts?.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

svnt wrote:
In a UART situation it seems like if you were still off you could auto-baud a little (or possible just increase OSCCAL - looking at the typical graphs) after detecting a few failed packets

Any thoughts?.


I do that - I have RxD connected to INT0 so I can measure the width of inbound start bits which not only lets me adjust OSCCAL but also auto baud switch so it doesn't matter if the user connects at 2400, 9600 or 115200 - they just hit return a few times and the AVR is ready to "talk" at an accurate baud rate. As the UART is the only thing in my app that needs totally accurate timing (but I'm too tight to pay for a crystal!) this solution works nicely.

Cliff