RC_calib_oscsampleif.c File Reference


Detailed Description

Functions for calibrating and estimating clock periods of the RC Oscillators.

Functions for: calibrating the Fast RC with Slow RC as reference, predicting Slow RC perod from temperature and measuring ULP RC period with Slow RC as reference. Supporting functions for measuring temperature and reading out signature data are also included.

Application note:
AVR351: Runtime calibration and compensation of RC oscillators using the Oscillator Sampling Interface
Documentation
For comprehensive code documentation, supported compilers, compiler settings and supported devices see readme.html
Author:
Atmel Corporation: http://www.atmel.com
Support email: avr@atmel.com
Revision
4809
Date
2008-11-04 12:17:59 +0100 (ti, 04 nov 2008)

Copyright (c) 2008, Atmel Corporation All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. The name of ATMEL may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Definition in file RC_calib_oscsampleif.c.

#include "RC_calib_oscsampleif.h"
#include "ATmega8HVA_16HVA_signature.h"
#include <ioavr.h>
#include <inavr.h>

Include dependency graph for RC_calib_oscsampleif.c:

Go to the source code of this file.

Defines

#define FAILED   -1
#define SUCCESS   0

Functions

uint16_t CalculateSlowRCperiod (int16_t temperature)
 Calculate Slow RC period time.
int8_t CalibrateFastRCruntime (uint16_t cal_RC_period)
 Calibrate the Fast RC against the Slow RC oscillator runtime.
uint16_t MeasureULPRCperiod (uint16_t cal_RC_period)
 Measure the ULP RC period time against the Slow RC.
uint16_t OSIsampleClockPeriod (uint8_t clock_source)
 Measure OSI prescaled clock periods.


Define Documentation

#define FAILED   -1

Definition at line 63 of file RC_calib_oscsampleif.c.

#define SUCCESS   0

Definition at line 62 of file RC_calib_oscsampleif.c.


Function Documentation

uint16_t CalculateSlowRCperiod ( int16_t  temperature  ) 

Calculate Slow RC period time.

Calculate Slow RC period time given a temperature. The formula for calculation of Slow RC period is used with the signature data (loaded from the signature row) to calculate the actual period as described in the data sheet and application note. The result is in ms * 1024. It can thus be seen as ms in 16 bit fixed point format, with 10 fractional bits, i.e. 0x XXXX XX.xx xxxx xxxx.

Parameters:
temperature in Kelvin (uint16_t)
Returns:
calculated Slow RC period in ms*1024 (uint16_t)

Definition at line 81 of file RC_calib_oscsampleif.c.

References READ_SIGNATUREBYTE, SIG_SLOW_RC_H, SIG_SLOW_RC_L, SIG_SLOW_RC_PRED_H, SIG_SLOW_RC_PRED_L, SIG_TEMPERATURE_HOT, and ZERO_C_IN_KELVIN.

Referenced by main().

00082 {
00083     uint16_t slow_RC_period;
00084     int16_t  slow_RC_temperature_coeff;
00085     uint16_t calib_temperature;
00086 
00087     /* Read necessary data from the signature row. The delay cycles are to avoid
00088      * accessing the SPMCSR register within 6 cycles of previous write, since it 
00089      * is locked for further writing during these cycles.
00090      */
00091     slow_RC_period = READ_SIGNATUREBYTE(SIG_SLOW_RC_L);
00092     
00093     // Avoid writing to SPMCSR register within 6 cycles of previous write.
00094     __delay_cycles(2);
00095     
00096     slow_RC_period |= READ_SIGNATUREBYTE(SIG_SLOW_RC_H) << 8;
00097     
00098     // Avoid writing to SPMCSR register within 6 cycles of previous write.
00099     __delay_cycles(2);
00100     
00101     slow_RC_temperature_coeff = READ_SIGNATUREBYTE(SIG_SLOW_RC_PRED_L);
00102     
00103     // Avoid writing to SPMCSR register within 6 cycles of previous write.
00104     __delay_cycles(2);
00105     
00106     slow_RC_temperature_coeff |= READ_SIGNATUREBYTE(SIG_SLOW_RC_PRED_H) << 8;
00107     
00108     // Avoid writing to SPMCSR register within 6 cycles of previous write.
00109     __delay_cycles(2);
00110     
00111     calib_temperature = READ_SIGNATUREBYTE(SIG_TEMPERATURE_HOT) + ZERO_C_IN_KELVIN;
00112     
00113     return (uint16_t)(slow_RC_period - ((temperature - calib_temperature)*slow_RC_temperature_coeff)/64);
00114 }

