Rev Author Line No. Line
3471 miho 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
5 * Tabsize: 4
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 $
9 */
10  
11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
12 * appropriate implementation!
13 */
14  
15 /*
16 General Description:
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%.
22  
23 See usbdrv.h for a description of the entire driver.
24  
25 LIMITATIONS
26 ===========
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
29 limitations:
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.
38  
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!
42  
43 Implementation notes:
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))
48  
49 sampling positions: (next even number in range [+/- 0.5])
50 cycle index range: 0 ... 66
51 bits:
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]
54  
55 bit number: 0 1 2 3 4 5 6 7
56 spare cycles 1 2 1 2 1 1 1 0
57  
58 operations to perform: duration cycle
59 ----------------
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
64 mov data, fix 1 -> 33
65 ser data 1 -> 41
66 subi cnt, 1 1 -> 49
67 brcs overflow 1 -> 50
68  
69 layout of samples and operations:
70 [##] = sample bit
71 <##> = sample phase
72 *##* = operation
73  
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 *****************************************************************************/
83  
84 /* we prefer positive expressions (do if condition) instead of negative
85 * (skip if condition), therefore use defines for skip instructions:
86 */
87 #define ifioclr sbis
88 #define ifioset sbic
89 #define ifrclr sbrs
90 #define ifrset sbrc
91  
92 /* The registers "fix" and "data" swap their meaning during the loop. Use
93 * defines to keep their name constant.
94 */
95 #define fix x2
96 #define data x1
97 #undef phase /* phase has a default definition to x4 */
98 #define phase x3
99  
100  
101 USB_INTR_VECTOR:
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
104 in YL, SREG ;1
105 push YL ;2
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.
114 waitForJ:
115 inc YL
116 sbis USBIN, USBMINUS
117 brne waitForJ ; just make sure we have ANY timeout
118 waitForK:
119 ;The following code results in a sampling window of 1/4 bit which meets the spec.
120 sbis USBIN, USBMINUS
121 rjmp foundK
122 sbis USBIN, USBMINUS
123 rjmp foundK
124 sbis USBIN, USBMINUS
125 rjmp foundK
126 sbis USBIN, USBMINUS
127 rjmp foundK
128 sbis USBIN, USBMINUS ;[0]
129 rjmp foundK ;[1]
130 #if USB_COUNT_SOF
131 lds YL, usbSofCount
132 inc YL
133 sts usbSofCount, YL
134 #endif /* USB_COUNT_SOF */
135 #ifdef USB_SOF_HOOK
136 USB_SOF_HOOK
137 #endif
138 rjmp sofError
139  
140 foundK:
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
144 push YH ;[2]
145 lds YL, usbInputBufOffset;[4]
146 clr YH ;[6]
147 subi YL, lo8(-(usbRxBuf));[7]
148 sbci YH, hi8(-(usbRxBuf));[8]
149  
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
154 haveTwoBitsK:
155 ;----------------------------------------------------------------------------
156 ; push more registers and initialize values while we sample the first bits:
157 ;----------------------------------------------------------------------------
158 #define fix x2
159 #define data x1
160  
161 push shift ;[12]
162 push x1 ;[14]
163 push x2 ;[16]
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]
167 push x3 ;[03]
168 push cnt ;[05]
169 push r0 ;[07]
170 ifioset USBIN, USBMINUS ;[09] <--- bit 1
171 ori shift, 1<<1 ;[10]
172 ser fix ;[11]
173 ldi cnt, USB_BUFSIZE ;[12]
174 mov data, shift ;[13]
175 lsl shift ;[14]
176 nop2 ;[15]
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
183 nop ;[23]
184 rjmp entryAfterClr ;[24]
185 jumpToEntryAfterSet:
186 rjmp entryAfterSet ;[24]
187  
188 ;----------------------------------------------------------------------------
189 ; Receiver loop (numbers in brackets are cycles within byte after instr)
190 ;----------------------------------------------------------------------------
191 #undef fix
192 #define fix x1
193 #undef data
194 #define data x2
195  
196 bit7IsSet:
197 ifrclr phase, USBMINUS ;[62] check phase only if D- changed
198 lpm ;[63]
199 in phase, USBIN ;[64] <- phase (one cycle too late)
200 ori shift, 1 << 7 ;[65]
201 nop ;[66]
202 ;;;;rjmp bit0AfterSet ; -> [00] == [67] moved block up to save jump
203 bit0AfterSet:
204 eor fix, shift ;[00]
205 #undef fix
206 #define fix x2
207 #undef data
208 #define data x1 /* we now have result in data, fix is reset to 0xff */
209 ifioclr USBIN, USBMINUS ;[01] <--- sample 0
210 rjmp bit0IsClr ;[02]
211 andi shift, ~(7 << 0) ;[03]
212 breq unstuff0s ;[04]
213 in phase, USBIN ;[05] <- phase
214 rjmp bit1AfterSet ;[06]
215 unstuff0s:
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
223 rjmp se0 ;[17/19]
224  
225 bit0IsClr:
226 ifrset phase, USBMINUS ;[04] check phase only if D- changed
227 lpm ;[05]
228 in phase, USBIN ;[06] <- phase (one cycle too late)
229 ori shift, 1 << 0 ;[07]
230 bit1AfterClr:
231 andi phase, USBMASK ;[08]
232 ifioset USBIN, USBMINUS ;[09] <--- sample 1
233 rjmp bit1IsSet ;[10]
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
237 breq unstuff1c ;[14]
238 rjmp bit2AfterClr ;[15]
239 unstuff1c:
240 andi fix, ~(1 << 1) ;[16]
241 nop2 ;[08]
242 nop2 ;[10]
243 bit1IsSet:
244 ifrclr phase, USBMINUS ;[12] check phase only if D- changed
245 lpm ;[13]
246 in phase, USBIN ;[14] <- phase (one cycle too late)
247 ori shift, 1 << 1 ;[15]
248 nop ;[16]
249 bit2AfterSet:
250 ifioclr USBIN, USBMINUS ;[17] <--- sample 2
251 rjmp bit2IsClr ;[18]
252 andi shift, ~(7 << 2) ;[19]
253 breq unstuff2s ;[20]
254 in phase, USBIN ;[21] <- phase
255 rjmp bit3AfterSet ;[22]
256 unstuff2s:
257 in phase, USBIN ;[22] <- phase (one cycle too late)
258 andi fix, ~(1 << 2) ;[23]
259 nop2 ;[16]
260 nop2 ;[18]
261 bit2IsClr:
262 ifrset phase, USBMINUS ;[20] check phase only if D- changed
263 lpm ;[21]
264 in phase, USBIN ;[22] <- phase (one cycle too late)
265 ori shift, 1 << 2 ;[23]
266 bit3AfterClr:
267 st y+, data ;[24]
268 entryAfterClr:
269 ifioset USBIN, USBMINUS ;[26] <--- sample 3
270 rjmp bit3IsSet ;[27]
271 andi shift, ~(7 << 3) ;[28]
272 breq unstuff3c ;[29]
273 in phase, USBIN ;[30] <- phase
274 rjmp bit4AfterClr ;[31]
275 unstuff3c:
276 in phase, USBIN ;[31] <- phase (one cycle too late)
277 andi fix, ~(1 << 3) ;[32]
278 nop2 ;[25]
279 nop2 ;[27]
280 bit3IsSet:
281 ifrclr phase, USBMINUS ;[29] check phase only if D- changed
282 lpm ;[30]
283 in phase, USBIN ;[31] <- phase (one cycle too late)
284 ori shift, 1 << 3 ;[32]
285 bit4AfterSet:
286 mov data, fix ;[33] undo this move by swapping defines
287 #undef fix
288 #define fix x1
289 #undef data
290 #define data x2
291 ifioclr USBIN, USBMINUS ;[34] <--- sample 4
292 rjmp bit4IsClr ;[35]
293 andi shift, ~(7 << 4) ;[36]
294 breq unstuff4s ;[37]
295 in phase, USBIN ;[38] <- phase
296 rjmp bit5AfterSet ;[39]
297 unstuff4s:
298 in phase, USBIN ;[39] <- phase (one cycle too late)
299 andi fix, ~(1 << 4) ;[40]
300 nop2 ;[33]
301 nop2 ;[35]
302 bit4IsClr:
303 ifrset phase, USBMINUS ;[37] check phase only if D- changed
304 lpm ;[38]
305 in phase, USBIN ;[39] <- phase (one cycle too late)
306 ori shift, 1 << 4 ;[40]
307 bit5AfterClr:
308 ser data ;[41]
309 ifioset USBIN, USBMINUS ;[42] <--- sample 5
310 rjmp bit5IsSet ;[43]
311 andi shift, ~(7 << 5) ;[44]
312 breq unstuff5c ;[45]
313 in phase, USBIN ;[46] <- phase
314 rjmp bit6AfterClr ;[47]
315 unstuff5c:
316 in phase, USBIN ;[47] <- phase (one cycle too late)
317 andi fix, ~(1 << 5) ;[48]
318 nop2 ;[41]
319 nop2 ;[43]
320 bit5IsSet:
321 ifrclr phase, USBMINUS ;[45] check phase only if D- changed
322 lpm ;[46]
323 in phase, USBIN ;[47] <- phase (one cycle too late)
324 ori shift, 1 << 5 ;[48]
325 bit6AfterSet:
326 subi cnt, 1 ;[49]
327 brcs jumpToOverflow ;[50]
328 ifioclr USBIN, USBMINUS ;[51] <--- sample 6
329 rjmp bit6IsClr ;[52]
330 andi shift, ~(3 << 6) ;[53]
331 cpi shift, 2 ;[54]
332 in phase, USBIN ;[55] <- phase
333 brlt unstuff6s ;[56]
334 rjmp bit7AfterSet ;[57]
335  
336 jumpToOverflow:
337 rjmp overflow
338  
339 unstuff6s:
340 andi fix, ~(1 << 6) ;[50]
341 lpm ;[51]
342 bit6IsClr:
343 ifrset phase, USBMINUS ;[54] check phase only if D- changed
344 lpm ;[55]
345 in phase, USBIN ;[56] <- phase (one cycle too late)
346 ori shift, 1 << 6 ;[57]
347 nop ;[58]
348 bit7AfterClr:
349 ifioset USBIN, USBMINUS ;[59] <--- sample 7
350 rjmp bit7IsSet ;[60]
351 andi shift, ~(1 << 7) ;[61]
352 cpi shift, 4 ;[62]
353 in phase, USBIN ;[63] <- phase
354 brlt unstuff7c ;[64]
355 rjmp bit0AfterClr ;[65] -> [00] == [67]
356 unstuff7c:
357 andi fix, ~(1 << 7) ;[58]
358 nop ;[59]
359 rjmp bit7IsSet ;[60]
360  
361 bit7IsClr:
362 ifrset phase, USBMINUS ;[62] check phase only if D- changed
363 lpm ;[63]
364 in phase, USBIN ;[64] <- phase (one cycle too late)
365 ori shift, 1 << 7 ;[65]
366 nop ;[66]
367 ;;;;rjmp bit0AfterClr ; -> [00] == [67] moved block up to save jump
368 bit0AfterClr:
369 eor fix, shift ;[00]
370 #undef fix
371 #define fix x2
372 #undef data
373 #define data x1 /* we now have result in data, fix is reset to 0xff */
374 ifioset USBIN, USBMINUS ;[01] <--- sample 0
375 rjmp bit0IsSet ;[02]
376 andi shift, ~(7 << 0) ;[03]
377 breq unstuff0c ;[04]
378 in phase, USBIN ;[05] <- phase
379 rjmp bit1AfterClr ;[06]
380 unstuff0c:
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
387 bit0IsSet:
388 ifrclr phase, USBMINUS ;[04] check phase only if D- changed
389 lpm ;[05]
390 in phase, USBIN ;[06] <- phase (one cycle too late)
391 ori shift, 1 << 0 ;[07]
392 bit1AfterSet:
393 andi shift, ~(7 << 1) ;[08] compensated by "ori shift, 1<<1" if bit1IsClr
394 ifioclr USBIN, USBMINUS ;[09] <--- sample 1
395 rjmp bit1IsClr ;[10]
396 breq unstuff1s ;[11]
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]
400 unstuff1s:
401 in phase, USBIN ;[13] <- phase
402 andi fix, ~(1 << 1) ;[14]
403 lpm ;[07]
404 nop2 ;[10]
405 bit1IsClr:
406 ifrset phase, USBMINUS ;[12] check phase only if D- changed
407 lpm ;[13]
408 in phase, USBIN ;[14] <- phase (one cycle too late)
409 ori shift, 1 << 1 ;[15]
410 nop ;[16]
411 bit2AfterClr:
412 ifioset USBIN, USBMINUS ;[17] <--- sample 2
413 rjmp bit2IsSet ;[18]
414 andi shift, ~(7 << 2) ;[19]
415 breq unstuff2c ;[20]
416 in phase, USBIN ;[21] <- phase
417 rjmp bit3AfterClr ;[22]
418 unstuff2c:
419 in phase, USBIN ;[22] <- phase (one cycle too late)
420 andi fix, ~(1 << 2) ;[23]
421 nop2 ;[16]
422 nop2 ;[18]
423 bit2IsSet:
424 ifrclr phase, USBMINUS ;[20] check phase only if D- changed
425 lpm ;[21]
426 in phase, USBIN ;[22] <- phase (one cycle too late)
427 ori shift, 1 << 2 ;[23]
428 bit3AfterSet:
429 st y+, data ;[24]
430 entryAfterSet:
431 ifioclr USBIN, USBMINUS ;[26] <--- sample 3
432 rjmp bit3IsClr ;[27]
433 andi shift, ~(7 << 3) ;[28]
434 breq unstuff3s ;[29]
435 in phase, USBIN ;[30] <- phase
436 rjmp bit4AfterSet ;[31]
437 unstuff3s:
438 in phase, USBIN ;[31] <- phase (one cycle too late)
439 andi fix, ~(1 << 3) ;[32]
440 nop2 ;[25]
441 nop2 ;[27]
442 bit3IsClr:
443 ifrset phase, USBMINUS ;[29] check phase only if D- changed
444 lpm ;[30]
445 in phase, USBIN ;[31] <- phase (one cycle too late)
446 ori shift, 1 << 3 ;[32]
447 bit4AfterClr:
448 mov data, fix ;[33] undo this move by swapping defines
449 #undef fix
450 #define fix x1
451 #undef data
452 #define data x2
453 ifioset USBIN, USBMINUS ;[34] <--- sample 4
454 rjmp bit4IsSet ;[35]
455 andi shift, ~(7 << 4) ;[36]
456 breq unstuff4c ;[37]
457 in phase, USBIN ;[38] <- phase
458 rjmp bit5AfterClr ;[39]
459 unstuff4c:
460 in phase, USBIN ;[39] <- phase (one cycle too late)
461 andi fix, ~(1 << 4) ;[40]
462 nop2 ;[33]
463 nop2 ;[35]
464 bit4IsSet:
465 ifrclr phase, USBMINUS ;[37] check phase only if D- changed
466 lpm ;[38]
467 in phase, USBIN ;[39] <- phase (one cycle too late)
468 ori shift, 1 << 4 ;[40]
469 bit5AfterSet:
470 ser data ;[41]
471 ifioclr USBIN, USBMINUS ;[42] <--- sample 5
472 rjmp bit5IsClr ;[43]
473 andi shift, ~(7 << 5) ;[44]
474 breq unstuff5s ;[45]
475 in phase, USBIN ;[46] <- phase
476 rjmp bit6AfterSet ;[47]
477 unstuff5s:
478 in phase, USBIN ;[47] <- phase (one cycle too late)
479 andi fix, ~(1 << 5) ;[48]
480 nop2 ;[41]
481 nop2 ;[43]
482 bit5IsClr:
483 ifrset phase, USBMINUS ;[45] check phase only if D- changed
484 lpm ;[46]
485 in phase, USBIN ;[47] <- phase (one cycle too late)
486 ori shift, 1 << 5 ;[48]
487 bit6AfterClr:
488 subi cnt, 1 ;[49]
489 brcs overflow ;[50]
490 ifioset USBIN, USBMINUS ;[51] <--- sample 6
491 rjmp bit6IsSet ;[52]
492 andi shift, ~(3 << 6) ;[53]
493 cpi shift, 2 ;[54]
494 in phase, USBIN ;[55] <- phase
495 brlt unstuff6c ;[56]
496 rjmp bit7AfterClr ;[57]
497 unstuff6c:
498 andi fix, ~(1 << 6) ;[50]
499 lpm ;[51]
500 bit6IsSet:
501 ifrclr phase, USBMINUS ;[54] check phase only if D- changed
502 lpm ;[55]
503 in phase, USBIN ;[56] <- phase (one cycle too late)
504 ori shift, 1 << 6 ;[57]
505 bit7AfterSet:
506 ifioclr USBIN, USBMINUS ;[59] <--- sample 7
507 rjmp bit7IsClr ;[60]
508 andi shift, ~(1 << 7) ;[61]
509 cpi shift, 4 ;[62]
510 in phase, USBIN ;[63] <- phase
511 brlt unstuff7s ;[64]
512 rjmp bit0AfterSet ;[65] -> [00] == [67]
513 unstuff7s:
514 andi fix, ~(1 << 7) ;[58]
515 nop ;[59]
516 rjmp bit7IsClr ;[60]
517  
518 macro POP_STANDARD ; 14 cycles
519 pop r0
520 pop cnt
521 pop x3
522 pop x2
523 pop x1
524 pop shift
525 pop YH
526 endm
527 macro POP_RETI ; 5 cycles
528 pop YL
529 out SREG, YL
530 pop YL
531 endm
532  
533 #include "asmcommon.inc"
534  
535 ;----------------------------------------------------------------------------
536 ; Transmitting data
537 ;----------------------------------------------------------------------------
538  
539 txByteLoop:
540 txBitloop:
541 stuffN1Delay: ; [03]
542 ror shift ;[-5] [11] [63]
543 brcc doExorN1 ;[-4] [64]
544 subi x3, 1 ;[-3]
545 brne commonN1 ;[-2]
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
549  
550 sendNakAndReti:
551 ldi cnt, USBPID_NAK ;[-19]
552 rjmp sendCntAndReti ;[-18]
553 sendAckAndReti:
554 ldi cnt, USBPID_ACK ;[-17]
555 sendCntAndReti:
556 mov r0, cnt ;[-16]
557 ldi YL, 0 ;[-15] R0 address is 0
558 ldi YH, 0 ;[-14]
559 ldi cnt, 2 ;[-13]
560 ; rjmp usbSendAndReti fallthrough
561  
562 ; USB spec says:
563 ; idle = J
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)
567  
568 ;usbSend:
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)
573 usbSendAndReti:
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]
581 doExorN1:
582 eor x1, x2 ;[-2] [06] [62]
583 ldi x3, 6 ;[-1] [07] [63]
584 commonN1:
585 stuffN2Delay:
586 out USBOUT, x1 ;[00] [08] [64] <--- set bit
587 ror shift ;[01]
588 brcc doExorN2 ;[02]
589 subi x3, 1 ;[03]
590 brne commonN2 ;[04]
591 lsl shift ;[05] compensate ror after rjmp stuffDelay
592 rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear
593 doExorN2:
594 eor x1, x2 ;[04] [12]
595 ldi x3, 6 ;[05] [13]
596 commonN2:
597 nop2 ;[06] [14]
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]
601  
602 stuff6Delay:
603 ror shift ;[45] [53]
604 brcc doExor6 ;[46]
605 subi x3, 1 ;[47]
606 brne common6 ;[48]
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
610 doExor6:
611 eor x1, x2 ;[48] [56]
612 ldi x3, 6 ;[49]
613 common6:
614 stuff7Delay:
615 ror shift ;[50] [58]
616 out USBOUT, x1 ;[51] <--- set bit
617 brcc doExor7 ;[52]
618 subi x3, 1 ;[53]
619 brne common7 ;[54]
620 lsl shift ;[55] compensate ror after rjmp stuffDelay
621 rjmp stuff7Delay ;[56] after ror, C bit is reliably clear
622 doExor7:
623 eor x1, x2 ;[54] [62]
624 ldi x3, 6 ;[55]
625 common7:
626 ld shift, y+ ;[56]
627 nop ;[58]
628 tst cnt ;[59]
629 out USBOUT, x1 ;[60] [00]<--- set bit
630 brne txByteLoop ;[61] [01]
631 ;make SE0:
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
636 sbci YH, 0 ;[07]
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
642 skipAddrAssign:
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]
647 in x2, USBDDR ;[06]
648 cbr x2, USBMASK ;[07] set both pins to input
649 mov x3, x1 ;[08]
650 cbr x3, USBMASK ;[09] configure no pullup on both pins
651 lpm ;[10]
652 lpm ;[13]
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
656 rjmp doReturn
657  
658  
659  
660 /*****************************************************************************
661 The following PHP script generates a code skeleton for the receiver routine:
662  
663 <?php
664  
665 function printCmdBuffer($thisBit)
666 {
667 global $cycle;
668  
669 $nextBit = ($thisBit + 1) % 8;
670 $s = ob_get_contents();
671 ob_end_clean();
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++){
676 $s = $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);
680 }
681 if(strlen($s) > 0)
682 echo "$s\n";
683 }
684 }
685  
686 function printBit($isAfterSet, $bitNum)
687 {
688 ob_start();
689 if($isAfterSet){
690 ?>
691 ifioclr USBIN, USBMINUS ;[00] <--- sample
692 rjmp bit#IsClr ;[01]
693 andi shift, ~(7 << #) ;[02]
694 breq unstuff#s ;[03]
695 in phase, USBIN ;[04] <- phase
696 rjmp bit@AfterSet ;[05]
697 unstuff#s:
698 in phase, USBIN ;[05] <- phase (one cycle too late)
699 andi fix, ~(1 << #) ;[06]
700 nop2 ;[-1]
701 nop2 ;[01]
702 bit#IsClr:
703 ifrset phase, USBMINUS ;[03] check phase only if D- changed
704 lpm ;[04]
705 in phase, USBIN ;[05] <- phase (one cycle too late)
706 ori shift, 1 << # ;[06]
707 <?php
708 }else{
709 ?>
710 ifioset USBIN, USBMINUS ;[00] <--- sample
711 rjmp bit#IsSet ;[01]
712 andi shift, ~(7 << #) ;[02]
713 breq unstuff#c ;[03]
714 in phase, USBIN ;[04] <- phase
715 rjmp bit@AfterClr ;[05]
716 unstuff#c:
717 in phase, USBIN ;[05] <- phase (one cycle too late)
718 andi fix, ~(1 << #) ;[06]
719 nop2 ;[-1]
720 nop2 ;[01]
721 bit#IsSet:
722 ifrclr phase, USBMINUS ;[03] check phase only if D- changed
723 lpm ;[04]
724 in phase, USBIN ;[05] <- phase (one cycle too late)
725 ori shift, 1 << # ;[06]
726 <?php
727 }
728 printCmdBuffer($bitNum);
729 }
730  
731 $bitStartCycles = array(1, 9, 17, 26, 34, 42, 51, 59);
732 for($i = 0; $i < 16; $i++){
733 $bit = $i % 8;
734 $emitClrCode = ($i + (int)($i / 8)) % 2;
735 $cycle = $bitStartCycles[$bit];
736 if($emitClrCode){
737 printf("bit%dAfterClr:\n", $bit);
738 }else{
739 printf("bit%dAfterSet:\n", $bit);
740 }
741 ob_start();
742 echo " ***** ;[-1]\n";
743 printCmdBuffer($bit);
744 printBit(!$emitClrCode, $bit);
745 if($i == 7)
746 echo "\n";
747 }
748  
749 ?>
750 *****************************************************************************/