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)
10 /* Do not link this file! Link usbdrvasm.S instead, which includes the
11 * appropriate implementation!
16 This file is the 12.8 MHz version of the USB driver. It is intended for use
17 with the internal RC oscillator. Although 12.8 MHz is outside the guaranteed
18 calibration range of the oscillator, almost all AVRs can reach this frequency.
19 This version contains a phase locked loop in the receiver routine to cope with
20 slight clock rate deviations of up to +/- 1%.
22 See usbdrv.h for a description of the entire driver.
26 Although it may seem very handy to save the crystal and use the internal
27 RC oscillator of the CPU, this method (and this module) has some serious
29 (1) The guaranteed calibration range of the oscillator is only 8.1 MHz.
30 They typical range is 14.5 MHz and most AVRs can actually reach this rate.
31 (2) Writing EEPROM and Flash may be unreliable (short data lifetime) since
32 the write procedure is timed from the RC oscillator.
33 (3) End Of Packet detection (SE0) should be in bit 1, bit it is only checked
34 if bits 0 and 1 both read as 0 on D- and D+ read as 0 in the middle. This may
35 cause problems with old hubs which delay SE0 by up to one cycle.
36 (4) Code size is much larger than that of the other modules.
38 Since almost all of this code is timing critical, don't change unless you
39 really know what you are doing! Many parts require not only a maximum number
40 of CPU cycles, but even an exact number of cycles!
43 ======================
44 min frequency: 67 cycles for 8 bit -> 12.5625 MHz
45 max frequency: 69.286 cycles for 8 bit -> 12.99 MHz
46 nominal frequency: 12.77 MHz ( = sqrt(min * max))
48 sampling positions: (next even number in range [+/- 0.5])
49 cycle index range: 0 ... 66
51 .5, 8.875, 17.25, 25.625, 34, 42.375, 50.75, 59.125
52 [0/1], [9], [17], [25/+26], [34], [+42/43], [51], [59]
54 bit number: 0 1 2 3 4 5 6 7
55 spare cycles 1 2 1 2 1 1 1 0
57 operations to perform: duration cycle
59 eor fix, shift 1 -> 00
60 andi phase, USBMASK 1 -> 08
61 breq se0 1 -> 16 (moved to 11)
62 st y+, data 2 -> 24, 25
68 layout of samples and operations:
73 0: *00* [01] 02 03 04 <05> 06 07
74 1: *08* [09] 10 11 12 <13> 14 15 *16*
75 2: [17] 18 19 20 <21> 22 23
76 3: *24* *25* [26] 27 28 29 <30> 31 32
77 4: *33* [34] 35 36 37 <38> 39 40
78 5: *41* [42] 43 44 45 <46> 47 48
79 6: *49* *50* [51] 52 53 54 <55> 56 57 58
80 7: [59] 60 61 62 <63> 64 65 66
81 *****************************************************************************/
83 /* we prefer positive expressions (do if condition) instead of negative
84 * (skip if condition), therefore use defines for skip instructions:
91 /* The registers "fix" and "data" swap their meaning during the loop. Use
92 * defines to keep their name constant.
96 #undef phase /* phase has a default definition to x4 */
101 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt, r0
102 push YL ;2 push only what is necessary to sync with edge ASAP
105 ;----------------------------------------------------------------------------
106 ; Synchronize with sync pattern:
107 ;----------------------------------------------------------------------------
108 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
109 ;sync up with J to K edge during sync pattern -- use fastest possible loops
110 ;The first part waits at most 1 bit long since we must be in sync pattern.
111 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
112 ;waitForJ, ensure that this prerequisite is met.
116 brne waitForJ ; just make sure we have ANY timeout
118 ;The following code results in a sampling window of 1/4 bit which meets the spec.
127 sbis USBIN, USBMINUS ;[0]
133 #endif /* USB_COUNT_SOF */
140 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
141 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
142 ;are cycles from center of first sync (double K) bit after the instruction
144 lds YL, usbInputBufOffset;[4]
146 subi YL, lo8(-(usbRxBuf));[7]
147 sbci YH, hi8(-(usbRxBuf));[8]
149 sbis USBIN, USBMINUS ;[9] we want two bits K [we want to sample at 8 + 4 - 1.5 = 10.5]
150 rjmp haveTwoBitsK ;[10]
151 pop YH ;[11] undo the push from before
152 rjmp waitForK ;[13] this was not the end of sync, retry
154 ;----------------------------------------------------------------------------
155 ; push more registers and initialize values while we sample the first bits:
156 ;----------------------------------------------------------------------------
163 ldi shift, 0x80 ;[18] prevent bit-unstuffing but init low bits to 0
164 ifioset USBIN, USBMINUS ;[19] [01] <--- bit 0 [10.5 + 8 = 18.5]
165 ori shift, 1<<0 ;[02]
169 ifioset USBIN, USBMINUS ;[09] <--- bit 1
170 ori shift, 1<<1 ;[10]
172 ldi cnt, USB_BUFSIZE ;[12]
173 mov data, shift ;[13]
176 ifioset USBIN, USBMINUS ;[17] <--- bit 2
177 ori data, 3<<2 ;[18] store in bit 2 AND bit 3
178 eor shift, data ;[19] do nrzi decoding
179 andi data, 1<<3 ;[20]
180 in phase, USBIN ;[21] <- phase
181 brne jumpToEntryAfterSet ;[22] if USBMINS at bit 3 was 1
183 rjmp entryAfterClr ;[24]
185 rjmp entryAfterSet ;[24]
187 ;----------------------------------------------------------------------------
188 ; Receiver loop (numbers in brackets are cycles within byte after instr)
189 ;----------------------------------------------------------------------------
196 ifrclr phase, USBMINUS ;[62] check phase only if D- changed
198 in phase, USBIN ;[64] <- phase (one cycle too late)
199 ori shift, 1 << 7 ;[65]
201 ;;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jump
207 #define data x1 /* we now have result in data, fix is reset to 0xff */
208 ifioclr USBIN, USBMINUS ;[01] <--- sample 0
210 andi shift, ~(7 << 0) ;[03]
212 in phase, USBIN ;[05] <- phase
213 rjmp bit1AfterSet ;[06]
215 in phase, USBIN ;[06] <- phase (one cycle too late)
216 andi fix, ~(1 << 0) ;[07]
217 ifioclr USBIN, USBMINUS ;[00]
218 ifioset USBIN, USBPLUS ;[01]
219 rjmp bit0IsClr ;[02] executed if first expr false or second true
220 se0AndStore: ; executed only if both bits 0
221 st y+, x1 ;[15/17] cycles after start of byte
225 ifrset phase, USBMINUS ;[04] check phase only if D- changed
227 in phase, USBIN ;[06] <- phase (one cycle too late)
228 ori shift, 1 << 0 ;[07]
230 andi phase, USBMASK ;[08]
231 ifioset USBIN, USBMINUS ;[09] <--- sample 1
233 breq se0AndStore ;[11] if D- was 0 in bits 0 AND 1 and D+ was 0 in between, we have SE0
234 andi shift, ~(7 << 1) ;[12]
235 in phase, USBIN ;[13] <- phase
237 rjmp bit2AfterClr ;[15]
239 andi fix, ~(1 << 1) ;[16]
243 ifrclr phase, USBMINUS ;[12] check phase only if D- changed
245 in phase, USBIN ;[14] <- phase (one cycle too late)
246 ori shift, 1 << 1 ;[15]
249 ifioclr USBIN, USBMINUS ;[17] <--- sample 2
251 andi shift, ~(7 << 2) ;[19]
253 in phase, USBIN ;[21] <- phase
254 rjmp bit3AfterSet ;[22]
256 in phase, USBIN ;[22] <- phase (one cycle too late)
257 andi fix, ~(1 << 2) ;[23]
261 ifrset phase, USBMINUS ;[20] check phase only if D- changed
263 in phase, USBIN ;[22] <- phase (one cycle too late)
264 ori shift, 1 << 2 ;[23]
268 ifioset USBIN, USBMINUS ;[26] <--- sample 3
270 andi shift, ~(7 << 3) ;[28]
272 in phase, USBIN ;[30] <- phase
273 rjmp bit4AfterClr ;[31]
275 in phase, USBIN ;[31] <- phase (one cycle too late)
276 andi fix, ~(1 << 3) ;[32]
280 ifrclr phase, USBMINUS ;[29] check phase only if D- changed
282 in phase, USBIN ;[31] <- phase (one cycle too late)
283 ori shift, 1 << 3 ;[32]
285 mov data, fix ;[33] undo this move by swapping defines
290 ifioclr USBIN, USBMINUS ;[34] <--- sample 4
292 andi shift, ~(7 << 4) ;[36]
294 in phase, USBIN ;[38] <- phase
295 rjmp bit5AfterSet ;[39]
297 in phase, USBIN ;[39] <- phase (one cycle too late)
298 andi fix, ~(1 << 4) ;[40]
302 ifrset phase, USBMINUS ;[37] check phase only if D- changed
304 in phase, USBIN ;[39] <- phase (one cycle too late)
305 ori shift, 1 << 4 ;[40]
308 ifioset USBIN, USBMINUS ;[42] <--- sample 5
310 andi shift, ~(7 << 5) ;[44]
312 in phase, USBIN ;[46] <- phase
313 rjmp bit6AfterClr ;[47]
315 in phase, USBIN ;[47] <- phase (one cycle too late)
316 andi fix, ~(1 << 5) ;[48]
320 ifrclr phase, USBMINUS ;[45] check phase only if D- changed
322 in phase, USBIN ;[47] <- phase (one cycle too late)
323 ori shift, 1 << 5 ;[48]
326 brcs jumpToOverflow ;[50]
327 ifioclr USBIN, USBMINUS ;[51] <--- sample 6
329 andi shift, ~(3 << 6) ;[53]
331 in phase, USBIN ;[55] <- phase
333 rjmp bit7AfterSet ;[57]
339 andi fix, ~(1 << 6) ;[50]
342 ifrset phase, USBMINUS ;[54] check phase only if D- changed
344 in phase, USBIN ;[56] <- phase (one cycle too late)
345 ori shift, 1 << 6 ;[57]
348 ifioset USBIN, USBMINUS ;[59] <--- sample 7
350 andi shift, ~(1 << 7) ;[61]
352 in phase, USBIN ;[63] <- phase
354 rjmp bit0AfterClr ;[65] -> [00] == [67]
356 andi fix, ~(1 << 7) ;[58]
361 ifrset phase, USBMINUS ;[62] check phase only if D- changed
363 in phase, USBIN ;[64] <- phase (one cycle too late)
364 ori shift, 1 << 7 ;[65]
366 ;;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jump
372 #define data x1 /* we now have result in data, fix is reset to 0xff */
373 ifioset USBIN, USBMINUS ;[01] <--- sample 0
375 andi shift, ~(7 << 0) ;[03]
377 in phase, USBIN ;[05] <- phase
378 rjmp bit1AfterClr ;[06]
380 in phase, USBIN ;[06] <- phase (one cycle too late)
381 andi fix, ~(1 << 0) ;[07]
382 ifioclr USBIN, USBMINUS ;[00]
383 ifioset USBIN, USBPLUS ;[01]
384 rjmp bit0IsSet ;[02] executed if first expr false or second true
385 rjmp se0AndStore ;[03] executed only if both bits 0
387 ifrclr phase, USBMINUS ;[04] check phase only if D- changed
389 in phase, USBIN ;[06] <- phase (one cycle too late)
390 ori shift, 1 << 0 ;[07]
392 andi shift, ~(7 << 1) ;[08] compensated by "ori shift, 1<<1" if bit1IsClr
393 ifioclr USBIN, USBMINUS ;[09] <--- sample 1
396 nop2 ;[12] do not check for SE0 if bit 0 was 1
397 in phase, USBIN ;[14] <- phase (one cycle too late)
398 rjmp bit2AfterSet ;[15]
400 in phase, USBIN ;[13] <- phase
401 andi fix, ~(1 << 1) ;[14]
405 ifrset phase, USBMINUS ;[12] check phase only if D- changed
407 in phase, USBIN ;[14] <- phase (one cycle too late)
408 ori shift, 1 << 1 ;[15]
411 ifioset USBIN, USBMINUS ;[17] <--- sample 2
413 andi shift, ~(7 << 2) ;[19]
415 in phase, USBIN ;[21] <- phase
416 rjmp bit3AfterClr ;[22]
418 in phase, USBIN ;[22] <- phase (one cycle too late)
419 andi fix, ~(1 << 2) ;[23]
423 ifrclr phase, USBMINUS ;[20] check phase only if D- changed
425 in phase, USBIN ;[22] <- phase (one cycle too late)
426 ori shift, 1 << 2 ;[23]
430 ifioclr USBIN, USBMINUS ;[26] <--- sample 3
432 andi shift, ~(7 << 3) ;[28]
434 in phase, USBIN ;[30] <- phase
435 rjmp bit4AfterSet ;[31]
437 in phase, USBIN ;[31] <- phase (one cycle too late)
438 andi fix, ~(1 << 3) ;[32]
442 ifrset phase, USBMINUS ;[29] check phase only if D- changed
444 in phase, USBIN ;[31] <- phase (one cycle too late)
445 ori shift, 1 << 3 ;[32]
447 mov data, fix ;[33] undo this move by swapping defines
452 ifioset USBIN, USBMINUS ;[34] <--- sample 4
454 andi shift, ~(7 << 4) ;[36]
456 in phase, USBIN ;[38] <- phase
457 rjmp bit5AfterClr ;[39]
459 in phase, USBIN ;[39] <- phase (one cycle too late)
460 andi fix, ~(1 << 4) ;[40]
464 ifrclr phase, USBMINUS ;[37] check phase only if D- changed
466 in phase, USBIN ;[39] <- phase (one cycle too late)
467 ori shift, 1 << 4 ;[40]
470 ifioclr USBIN, USBMINUS ;[42] <--- sample 5
472 andi shift, ~(7 << 5) ;[44]
474 in phase, USBIN ;[46] <- phase
475 rjmp bit6AfterSet ;[47]
477 in phase, USBIN ;[47] <- phase (one cycle too late)
478 andi fix, ~(1 << 5) ;[48]
482 ifrset phase, USBMINUS ;[45] check phase only if D- changed
484 in phase, USBIN ;[47] <- phase (one cycle too late)
485 ori shift, 1 << 5 ;[48]
489 ifioset USBIN, USBMINUS ;[51] <--- sample 6
491 andi shift, ~(3 << 6) ;[53]
493 in phase, USBIN ;[55] <- phase
495 rjmp bit7AfterClr ;[57]
497 andi fix, ~(1 << 6) ;[50]
500 ifrclr phase, USBMINUS ;[54] check phase only if D- changed
502 in phase, USBIN ;[56] <- phase (one cycle too late)
503 ori shift, 1 << 6 ;[57]
505 ifioclr USBIN, USBMINUS ;[59] <--- sample 7
507 andi shift, ~(1 << 7) ;[61]
509 in phase, USBIN ;[63] <- phase
511 rjmp bit0AfterSet ;[65] -> [00] == [67]
513 andi fix, ~(1 << 7) ;[58]
517 macro POP_STANDARD ; 14 cycles
526 macro POP_RETI ; 5 cycles
532 #include "asmcommon.inc"
534 ;----------------------------------------------------------------------------
536 ;----------------------------------------------------------------------------
541 ror shift ;[-5] [11] [63]
542 brcc doExorN1 ;[-4] [64]
545 lsl shift ;[-1] compensate ror after rjmp stuffDelay
546 nop ;[00] stuffing consists of just waiting 8 cycles
547 rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear
550 ldi cnt, USBPID_NAK ;[-19]
551 rjmp sendCntAndReti ;[-18]
553 ldi cnt, USBPID_ACK ;[-17]
556 ldi YL, 0 ;[-15] R0 address is 0
559 ; rjmp usbSendAndReti fallthrough
563 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
564 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
565 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
568 ;pointer to data in 'Y'
569 ;number of bytes in 'cnt' -- including sync byte
570 ;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt]
571 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
573 in x2, USBDDR ;[-10] 10 cycles until SOP
574 ori x2, USBMASK ;[-9]
575 sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups)
576 out USBDDR, x2 ;[-6] <--- acquire bus
577 in x1, USBOUT ;[-5] port mirror for tx loop
578 ldi shift, 0x40 ;[-4] sync byte is first byte sent (we enter loop after ror)
579 ldi x2, USBMASK ;[-3]
581 eor x1, x2 ;[-2] [06] [62]
582 ldi x3, 6 ;[-1] [07] [63]
585 out USBOUT, x1 ;[00] [08] [64] <--- set bit
590 lsl shift ;[05] compensate ror after rjmp stuffDelay
591 rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear
593 eor x1, x2 ;[04] [12]
597 subi cnt, 171 ;[08] [16] trick: (3 * 171) & 0xff = 1
598 out USBOUT, x1 ;[09] [17] <--- set bit
599 brcs txBitloop ;[10] [27] [44]
606 lsl shift ;[49] compensate ror after rjmp stuffDelay
607 nop ;[50] stuffing consists of just waiting 8 cycles
608 rjmp stuff6Delay ;[51] after ror, C bit is reliably clear
610 eor x1, x2 ;[48] [56]
615 out USBOUT, x1 ;[51] <--- set bit
619 lsl shift ;[55] compensate ror after rjmp stuffDelay
620 rjmp stuff7Delay ;[56] after ror, C bit is reliably clear
622 eor x1, x2 ;[54] [62]
628 out USBOUT, x1 ;[60] [00]<--- set bit
629 brne txByteLoop ;[61] [01]
631 cbr x1, USBMASK ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles]
632 lds x2, usbNewDeviceAddr;[03]
633 lsl x2 ;[05] we compare with left shifted address
634 subi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0
636 out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
637 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
638 ;set address only after data packet was sent, not after handshake
639 breq skipAddrAssign ;[01]
640 sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer
642 ;end of usbDeviceAddress transfer
643 ldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
644 USB_STORE_PENDING(x2) ;[04]
645 ori x1, USBIDLE ;[05]
647 cbr x2, USBMASK ;[07] set both pins to input
649 cbr x3, USBMASK ;[09] configure no pullup on both pins
652 out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
653 out USBDDR, x2 ;[17] <-- release bus now
654 out USBOUT, x3 ;[18] <-- ensure no pull-up resistors are active
659 /*****************************************************************************
660 The following PHP script generates a code skeleton for the receiver routine:
664 function printCmdBuffer($thisBit)
668 $nextBit = ($thisBit + 1) % 8;
669 $s = ob_get_contents();
671 $s = str_replace("#", $thisBit, $s);
672 $s = str_replace("@", $nextBit, $s);
673 $lines = explode("\n", $s);
674 for($i = 0; $i < count($lines); $i++){
676 if(ereg("\\[([0-9-][0-9])\\]", $s, $regs)){
677 $c = $cycle + (int)$regs[1];
678 $s = ereg_replace("\\[[0-9-][0-9]\\]", sprintf("[%02d]", $c), $s);
685 function printBit($isAfterSet, $bitNum)
690 ifioclr USBIN, USBMINUS ;[00] <--- sample
692 andi shift, ~(7 << #) ;[02]
694 in phase, USBIN ;[04] <- phase
695 rjmp bit@AfterSet ;[05]
697 in phase, USBIN ;[05] <- phase (one cycle too late)
698 andi fix, ~(1 << #) ;[06]
702 ifrset phase, USBMINUS ;[03] check phase only if D- changed
704 in phase, USBIN ;[05] <- phase (one cycle too late)
705 ori shift, 1 << # ;[06]
709 ifioset USBIN, USBMINUS ;[00] <--- sample
711 andi shift, ~(7 << #) ;[02]
713 in phase, USBIN ;[04] <- phase
714 rjmp bit@AfterClr ;[05]
716 in phase, USBIN ;[05] <- phase (one cycle too late)
717 andi fix, ~(1 << #) ;[06]
721 ifrclr phase, USBMINUS ;[03] check phase only if D- changed
723 in phase, USBIN ;[05] <- phase (one cycle too late)
724 ori shift, 1 << # ;[06]
727 printCmdBuffer($bitNum);
730 $bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59);
731 for($i = 0; $i < 16; $i++){
733 $emitClrCode = ($i + (int)($i / 8)) % 2;
734 $cycle = $bitStartCycles[$bit];
736 printf("bit%dAfterClr:\n", $bit);
738 printf("bit%dAfterSet:\n", $bit);
741 echo " ***** ;[-1]\n";
742 printCmdBuffer($bit);
743 printBit(!$emitClrCode, $bit);
749 *****************************************************************************/