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
6 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
10 /* Do not link this file! Link usbdrvasm.S instead, which includes the
11 * appropriate implementation!
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%.
21 See usbdrv.h for a description of the entire driver.
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!
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
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
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.
54 brne waitForJ ; just make sure we have ANY timeout
56 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
57 sbis USBIN, USBMINUS ;[-15]
73 #endif /* USB_COUNT_SOF */
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
86 lds YL, usbInputBufOffset;[-8]
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
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).
100 ;----------------------------------------------------------------------------
101 ; push more registers and initialize values while we sample the first bits:
102 ;----------------------------------------------------------------------------
108 ldi shift, 0xff ;[9] [rx loop init]
109 ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag
111 in x1, USBIN ;[11] <-- sample bit 0
112 bst x1, USBMINUS ;[12]
114 push x4 ;[14] == phase
118 ldi phase, 0 ;[18] [rx loop init]
119 ldi cnt, USB_BUFSIZE;[19] [rx loop init]
123 ;----------------------------------------------------------------------------
124 ; Receiver loop (numbers in brackets are cycles within byte after instr)
125 ;----------------------------------------------------------------------------
127 byte oriented operations done during loop:
130 bit 2: overflow check
132 bit 4: rjmp to achieve conditional jump range
135 bit 7: jump, fixup bitstuff
137 ------------------------------------------------------------------
140 in x2, USBIN ;[055] <-- bit 5
143 sbrc phase, USBMINUS ;[058]
144 lpm ;[059] optional nop3; modifies r0
145 in phase, USBIN ;[060] <-- phase
147 bst x1, USBMINUS ;[062]
149 andi shift, 0x3f ;[064]
150 in x1, USBIN ;[065] <-- bit 6
151 breq unstuff5 ;[066] *** unstuff escape
154 bst x2, USBMINUS ;[069]
157 in r0, USBIN ;[071] <-- phase
158 cpi shift, 0x02 ;[072]
159 brlo unstuff6 ;[073] *** unstuff escape
163 in x2, USBIN ;[076] <-- bit 7
165 bst x1, USBMINUS ;[078]
170 in r0, USBIN ;[082] <-- phase
171 cpi shift, 0x04 ;[083]
175 andi x3, ~0x80 ;[085]
176 ori shift, 0x80 ;[086]
177 in x2, USBIN ;[087] <-- sample stuffed bit 7
179 rjmp didUnstuff7 ;[089]
185 andi x3, ~0x20 ;[069]
186 ori shift, 0x20 ;[070]
187 in r0, USBIN ;[071] <-- phase
192 in x1, USBIN ;[076] <-- bit 6
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]
204 andi x3, ~0x40 ;[075]
205 in x1, USBIN ;[076] <-- bit 6 again
206 ori shift, 0x40 ;[077]
209 rjmp didUnstuff6 ;[080]
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]
230 andi x3, ~0x02 ;[027]
231 in r0, USBIN ;[028] <-- phase
232 ori shift, 0x02 ;[029]
234 rjmp didUnstuff1 ;[031]
241 andi x3, ~0x04 ;[038]
242 in r0, USBIN ;[039] <-- phase
243 ori shift, 0x04 ;[040]
245 rjmp didUnstuff2 ;[042]
250 in x2, USBIN ;[044] <-- bit 3 again
253 andi x3, ~0x08 ;[047]
254 ori shift, 0x08 ;[048]
256 in r0, USBIN ;[050] <-- phase
257 rjmp didUnstuff3 ;[051]
262 andi x3, ~0x10 ;[054]
263 in x1, USBIN ;[055] <-- bit 4 again
264 ori shift, 0x10 ;[056]
265 rjmp didUnstuff4 ;[057]
270 eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
271 in x1, USBIN ;[000] <-- bit 0
277 in r0, USBIN ;[006] <-- phase
279 bst x2, USBMINUS ;[008]
281 andi shift, 0xf9 ;[010]
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
290 in r0, USBIN ;[017] <-- phase
292 bst x1, USBMINUS ;[019]
294 andi shift, 0xf3 ;[021]
296 in x1, USBIN ;[022] <-- bit 2
297 breq unstuff1 ;[023] *** unstuff escape
300 subi cnt, 1 ;[026] overflow check
302 in r0, USBIN ;[028] <-- phase
304 bst x2, USBMINUS ;[030]
306 andi shift, 0xe7 ;[032]
308 in x2, USBIN ;[033] <-- bit 3
309 breq unstuff2 ;[034] *** unstuff escape
313 bst x1, USBMINUS ;[038]
314 in r0, USBIN ;[039] <-- phase
316 andi shift, 0xcf ;[041]
318 breq unstuff3 ;[042] *** unstuff escape
320 in x1, USBIN ;[044] <-- bit 4
322 bst x2, USBMINUS ;[046]
327 in r0, USBIN ;[050] <-- phase
328 andi shift, 0x9f ;[051]
329 breq unstuff4 ;[052] *** unstuff escape
330 rjmp continueWithBit5;[053]
333 macro POP_STANDARD ; 16 cycles
343 macro POP_RETI ; 5 cycles
349 #include "asmcommon.inc"
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
361 nop2 ;[6] C is zero (brcc)
367 lpm ;[7] 3 cycle NOP, modifies r0
368 out USBOUT, x1 ;[10] <-- out
374 ldi cnt, USBPID_NAK ;[-19]
375 rjmp sendCntAndReti ;[-18]
377 ldi cnt, USBPID_ACK ;[-17]
380 ldi YL, 0 ;[-15] R0 address is 0
383 ; rjmp usbSendAndReti fallthrough
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
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
402 sbrs shift, 0 ;[8] [-3]
404 out USBOUT, x1 ;[10] [-1] <-- out
411 subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37
412 brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value
417 out USBOUT, x1 ;[10] <-- out
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
433 breq skipAddrAssign ;[2]
434 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
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]
441 cbr x2, USBMASK ;[8] set both pins to input
443 cbr x3, USBMASK ;[10] configure no pullup on both pins
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