From 824c303782a62b57b6525875b3c2dee81056baa4 Mon Sep 17 00:00:00 2001 From: Jenna Fox Date: Sun, 23 Sep 2012 16:09:28 +1000 Subject: Begin work to convert embedded-creations USBaspLoader-tiny85 port to bootloadHID --- firmware/libs-device/Readme.txt | 22 ++++++++ firmware/libs-device/osccal.c | 63 +++++++++++++++++++++++ firmware/libs-device/osccal.c.lst | 102 ++++++++++++++++++++++++++++++++++++++ firmware/libs-device/osccal.h | 65 ++++++++++++++++++++++++ firmware/libs-device/osccal.o | Bin 0 -> 956 bytes firmware/libs-device/osctune.h | 88 ++++++++++++++++++++++++++++++++ 6 files changed, 340 insertions(+) create mode 100644 firmware/libs-device/Readme.txt create mode 100644 firmware/libs-device/osccal.c create mode 100644 firmware/libs-device/osccal.c.lst create mode 100644 firmware/libs-device/osccal.h create mode 100644 firmware/libs-device/osccal.o create mode 100644 firmware/libs-device/osctune.h (limited to 'firmware/libs-device') diff --git a/firmware/libs-device/Readme.txt b/firmware/libs-device/Readme.txt new file mode 100644 index 0000000..76518dc --- /dev/null +++ b/firmware/libs-device/Readme.txt @@ -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/ 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 + +#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. +*/ diff --git a/firmware/libs-device/osccal.c.lst b/firmware/libs-device/osccal.c.lst new file mode 100644 index 0000000..25eda0a --- /dev/null +++ b/firmware/libs-device/osccal.c.lst @@ -0,0 +1,102 @@ +GAS LISTING /var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s page 1 + + + 1 .file "osccal.c" + 2 __SREG__ = 0x3f + 3 __SP_H__ = 0x3e + 4 __SP_L__ = 0x3d + 5 __CCP__ = 0x34 + 6 __tmp_reg__ = 0 + 7 __zero_reg__ = 1 + 8 .text + 9 .global calibrateOscillator + 10 .type calibrateOscillator, @function + 11 calibrateOscillator: + 12 0000 FF92 push r15 + 13 0002 0F93 push r16 + 14 0004 1F93 push r17 + 15 0006 CF93 push r28 + 16 0008 DF93 push r29 + 17 /* prologue: function */ + 18 /* frame size = 0 */ + 19 /* stack size = 5 */ + 20 .L__stack_usage = 5 + 21 000a C8E0 ldi r28,lo8(8) + 22 000c D0E0 ldi r29,hi8(8) + 23 000e 10E0 ldi r17,lo8(0) + 24 0010 00E8 ldi r16,lo8(-128) + 25 .L3: + 26 0012 F12E mov r15,r17 + 27 0014 F00E add r15,r16 + 28 0016 F1BE out 81-32,r15 + 29 0018 00D0 rcall usbMeasureFrameLength + 30 001a 29E0 ldi r18,hi8(2356) + 31 001c 8433 cpi r24,lo8(2356) + 32 001e 9207 cpc r25,r18 + 33 0020 04F4 brge .L2 + 34 0022 1F2D mov r17,r15 + 35 .L2: + 36 0024 0695 lsr r16 + 37 0026 2197 sbiw r28,1 + 38 0028 01F4 brne .L3 + 39 002a 212F mov r18,r17 + 40 002c 2150 subi r18,lo8(-(-1)) + 41 002e 21BF out 81-32,r18 + 42 0030 EC01 movw r28,r24 + 43 0032 012F mov r16,r17 + 44 0034 00C0 rjmp .L4 + 45 .L7: + 46 0036 00D0 rcall usbMeasureFrameLength + 47 0038 8453 subi r24,lo8(-(-2356)) + 48 003a 9940 sbci r25,hi8(-(-2356)) + 49 003c 97FF sbrs r25,7 + 50 003e 00C0 rjmp .L5 + 51 0040 9095 com r25 + 52 0042 8195 neg r24 + 53 0044 9F4F sbci r25,lo8(-1) + 54 .L5: + 55 0046 8C17 cp r24,r28 + 56 0048 9D07 cpc r25,r29 + 57 004a 04F4 brge .L6 + GAS LISTING /var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s page 2 + + + 58 004c 01B7 in r16,81-32 + 59 004e EC01 movw r28,r24 + 60 .L6: + 61 0050 81B7 in r24,81-32 + 62 0052 8F5F subi r24,lo8(-(1)) + 63 0054 81BF out 81-32,r24 + 64 .L4: + 65 0056 21B7 in r18,81-32 + 66 0058 30E0 ldi r19,lo8(0) + 67 005a 812F mov r24,r17 + 68 005c 90E0 ldi r25,lo8(0) + 69 005e 0196 adiw r24,1 + 70 0060 8217 cp r24,r18 + 71 0062 9307 cpc r25,r19 + 72 0064 04F4 brge .L7 + 73 0066 01BF out 81-32,r16 + 74 /* epilogue start */ + 75 0068 DF91 pop r29 + 76 006a CF91 pop r28 + 77 006c 1F91 pop r17 + 78 006e 0F91 pop r16 + 79 0070 FF90 pop r15 + 80 0072 0895 ret + 81 .size calibrateOscillator, .-calibrateOscillator + GAS LISTING /var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s page 3 + + +DEFINED SYMBOLS + *ABS*:00000000 osccal.c +/var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s:2 *ABS*:0000003f __SREG__ +/var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s:3 *ABS*:0000003e __SP_H__ +/var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s:4 *ABS*:0000003d __SP_L__ +/var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s:5 *ABS*:00000034 __CCP__ +/var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s:6 *ABS*:00000000 __tmp_reg__ +/var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s:7 *ABS*:00000001 __zero_reg__ +/var/folders/nd/dq8cd7_x03d_z3x899kwf__80000gn/T//ccgky3fN.s:11 .text:00000000 calibrateOscillator + +UNDEFINED SYMBOLS +usbMeasureFrameLength diff --git a/firmware/libs-device/osccal.h b/firmware/libs-device/osccal.h new file mode 100644 index 0000000..710ce05 --- /dev/null +++ b/firmware/libs-device/osccal.h @@ -0,0 +1,65 @@ +/* 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 762 2009-08-12 17:10:30Z 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 recommended to call +calibrateOscillator() from the reset hook in usbconfig.h: +*/ + +#ifndef __ASSEMBLER__ +#include // 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 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__ + +//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__ */ diff --git a/firmware/libs-device/osccal.o b/firmware/libs-device/osccal.o new file mode 100644 index 0000000..79622f1 Binary files /dev/null and b/firmware/libs-device/osccal.o differ diff --git a/firmware/libs-device/osctune.h b/firmware/libs-device/osctune.h new file mode 100644 index 0000000..c751648 --- /dev/null +++ b/firmware/libs-device/osctune.h @@ -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 -- cgit v1.2.3