You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
63 lines
2.5 KiB
63 lines
2.5 KiB
#ifdef CALIB
|
|
|
|
/*
|
|
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();
|
|
/*first read the oscilator; if the value differs then we change it*/
|
|
if(eeprom_read_byte(0)!=OSCCAL){
|
|
/* store the calibrated value in EEPROM */
|
|
eeprom_write_byte(0, OSCCAL);
|
|
}
|
|
}
|
|
|
|
/* 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){
|
|
uint8_t step = 128;
|
|
uint8_t trialValue = 0, optimumValue;
|
|
int x, optimumDev, 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;
|
|
}
|
|
|
|
#else
|
|
void usbEventResetReady(void){}
|
|
#endif //CALIB
|
|
|