Subversion Repositories group.electronics

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
33 pfowler 1
/* Name: usbdrvasm165.inc
2
 * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
3
 * Author: Christian Starkjohann
4
 * Creation Date: 2007-04-22
5
 * Tabsize: 4
6
 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7
 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
8
 * Revision: $Id$
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 16.5 MHz version of the USB driver. It is intended for the
18
ATTiny45 and similar controllers running on 16.5 MHz internal RC oscillator.
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
Since almost all of this code is timing critical, don't change unless you
25
really know what you are doing! Many parts require not only a maximum number
26
of CPU cycles, but even an exact number of cycles!
27
*/
28
 
29
;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
30
;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
31
;max allowable interrupt latency: 59 cycles -> max 52 cycles interrupt disable
32
;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes
33
;nominal frequency: 16.5 MHz -> 11 cycles per bit
34
; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%)
35
; Numbers in brackets are clocks counted from center of last sync bit
36
; when instruction starts
37
 
38
 
39
USB_INTR_VECTOR:
40
;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt
41
    push    YL                  ;[-23] push only what is necessary to sync with edge ASAP
42
    in      YL, SREG            ;[-21]
43
    push    YL                  ;[-20]
44
;----------------------------------------------------------------------------
45
; Synchronize with sync pattern:
46
;----------------------------------------------------------------------------
47
;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
48
;sync up with J to K edge during sync pattern -- use fastest possible loops
49
;The first part waits at most 1 bit long since we must be in sync pattern.
50
;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
51
;waitForJ, ensure that this prerequisite is met.
52
waitForJ:
53
    inc     YL
54
    sbis    USBIN, USBMINUS
55
    brne    waitForJ        ; just make sure we have ANY timeout
56
waitForK:
57
;The following code results in a sampling window of < 1/4 bit which meets the spec.
58
    sbis    USBIN, USBMINUS     ;[-15]
59
    rjmp    foundK              ;[-14]
60
    sbis    USBIN, USBMINUS
61
    rjmp    foundK
62
    sbis    USBIN, USBMINUS
63
    rjmp    foundK
64
    sbis    USBIN, USBMINUS
65
    rjmp    foundK
66
    sbis    USBIN, USBMINUS
67
    rjmp    foundK
68
    sbis    USBIN, USBMINUS
69
    rjmp    foundK
70
#if USB_COUNT_SOF
71
    lds     YL, usbSofCount
72
    inc     YL
73
    sts     usbSofCount, YL
74
#endif  /* USB_COUNT_SOF */
75
#ifdef USB_SOF_HOOK
76
    USB_SOF_HOOK
77
#endif
78
    rjmp    sofError
79
foundK:                         ;[-12]
80
;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
81
;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
82
;are cycles from center of first sync (double K) bit after the instruction
83
    push    r0                  ;[-12]
84
;   [---]                       ;[-11]
85
    push    YH                  ;[-10]
86
;   [---]                       ;[-9]
87
    lds     YL, usbInputBufOffset;[-8]
88
;   [---]                       ;[-7]
89
    clr     YH                  ;[-6]
90
    subi    YL, lo8(-(usbRxBuf));[-5] [rx loop init]
91
    sbci    YH, hi8(-(usbRxBuf));[-4] [rx loop init]
92
    mov     r0, x2              ;[-3] [rx loop init]
93
    sbis    USBIN, USBMINUS     ;[-2] we want two bits K (sample 2 cycles too early)
94
    rjmp    haveTwoBitsK        ;[-1]
95
    pop     YH                  ;[0] undo the pushes from before
96
    pop     r0                  ;[2]
97
    rjmp    waitForK            ;[4] this was not the end of sync, retry
98
; The entire loop from waitForK until rjmp waitForK above must not exceed two
99
; bit times (= 22 cycles).
100
 
101
;----------------------------------------------------------------------------
102
; push more registers and initialize values while we sample the first bits:
103
;----------------------------------------------------------------------------
104
haveTwoBitsK:               ;[1]
105
    push    shift           ;[1]
106
    push    x1              ;[3]
107
    push    x2              ;[5]
108
    push    x3              ;[7]
109
    ldi     shift, 0xff     ;[9] [rx loop init]
110
    ori     x3, 0xff        ;[10] [rx loop init] == ser x3, clear zero flag
111
 
112
    in      x1, USBIN       ;[11] <-- sample bit 0
113
    bst     x1, USBMINUS    ;[12]
114
    bld     shift, 0        ;[13]
115
    push    x4              ;[14] == phase
116
;   [---]                   ;[15]
117
    push    cnt             ;[16]
118
;   [---]                   ;[17]
119
    ldi     phase, 0        ;[18] [rx loop init]
120
    ldi     cnt, USB_BUFSIZE;[19] [rx loop init]
121
    rjmp    rxbit1          ;[20]
122
;   [---]                   ;[21]
123
 
124
;----------------------------------------------------------------------------
125
; Receiver loop (numbers in brackets are cycles within byte after instr)
126
;----------------------------------------------------------------------------
127
/*
128
byte oriented operations done during loop:
129
bit 0: store data
130
bit 1: SE0 check
131
bit 2: overflow check
132
bit 3: catch up
133
bit 4: rjmp to achieve conditional jump range
134
bit 5: PLL
135
bit 6: catch up
136
bit 7: jump, fixup bitstuff
137
; 87 [+ 2] cycles
138
------------------------------------------------------------------
139
*/
140
continueWithBit5:
141
    in      x2, USBIN       ;[055] <-- bit 5
142
    eor     r0, x2          ;[056]
143
    or      phase, r0       ;[057]
144
    sbrc    phase, USBMINUS ;[058]
145
    lpm                     ;[059] optional nop3; modifies r0
146
    in      phase, USBIN    ;[060] <-- phase
147
    eor     x1, x2          ;[061]
148
    bst     x1, USBMINUS    ;[062]
149
    bld     shift, 5        ;[063]
150
    andi    shift, 0x3f     ;[064]
151
    in      x1, USBIN       ;[065] <-- bit 6
152
    breq    unstuff5        ;[066] *** unstuff escape
153
    eor     phase, x1       ;[067]
154
    eor     x2, x1          ;[068]
155
    bst     x2, USBMINUS    ;[069]
156
    bld     shift, 6        ;[070]
157
didUnstuff6:                ;[   ]
158
    in      r0, USBIN       ;[071] <-- phase
159
    cpi     shift, 0x02     ;[072]
160
    brlo    unstuff6        ;[073] *** unstuff escape
161
didUnstuff5:                ;[   ]
162
    nop2                    ;[074]
163
;   [---]                   ;[075]
164
    in      x2, USBIN       ;[076] <-- bit 7
165
    eor     x1, x2          ;[077]
166
    bst     x1, USBMINUS    ;[078]
167
    bld     shift, 7        ;[079]
168
didUnstuff7:                ;[   ]
169
    eor     r0, x2          ;[080]
170
    or      phase, r0       ;[081]
171
    in      r0, USBIN       ;[082] <-- phase
172
    cpi     shift, 0x04     ;[083]
173
    brsh    rxLoop          ;[084]
174
;   [---]                   ;[085]
175
unstuff7:                   ;[   ]
176
    andi    x3, ~0x80       ;[085]
177
    ori     shift, 0x80     ;[086]
178
    in      x2, USBIN       ;[087] <-- sample stuffed bit 7
179
    nop                     ;[088]
180
    rjmp    didUnstuff7     ;[089]
181
;   [---]                   ;[090]
182
                            ;[080]
183
 
184
unstuff5:                   ;[067]
185
    eor     phase, x1       ;[068]
186
    andi    x3, ~0x20       ;[069]
187
    ori     shift, 0x20     ;[070]
188
    in      r0, USBIN       ;[071] <-- phase
189
    mov     x2, x1          ;[072]
190
    nop                     ;[073]
191
    nop2                    ;[074]
192
;   [---]                   ;[075]
193
    in      x1, USBIN       ;[076] <-- bit 6
194
    eor     r0, x1          ;[077]
195
    or      phase, r0       ;[078]
196
    eor     x2, x1          ;[079]
197
    bst     x2, USBMINUS    ;[080]
198
    bld     shift, 6        ;[081] no need to check bitstuffing, we just had one
199
    in      r0, USBIN       ;[082] <-- phase
200
    rjmp    didUnstuff5     ;[083]
201
;   [---]                   ;[084]
202
                            ;[074]
203
 
204
unstuff6:                   ;[074]
205
    andi    x3, ~0x40       ;[075]
206
    in      x1, USBIN       ;[076] <-- bit 6 again
207
    ori     shift, 0x40     ;[077]
208
    nop2                    ;[078]
209
;   [---]                   ;[079]
210
    rjmp    didUnstuff6     ;[080]
211
;   [---]                   ;[081]
212
                            ;[071]
213
 
214
unstuff0:                   ;[013]
215
    eor     r0, x2          ;[014]
216
    or      phase, r0       ;[015]
217
    andi    x2, USBMASK     ;[016] check for SE0
218
    in      r0, USBIN       ;[017] <-- phase
219
    breq    didUnstuff0     ;[018] direct jump to se0 would be too long
220
    andi    x3, ~0x01       ;[019]
221
    ori     shift, 0x01     ;[020]
222
    mov     x1, x2          ;[021] mov existing sample
223
    in      x2, USBIN       ;[022] <-- bit 1 again
224
    rjmp    didUnstuff0     ;[023]
225
;   [---]                   ;[024]
226
                            ;[014]
227
 
228
unstuff1:                   ;[024]
229
    eor     r0, x1          ;[025]
230
    or      phase, r0       ;[026]
231
    andi    x3, ~0x02       ;[027]
232
    in      r0, USBIN       ;[028] <-- phase
233
    ori     shift, 0x02     ;[029]
234
    mov     x2, x1          ;[030]
235
    rjmp    didUnstuff1     ;[031]
236
;   [---]                   ;[032]
237
                            ;[022]
238
 
239
unstuff2:                   ;[035]
240
    eor     r0, x2          ;[036]
241
    or      phase, r0       ;[037]
242
    andi    x3, ~0x04       ;[038]
243
    in      r0, USBIN       ;[039] <-- phase
244
    ori     shift, 0x04     ;[040]
245
    mov     x1, x2          ;[041]
246
    rjmp    didUnstuff2     ;[042]
247
;   [---]                   ;[043]
248
                            ;[033]
249
 
250
unstuff3:                   ;[043]
251
    in      x2, USBIN       ;[044] <-- bit 3 again
252
    eor     r0, x2          ;[045]
253
    or      phase, r0       ;[046]
254
    andi    x3, ~0x08       ;[047]
255
    ori     shift, 0x08     ;[048]
256
    nop                     ;[049]
257
    in      r0, USBIN       ;[050] <-- phase
258
    rjmp    didUnstuff3     ;[051]
259
;   [---]                   ;[052]
260
                            ;[042]
261
 
262
unstuff4:                   ;[053]
263
    andi    x3, ~0x10       ;[054]
264
    in      x1, USBIN       ;[055] <-- bit 4 again
265
    ori     shift, 0x10     ;[056]
266
    rjmp    didUnstuff4     ;[057]
267
;   [---]                   ;[058]
268
                            ;[048]
269
 
270
rxLoop:                     ;[085]
271
    eor     x3, shift       ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
272
    in      x1, USBIN       ;[000] <-- bit 0
273
    st      y+, x3          ;[001]
274
;   [---]                   ;[002]
275
    eor     r0, x1          ;[003]
276
    or      phase, r0       ;[004]
277
    eor     x2, x1          ;[005]
278
    in      r0, USBIN       ;[006] <-- phase
279
    ser     x3              ;[007]
280
    bst     x2, USBMINUS    ;[008]
281
    bld     shift, 0        ;[009]
282
    andi    shift, 0xf9     ;[010]
283
rxbit1:                     ;[   ]
284
    in      x2, USBIN       ;[011] <-- bit 1
285
    breq    unstuff0        ;[012] *** unstuff escape
286
    andi    x2, USBMASK     ;[013] SE0 check for bit 1
287
didUnstuff0:                ;[   ] Z only set if we detected SE0 in bitstuff
288
    breq    se0             ;[014]
289
    eor     r0, x2          ;[015]
290
    or      phase, r0       ;[016]
291
    in      r0, USBIN       ;[017] <-- phase
292
    eor     x1, x2          ;[018]
293
    bst     x1, USBMINUS    ;[019]
294
    bld     shift, 1        ;[020]
295
    andi    shift, 0xf3     ;[021]
296
didUnstuff1:                ;[   ]
297
    in      x1, USBIN       ;[022] <-- bit 2
298
    breq    unstuff1        ;[023] *** unstuff escape
299
    eor     r0, x1          ;[024]
300
    or      phase, r0       ;[025]
301
    subi    cnt, 1          ;[026] overflow check
302
    brcs    overflow        ;[027]
303
    in      r0, USBIN       ;[028] <-- phase
304
    eor     x2, x1          ;[029]
305
    bst     x2, USBMINUS    ;[030]
306
    bld     shift, 2        ;[031]
307
    andi    shift, 0xe7     ;[032]
308
didUnstuff2:                ;[   ]
309
    in      x2, USBIN       ;[033] <-- bit 3
310
    breq    unstuff2        ;[034] *** unstuff escape
311
    eor     r0, x2          ;[035]
312
    or      phase, r0       ;[036]
313
    eor     x1, x2          ;[037]
314
    bst     x1, USBMINUS    ;[038]
315
    in      r0, USBIN       ;[039] <-- phase
316
    bld     shift, 3        ;[040]
317
    andi    shift, 0xcf     ;[041]
318
didUnstuff3:                ;[   ]
319
    breq    unstuff3        ;[042] *** unstuff escape
320
    nop                     ;[043]
321
    in      x1, USBIN       ;[044] <-- bit 4
322
    eor     x2, x1          ;[045]
323
    bst     x2, USBMINUS    ;[046]
324
    bld     shift, 4        ;[047]
325
didUnstuff4:                ;[   ]
326
    eor     r0, x1          ;[048]
327
    or      phase, r0       ;[049]
328
    in      r0, USBIN       ;[050] <-- phase
329
    andi    shift, 0x9f     ;[051]
330
    breq    unstuff4        ;[052] *** unstuff escape
331
    rjmp    continueWithBit5;[053]
332
;   [---]                   ;[054]
333
 
334
macro POP_STANDARD ; 16 cycles
335
    pop     cnt
336
    pop     x4
337
    pop     x3
338
    pop     x2
339
    pop     x1
340
    pop     shift
341
    pop     YH
342
    pop     r0
343
    endm
344
macro POP_RETI     ; 5 cycles
345
    pop     YL
346
    out     SREG, YL
347
    pop     YL
348
    endm
349
 
350
#include "asmcommon.inc"
351
 
352
 
353
; USB spec says:
354
; idle = J
355
; J = (D+ = 0), (D- = 1)
356
; K = (D+ = 1), (D- = 0)
357
; Spec allows 7.5 bit times from EOP to SOP for replies
358
 
359
bitstuff7:
360
    eor     x1, x4          ;[4]
361
    ldi     x2, 0           ;[5]
362
    nop2                    ;[6] C is zero (brcc)
363
    rjmp    didStuff7       ;[8]
364
 
365
bitstuffN:
366
    eor     x1, x4          ;[5]
367
    ldi     x2, 0           ;[6]
368
    lpm                     ;[7] 3 cycle NOP, modifies r0
369
    out     USBOUT, x1      ;[10] <-- out
370
    rjmp    didStuffN       ;[0]
371
 
372
#define bitStatus   x3
373
 
