From c6b12b287746ac950f4efcd1e5e872f5fe5acfe2 Mon Sep 17 00:00:00 2001
From: cpldcpu <cpldcpu@gmail.com>
Date: Sun, 15 Dec 2013 21:16:32 +0100
Subject: clean up osccal

---
 firmware/Makefile                |   4 +-
 firmware/libs-device/Readme.txt  |  22 ----
 firmware/libs-device/osccal.c    | 183 -------------------------------
 firmware/libs-device/osccal.h    |  57 ----------
 firmware/libs-device/osccalASM.S | 228 ---------------------------------------
 firmware/libs-device/osctune.h   |  88 ---------------
 firmware/osccal.h                |  57 ++++++++++
 firmware/osccalASM.S             | 228 +++++++++++++++++++++++++++++++++++++++
 firmware/osccalASM.o             | Bin 0 -> 1684 bytes
 9 files changed, 287 insertions(+), 580 deletions(-)
 delete mode 100644 firmware/libs-device/Readme.txt
 delete mode 100644 firmware/libs-device/osccal.c
 delete mode 100644 firmware/libs-device/osccal.h
 delete mode 100644 firmware/libs-device/osccalASM.S
 delete mode 100644 firmware/libs-device/osctune.h
 create mode 100644 firmware/osccal.h
 create mode 100644 firmware/osccalASM.S
 create mode 100644 firmware/osccalASM.o

(limited to 'firmware')

diff --git a/firmware/Makefile b/firmware/Makefile
index 0905d0a..9da5be6 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -149,12 +149,12 @@ CC = avr-gcc
 DEFINES = -DBOOTLOADER_ADDRESS=0x$(BOOTLOADER_ADDRESS) #-DDEBUG_LEVEL=2
 # Remove the -fno-* options when you use gcc 3, it does not understand them
 # 
-CFLAGS = -g2 -nostartfiles -ffunction-sections -fdata-sections -fpack-struct -Wall -Os  -fno-inline-small-functions -fno-move-loop-invariants -fno-tree-scev-cprop  -I. -Ilibs-device -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) $(DEFINES)
+CFLAGS = -g2 -nostartfiles -ffunction-sections -fdata-sections -fpack-struct -Wall -Os  -fno-inline-small-functions -fno-move-loop-invariants -fno-tree-scev-cprop  -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) $(DEFINES)
 LDFLAGS = -Wl,--relax,--section-start=.text=$(BOOTLOADER_ADDRESS),-Map=main.map,--section-start=.zerotable=0
 
 
 OBJECTS =  crt1.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o 
-OBJECTS += libs-device/osccalASM.o
+OBJECTS += osccalASM.o
 # symbolic targets:
 all: main.hex
 
