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.
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>

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 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.
| 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.
| temperature | in Kelvin (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.
| cal_RC_period | Slow RC period in ms * 1024 |
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 }

| 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
| cal_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 }

| 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.
| clock_source | (uint8_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 }
1.5.5