1 /* Name: usbdrvasm128.inc
2 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3 * Author: Christian Starkjohann
4 * Creation Date: 2008-10-11
6 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
8 * This Revision: $Id: usbdrvasm128.inc 758 2009-08-06 10:12:54Z cs $
11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
12 * appropriate implementation!
17 This file is the 12.8 MHz version of the USB driver. It is intended for use
18 with the internal RC oscillator. Although 12.8 MHz is outside the guaranteed
19 calibration range of the oscillator, almost all AVRs can reach this frequency.
20 This version contains a phase locked loop in the receiver routine to cope with
21 slight clock rate deviations of up to +/- 1%.
23 See usbdrv.h for a description of the entire driver.
27 Although it may seem very handy to save the crystal and use the internal
28 RC oscillator of the CPU, this method (and this module) has some serious
30 (1) The guaranteed calibration range of the oscillator is only 8.1 MHz.
31 They typical range is 14.5 MHz and most AVRs can actually reach this rate.
32 (2) Writing EEPROM and Flash may be unreliable (short data lifetime) since
33 the write procedure is timed from the RC oscillator.
34 (3) End Of Packet detection (SE0) should be in bit 1, bit it is only checked
35 if bits 0 and 1 both read as 0 on D- and D+ read as 0 in the middle. This may
36 cause problems with old hubs which delay SE0 by up to one cycle.
37 (4) Code size is much larger than that of the other modules.
39 Since almost all of this code is timing critical, don't change unless you
40 really know what you are doing! Many parts require not only a maximum number
41 of CPU cycles, but even an exact number of cycles!
44 ======================
45 min frequency: 67 cycles for 8 bit -> 12.5625 MHz
46 max frequency: 69.286 cycles for 8 bit -> 12.99 MHz
47 nominal frequency: 12.77 MHz ( = sqrt(min * max))
49 sampling positions: (next even number in range [+/- 0.5])
50 cycle index range: 0 ... 66
52 .5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125
53 [0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59]
55 bit number: 0 1 2 3 4 5 6 7
56 spare cycles 1 2 1 2 1 1 1 0
58 operations to perform: duration cycle
60 eor fix, shift 1 -> 00
61 andi phase, USBMASK 1 -> 08
62 breq se0 1 -> 16 (moved to 11)
63 st y+, data 2 -> 24, 25
69 layout of samples and operations:
74 0: *00* [01] 02 03 04 <05> 06 07
75 1: *08* [09] 10 11 12 <13> 14 15 *16*
76 2: [17] 18 19 20 <21> 22 23
77 3: *24* *25* [26] 27 28 29 <30> 31 32
78 4: *33* [34] 35 36 37 <38> 39 40
79 5: *41* [42] 43 44 45 <46> 47 48
80 6: *49* *50* [51] 52 53 54 <55> 56 57 58
81 7: [59] 60 61 62 <63> 64 65 66
82 *****************************************************************************/
84 /* we prefer positive expressions (do if condition) instead of negative
85 * (skip if condition), therefore use defines for skip instructions:
92 /* The registers "fix" and "data" swap their meaning during the loop. Use
93 * defines to keep their name constant.
97 #undef phase /* phase has a default definition to x4 */
102 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0
103 push YL ;2 push only what is necessary to sync with edge ASAP
106 ;----------------------------------------------------------------------------
107 ; Synchronize with sync pattern:
108 ;----------------------------------------------------------------------------
109 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
110 ;sync up with J to K edge during sync pattern -- use fastest possible loops
111 ;The first part waits at most 1 bit long since we must be in sync pattern.
112 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
113 ;waitForJ, ensure that this prerequisite is met.
117 brne waitForJ ; just make sure we have ANY timeout
119 ;The following code results in a sampling window of 1/4 bit which meets the spec.
128 sbis USBIN, USBMINUS ;[0]
134 #endif /* USB_COUNT_SOF */
141 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
142 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
143 ;are cycles from center of first sync (double K) bit after the instruction
145 lds YL, usbInputBufOffset;[4]
147 subi YL, lo8(-(usbRxBuf));[7]
148 sbci YH, hi8(-(usbRxBuf));[8]
150 sbis USBIN, USBMINUS ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5]
151 rjmp haveTwoBitsK ;[10]
152 pop YH ;[11] undo the push from before
153 rjmp waitForK ;[13] this was not the end of sync, retry
155 ;----------------------------------------------------------------------------
156 ; push more registers and initialize values while we sample the first bits:
157 ;----------------------------------------------------------------------------
164 ldi shift, 0x80 ;[18] prevent bit-unstuffing but init low bits to 0
165 ifioset USBIN, USBMINUS ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5]
166 ori shift, 1<<0 ;[02]
170 ifioset USBIN, USBMINUS ;[09] <--- bit 1
171 ori shift, 1<<1 ;[10]
173 ldi cnt, USB_BUFSIZE ;[12]
174 mov data, shift ;[13]
177 ifioset USBIN, USBMINUS ;[17] <--- bit 2
178 ori data, 3<<2 ;[18] store in bit 2 AND bit 3
179 eor shift, data ;[19] do nrzi decoding
180 andi data, 1<<3 ;[20]
181 in phase, USBIN ;[21] <- phase
182 brne jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1
184 rjmp entryAfterClr ;[24]
186 rjmp entryAfterSet ;[24]
188 ;----------------------------------------------------------------------------
189 ; Receiver loop (numbers in brackets are cycles within byte after instr)
190 ;----------------------------------------------------------------------------
197 ifrclr phase, USBMINUS ;[62] check phase only if D- changed
199 in phase, USBIN ;[64] <- phase (one cycle too late)
200 ori shift, 1 << 7 ;[65]
202 ;;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jump
208 #define data x1 /* we now have result in data, fix is reset to 0xff */
209 ifioclr USBIN, USBMINUS ;[01] <--- sample 0
211 andi shift, ~(7 << 0) ;[03]
213 in phase, USBIN ;[05] <- phase
214 rjmp bit1AfterSet ;[06]
216 in phase, USBIN ;[06] <- phase (one cycle too late)
217 andi fix, ~(1 << 0) ;[07]
218 ifioclr USBIN, USBMINUS ;[00]
219 ifioset USBIN, USBPLUS ;[01]
220 rjmp bit0IsClr ;[02] executed if first expr false or second true
221 se0AndStore: ; executed only if both bits 0
222 st y+, x1 ;[15/17] cycles after start of byte
226 ifrset phase, USBMINUS ;[04] check phase only if D- changed
228 in phase, USBIN ;[06] <- phase (one cycle too late)
229 ori shift, 1 << 0 ;[07]
231 andi phase, USBMASK ;[08]
232 ifioset USBIN, USBMINUS ;[09] <--- sample 1
234 breq se0AndStore ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0
235 andi shift, ~(7 << 1) ;[12]
236 in phase, USBIN ;[13] <- phase
238 rjmp bit2AfterClr ;[15]
240 andi fix, ~(1 << 1) ;[16]
244 ifrclr phase, USBMINUS ;[12] check phase only if D- changed
246 in phase, USBIN ;[14] <- phase (one cycle too late)
247 ori shift, 1 << 1 ;[15]
250 ifioclr USBIN, USBMINUS ;[17] <--- sample 2
252 andi shift, ~(7 << 2) ;[19]
254 in phase, USBIN ;[21] <- phase
255 rjmp bit3AfterSet ;[22]
257 in phase, USBIN ;[22] <- phase (one cycle too late)
258 andi fix, ~(1 << 2) ;[23]
262 ifrset phase, USBMINUS ;[20] check phase only if D- changed
264 in phase, USBIN ;[22] <- phase (one cycle too late)
265 ori shift, 1 << 2 ;[23]
269 ifioset USBIN, USBMINUS ;[26] <--- sample 3
271 andi shift, ~(7 << 3) ;[28]
273 in phase, USBIN ;[30] <- phase
274 rjmp bit4AfterClr ;[31]
276 in phase, USBIN ;[31] <- phase (one cycle too late)
277 andi fix, ~(1 << 3) ;[32]
281 ifrclr phase, USBMINUS ;[29] check phase only if D- changed
283 in phase, USBIN ;[31] <- phase (one cycle too late)
284 ori shift, 1 << 3 ;[32]
286 mov data, fix ;[33] undo this move by swapping defines
291 ifioclr USBIN, USBMINUS ;[34] <--- sample 4
293 andi shift, ~(7 << 4) ;[36]
295 in phase, USBIN ;[38] <- phase
296 rjmp bit5AfterSet ;[39]
298 in phase, USBIN ;[39] <- phase (one cycle too late)
299 andi fix, ~(1 << 4) ;[40]
303 ifrset phase, USBMINUS ;[37] check phase only if D- changed
305 in phase, USBIN ;[39] <- phase (one cycle too late)
306 ori shift, 1 << 4 ;[40]
309 ifioset USBIN, USBMINUS ;[42] <--- sample 5
311 andi shift, ~(7 << 5) ;[44]
313 in phase, USBIN ;[46] <- phase
314 rjmp bit6AfterClr ;[47]
316 in phase, USBIN ;[47] <- phase (one cycle too late)
317 andi fix, ~(1 << 5) ;[48]
321 ifrclr phase, USBMINUS ;[45] check phase only if D- changed
323 in phase, USBIN ;[47] <- phase (one cycle too late)
324 ori shift, 1 << 5 ;[48]
327 brcs jumpToOverflow ;[50]
328 ifioclr USBIN, USBMINUS ;[51] <--- sample 6
330 andi shift, ~(3 << 6) ;[53]
332 in phase, USBIN ;[55] <- phase
334 rjmp bit7AfterSet ;[57]
340 andi fix, ~(1 << 6) ;[50]
343 ifrset phase, USBMINUS ;[54] check phase only if D- changed
345 in phase, USBIN ;[56] <- phase (one cycle too late)
346 ori shift, 1 << 6 ;[57]
349 ifioset USBIN, USBMINUS ;[59] <--- sample 7
351 andi shift, ~(1 << 7) ;[61]
353 in phase, USBIN ;[63] <- phase
355 rjmp bit0AfterClr ;[65] -> [00] == [67]
357 andi fix, ~(1 << 7) ;[58]
362 ifrset phase, USBMINUS ;[62] check phase only if D- changed
364 in phase, USBIN ;[64] <- phase (one cycle too late)
365 ori shift, 1 << 7 ;[65]
367 ;;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jump
373 #define data x1 /* we now have result in data, fix is reset to 0xff */
374 ifioset USBIN, USBMINUS ;[01] <--- sample 0
376 andi shift, ~(7 << 0) ;[03]
378 in phase, USBIN ;[05] <- phase
379 rjmp bit1AfterClr ;[06]
381 in phase, USBIN ;[06] <- phase (one cycle too late)
382 andi fix, ~(1 << 0) ;[07]
383 ifioclr USBIN, USBMINUS ;[00]
384 ifioset USBIN, USBPLUS ;[01]
385 rjmp bit0IsSet ;[02] executed if first expr false or second true
386 rjmp se0AndStore ;[03] executed only if both bits 0
388 ifrclr phase, USBMINUS ;[04] check phase only if D- changed
390 in phase, USBIN ;[06] <- phase (one cycle too late)
391 ori shift, 1 << 0 ;[07]
393 andi shift, ~(7 << 1) ;[08] compensated by "ori shift, 1<<1" if bit1IsClr
394 ifioclr USBIN, USBMINUS ;[09] <--- sample 1
397 nop2 ;[12] do not check for SE0 if bit 0 was 1
398 in phase, USBIN ;[14] <- phase (one cycle too late)
399 rjmp bit2AfterSet ;[15]
401 in phase, USBIN ;[13] <- phase
402 andi fix, ~(1 << 1) ;[14]
406 ifrset phase, USBMINUS ;[12] check phase only if D- changed
408 in phase, USBIN ;[14] <- phase (one cycle too late)
409 ori shift, 1 << 1 ;[15]
412 ifioset USBIN, USBMINUS ;[17] <--- sample 2
414 andi shift, ~(7 << 2) ;[19]
416 in phase, USBIN ;[21] <- phase
417 rjmp bit3AfterClr ;[22]
419 in phase, USBIN ;[22] <- phase (one cycle too late)
420 andi fix, ~(1 << 2) ;[23]
424 ifrclr phase, USBMINUS ;[20] check phase only if D- changed
426 in phase, USBIN ;[22] <- phase (one cycle too late)
427 ori shift, 1 << 2 ;[23]
431 ifioclr USBIN, USBMINUS ;[26] <--- sample 3
433 andi shift, ~(7 << 3) ;[28]
435 in phase, USBIN ;[30] <- phase
436 rjmp bit4AfterSet ;[31]
438 in phase, USBIN ;[31] <- phase (one cycle too late)
439 andi fix, ~(1 << 3) ;[32]
443 ifrset phase, USBMINUS ;[29] check phase only if D- changed
445 in phase, USBIN ;[31] <- phase (one cycle too late)
446 ori shift, 1 << 3 ;[32]
448 mov data, fix ;[33] undo this move by swapping defines
453 ifioset USBIN, USBMINUS ;[34] <--- sample 4
455 andi shift, ~(7 << 4) ;[36]
457 in phase, USBIN ;[38] <- phase
458 rjmp bit5AfterClr ;[39]
460 in phase, USBIN ;[39] <- phase (one cycle too late)
461 andi fix, ~(1 << 4) ;[40]
465 ifrclr phase, USBMINUS ;[37] check phase only if D- changed
467 in phase, USBIN ;[39] <- phase (one cycle too late)
468 ori shift, 1 << 4 ;[40]
471 ifioclr USBIN, USBMINUS ;[42] <--- sample 5
473 andi shift, ~(7 << 5) ;[44]
475 in phase, USBIN ;[46] <- phase
476 rjmp bit6AfterSet ;[47]
478 in phase, USBIN ;[47] <- phase (one cycle too late)
479 andi fix, ~(1 << 5) ;[48]
483 ifrset phase, USBMINUS ;[45] check phase only if D- changed
485 in phase, USBIN ;[47] <- phase (one cycle too late)
486 ori shift, 1 << 5 ;[48]
490 ifioset USBIN, USBMINUS ;[51] <--- sample 6
492 andi shift, ~(3 << 6) ;[53]
494 in phase, USBIN ;[55] <- phase
496 rjmp bit7AfterClr ;[57]
498 andi fix, ~(1 << 6) ;[50]
501 ifrclr phase, USBMINUS ;[54] check phase only if D- changed
503 in phase, USBIN ;[56] <- phase (one cycle too late)
504 ori shift, 1 << 6 ;[57]
506 ifioclr USBIN, USBMINUS ;[59] <--- sample 7
508 andi shift, ~(1 << 7) ;[61]
510 in phase, USBIN ;[63] <- phase
512 rjmp bit0AfterSet ;[65] -> [00] == [67]
514 andi fix, ~(1 << 7) ;[58]
518 macro POP_STANDARD ; 14 cycles
527 macro POP_RETI ; 5 cycles
533 #include "asmcommon.inc"
535 ;----------------------------------------------------------------------------
537 ;----------------------------------------------------------------------------
542 ror shift ;[-5] [11] [63]
543 brcc doExorN1 ;[-4] [64]
546 lsl shift ;[-1] compensate ror after rjmp stuffDelay
547 nop ;[00] stuffing consists of just waiting 8 cycles
548 rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear
551 ldi cnt, USBPID_NAK ;[-19]
552 rjmp sendCntAndReti ;[-18]
554 ldi cnt, USBPID_ACK ;[-17]
557 ldi YL, 0 ;[-15] R0 address is 0
560 ; rjmp usbSendAndReti fallthrough
564 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
565 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
566 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
569 ;pointer to data in 'Y'
570 ;number of bytes in 'cnt' -- including sync byte
571 ;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt]
572 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
574 in x2, USBDDR ;[-10] 10 cycles until SOP
575 ori x2, USBMASK ;[-9]
576 sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups)
577 out USBDDR, x2 ;[-6] <--- acquire bus
578 in x1, USBOUT ;[-5] port mirror for tx loop
579 ldi shift, 0x40 ;[-4] sync byte is first byte sent (we enter loop after ror)
580 ldi x2, USBMASK ;[-3]
582 eor x1, x2 ;[-2] [06] [62]
583 ldi x3, 6 ;[-1] [07] [63]
586 out USBOUT, x1 ;[00] [08] [64] <--- set bit
591 lsl shift ;[05] compensate ror after rjmp stuffDelay
592 rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear
594 eor x1, x2 ;[04] [12]
598 subi cnt, 171 ;[08] [16] trick: (3 * 171) & 0xff = 1
599 out USBOUT, x1 ;[09] [17] <--- set bit
600 brcs txBitloop ;[10] [27] [44]
607 lsl shift ;[49] compensate ror after rjmp stuffDelay
608 nop ;[50] stuffing consists of just waiting 8 cycles
609 rjmp stuff6Delay ;[51] after ror, C bit is reliably clear
611 eor x1, x2 ;[48] [56]
616 out USBOUT, x1 ;[51] <--- set bit
620 lsl shift ;[55] compensate ror after rjmp stuffDelay
621 rjmp stuff7Delay ;[56] after ror, C bit is reliably clear
623 eor x1, x2 ;[54] [62]
629 out USBOUT, x1 ;[60] [00]<--- set bit
630 brne txByteLoop ;[61] [01]
632 cbr x1, USBMASK ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles]
633 lds x2, usbNewDeviceAddr;[03]
634 lsl x2 ;[05] we compare with left shifted address
635 subi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0
637 out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
638 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
639 ;set address only after data packet was sent, not after handshake
640 breq skipAddrAssign ;[01]
641 sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer
643 ;end of usbDeviceAddress transfer
644 ldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
645 USB_STORE_PENDING(x2) ;[04]
646 ori x1, USBIDLE ;[05]
648 cbr x2, USBMASK ;[07] set both pins to input
650 cbr x3, USBMASK ;[09] configure no pullup on both pins
653 out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
654 out USBDDR, x2 ;[17] <-- release bus now
655 out USBOUT, x3 ;[18] <-- ensure no pull-up resistors are active
660 /*****************************************************************************
661 The following PHP script generates a code skeleton for the receiver routine:
665 function printCmdBuffer($thisBit)
669 $nextBit = ($thisBit + 1) % 8;
670 $s = ob_get_contents();
672 $s = str_replace("#", $thisBit, $s);
673 $s = str_replace("@", $nextBit, $s);
674 $lines = explode("\n", $s);
675 for($i = 0; $i < count($lines); $i++){
677 if(ereg("\\[([0-9-][0-9])\\]", $s, $regs)){
678 $c = $cycle + (int)$regs[1];
679 $s = ereg_replace("\\[[0-9-][0-9]\\]", sprintf("[%02d]", $c), $s);
686 function printBit($isAfterSet, $bitNum)
691 ifioclr USBIN, USBMINUS ;[00] <--- sample
693 andi shift, ~(7 << #) ;[02]
695 in phase, USBIN ;[04] <- phase
696 rjmp bit@AfterSet ;[05]
698 in phase, USBIN ;[05] <- phase (one cycle too late)
699 andi fix, ~(1 << #) ;[06]
703 ifrset phase, USBMINUS ;[03] check phase only if D- changed
705 in phase, USBIN ;[05] <- phase (one cycle too late)
706 ori shift, 1 << # ;[06]
710 ifioset USBIN, USBMINUS ;[00] <--- sample
712 andi shift, ~(7 << #) ;[02]
714 in phase, USBIN ;[04] <- phase
715 rjmp bit@AfterClr ;[05]
717 in phase, USBIN ;[05] <- phase (one cycle too late)
718 andi fix, ~(1 << #) ;[06]
722 ifrclr phase, USBMINUS ;[03] check phase only if D- changed
724 in phase, USBIN ;[05] <- phase (one cycle too late)
725 ori shift, 1 << # ;[06]
728 printCmdBuffer($bitNum);
731 $bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59);
732 for($i = 0; $i < 16; $i++){
734 $emitClrCode = ($i + (int)($i / 8)) % 2;
735 $cycle = $bitStartCycles[$bit];
737 printf("bit%dAfterClr:\n", $bit);
739 printf("bit%dAfterSet:\n", $bit);
742 echo " ***** ;[-1]\n";
743 printCmdBuffer($bit);
744 printBit(!$emitClrCode, $bit);
750 *****************************************************************************/