374
sendNakAndReti:
375
    ldi     cnt, USBPID_NAK ;[-19]
376
    rjmp    sendCntAndReti  ;[-18]
377
sendAckAndReti:
378
    ldi     cnt, USBPID_ACK ;[-17]
379
sendCntAndReti:
380
    mov     r0, cnt         ;[-16]
381
    ldi     YL, 0           ;[-15] R0 address is 0
382
    ldi     YH, 0           ;[-14]
383
    ldi     cnt, 2          ;[-13]
384
;   rjmp    usbSendAndReti      fallthrough
385
 
386
;usbSend:
387
;pointer to data in 'Y'
388
;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
389
;uses: x1...x4, shift, cnt, Y
390
;Numbers in brackets are time since first bit of sync pattern is sent
391
usbSendAndReti:             ; 12 cycles until SOP
392
    in      x2, USBDDR      ;[-12]
393
    ori     x2, USBMASK     ;[-11]
394
    sbi     USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
395
    in      x1, USBOUT      ;[-8] port mirror for tx loop
396
    out     USBDDR, x2      ;[-7] <- acquire bus
397
; need not init x2 (bitstuff history) because sync starts with 0
398
    ldi     x4, USBMASK     ;[-6] exor mask
399
    ldi     shift, 0x80     ;[-5] sync byte is first byte sent
400
    ldi     bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes
401
byteloop:
402
bitloop:
403
    sbrs    shift, 0        ;[8] [-3]
404
    eor     x1, x4          ;[9] [-2]
405
    out     USBOUT, x1      ;[10] [-1] <-- out
406
    ror     shift           ;[0]
407
    ror     x2              ;[1]
408
didStuffN:
409
    cpi     x2, 0xfc        ;[2]
410
    brcc    bitstuffN       ;[3]
411
    nop                     ;[4]
412
    subi    bitStatus, 37   ;[5] 256 / 7 ~=~ 37
413
    brcc    bitloop         ;[6] when we leave the loop, bitStatus has almost the initial value
414
    sbrs    shift, 0        ;[7]
415
    eor     x1, x4          ;[8]
416
    ror     shift           ;[9]
417
didStuff7:
418
    out     USBOUT, x1      ;[10] <-- out
419
    ror     x2              ;[0]
420
    cpi     x2, 0xfc        ;[1]
421
    brcc    bitstuff7       ;[2]
422
    ld      shift, y+       ;[3]
423
    dec     cnt             ;[5]
424
    brne    byteloop        ;[6]
425
;make SE0:
426
    cbr     x1, USBMASK     ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles]
427
    lds     x2, usbNewDeviceAddr;[8]
428
    lsl     x2              ;[10] we compare with left shifted address
429
    out     USBOUT, x1      ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
430
;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
431
;set address only after data packet was sent, not after handshake
432
    subi    YL, 2           ;[0] Only assign address on data packets, not ACK/NAK in r0
433
    sbci    YH, 0           ;[1]
434
    breq    skipAddrAssign  ;[2]
435
    sts     usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
436
skipAddrAssign:
437
;end of usbDeviceAddress transfer
438
    ldi     x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag
439
    USB_STORE_PENDING(x2)   ;[5]
440
    ori     x1, USBIDLE     ;[6]
441
    in      x2, USBDDR      ;[7]
442
    cbr     x2, USBMASK     ;[8] set both pins to input
443
    mov     x3, x1          ;[9]
444
    cbr     x3, USBMASK     ;[10] configure no pullup on both pins
445
    ldi     x4, 4           ;[11]
446
se0Delay:
447
    dec     x4              ;[12] [15] [18] [21]
448
    brne    se0Delay        ;[13] [16] [19] [22]
449
    out     USBOUT, x1      ;[23] <-- out J (idle) -- end of SE0 (EOP signal)
450
    out     USBDDR, x2      ;[24] <-- release bus now
451
    out     USBOUT, x3      ;[25] <-- ensure no pull-up resistors are active
452
    rjmp    doReturn
453