📄 usbdrvasm128.inc
字号:
/* Name: usbdrvasm128.inc * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2008-10-11 * 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: usbdrvasm128.inc 692 2008-11-07 15:07:40Z cs $ *//* Do not link this file! Link usbdrvasm.S instead, which includes the * appropriate implementation! *//*General Description:This file is the 12.8 MHz version of the USB driver. It is intended for usewith the internal RC oscillator. Although 12.8 MHz is outside the guaranteedcalibration range of the oscillator, almost all AVRs can reach this frequency.This version contains a phase locked loop in the receiver routine to cope withslight clock rate deviations of up to +/- 1%.See usbdrv.h for a description of the entire driver.LIMITATIONS===========Although it may seem very handy to save the crystal and use the internalRC oscillator of the CPU, this method (and this module) has some seriouslimitations:(1) The guaranteed calibration range of the oscillator is only 8.1 MHz.They typical range is 14.5 MHz and most AVRs can actually reach this rate.(2) Writing EEPROM and Flash may be unreliable (short data lifetime) sincethe write procedure is timed from the RC oscillator.(3) End Of Packet detection is between bit 0 and bit 1 where the EOP conditionmay not be reliable when a hub is used. It should be in bit 1.(4) Code size is much larger than that of the other modules.Since almost all of this code is timing critical, don't change unless youreally know what you are doing! Many parts require not only a maximum numberof CPU cycles, but even an exact number of cycles!Implementation notes:======================min frequency: 67 cycles for 8 bit -> 12.5625 MHzmax frequency: 69.286 cycles for 8 bit -> 12.99 MHznominal frequency: 12.77 MHz ( = sqrt(min * max))sampling positions: (next even number in range [+/- 0.5])cycle index range: 0 ... 66bits:.5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125[0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59]bit number: 0 1 2 3 4 5 6 7spare cycles 1 2 1 2 1 1 1 0operations to perform: duration cycle ---------------- eor fix, shift 1 -> 00 andi phase, USBMASK 1 -> 08 breq se0 1 -> 16 (moved to 11) st y+, data 2 -> 24, 25 mov data, fix 1 -> 33 ser data 1 -> 41 subi cnt, 1 1 -> 49 brcs overflow 1 -> 50layout of samples and operations:[##] = sample bit<##> = sample phase*##* = operation0: *00* [01] 02 03 04 <05> 06 071: *08* [09] 10 11 12 <13> 14 15 *16*2: [17] 18 19 20 <21> 22 233: *24* *25* [26] 27 28 29 <30> 31 324: *33* [34] 35 36 37 <38> 39 405: *41* [42] 43 44 45 <46> 47 486: *49* *50* [51] 52 53 54 <55> 56 57 587: [59] 60 61 62 <63> 64 65 66*****************************************************************************//* we prefer positive expressions (do if condition) instead of negative * (skip if condition), therefore use defines for skip instructions: */#define ifioclr sbis#define ifioset sbic#define ifrclr sbrs#define ifrset sbrc/* The registers "fix" and "data" swap their meaning during the loop. Use * defines to keep their name constant. */#define fix x2#define data x1#undef phase /* phase has a default definition to x4 */#define phase x3USB_INTR_VECTOR:;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0 push YL ;2 push only what is necessary to sync with edge ASAP in YL, SREG ;1 push YL ;2;----------------------------------------------------------------------------; Synchronize with sync pattern:;----------------------------------------------------------------------------;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K];sync up with J to K edge during sync pattern -- use fastest possible loops;The first part waits at most 1 bit long since we must be in sync pattern.;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to;waitForJ, ensure that this prerequisite is met.waitForJ: inc YL sbis USBIN, USBMINUS brne waitForJ ; just make sure we have ANY timeoutwaitForK:;The following code results in a sampling window of 1/4 bit which meets the spec. sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS rjmp foundK sbis USBIN, USBMINUS ;[0] rjmp foundK ;[1]#if USB_COUNT_SOF lds YL, usbSofCount inc YL sts usbSofCount, YL#endif /* USB_COUNT_SOF */#ifdef USB_SOF_HOOK USB_SOF_HOOK#endif rjmp sofErrorfoundK:;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling];we have 1 bit time for setup purposes, then sample again. Numbers in brackets;are cycles from center of first sync (double K) bit after the instruction push YH ;[2] lds YL, usbInputBufOffset;[4] clr YH ;[6] subi YL, lo8(-(usbRxBuf));[7] sbci YH, hi8(-(usbRxBuf));[8] sbis USBIN, USBMINUS ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5] rjmp haveTwoBitsK ;[10] pop YH ;[11] undo the push from before rjmp waitForK ;[13] this was not the end of sync, retryhaveTwoBitsK:;----------------------------------------------------------------------------; push more registers and initialize values while we sample the first bits:;----------------------------------------------------------------------------#define fix x2#define data x1 push shift ;[12] push x1 ;[14] push x2 ;[16] ldi shift, 0x80 ;[18] prevent bit-unstuffing but init low bits to 0 ifioset USBIN, USBMINUS ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5] ori shift, 1<<0 ;[02] push x3 ;[03] push cnt ;[05] push r0 ;[07] ifioset USBIN, USBMINUS ;[09] <--- bit 1 ori shift, 1<<1 ;[10] ser fix ;[11] ldi cnt, USB_BUFSIZE ;[12] mov data, shift ;[13] lsl shift ;[14] nop2 ;[15] ifioset USBIN, USBMINUS ;[17] <--- bit 2 ori data, 3<<2 ;[18] store in bit 2 AND bit 3 eor shift, data ;[19] do nrzi decoding andi data, 1<<3 ;[20] in phase, USBIN ;[21] <- phase brne jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1 nop ;[23] rjmp entryAfterClr ;[24]jumpToEntryAfterSet: rjmp entryAfterSet ;[24];----------------------------------------------------------------------------; Receiver loop (numbers in brackets are cycles within byte after instr);----------------------------------------------------------------------------#undef fix#define fix x1#undef data#define data x2bit7IsSet: ifrclr phase, USBMINUS ;[62] check phase only if D- changed lpm ;[63] in phase, USBIN ;[64] <- phase (one cycle too late) ori shift, 1 << 7 ;[65] nop ;[66];;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jumpbit0AfterSet: eor fix, shift ;[00]#undef fix#define fix x2#undef data#define data x1 /* we now have result in data, fix is reset to 0xff */ ifioclr USBIN, USBMINUS ;[01] <--- sample 0 rjmp bit0IsClr ;[02] andi shift, ~(7 << 0) ;[03] breq unstuff0s ;[04] in phase, USBIN ;[05] <- phase rjmp bit1AfterSet ;[06]unstuff0s: in phase, USBIN ;[06] <- phase (one cycle too late) andi fix, ~(1 << 0) ;[07] ifioclr USBIN, USBMINUS ;[00] ifioset USBIN, USBPLUS ;[01] rjmp bit0IsClr ;[02] executed if first expr false or second truejumpToSe0AndStore: rjmp se0AndStore ;[03] executed only if both bits 0bit0IsClr: ifrset phase, USBMINUS ;[04] check phase only if D- changed lpm ;[05] in phase, USBIN ;[06] <- phase (one cycle too late) ori shift, 1 << 0 ;[07]bit1AfterClr: andi phase, USBMASK ;[08] ifioset USBIN, USBMINUS ;[09] <--- sample 1 rjmp bit1IsSet ;[10] breq jumpToSe0AndStore ;[11] andi shift, ~(7 << 1) ;[12] in phase, USBIN ;[13] <- phase breq unstuff1c ;[14] rjmp bit2AfterClr ;[15]unstuff1c: andi fix, ~(1 << 1) ;[16] nop2 ;[08] nop2 ;[10]bit1IsSet: ifrclr phase, USBMINUS ;[12] check phase only if D- changed lpm ;[13] in phase, USBIN ;[14] <- phase (one cycle too late) ori shift, 1 << 1 ;[15] nop ;[16]bit2AfterSet: ifioclr USBIN, USBMINUS ;[17] <--- sample 2 rjmp bit2IsClr ;[18] andi shift, ~(7 << 2) ;[19] breq unstuff2s ;[20] in phase, USBIN ;[21] <- phase rjmp bit3AfterSet ;[22]unstuff2s: in phase, USBIN ;[22] <- phase (one cycle too late) andi fix, ~(1 << 2) ;[23] nop2 ;[16] nop2 ;[18]bit2IsClr: ifrset phase, USBMINUS ;[20] check phase only if D- changed lpm ;[21] in phase, USBIN ;[22] <- phase (one cycle too late) ori shift, 1 << 2 ;[23]bit3AfterClr: st y+, data ;[24]entryAfterClr: ifioset USBIN, USBMINUS ;[26] <--- sample 3 rjmp bit3IsSet ;[27] andi shift, ~(7 << 3) ;[28] breq unstuff3c ;[29] in phase, USBIN ;[30] <- phase rjmp bit4AfterClr ;[31]unstuff3c: in phase, USBIN ;[31] <- phase (one cycle too late) andi fix, ~(1 << 3) ;[32] nop2 ;[25] nop2 ;[27]bit3IsSet: ifrclr phase, USBMINUS ;[29] check phase only if D- changed lpm ;[30] in phase, USBIN ;[31] <- phase (one cycle too late) ori shift, 1 << 3 ;[32]bit4AfterSet: mov data, fix ;[33] undo this move by swapping defines#undef fix#define fix x1#undef data#define data x2 ifioclr USBIN, USBMINUS ;[34] <--- sample 4 rjmp bit4IsClr ;[35] andi shift, ~(7 << 4) ;[36] breq unstuff4s ;[37] in phase, USBIN ;[38] <- phase rjmp bit5AfterSet ;[39]unstuff4s: in phase, USBIN ;[39] <- phase (one cycle too late) andi fix, ~(1 << 4) ;[40] nop2 ;[33] nop2 ;[35]bit4IsClr: ifrset phase, USBMINUS ;[37] check phase only if D- changed lpm ;[38] in phase, USBIN ;[39] <- phase (one cycle too late) ori shift, 1 << 4 ;[40]bit5AfterClr: ser data ;[41] ifioset USBIN, USBMINUS ;[42] <--- sample 5 rjmp bit5IsSet ;[43] andi shift, ~(7 << 5) ;[44] breq unstuff5c ;[45] in phase, USBIN ;[46] <- phase rjmp bit6AfterClr ;[47]unstuff5c: in phase, USBIN ;[47] <- phase (one cycle too late) andi fix, ~(1 << 5) ;[48] nop2 ;[41] nop2 ;[43]bit5IsSet: ifrclr phase, USBMINUS ;[45] check phase only if D- changed lpm ;[46] in phase, USBIN ;[47] <- phase (one cycle too late) ori shift, 1 << 5 ;[48]bit6AfterSet: subi cnt, 1 ;[49] brcs jumpToOverflow ;[50] ifioclr USBIN, USBMINUS ;[51] <--- sample 6 rjmp bit6IsClr ;[52] andi shift, ~(3 << 6) ;[53] cpi shift, 2 ;[54] in phase, USBIN ;[55] <- phase brlt unstuff6s ;[56] rjmp bit7AfterSet ;[57]jumpToOverflow: rjmp overflowunstuff6s: andi fix, ~(1 << 6) ;[50] lpm ;[51]bit6IsClr: ifrset phase, USBMINUS ;[54] check phase only if D- changed lpm ;[55] in phase, USBIN ;[56] <- phase (one cycle too late) ori shift, 1 << 6 ;[57] nop ;[58]bit7AfterClr: ifioset USBIN, USBMINUS ;[59] <--- sample 7 rjmp bit7IsSet ;[60] andi shift, ~(1 << 7) ;[61] cpi shift, 4 ;[62] in phase, USBIN ;[63] <- phase brlt unstuff7c ;[64] rjmp bit0AfterClr ;[65] -> [00] == [67]unstuff7c: andi fix, ~(1 << 7) ;[58] nop ;[59] rjmp bit7IsSet ;[60]se0AndStore: st y+, x1 ;[15/17] cycles after start of byte rjmp se0 ;[17/19]bit7IsClr: ifrset phase, USBMINUS ;[62] check phase only if D- changed lpm ;[63] in phase, USBIN ;[64] <- phase (one cycle too late) ori shift, 1 << 7 ;[65] nop ;[66];;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jumpbit0AfterClr: eor fix, shift ;[00]#undef fix#define fix x2#undef data#define data x1 /* we now have result in data, fix is reset to 0xff */ ifioset USBIN, USBMINUS ;[01] <--- sample 0 rjmp bit0IsSet ;[02] andi shift, ~(7 << 0) ;[03]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -