Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

86 lines (76 sloc) 3.09 kB
#ifndef __OSCAL_H__
#define __OSCAL_H__
#include <avr/eeprom.h>
#include <avr/interrupt.h>
const uint8_t EEPROM_ADDR_OSCCAL = 0;
/* ------------------------------------------------------------------------- */
/* ------------------------ Oscillator Calibration ------------------------- */
/* ------------------------------------------------------------------------- */
// put this in main() before usbInit
static void calibrationLoad(void)
{
uint8_t calibrationValue;
// calibration value from last time
calibrationValue = eeprom_read_byte(EEPROM_ADDR_OSCCAL);
if(calibrationValue != 0xff){
OSCCAL = calibrationValue;
}
}
/* Calibrate the RC oscillator to 8.25 MHz. The core clock of 16.5 MHz is
* derived from the 66 MHz peripheral clock by dividing. Our timing reference
* is the Start Of Frame signal (a single SE0 bit) available immediately after
* a USB RESET. We first do a binary search for the OSCCAL value and then
* optimize this value with a neighboorhod search.
* This algorithm may also be used to calibrate the RC oscillator directly to
* 12 MHz (no PLL involved, can therefore be used on almost ALL AVRs), but this
* is wide outside the spec for the OSCCAL value and the required precision for
* the 12 MHz clock! Use the RC oscillator calibrated to 12 MHz for
* experimental purposes only!
*/
static void calibrateOscillator(void)
{
uchar step = 128;
uchar trialValue = 0, optimumValue;
int x, optimumDev;
int targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
/* do a binary search: */
do{
OSCCAL = trialValue + step;
x = usbMeasureFrameLength(); // proportional to current real frequency
if(x < targetValue) // frequency still too low
trialValue += step;
step >>= 1;
}while(step > 0);
/* We have a precision of +/- 1 for optimum OSCCAL here */
/* now do a neighborhood search for optimum value */
optimumValue = trialValue;
optimumDev = x; /* this is certainly far away from optimum */
for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
x = usbMeasureFrameLength() - targetValue;
if(x < 0)
x = -x;
if(x < optimumDev){
optimumDev = x;
optimumValue = OSCCAL;
}
}
OSCCAL = optimumValue;
}
/*
Note: This calibration algorithm may try OSCCAL values of up to 192 even if
the optimum value is far below 192. It may therefore exceed the allowed clock
frequency of the CPU in low voltage designs!
You may replace this search algorithm with any other algorithm you like if
you have additional constraints such as a maximum CPU clock.
For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g.
ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in
both regions.
*/
void usbEventResetReady(void)
{
calibrateOscillator();
// store the calibrated value in EEPROM
eeprom_write_byte(EEPROM_ADDR_OSCCAL, OSCCAL);
usbHasBeenSetup++;
}
#endif
Jump to Line
Something went wrong with that request. Please try again.