usbdrv/usbdrvasm128.inc

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

mercurial