Subversion Repositories group.electronics

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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