summaryrefslogtreecommitdiffstats
path: root/firmware/libs-device/osccal.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/libs-device/osccal.c')
-rw-r--r--firmware/libs-device/osccal.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/firmware/libs-device/osccal.c b/firmware/libs-device/osccal.c
new file mode 100644
index 0000000..939d5c3
--- /dev/null
+++ b/firmware/libs-device/osccal.c
@@ -0,0 +1,63 @@
+/* Name: osccal.c
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-10
+ * Tabsize: 4
+ * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
+ * This Revision: $Id: osccal.c 762 2009-08-12 17:10:30Z cs $
+ */
+
+#include <avr/io.h>
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* ------------------------ Oscillator Calibration ------------------------- */
+/* ------------------------------------------------------------------------- */
+
+/* Calibrate the RC oscillator. Our timing reference is the Start Of Frame
+ * signal (a single SE0 bit) repeating every millisecond immediately after
+ * a USB RESET. We first do a binary search for the OSCCAL value and then
+ * optimize this value with a neighboorhod search.
+ */
+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;
+}
+/*
+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.
+*/