int8_t CalibrateFastRCruntime ( uint16_t  cal_RC_period  ) 

Calibrate the Fast RC against the Slow RC oscillator runtime.

Since the value we're searching for is probably close to the current, we do a linear search. It searches the segment where FOSCCAL default is and the one below. When searching downwards we use the FOSC SEGMENT signature byte to avoid a jump in frequency when reaching the lower segment and thus giving a longer continous search range. FOSC segment is the first value in the previous segment that gives a lower frequency than the lowest value in the FOSCCAL default segment. If we reach the bottom of the lower segment or the top of the default segment we select the default FOSCCAL value and return failed as this range should provide a more than sufficient range for adjusting FOSCCAL over all temperatures, so something is wrong.

Note that no other boundary check is done, but even if the FOSCCAL value is outside the search range the frequency should be correctly calibrated, although jumps in frequency results will be encountered. If the FOSCCAL value is between the lowest value in FOSCCAL default segment and the FOSC SEGMENT, a value in that range might be selected.

The Oscillator Sampling interface with timer input capture is used in a polled way to minimize interrupt routines.

Parameters:
cal_RC_period Slow RC period in ms * 1024
Returns:
Status, SUCCESS or FAILED

Definition at line 143 of file RC_calib_oscsampleif.c.

References FAILED, FAST_RC_TARGET_MHZ, OSIsampleClockPeriod(), READ_SIGNATUREBYTE, SIG_FOSC_SEGMENT, SIG_FOSCCAL_DEFAULT, SLOW_RC, and SUCCESS.

Referenced by main().

00144 {
00145     uint16_t target_period;
00146     int16_t  error;
00147     int16_t  last_error;
00148     uint8_t  fosccal_saved;
00149     
00150     /* Read necessary data from the signature row. The delay cycles are to avoid
00151      * accessing the SPMCSR register within 6 cycles of previous write, since it 
00152      * is locked for further writing during these cycles.
00153      */
00154     uint8_t fosccal_default = READ_SIGNATUREBYTE(SIG_FOSCCAL_DEFAULT);
00155     
00156     // Avoid writing to SPMCSR register within 6 cycles of previous write.
00157     __delay_cycles(2);
00158     
00159     uint8_t fosccal_segment = READ_SIGNATUREBYTE(SIG_FOSC_SEGMENT);
00160 
00161     uint8_t bottom_limit = fosccal_segment & 0xE0;
00162     uint8_t top_limit =  (fosccal_default & 0xE0) + 0x1F;
00163 
00164     // Only whole MHz accounted for.
00165     target_period = cal_RC_period * FAST_RC_TARGET_MHZ;
00166     
00167     // Initial measurement to determine search direction.
00168     uint8_t  check_value;
00169     error = OSIsampleClockPeriod(SLOW_RC) - target_period;
00170     
00171     if(error > 0){
00172         // Search downwards.
00173         check_value = bottom_limit + 0x1F;
00174         do {
00175             last_error = error;
00176             fosccal_saved = FOSCCAL;
00177             if ( FOSCCAL-- == check_value ){
00178                 // Use fosccal segment value to avoid a step in frequency when going to lower segment. 
00179                 FOSCCAL = fosccal_segment;
00180             } else if (FOSCCAL < bottom_limit){ 
00181                 // The range have been searched without success, so we select default fosccal value.
00182                 FOSCCAL = fosccal_default;
00183                 return FAILED;
00184             }
00185             error = OSIsampleClockPeriod(SLOW_RC) - target_period;
00186         } while (error > 0);
00187     }else{
00188         // Search upwards.
00189         check_value = fosccal_segment + 0x01;
00190         do {
00191             last_error = error;
00192             fosccal_saved = FOSCCAL;
00193             if ( FOSCCAL++ == check_value ){    
00194                 // Use fosccal segment value to avoid a step in frequency when going to upper segment. 
00195                 FOSCCAL = fosccal_default & 0xE0;
00196             } else if ( FOSCCAL > top_limit ){ 
00197                 // The range have been searched without success, so we select default fosccal value.
00198                 FOSCCAL = fosccal_default;
00199                 return FAILED;
00200             }
00201             error = OSIsampleClockPeriod(SLOW_RC) - target_period;
00202         }while ( error < 0 );
00203     }
00204 
00205     /* Neighbor check. Since we're just searching until frequency is too low or 
00206      * too high a neighbor check is needed to get the best value. Not needed if 
00207      * ~2% accuracy is sufficient. Saves ~60 bytes code in release version if omitted.
00208      */
00209     if(error < 0){
00210         // Oscillator frequency to low? If so check if last error was smaller (in absolute value).
00211         if (last_error < -error){
00212             FOSCCAL = fosccal_saved;
00213         }
00214     }else{
00215         // Oscillator frequency is to high, so test next lower FOSCCAL setting.
00216         if (-last_error < error){
00217             FOSCCAL = fosccal_saved;
00218         }
00219     }
00220 
00221     return SUCCESS;
00222 }

