o cleanup
This commit is contained in:
22
tools/avrusb/libs-device/Readme.txt
Normal file
22
tools/avrusb/libs-device/Readme.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
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/
|
||||
59
tools/avrusb/libs-device/osccal.c
Normal file
59
tools/avrusb/libs-device/osccal.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 692 2008-11-07 15:07:40Z cs $
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------ 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.
|
||||
*/
|
||||
63
tools/avrusb/libs-device/osccal.h
Normal file
63
tools/avrusb/libs-device/osccal.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* Name: osccal.h
|
||||
* 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.h 692 2008-11-07 15:07:40Z cs $
|
||||
*/
|
||||
|
||||
/*
|
||||
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. 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 also recommended to call
|
||||
calibrateOscillator() from the reset hook in usbconfig.h:
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <avr/interrupt.h> /* for sei() */
|
||||
extern void calibrateOscillator(void);
|
||||
#endif
|
||||
#define USB_RESET_HOOK(resetStarts) if(!resetStarts){cli(); calibrateOscillator(); sei();}
|
||||
|
||||
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.
|
||||
|
||||
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 AVR-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__
|
||||
|
||||
void calibrateOscillator(void);
|
||||
/* 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__ */
|
||||
88
tools/avrusb/libs-device/osctune.h
Normal file
88
tools/avrusb/libs-device/osctune.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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
|
||||
Reference in New Issue
Block a user