1 /* Name: usbdrvasm128.inc
2 * Project: AVR USB driver
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 692 2008-11-07 15:07:40Z 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 is between bit 0 and bit 1 where the EOP condition
35 may not be reliable when a hub is used. It should be in bit 1.
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
221 rjmp se0AndStore ;[03] executed only if both bits 0
223 ifrset phase, USBMINUS ;[04] check phase only if D- changed
225 in phase, USBIN ;[06] <- phase (one cycle too late)
226 ori shift, 1 << 0 ;[07]
228 andi phase, USBMASK ;[08]
229 ifioset USBIN, USBMINUS ;[09] <--- sample 1
231 breq jumpToSe0AndStore ;[11]
232 andi shift, ~(7 << 1) ;[12]
233 in phase, USBIN ;[13] <- phase
235 rjmp bit2AfterClr ;[15]
237 andi fix, ~(1 << 1) ;[16]
241 ifrclr phase, USBMINUS ;[12] check phase only if D- changed
243 in phase, USBIN ;[14] <- phase (one cycle too late)
244 ori shift, 1 << 1 ;[15]
247 ifioclr USBIN, USBMINUS ;[17] <--- sample 2
249 andi shift, ~(7 << 2) ;[19]
251 in phase, USBIN ;[21] <- phase
252 rjmp bit3AfterSet ;[22]
254 in phase, USBIN ;[22] <- phase (one cycle too late)
255 andi fix, ~(1 << 2) ;[23]
259 ifrset phase, USBMINUS ;[20] check phase only if D- changed
261 in phase, USBIN ;[22] <- phase (one cycle too late)
262 ori shift, 1 << 2 ;[23]
266 ifioset USBIN, USBMINUS ;[26] <--- sample 3
268 andi shift, ~(7 << 3) ;[28]
270 in phase, USBIN ;[30] <- phase
271 rjmp bit4AfterClr ;[31]
273 in phase, USBIN ;[31] <- phase (one cycle too late)
274 andi fix, ~(1 << 3) ;[32]
278 ifrclr phase, USBMINUS ;[29] check phase only if D- changed
280 in phase, USBIN ;[31] <- phase (one cycle too late)
281 ori shift, 1 << 3 ;[32]
283 mov data, fix ;[33] undo this move by swapping defines
288 ifioclr USBIN, USBMINUS ;[34] <--- sample 4
290 andi shift, ~(7 << 4) ;[36]
292 in phase, USBIN ;[38] <- phase
293 rjmp bit5AfterSet ;[39]
295 in phase, USBIN ;[39] <- phase (one cycle too late)
296 andi fix, ~(1 << 4) ;[40]
300 ifrset phase, USBMINUS ;[37] check phase only if D- changed
302 in phase, USBIN ;[39] <- phase (one cycle too late)
303 ori shift, 1 << 4 ;[40]
306 ifioset USBIN, USBMINUS ;[42] <--- sample 5
308 andi shift, ~(7 << 5) ;[44]
310 in phase, USBIN ;[46] <- phase
311 rjmp bit6AfterClr ;[47]
313 in phase, USBIN ;[47] <- phase (one cycle too late)
314 andi fix, ~(1 << 5) ;[48]
318 ifrclr phase, USBMINUS ;[45] check phase only if D- changed
320 in phase, USBIN ;[47] <- phase (one cycle too late)
321 ori shift, 1 << 5 ;[48]
324 brcs jumpToOverflow ;[50]
325 ifioclr USBIN, USBMINUS ;[51] <--- sample 6
327 andi shift, ~(3 << 6) ;[53]
329 in phase, USBIN ;[55] <- phase
331 rjmp bit7AfterSet ;[57]
337 andi fix, ~(1 << 6) ;[50]
340 ifrset phase, USBMINUS ;[54] check phase only if D- changed
342 in phase, USBIN ;[56] <- phase (one cycle too late)
343 ori shift, 1 << 6 ;[57]
346 ifioset USBIN, USBMINUS ;[59] <--- sample 7
348 andi shift, ~(1 << 7) ;[61]
350 in phase, USBIN ;[63] <- phase
352 rjmp bit0AfterClr ;[65] -> [00] == [67]
354 andi fix, ~(1 << 7) ;[58]
359 st y+, x1 ;[15/17] cycles after start of byte
363 ifrset phase, USBMINUS ;[62] check phase only if D- changed
365 in phase, USBIN ;[64] <- phase (one cycle too late)
366 ori shift, 1 << 7 ;[65]
368 ;;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jump
374 #define data x1 /* we now have result in data, fix is reset to 0xff */
375 ifioset USBIN, USBMINUS ;[01] <--- sample 0
377 andi shift, ~(7 << 0) ;[03]
379 in phase, USBIN ;[05] <- phase
380 rjmp bit1AfterClr ;[06]
382 in phase, USBIN ;[06] <- phase (one cycle too late)
383 andi fix, ~(1 << 0) ;[07]
384 ifioclr USBIN, USBMINUS ;[00]
385 ifioset USBIN, USBPLUS ;[01]
386 rjmp bit0IsSet ;[02] executed if first expr false or second true
387 rjmp se0AndStore ;[03] executed only if both bits 0
389 ifrclr phase, USBMINUS ;[04] check phase only if D- changed
391 in phase, USBIN ;[06] <- phase (one cycle too late)
392 ori shift, 1 << 0 ;[07]
394 andi phase, USBMASK ;[08]
395 ifioclr USBIN, USBMINUS ;[09] <--- sample 1
397 andi shift, ~(7 << 1) ;[11]
399 in phase, USBIN ;[13] <- phase
401 rjmp bit2AfterSet ;[15]
403 in phase, USBIN ;[14] <- phase (one cycle too late)
404 andi fix, ~(1 << 1) ;[15]
408 ifrset phase, USBMINUS ;[12] check phase only if D- changed
410 in phase, USBIN ;[14] <- phase (one cycle too late)
411 breq se0AndStore ;[15] if we come from unstuff1s, Z bit is never set
412 ori shift, 1 << 1 ;[16]
414 ifioset USBIN, USBMINUS ;[17] <--- sample 2
416 andi shift, ~(7 << 2) ;[19]
418 in phase, USBIN ;[21] <- phase
419 rjmp bit3AfterClr ;[22]
421 in phase, USBIN ;[22] <- phase (one cycle too late)
422 andi fix, ~(1 << 2) ;[23]
426 ifrclr phase, USBMINUS ;[20] check phase only if D- changed
428 in phase, USBIN ;[22] <- phase (one cycle too late)
429 ori shift, 1 << 2 ;[23]
433 ifioclr USBIN, USBMINUS ;[26] <--- sample 3
435 andi shift, ~(7 << 3) ;[28]
437 in phase, USBIN ;[30] <- phase
438 rjmp bit4AfterSet ;[31]
440 in phase, USBIN ;[31] <- phase (one cycle too late)
441 andi fix, ~(1 << 3) ;[32]
445 ifrset phase, USBMINUS ;[29] check phase only if D- changed
447 in phase, USBIN ;[31] <- phase (one cycle too late)
448 ori shift, 1 << 3 ;[32]
450 mov data, fix ;[33] undo this move by swapping defines
455 ifioset USBIN, USBMINUS ;[34] <--- sample 4
457 andi shift, ~(7 << 4) ;[36]
459 in phase, USBIN ;[38] <- phase
460 rjmp bit5AfterClr ;[39]
462 in phase, USBIN ;[39] <- phase (one cycle too late)
463 andi fix, ~(1 << 4) ;[40]
467 ifrclr phase, USBMINUS ;[37] check phase only if D- changed
469 in phase, USBIN ;[39] <- phase (one cycle too late)
470 ori shift, 1 << 4 ;[40]
473 ifioclr USBIN, USBMINUS ;[42] <--- sample 5
475 andi shift, ~(7 << 5) ;[44]
477 in phase, USBIN ;[46] <- phase
478 rjmp bit6AfterSet ;[47]
480 in phase, USBIN ;[47] <- phase (one cycle too late)
481 andi fix, ~(1 << 5) ;[48]
485 ifrset phase, USBMINUS ;[45] check phase only if D- changed
487 in phase, USBIN ;[47] <- phase (one cycle too late)
488 ori shift, 1 << 5 ;[48]
492 ifioset USBIN, USBMINUS ;[51] <--- sample 6
494 andi shift, ~(3 << 6) ;[53]
496 in phase, USBIN ;[55] <- phase
498 rjmp bit7AfterClr ;[57]
500 andi fix, ~(1 << 6) ;[50]
503 ifrclr phase, USBMINUS ;[54] check phase only if D- changed
505 in phase, USBIN ;[56] <- phase (one cycle too late)
506 ori shift, 1 << 6 ;[57]
508 ifioclr USBIN, USBMINUS ;[59] <--- sample 7
510 andi shift, ~(1 << 7) ;[61]
512 in phase, USBIN ;[63] <- phase
514 rjmp bit0AfterSet ;[65] -> [00] == [67]
516 andi fix, ~(1 << 7) ;[58]
520 macro POP_STANDARD ; 14 cycles
529 macro POP_RETI ; 5 cycles
535 #include "asmcommon.inc"
537 ;----------------------------------------------------------------------------
539 ;----------------------------------------------------------------------------
544 ror shift ;[-5] [11] [63]
545 brcc doExorN1 ;[-4] [64]
548 lsl shift ;[-1] compensate ror after rjmp stuffDelay
549 nop ;[00] stuffing consists of just waiting 8 cycles
550 rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear
553 ldi cnt, USBPID_NAK ;[-19]
554 rjmp sendCntAndReti ;[-18]
556 ldi cnt, USBPID_ACK ;[-17]
559 ldi YL, 0 ;[-15] R0 address is 0
562 ; rjmp usbSendAndReti fallthrough
566 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
567 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
568 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
571 ;pointer to data in 'Y'
572 ;number of bytes in 'cnt' -- including sync byte
573 ;uses: x1...x3, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x3 = bitstuff cnt]
574 ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction)
576 in x2, USBDDR ;[-10] 10 cycles until SOP
577 ori x2, USBMASK ;[-9]
578 sbi USBOUT, USBMINUS ;[-8] prepare idle state; D+ and D- must have been 0 (no pullups)
579 out USBDDR, x2 ;[-6] <--- acquire bus
580 in x1, USBOUT ;[-5] port mirror for tx loop
581 ldi shift, 0x40 ;[-4] sync byte is first byte sent (we enter loop after ror)
582 ldi x2, USBMASK ;[-3]
584 eor x1, x2 ;[-2] [06] [62]
585 ldi x3, 6 ;[-1] [07] [63]
588 out USBOUT, x1 ;[00] [08] [64] <--- set bit
593 lsl shift ;[05] compensate ror after rjmp stuffDelay
594 rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear
596 eor x1, x2 ;[04] [12]
600 subi cnt, 171 ;[08] [16] trick: (3 * 171) & 0xff = 1
601 out USBOUT, x1 ;[09] [17] <--- set bit
602 brcs txBitloop ;[10] [27] [44]
609 lsl shift ;[49] compensate ror after rjmp stuffDelay
610 nop ;[50] stuffing consists of just waiting 8 cycles
611 rjmp stuff6Delay ;[51] after ror, C bit is reliably clear
613 eor x1, x2 ;[48] [56]
618 out USBOUT, x1 ;[51] <--- set bit
622 lsl shift ;[55] compensate ror after rjmp stuffDelay
623 rjmp stuff7Delay ;[56] after ror, C bit is reliably clear
625 eor x1, x2 ;[54] [62]
631 out USBOUT, x1 ;[60] [00]<--- set bit
632 brne txByteLoop ;[61] [01]
634 cbr x1, USBMASK ;[02] prepare SE0 [spec says EOP may be 15 to 18 cycles]
635 lds x2, usbNewDeviceAddr;[03]
636 lsl x2 ;[05] we compare with left shifted address
637 subi YL, 2 + 0 ;[06] Only assign address on data packets, not ACK/NAK in r0
639 out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
640 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
641 ;set address only after data packet was sent, not after handshake
642 breq skipAddrAssign ;[01]
643 sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer
645 ;end of usbDeviceAddress transfer
646 ldi x2, 1<<USB_INTR_PENDING_BIT;[03] int0 occurred during TX -- clear pending flag
647 USB_STORE_PENDING(x2) ;[04]
648 ori x1, USBIDLE ;[05]
650 cbr x2, USBMASK ;[07] set both pins to input
652 cbr x3, USBMASK ;[09] configure no pullup on both pins
655 out USBOUT, x1 ;[16] <-- out J (idle) -- end of SE0 (EOP signal)
656 out USBDDR, x2 ;[17] <-- release bus now
657 out USBOUT, x3 ;[18] <-- ensure no pull-up resistors are active
662 /*****************************************************************************
663 The following PHP script generates a code skeleton for the receiver routine:
667 function printCmdBuffer($thisBit)
671 $nextBit = ($thisBit + 1) % 8;
672 $s = ob_get_contents();
674 $s = str_replace("#", $thisBit, $s);
675 $s = str_replace("@", $nextBit, $s);
676 $lines = explode("\n", $s);
677 for($i = 0; $i < count($lines); $i++){
679 if(ereg("\\[([0-9-][0-9])\\]", $s, $regs)){
680 $c = $cycle + (int)$regs[1];
681 $s = ereg_replace("\\[[0-9-][0-9]\\]", sprintf("[%02d]", $c), $s);
688 function printBit($isAfterSet, $bitNum)
693 ifioclr USBIN, USBMINUS ;[00] <--- sample
695 andi shift, ~(7 << #) ;[02]
697 in phase, USBIN ;[04] <- phase
698 rjmp bit@AfterSet ;[05]
700 in phase, USBIN ;[05] <- phase (one cycle too late)
701 andi fix, ~(1 << #) ;[06]
705 ifrset phase, USBMINUS ;[03] check phase only if D- changed
707 in phase, USBIN ;[05] <- phase (one cycle too late)
708 ori shift, 1 << # ;[06]
712 ifioset USBIN, USBMINUS ;[00] <--- sample
714 andi shift, ~(7 << #) ;[02]
716 in phase, USBIN ;[04] <- phase
717 rjmp bit@AfterClr ;[05]
719 in phase, USBIN ;[05] <- phase (one cycle too late)
720 andi fix, ~(1 << #) ;[06]
724 ifrclr phase, USBMINUS ;[03] check phase only if D- changed
726 in phase, USBIN ;[05] <- phase (one cycle too late)
727 ori shift, 1 << # ;[06]
730 printCmdBuffer($bitNum);
733 $bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59);
734 for($i = 0; $i < 16; $i++){
736 $emitClrCode = ($i + (int)($i / 8)) % 2;
737 $cycle = $bitStartCycles[$bit];
739 printf("bit%dAfterClr:\n", $bit);
741 printf("bit%dAfterSet:\n", $bit);
744 echo " ***** ;[-1]\n";
745 printCmdBuffer($bit);
746 printBit(!$emitClrCode, $bit);
752 *****************************************************************************/