Here is the call graph for this function:

uint16_t MeasureULPRCperiod ( uint16_t  cal_RC_period  ) 

Measure the ULP RC period time against the Slow RC.

The period of the ULP RC is measured with the Slow RC as reference using the Oscillator Sampling interface. Result is in ms * 1024. It can thus be seen as 16 bit fixed point format, with 10 fractional bits, i.e. 0x XXXX XX.xx xxxx xxxx

Parameters:
cal_RC_period (uint16_t)
Returns:
ULP RC period (uint16_t)

Definition at line 236 of file RC_calib_oscsampleif.c.

References OSIsampleClockPeriod(), SLOW_RC, and ULP_RC.

Referenced by main().

00237 {
00238     uint16_t slow_RC_measurement, ULP_RC_measurement;
00239     uint32_t result;
00240 
00241     slow_RC_measurement = OSIsampleClockPeriod(SLOW_RC);
00242     ULP_RC_measurement = OSIsampleClockPeriod(ULP_RC);
00243 
00244     result = (uint32_t)cal_RC_period * ULP_RC_measurement / slow_RC_measurement;
00245     return (uint16_t)result;
00246 }

Here is the call graph for this function:

uint16_t OSIsampleClockPeriod ( uint8_t  clock_source  ) 

Measure OSI prescaled clock periods.

Measure number of Fast RC clock cycles in RC_CALIB_CYCLES number of Oscillator Sampling Interface prescaled Clock periods. The prescaler is 128 for ATmega16HVA. osi_cycles is typically 8, giving a total of 1024 cycles for the selected input clock. Available inputs are Slow RC and ULP RC.

Warning: The routine only takes into account one overflow of OCR0, so make sure the number of Fast RC cycles used for calibration are less than 2^16.

Parameters:
clock_source (uint8_t)
Returns:
Fast RC cycles in 1024 clock periods from selected clock (uint16_t)

Definition at line 262 of file RC_calib_oscsampleif.c.

References RC_CALIB_CYCLES, and T0_PRESCALER.

Referenced by CalibrateFastRCruntime(), and MeasureULPRCperiod().

00263 {
00264     uint16_t initial_capture, final_capture, result;
00265     
00266     // OSI enable and select
00267     OSICSR = clock_source | (1 << OSIEN);
00268     
00269     // 16-bit mode, falling edge trigger
00270     TCCR0A = (1 << TCW0) | (1 << ICEN0) | (0 << ICS0);
00271     
00272     // Timer0 running with 1x prescaling.
00273     TCCR0B = T0_PRESCALER;
00274     
00275     // Clear interrupt flag.
00276     TIFR0 |= (1 << ICF0);
00277 
00278     // Wait for negative edge.
00279     do {} while(!(TIFR0 & (1 << ICF0)));
00280     initial_capture = OCR0A;
00281     initial_capture |= OCR0B << 8;
00282     
00283     // Clear interrupt flag.
00284     TIFR0 |= (1 << ICF0);
00285     
00286     for(uint8_t i = 0 ; i < RC_CALIB_CYCLES ; i++) {
00287         // Wait for negative edge.
00288         do {} while(!(TIFR0 & (1 << ICF0)));
00289         TIFR0 |= (1 << ICF0);
00290     }
00291     final_capture = OCR0A;
00292     final_capture |= OCR0B << 8;
00293 
00294     // This line doesn't take sign into account, but gives correct results. 
00295     result = final_capture - initial_capture;
00296     
00297     return result;
00298 }


Generated on Tue Nov 4 14:58:59 2008 for AVR351 Runtime calibration and compensation of oscillators by  doxygen 1.5.5