/* 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, 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; }
/* 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! * 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 calibrateOscillator(void) { uchar step = 128; uchar trialValue = 0; uchar optimumValue; int x; int 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, now do a neighbourhood * search for the 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; }
// Called by V-USB after device reset void hadUsbReset() { int frameLength, targetLength = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5); int bestDeviation = 9999; uchar bestCal = 0; uchar trialCal; uchar step; uchar region; // do a binary search in regions 0-127 and 128-255 to get optimum OSCCAL for(region = 0; region <= 1; region++) { frameLength = 0; trialCal = (region == 0) ? 0 : 128; for(step = 64; step > 0; step >>= 1) { if(frameLength < targetLength) // true for initial iteration trialCal += step; // frequency too low else trialCal -= step; // frequency too high OSCCAL = trialCal; frameLength = usbMeasureFrameLength(); if(abs(frameLength-targetLength) < bestDeviation) { bestCal = trialCal; // new optimum found bestDeviation = abs(frameLength -targetLength); } } } OSCCAL = bestCal; }
/* 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. */ static void calibrateOscillator(void) { int frameLength, targetLength = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5); int bestDeviation = 9999; uchar trialCal, bestCal, step, region; /* do a binary search in regions 0-127 and 128-255 to get optimum OSCCAL */ for (region = 0; region <= 1; region++) { frameLength = 0; trialCal = (region == 0) ? 0 : 128; for (step = 64; step > 0; step >>= 1) { if (frameLength < targetLength) /* true for initial iteration */ { trialCal += step; /* frequency too low */ } else { trialCal -= step; /* frequency too high */ } OSCCAL = trialCal; frameLength = usbMeasureFrameLength(); if (abs(frameLength-targetLength) < bestDeviation) { bestCal = trialCal; /* new optimum found */ bestDeviation = abs(frameLength -targetLength); } } } OSCCAL = bestCal; }