diff options
| -rw-r--r-- | firmware/Makefile | 11 | ||||
| -rw-r--r-- | firmware/bootloaderconfig.h | 2 | ||||
| -rw-r--r-- | firmware/libs-device/osccal.h | 35 | ||||
| -rw-r--r-- | firmware/libs-device/osccalASM.S | 228 | ||||
| -rw-r--r-- | firmware/libs-device/osccalASM.o | bin | 0 -> 1708 bytes | |||
| -rw-r--r-- | firmware/usbconfig.h | 7 | ||||
| -rw-r--r-- | firmware/usbdrv/usbdrvasm.S | 195 | 
7 files changed, 251 insertions, 227 deletions
| diff --git a/firmware/Makefile b/firmware/Makefile index 2d6f357..2f539b6 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -24,7 +24,7 @@ LOCKOPT = -U lock:w:0x2f:m  # - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068  # - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125  # - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 -BOOTLOADER_ADDRESS = 1780 +BOOTLOADER_ADDRESS = 1840  PROGRAMMER = -c USBasp  # PROGRAMMER contains AVRDUDE options to address your programmer @@ -148,13 +148,12 @@ CC = avr-gcc  # Options:  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 -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 -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)  LDFLAGS = -Wl,--relax,--gc-sections -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS),-Map=main.map  OBJECTS =  usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o -OBJECTS += libs-device/osccal.o  - +OBJECTS += libs-device/osccalASM.o  # symbolic targets:  all: main.hex @@ -172,7 +171,7 @@ all: main.hex  	$(CC) $(CFLAGS) -S $< -o $@  flash:	all -	$(AVRDUDE) -U flash:w:main.hex:i +	$(AVRDUDE) -U flash:w:main.hex:i -B 10  readflash:  	$(AVRDUDE) -U flash:r:read.hex:i diff --git a/firmware/bootloaderconfig.h b/firmware/bootloaderconfig.h index d78a614..641a9e0 100644 --- a/firmware/bootloaderconfig.h +++ b/firmware/bootloaderconfig.h @@ -222,7 +222,7 @@ these macros are defined, the boot loader uses them.  // LED will turn on when output=low and act as external pull up otherwise  // button shorts to GND -// #define NANITE +//#define NANITE  #define NANITE_CTRLPIN PB5 diff --git a/firmware/libs-device/osccal.h b/firmware/libs-device/osccal.h index bfc5530..af37a43 100644 --- a/firmware/libs-device/osccal.h +++ b/firmware/libs-device/osccal.h @@ -1,10 +1,10 @@  /* 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) - * This Revision: $Id: osccal.h 762 2009-08-12 17:10:30Z cs $   */  /* @@ -14,31 +14,18 @@ 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. For -low level timing measurements, usbMeasureFrameLength() is called. This -function must be enabled in usbconfig.h by defining -USB_CFG_HAVE_MEASURE_FRAME_LENGTH to 1. It is recommended to call -calibrateOscillator() from the reset hook in usbconfig.h: -*/ +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: -#ifndef __ASSEMBLER__ -//extern void calibrateOscillator(void); -extern void calibrateOscillatorASM(void); -#endif -//#define USB_RESET_HOOK(resetStarts)  if(!resetStarts){  calibrateOscillator(); } -#define USB_RESET_HOOK(resetStarts)  if(!resetStarts){  calibrateOscillatorASM(); } +#include "osccal.h" -/*  This routine is an alternative to the continuous synchronization described  in osctune.h. -Algorithm used: -calibrateOscillator() first does a binary search in the OSCCAL register for -the best matching oscillator frequency. Then it does a next neighbor search -to find the value with the lowest clock rate deviation. It is guaranteed to -find the best match among neighboring values, but for version 5 oscillators -(which have a discontinuous relationship between OSCCAL and frequency) a -better match might be available in another OSCCAL region. +Algorithm used:  See osccalASM.x  Limitations:  This calibration algorithm may try OSCCAL values of up to 192 even if the @@ -54,7 +41,11 @@ deviation! All other frequency modules require at least 0.2% precision.  #ifndef __OSCCAL_H_INCLUDED__  #define __OSCCAL_H_INCLUDED__ -//void    calibrateOscillator(void); +#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! diff --git a/firmware/libs-device/osccalASM.S b/firmware/libs-device/osccalASM.S new file mode 100644 index 0000000..9a317f1 --- /dev/null +++ b/firmware/libs-device/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/libs-device/osccalASM.o b/firmware/libs-device/osccalASM.oBinary files differ new file mode 100644 index 0000000..1dac9d8 --- /dev/null +++ b/firmware/libs-device/osccalASM.o diff --git a/firmware/usbconfig.h b/firmware/usbconfig.h index 55707cb..bba210d 100644 --- a/firmware/usbconfig.h +++ b/firmware/usbconfig.h @@ -158,11 +158,10 @@   * for each control- and out-endpoint to check for duplicate packets.   */  //#if USB_CFG_CLOCK_KHZ==16500 -#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH   1 + +  #include "osccal.h" -//#else -//#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH   0 -//#endif +  /* define this macro to 1 if you want the function usbMeasureFrameLength()   * compiled in. This function can be used to calibrate the AVR's RC oscillator.   */ diff --git a/firmware/usbdrv/usbdrvasm.S b/firmware/usbdrv/usbdrvasm.S index 29c634a..32ce8ef 100644 --- a/firmware/usbdrv/usbdrvasm.S +++ b/firmware/usbdrv/usbdrvasm.S @@ -282,7 +282,7 @@ usbCrc16Append:  #undef scratch -#if USB_CFG_HAVE_MEASURE_FRAME_LENGTHx +#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH  #ifdef __IAR_SYSTEMS_ASM__  /* Register assignments for usbMeasureFrameLength on IAR cc */  /* Calling conventions on IAR: @@ -355,199 +355,6 @@ usbMFTimeout:  #endif  /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */ - -#if USB_CFG_HAVE_MEASURE_FRAME_LENGTHx -#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". - */ -#   define resL     r16 -#   define resH     r17 -#   define cnt16L   r30 -#   define cnt16H   r31 -#   define cntH     r18 - -#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 resL     r24 -#   define resH     r25 -#   define cnt16L   r24 -#   define cnt16H   r25 -#   define cntH     r26 -#endif -#   define cnt16    cnt16L - -; extern int usbMeasurePacketLengthDecreasing(int); -; input: timer start value -; return: counts down time between two idle strobes in multiples of 5 CPU clocks -.global usbMeasureFrameLengthDecreasing -usbMeasureFrameLengthDecreasing: - -#if resL != cnt16L -    mov     cnt16L, resL -    mov     cnt16H, resH -#endif - -usbDFWaitStrobe:            ; first wait for D- == 0 (idle strobe) -    sbic    USBIN, USBMINUS ; -    rjmp    usbDFWaitStrobe ; -usbDFWaitIdle:              ; then wait until idle again -    sbis    USBIN, USBMINUS ;1 wait for D- == 1 -    rjmp    usbDFWaitIdle   ;2 -usbDFWaitLoop: -	sbiw	cnt16,1			;[0] [5] -    sbic    USBIN, USBMINUS ;[2]  -    rjmp    usbDFWaitLoop   ;[3] - -#if resL != cnt16L -    mov     resL, cnt16L -    mov     resH, cnt16H -#endif -    ret - -#undef resL -#undef resH -#undef cnt16 -#undef cnt16L -#undef cnt16H -#undef cntH - -#endif  /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */ - - - -#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH -#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". - */ - -#   define resL     r16 -#   define resH     r17 -#   define cnt16L   r30 -#   define cnt16H   r31 -#   define cntH     r18 - -#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		i, 10		; 10 iterations - -	ldi		opD, 255	 - -	ldi		try, 128	; calibration start value -	ldi		stp, 64		; initial step width - -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) -#define usbok -#endif - -#if (F_CPU == 12800000) -	ldi		cnt16L, lo8(2557) -	ldi		cnt16H, hi8(2557) -#define usbok -#endif - -#ifndef usbok -	#error "calibrateOscillatorASM: no delayvalues defined for this F_CPU setting" -#endif -#undef usbok - -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	usbCOstepnotzero -	cp		opD, cnt16L -	brcs	usbCOnoimprovement -	in		opV, OSCCAL -	mov		opD, cnt16L -usbCOnoimprovement: -	ldi		stp, 1 -usbCOstepnotzero: -	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 - - -#endif  /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */ - - -  ;----------------------------------------------------------------------------  ; Now include the clock rate specific code  ;---------------------------------------------------------------------------- | 