diff --git a/firmware/libs-device/Readme.txt b/firmware/libs-device/Readme.txt
deleted file mode 100644
index 76518dc..0000000
--- a/firmware/libs-device/Readme.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-This is the Readme file for the libs-device directory. This directory contains
-code snippets which may be useful for USB device firmware.
-
-
-WHAT IS INCLUDED IN THIS DIRECTORY?
-===================================
-
-osccal.c and osccal.h
-  This module contains a function which calibrates the AVR's built-in RC
-  oscillator based on the USB frame clock. See osccal.h for a documentation
-  of the API.
-
-osctune.h
-  This header file contains a code snippet for usbconfig.h. With this code,
-  you can keep the AVR's internal RC oscillator in sync with the USB frame
-  clock. This is a continuous synchronization, not a single calibration at
-  USB reset as with osccal.c above. Please note that this code works only
-  if D- is wired to the interrupt, not D+.
-
-----------------------------------------------------------------------------
-(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH.
-http://www.obdev.at/
diff --git a/firmware/libs-device/osccal.c b/firmware/libs-device/osccal.c
deleted file mode 100644
index 8debe49..0000000
--- a/firmware/libs-device/osccal.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/* 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>
-#include <avr/interrupt.h>
-#ifndef uchar
-#define uchar   unsigned char
-#endif
-
-int usbMeasureFrameLengthDecreasing(int);
-
-/* ------------------------------------------------------------------------- */
-/* ------------------------ 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. 
- *
- * 
- * Optimized version by cpldcpu@gmail.com, Nov 3rd 2013.
- *
- * Benefits:
- *	  - Codesize reduced by 54 bytes.
- *    - Improved robustness due to removing timeout from frame length measurement and 
- *	    inserted NOP after OSCCAL writes.
- *
- * Changes:
- *    - The new routine performs a combined binary and neighborhood search
- *      in a single loop.
- *      Note that the neighborhood search is necessary due to the quasi-monotonic 
- *      nature of OSCCAL. (See Atmel application note AVR054).
- *	  - Inserted NOP after writes to OSCCAL to avoid CPU errors during oscillator
- *      stabilization. 
- *    - Implemented new routine to measure frame time "usbMeasureFrameLengthDecreasing".
- *		This routine takes the target time as a parameter and returns the deviation.
- *	  - usbMeasureFrameLengthDecreasing measures in multiples of 5 cycles and is thus
- *	    slighly more accurate.
- *	  - usbMeasureFrameLengthDecreasing does not support time out anymore. The original
- *	    implementation returned zero in case of time out, which would have caused the old
- *      calibrateOscillator() implementation to increase OSSCAL to 255, effictively
- *      overclocking and most likely crashing the CPU. The new implementation will enter
- *		an infinite loop when no USB activity is encountered. The user program should
- *      use the watchdog to escape from situations like this.
-  * 
- * This routine will work both on controllers with and without split OSCCAL range.
- * The first trial value is 128 which is the lowest value of the upper OSCCAL range
- * on Attiny85 and will effectively limit the search to the upper range, unless the
- * RC oscillator frequency is unusually high. Under normal operation, the highest 
- * tested frequency setting is 192. This corresponds to ~20 Mhz core frequency and 
- * is still within spec for a 5V device.
- */
-
-void    calibrateOscillator(void)
-{
-	uchar       step, trialValue, optimumValue;
-	int         x, targetValue;
-	uchar		optimumDev;
-	uchar		i,xl;
-	
-	targetValue = (unsigned)((double)F_CPU * 999e-6 / 5.0 + 0.5);  /* Time is measured in multiples of 5 cycles. Target is 0.999�s */
-    optimumDev = 0xff;   
-  //  optimumValue = OSCCAL; 
-	step=64;
-	trialValue = 128;
-	
-	cli(); // disable interrupts
-	
-	/*
-		Performs seven iterations of a binary search (stepwidth decreasing9
-		with three additional steps of a neighborhood search (step=1, trialvalue will oscillate around target value to find optimum)
-	*/
-
-	for(i=0; i<10; i++){
-		OSCCAL = trialValue;
-		asm volatile(" NOP");
-	
-		x = usbMeasureFrameLengthDecreasing(targetValue);
-
-		if(x < 0)             /* frequency too high */
-		{
-			trialValue -= step;
-			xl=(uchar)-x;
-		}
-		else                  /* frequency too low */
-		{
-			trialValue += step;			
-			xl=(uchar)x;
-		}
-		
-		/*
-			Halve stepwidth to perform binary search. Logical oring with 1 to ensure step is never equal to zero. 
-			This results in a neighborhood search with stepwidth 1 after binary search is finished.			
-			Once the neighbourhood search stage is reached, x will be smaller than +-255, hence more code can be
-			saved by only working with the lower 8 bits.
-		*/
-		
-		step >>= 1;
-		
-		if (step==0)
-		{
-			step=1;			
-			if(xl <= optimumDev){
-				optimumDev = xl;
-				optimumValue = OSCCAL;
-			}
-		}
-
-	}
-
-	OSCCAL = optimumValue;
-	asm volatile(" NOP");
-	
-	sei(); // enable interrupts
-}
-
-void    calibrateOscillator_old(void)
-{
-	uchar       step, trialValue, optimumValue;
-	int         x, optimumDev, targetValue;
-	uchar		i;
-	
-	targetValue = (unsigned)((double)F_CPU * 999e-6 / 5.0 + 0.5);  /* Time is measured in multiples of 5 cycles. Target is 0.999�s */
-    optimumDev = 0x7f00;   // set to high positive value
-    optimumValue = OSCCAL; 
-	step=64;
-	trialValue = 128;
-	
-	/*
-		Performs seven iterations of a binary search (stepwidth decreasing9
-		with three additional steps of a neighborhood search (step=1, trialvalue will oscillate around target value to find optimum)
-	*/
-
-	for(i=0; i<10; i++){
-		OSCCAL = trialValue;
-		asm volatile(" NOP");
-	
-		x = usbMeasureFrameLengthDecreasing(targetValue);
-
-		if(x < 0)             /* frequency too high */
-		{
-			trialValue -= step;
-			x = -x;
-		}
-		else                  /* frequency too low */
-		{
-			trialValue += step;			
-		}
-		
-		/*
-			Halve stepwidth to perform binary search. Logical oring with 1 to ensure step is never equal to zero. 
-			This results in a neighborhood search with stepwidth 1 after binary search is finished.			
-		*/
-		
-		step >>= 1;
-		step |=1;	
-
-		if(x < optimumDev){
-			optimumDev = x;
-			optimumValue = OSCCAL;
-		}
-	}
-
-	OSCCAL = optimumValue;
-	asm volatile(" NOP");
-}
-
-/*
-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.
-*/
diff --git a/firmware/libs-device/osccal.h b/firmware/libs-device/osccal.h
deleted file mode 100644
index af37a43..0000000
--- a/firmware/libs-device/osccal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Name: osccal.h
- * Author: Christian Starkjohann
- * Creation Date: 2008-04-10
- * Changes 2013-11-04 cpldcpu@gmail.com
- * Tabsize: 4
- * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
- * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
- */
-
-/*
-General Description:
-This module contains a function which calibrates the AVR's internal RC
-oscillator so that the CPU runs at F_CPU (F_CPU is a macro which must be
-defined when the module is compiled, best passed in the compiler command
-line). The time reference is the USB frame clock of 1 kHz available
-immediately after a USB RESET condition. Timing is done by counting CPU
-cycles, so all interrupts must be disabled while the calibration runs. 
-The size optimized assembler implementation includes its own implementation
-of usbMeasureFrameLength. Therefore USB_CFG_HAVE_MEASURE_FRAME_LENGTH should 
-be set to 0 to avoid including unused code sections. It is recommended to call
-calibrateOscillatorASM() from the reset hook in usbconfig.h by including osccal.h:
-
-#include "osccal.h"
-
-This routine is an alternative to the continuous synchronization described
-in osctune.h.
-
-Algorithm used:  See osccalASM.x
-
-Limitations:
-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!
-Precision depends on the OSCCAL vs. frequency dependency of the oscillator.
-Typical precision for an ATMega168 (derived from the OSCCAL vs. F_RC diagram
-in the data sheet) should be in the range of 0.4%. Only the 12.8 MHz and
-16.5 MHz versions of V-USB (with built-in receiver PLL) can tolerate this
-deviation! All other frequency modules require at least 0.2% precision.
-*/
-
-#ifndef __OSCCAL_H_INCLUDED__
-#define __OSCCAL_H_INCLUDED__
-
-#ifndef __ASSEMBLER__
-	void calibrateOscillatorASM(void);
-#	define USB_RESET_HOOK(resetStarts)  if(!resetStarts){ calibrateOscillatorASM();}
-#	define USB_CFG_HAVE_MEASURE_FRAME_LENGTH   0
-#endif	
-/* This function calibrates the RC oscillator so that the CPU runs at F_CPU.
- * It MUST be called immediately after the end of a USB RESET condition!
- * Disable all interrupts during the call!
- * It is recommended that you store the resulting value in EEPROM so that a
- * good guess value is available after the next reset.
- */
-
-
-#endif /* __OSCCAL_H_INCLUDED__ */
diff --git a/firmware/libs-device/osccalASM.S b/firmware/libs-device/osccalASM.S
deleted file mode 100644
index 9a317f1..0000000
--- a/firmware/libs-device/osccalASM.S
+++ /dev/null
@@ -1,228 +0,0 @@
-/* Name: osccalASM.S
- * Author: cpldcpu@gmail.com
- * Creation Date: 2013-11-3
- * Tabsize: 4
- * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
- */
-
-/* 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. 
- *
- *
- * Benefits:
- *	  - Codesize reduced by 90 bytes.
- *    - Improved robustness due to removing timeout from frame length measurement and 
- *	    inserted NOP after OSCCAL writes.
- *
- * Changes:
- *    - The new routine performs a combined binary and neighborhood search
- *      in a single loop.
- *      Note that the neighborhood search is necessary due to the quasi-monotonic 
- *      nature of OSCCAL. (See Atmel application note AVR054).
- *	  - Inserted NOP after writes to OSCCAL to avoid CPU errors during oscillator
- *      stabilization. 
- *    - Implemented new routine to measure frame time "usbMeasureFrameLengthDecreasing".
- *		This routine takes the target time as a parameter and returns the deviation.
- *	  - usbMeasureFrameLengthDecreasing measures in multiples of 5 cycles and is thus
- *	    slighly more accurate.
- *	  - usbMeasureFrameLengthDecreasing does not support time out anymore. The original
- *	    implementation returned zero in case of time out, which would have caused the old
- *      calibrateOscillator() implementation to increase OSSCAL to 255, effictively
- *      overclocking and most likely crashing the CPU. The new implementation will enter
- *		an infinite loop when no USB activity is encountered. The user program should
- *      use the watchdog to escape from situations like this.
-  * 
- * This routine will work both on controllers with and without split OSCCAL range.
- * The first trial value is 128 which is the lowest value of the upper OSCCAL range
- * on Attiny85 and will effectively limit the search to the upper range, unless the
- * RC oscillator frequency is unusually high. Under normal operation, the highest 
- * tested frequency setting is 192. This corresponds to ~20 Mhz core frequency and 
- * is still within spec for a 5V device.
- */
- 
-
-#define __SFR_OFFSET 0      /* used by avr-libc's register definitions */
-#include "./usbdrv/usbdrv.h"         /* for common defs */
-
-#ifdef __IAR_SYSTEMS_ASM__
-/* Register assignments for usbMeasureFrameLengthDecreasing on IAR cc */
-/* Calling conventions on IAR:
- * First parameter passed in r16/r17, second in r18/r19 and so on.
- * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
- * Result is passed in r16/r17
- * In case of the "tiny" memory model, pointers are only 8 bit with no
- * padding. We therefore pass argument 1 as "16 bit unsigned".
- */
-
-//Untested
-
-#   define i		r20	
-#   define opV		r19
-#   define opD		r18
-#   define try		r21
-#   define stp		r22
-
-#   define cnt16L   r30
-#   define cnt16H   r31
-
-
-#else  /* __IAR_SYSTEMS_ASM__ */ 
-/* Register assignments for usbMeasureFrameLength on gcc */
-/* Calling conventions on gcc:
- * First parameter passed in r24/r25, second in r22/23 and so on.
- * Callee must preserve r1-r17, r28/r29
- * Result is passed in r24/r25
- */
-
-#   define i		r20	
-#   define opV		r19
-#   define opD		r18
-#   define try		r27
-#   define stp		r26
-#   define cnt16L   r24
-#   define cnt16H   r25
-#endif
-#   define cnt16    cnt16L
-
-; extern void calibrateOscillatorASM(void);
-
-.global calibrateOscillatorASM
-calibrateOscillatorASM:
-
-	cli
-	ldi		opD, 255	
-
-	ldi		try, 128	; calibration start value
-	ldi		stp, 64		; initial step width
-	ldi		i, 10		; 10 iterations
-
-usbCOloop:
-
-	out		OSCCAL, try
-	nop
-
-	; Delay values = F_CPU * 999e-6 / 5 + 0.5
-	
-#if (F_CPU == 16500000)
-	ldi		cnt16L, lo8(3297)
-	ldi		cnt16H, hi8(3297)
-#elif (F_CPU == 12800000)
-	ldi		cnt16L, lo8(2557)
-	ldi		cnt16H, hi8(2557)
-#else
-	#error "calibrateOscillatorASM: no delayvalues defined for this F_CPU setting"
-#endif
-
-usbCOWaitStrobe:            ; first wait for D- == 0 (idle strobe)
-    sbic    USBIN, USBMINUS ;
-    rjmp    usbCOWaitStrobe ;
-usbCOWaitIdle:              ; then wait until idle again
-    sbis    USBIN, USBMINUS ;1 wait for D- == 1
-    rjmp    usbCOWaitIdle   ;2
-usbCOWaitLoop:
-	sbiw	cnt16,1			;[0] [5]
-    sbic    USBIN, USBMINUS ;[2] 
-    rjmp    usbCOWaitLoop   ;[3]
-
-	sbrs	cnt16H, 7		;delay overflow?
-	rjmp	usbCOclocktoolow
-	sub		try, stp
-	neg		cnt16L
-	rjmp	usbCOclocktoohigh
-usbCOclocktoolow:
-	add		try, stp
-usbCOclocktoohigh:
-	lsr		stp
-	brne	usbCOnoneighborhoodsearch
-	cp		opD, cnt16L
-	brcs	usbCOnoimprovement
-	in		opV, OSCCAL
-	mov		opD, cnt16L
-usbCOnoimprovement:
-	ldi		stp, 1
-usbCOnoneighborhoodsearch:
-	subi	i, 1
-	brne	usbCOloop
-
-	out		OSCCAL, opV
-	nop
-	sei
-    ret
-
-#undef i
-#undef opV
-#undef opD
-#undef try
-#undef stp
-#undef cnt16
-#undef cnt16L
-#undef cnt16H
-
-/* ------------------------------------------------------------------------- */
-/* ------ Original C Implementation of improved calibrateOscillator -------- */
-/* ----------------------   for Reference only ----------------------------- */
-/* ------------------------------------------------------------------------- */
-
-#if 0
-void    calibrateOscillator(void)
-{
-	uchar       step, trialValue, optimumValue;
-	int         x, targetValue;
-	uchar		optimumDev;
-	uchar		i,xl;
-	
-	targetValue = (unsigned)((double)F_CPU * 999e-6 / 5.0 + 0.5);  /* Time is measured in multiples of 5 cycles. Target is 0.999�s */
-    optimumDev = 0xff;   
-  //  optimumValue = OSCCAL; 
-	step=64;
-	trialValue = 128;
-	
-	cli(); // disable interrupts
-	
-	/*
-		Performs seven iterations of a binary search (stepwidth decreasing9
-		with three additional steps of a neighborhood search (step=1, trialvalue will oscillate around target value to find optimum)
-	*/
-
-	for(i=0; i<10; i++){
-		OSCCAL = trialValue;
-		asm volatile(" NOP");
-	
-		x = usbMeasureFrameLengthDecreasing(targetValue);
-
-		if(x < 0)             /* frequency too high */
-		{
-			trialValue -= step;
-			xl=(uchar)-x;
-		}
-		else                  /* frequency too low */
-		{
-			trialValue += step;			
-			xl=(uchar)x;
-		}
-		
-		/*
-			Halve stepwidth to perform binary search. At step=1 the mode changes to neighbourhood search.
-			Once the neighbourhood search stage is reached, x will be smaller than +-255, hence more code can be
-			saved by only working with the lower 8 bits.
-		*/
-		
-		step >>= 1;
-		
-		if (step==0)   // Enter neighborhood search mode
-		{
-			step=1;			
-			if(xl <= optimumDev){
-				optimumDev = xl;
-				optimumValue = OSCCAL;
-			}
-		}
-	}
-
-	OSCCAL = optimumValue;
-	asm volatile(" NOP");
-	
-	sei(); // enable interrupts
-}
-#endif
\ No newline at end of file
diff --git a/firmware/libs-device/osctune.h b/firmware/libs-device/osctune.h
deleted file mode 100644
index c751648..0000000
--- a/firmware/libs-device/osctune.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* Name: osctune.h
- * Author: Christian Starkjohann
- * Creation Date: 2008-10-18
- * 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: osctune.h 692 2008-11-07 15:07:40Z cs $
- */
-
-/*
-General Description:
-This file is declared as C-header file although it is mostly documentation
-how the RC oscillator can be kept in sync to the USB frame rate. The code
-shown here must be added to usbconfig.h or this header file is included from
-there. This code works only if D- is wired to the interrupt, not D+!!!
-
-This is an alternative to the osccal routine in osccal.c. It has the advantage
-that the synchronization is done continuously and that it has more compact
-code size. The disadvantages are slow synchronization (it may take a while
-until the driver works), that messages immediately after the SOF pulse may be
-lost (and need to be retried by the host) and that the interrupt is on D-
-contrary to most examples.
-
-You may want to store a good calibration value in EEPROM for the next startup.
-You know that the calibration value is good when the first USB message is
-received. Do not store the value on every received message because the EEPROM
-has a limited endurance.
-
-Notes:
-(*) You must declare the global character variable "lastTimer0Value" in your
-main code.
-
-(*) Timer 0 must be free running (not written by your code) and the prescaling
-must be consistent with the TIMER0_PRESCALING define.
-
-(*) Good values for Timer 0 prescaling depend on how precise the clock must
-be tuned and how far away from the default clock rate the target clock is.
-For precise tuning, choose a low prescaler factor, for a broad range of tuning
-choose a high one. A prescaler factor of 64 is good for the entire OSCCAL
-range and allows a precision of better than +/-1%. A prescaler factor of 8
-allows tuning to slightly more than +/-6% of the default frequency and is
-more precise than one step of OSCCAL. It is therefore not suitable to tune an
-8 MHz oscillator to 12.5 MHz.
-
-Thanks to Henrik Haftmann for the idea to this routine!
-*/
-
-#define TIMER0_PRESCALING           64 /* must match the configuration for TIMER0 in main */
-#define TOLERATED_DEVIATION_PPT     5  /* max clock deviation before we tune in 1/10 % */
-/* derived constants: */
-#define EXPECTED_TIMER0_INCREMENT   ((F_CPU / (1000 * TIMER0_PRESCALING)) & 0xff)
-#define TOLERATED_DEVIATION         (TOLERATED_DEVIATION_PPT * F_CPU / (1000000 * TIMER0_PRESCALING))
-
-#ifdef __ASSEMBLER__
-macro tuneOsccal
-    push    YH                              ;[0]
-    in      YL, TCNT0                       ;[2]
-    lds     YH, lastTimer0Value             ;[3]
-    sts     lastTimer0Value, YL             ;[5]
-    sub     YL, YH                          ;[7] time passed since last frame
-    subi    YL, EXPECTED_TIMER0_INCREMENT   ;[8]
-#if OSCCAL > 0x3f   /* outside I/O addressable range */
-    lds     YH, OSCCAL                      ;[6]
-#else
-    in      YH, OSCCAL                      ;[6] assembler modle uses __SFR_OFFSET == 0
-#endif
-    cpi     YL, TOLERATED_DEVIATION + 1     ;[10]
-    brmi    notTooHigh                      ;[11]
-    subi    YH, 1                           ;[12] clock rate was too high
-;   brcs    tuningOverflow                  ; optionally check for overflow
-    rjmp    osctuneDone                     ;[13]
-notTooHigh:
-    cpi     YL, -TOLERATED_DEVIATION        ;[13]
-    brpl    osctuneDone                     ;[14] not too low
-    inc     YH                              ;[15] clock rate was too low
-;   breq    tuningOverflow                  ; optionally check for overflow
-osctuneDone:
-#if OSCCAL > 0x3f   /* outside I/O addressable range */
-    sts     OSCCAL, YH                      ;[12-13] store tuned value
-#else
-    out     OSCCAL, YH                      ;[12-13] store tuned value
-#endif
-tuningOverflow:
-    pop     YH                              ;[17]
-    endm                                    ;[19] max number of cycles
-#endif
-
-#define USB_SOF_HOOK        tuneOsccal
diff --git a/firmware/osccal.h b/firmware/osccal.h
new file mode 100644
index 0000000..af37a43
--- /dev/null
+++ b/firmware/osccal.h
@@ -0,0 +1,57 @@
+/* Name: osccal.h
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-10
+ * Changes 2013-11-04 cpldcpu@gmail.com
+ * Tabsize: 4
+ * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
+ */
+
+/*
+General Description:
+This module contains a function which calibrates the AVR's internal RC
+oscillator so that the CPU runs at F_CPU (F_CPU is a macro which must be
+defined when the module is compiled, best passed in the compiler command
+line). The time reference is the USB frame clock of 1 kHz available
+immediately after a USB RESET condition. Timing is done by counting CPU
+cycles, so all interrupts must be disabled while the calibration runs. 
+The size optimized assembler implementation includes its own implementation
+of usbMeasureFrameLength. Therefore USB_CFG_HAVE_MEASURE_FRAME_LENGTH should 
+be set to 0 to avoid including unused code sections. It is recommended to call
+calibrateOscillatorASM() from the reset hook in usbconfig.h by including osccal.h:
+
+#include "osccal.h"
+
+This routine is an alternative to the continuous synchronization described
+in osctune.h.
+
+Algorithm used:  See osccalASM.x
+
+Limitations:
+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!
+Precision depends on the OSCCAL vs. frequency dependency of the oscillator.
+Typical precision for an ATMega168 (derived from the OSCCAL vs. F_RC diagram
+in the data sheet) should be in the range of 0.4%. Only the 12.8 MHz and
+16.5 MHz versions of V-USB (with built-in receiver PLL) can tolerate this
+deviation! All other frequency modules require at least 0.2% precision.
+*/
+
+#ifndef __OSCCAL_H_INCLUDED__
+#define __OSCCAL_H_INCLUDED__
+
+#ifndef __ASSEMBLER__
+	void calibrateOscillatorASM(void);
+#	define USB_RESET_HOOK(resetStarts)  if(!resetStarts){ calibrateOscillatorASM();}
+#	define USB_CFG_HAVE_MEASURE_FRAME_LENGTH   0
+#endif	
+/* This function calibrates the RC oscillator so that the CPU runs at F_CPU.
+ * It MUST be called immediately after the end of a USB RESET condition!
+ * Disable all interrupts during the call!
+ * It is recommended that you store the resulting value in EEPROM so that a
+ * good guess value is available after the next reset.
+ */
+
+
+#endif /* __OSCCAL_H_INCLUDED__ */
diff --git a/firmware/osccalASM.S b/firmware/osccalASM.S
new file mode 100644
index 0000000..9a317f1
--- /dev/null
+++ b/firmware/osccalASM.S
@@ -0,0 +1,228 @@
+/* Name: osccalASM.S
+ * Author: cpldcpu@gmail.com
+ * Creation Date: 2013-11-3
+ * Tabsize: 4
+ * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
+ */
+
+/* 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. 
+ *
+ *
+ * Benefits:
+ *	  - Codesize reduced by 90 bytes.
+ *    - Improved robustness due to removing timeout from frame length measurement and 
+ *	    inserted NOP after OSCCAL writes.
+ *
+ * Changes:
+ *    - The new routine performs a combined binary and neighborhood search
+ *      in a single loop.
+ *      Note that the neighborhood search is necessary due to the quasi-monotonic 
+ *      nature of OSCCAL. (See Atmel application note AVR054).
+ *	  - Inserted NOP after writes to OSCCAL to avoid CPU errors during oscillator
+ *      stabilization. 
+ *    - Implemented new routine to measure frame time "usbMeasureFrameLengthDecreasing".
+ *		This routine takes the target time as a parameter and returns the deviation.
+ *	  - usbMeasureFrameLengthDecreasing measures in multiples of 5 cycles and is thus
+ *	    slighly more accurate.
+ *	  - usbMeasureFrameLengthDecreasing does not support time out anymore. The original
+ *	    implementation returned zero in case of time out, which would have caused the old
+ *      calibrateOscillator() implementation to increase OSSCAL to 255, effictively
+ *      overclocking and most likely crashing the CPU. The new implementation will enter
+ *		an infinite loop when no USB activity is encountered. The user program should
+ *      use the watchdog to escape from situations like this.
+  * 
+ * This routine will work both on controllers with and without split OSCCAL range.
+ * The first trial value is 128 which is the lowest value of the upper OSCCAL range
+ * on Attiny85 and will effectively limit the search to the upper range, unless the
+ * RC oscillator frequency is unusually high. Under normal operation, the highest 
+ * tested frequency setting is 192. This corresponds to ~20 Mhz core frequency and 
+ * is still within spec for a 5V device.
+ */
+ 
+
+#define __SFR_OFFSET 0      /* used by avr-libc's register definitions */
+#include "./usbdrv/usbdrv.h"         /* for common defs */
+
+#ifdef __IAR_SYSTEMS_ASM__
+/* Register assignments for usbMeasureFrameLengthDecreasing on IAR cc */
+/* Calling conventions on IAR:
+ * First parameter passed in r16/r17, second in r18/r19 and so on.
+ * Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
+ * Result is passed in r16/r17
+ * In case of the "tiny" memory model, pointers are only 8 bit with no
+ * padding. We therefore pass argument 1 as "16 bit unsigned".
+ */
+
+//Untested
+
+#   define i		r20	
+#   define opV		r19
+#   define opD		r18
+#   define try		r21
+#   define stp		r22
+
+#   define cnt16L   r30
+#   define cnt16H   r31
+
+
+#else  /* __IAR_SYSTEMS_ASM__ */ 
+/* Register assignments for usbMeasureFrameLength on gcc */
+/* Calling conventions on gcc:
+ * First parameter passed in r24/r25, second in r22/23 and so on.
+ * Callee must preserve r1-r17, r28/r29
+ * Result is passed in r24/r25
+ */
+
+#   define i		r20	
+#   define opV		r19
+#   define opD		r18
+#   define try		r27
+#   define stp		r26
+#   define cnt16L   r24
+#   define cnt16H   r25
+#endif
+#   define cnt16    cnt16L
+
+; extern void calibrateOscillatorASM(void);
+
+.global calibrateOscillatorASM
+calibrateOscillatorASM:
+
+	cli
+	ldi		opD, 255	
+
+	ldi		try, 128	; calibration start value
+	ldi		stp, 64		; initial step width
+	ldi		i, 10		; 10 iterations
+
+usbCOloop:
+
+	out		OSCCAL, try
+	nop
+
+	; Delay values = F_CPU * 999e-6 / 5 + 0.5
+	
+#if (F_CPU == 16500000)
+	ldi		cnt16L, lo8(3297)
+	ldi		cnt16H, hi8(3297)
+#elif (F_CPU == 12800000)
+	ldi		cnt16L, lo8(2557)
+	ldi		cnt16H, hi8(2557)
+#else
+	#error "calibrateOscillatorASM: no delayvalues defined for this F_CPU setting"
+#endif
+
+usbCOWaitStrobe:            ; first wait for D- == 0 (idle strobe)
+    sbic    USBIN, USBMINUS ;
+    rjmp    usbCOWaitStrobe ;
+usbCOWaitIdle:              ; then wait until idle again
+    sbis    USBIN, USBMINUS ;1 wait for D- == 1
+    rjmp    usbCOWaitIdle   ;2
+usbCOWaitLoop:
+	sbiw	cnt16,1			;[0] [5]
+    sbic    USBIN, USBMINUS ;[2] 
+    rjmp    usbCOWaitLoop   ;[3]
+
+	sbrs	cnt16H, 7		;delay overflow?
+	rjmp	usbCOclocktoolow
+	sub		try, stp
+	neg		cnt16L
+	rjmp	usbCOclocktoohigh
+usbCOclocktoolow:
+	add		try, stp
+usbCOclocktoohigh:
+	lsr		stp
+	brne	usbCOnoneighborhoodsearch
+	cp		opD, cnt16L
+	brcs	usbCOnoimprovement
+	in		opV, OSCCAL
+	mov		opD, cnt16L
+usbCOnoimprovement:
+	ldi		stp, 1
+usbCOnoneighborhoodsearch:
+	subi	i, 1
+	brne	usbCOloop
+
+	out		OSCCAL, opV
+	nop
+	sei
+    ret
+
+#undef i
+#undef opV
+#undef opD
+#undef try
+#undef stp
+#undef cnt16
+#undef cnt16L
+#undef cnt16H
+
+/* ------------------------------------------------------------------------- */
+/* ------ Original C Implementation of improved calibrateOscillator -------- */
+/* ----------------------   for Reference only ----------------------------- */
+/* ------------------------------------------------------------------------- */
+
+#if 0
+void    calibrateOscillator(void)
+{
+	uchar       step, trialValue, optimumValue;
+	int         x, targetValue;
+	uchar		optimumDev;
+	uchar		i,xl;
+	
+	targetValue = (unsigned)((double)F_CPU * 999e-6 / 5.0 + 0.5);  /* Time is measured in multiples of 5 cycles. Target is 0.999�s */
+    optimumDev = 0xff;   
+  //  optimumValue = OSCCAL; 
+	step=64;
+	trialValue = 128;
+	
+	cli(); // disable interrupts
+	
+	/*
+		Performs seven iterations of a binary search (stepwidth decreasing9
+		with three additional steps of a neighborhood search (step=1, trialvalue will oscillate around target value to find optimum)
+	*/
+
+	for(i=0; i<10; i++){
+		OSCCAL = trialValue;
+		asm volatile(" NOP");
+	
+		x = usbMeasureFrameLengthDecreasing(targetValue);
+
+		if(x < 0)             /* frequency too high */
+		{
+			trialValue -= step;
+			xl=(uchar)-x;
+		}
+		else                  /* frequency too low */
+		{
+			trialValue += step;			
+			xl=(uchar)x;
+		}
+		
+		/*
+			Halve stepwidth to perform binary search. At step=1 the mode changes to neighbourhood search.
+			Once the neighbourhood search stage is reached, x will be smaller than +-255, hence more code can be
+			saved by only working with the lower 8 bits.
+		*/
+		
+		step >>= 1;
+		
+		if (step==0)   // Enter neighborhood search mode
+		{
+			step=1;			
+			if(xl <= optimumDev){
+				optimumDev = xl;
+				optimumValue = OSCCAL;
+			}
+		}
+	}
+
+	OSCCAL = optimumValue;
+	asm volatile(" NOP");
+	
+	sei(); // enable interrupts
+}
+#endif
\ No newline at end of file
diff --git a/firmware/osccalASM.o b/firmware/osccalASM.o
new file mode 100644
index 0000000..2a829d4
Binary files /dev/null and b/firmware/osccalASM.o differ
-- 
cgit v1.2.3