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)
8 * Revision: $Id: usbdrvasm165.inc 740 2009-04-13 18:23:31Z cs $
11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
12 * appropriate implementation!
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%.
22 See usbdrv.h for a description of the entire driver.
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!
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
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
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.
55 brne waitForJ ; just make sure we have ANY timeout
57 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
58 sbis USBIN, USBMINUS ;[-15]
74 #endif /* USB_COUNT_SOF */
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
87 lds YL, usbInputBufOffset;[-8]
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
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).
101 ;----------------------------------------------------------------------------
102 ; push more registers and initialize values while we sample the first bits:
103 ;----------------------------------------------------------------------------
109 ldi shift, 0xff ;[9] [rx loop init]
110 ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag
112 in x1, USBIN ;[11] <-- sample bit 0
113 bst x1, USBMINUS ;[12]
115 push x4 ;[14] == phase
119 ldi phase, 0 ;[18] [rx loop init]
120 ldi cnt, USB_BUFSIZE;[19] [rx loop init]
124 ;----------------------------------------------------------------------------
125 ; Receiver loop (numbers in brackets are cycles within byte after instr)
126 ;----------------------------------------------------------------------------
128 byte oriented operations done during loop:
131 bit 2: overflow check
133 bit 4: rjmp to achieve conditional jump range
136 bit 7: jump, fixup bitstuff
138 ------------------------------------------------------------------
141 in x2, USBIN ;[055] <-- bit 5
144 sbrc phase, USBMINUS ;[058]
145 lpm ;[059] optional nop3; modifies r0
146 in phase, USBIN ;[060] <-- phase
148 bst x1, USBMINUS ;[062]
150 andi shift, 0x3f ;[064]
151 in x1, USBIN ;[065] <-- bit 6
152 breq unstuff5 ;[066] *** unstuff escape
155 bst x2, USBMINUS ;[069]
158 in r0, USBIN ;[071] <-- phase
159 cpi shift, 0x02 ;[072]
160 brlo unstuff6 ;[073] *** unstuff escape
164 in x2, USBIN ;[076] <-- bit 7
166 bst x1, USBMINUS ;[078]
171 in r0, USBIN ;[082] <-- phase
172 cpi shift, 0x04 ;[083]
176 andi x3, ~0x80 ;[085]
177 ori shift, 0x80 ;[086]
178 in x2, USBIN ;[087] <-- sample stuffed bit 7
180 rjmp didUnstuff7 ;[089]
186 andi x3, ~0x20 ;[069]
187 ori shift, 0x20 ;[070]
188 in r0, USBIN ;[071] <-- phase
193 in x1, USBIN ;[076] <-- bit 6
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]
205 andi x3, ~0x40 ;[075]
206 in x1, USBIN ;[076] <-- bit 6 again
207 ori shift, 0x40 ;[077]
210 rjmp didUnstuff6 ;[080]
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]
231 andi x3, ~0x02 ;[027]
232 in r0, USBIN ;[028] <-- phase
233 ori shift, 0x02 ;[029]
235 rjmp didUnstuff1 ;[031]
242 andi x3, ~0x04 ;[038]
243 in r0, USBIN ;[039] <-- phase
244 ori shift, 0x04 ;[040]
246 rjmp didUnstuff2 ;[042]
251 in x2, USBIN ;[044] <-- bit 3 again
254 andi x3, ~0x08 ;[047]
255 ori shift, 0x08 ;[048]
257 in r0, USBIN ;[050] <-- phase
258 rjmp didUnstuff3 ;[051]
263 andi x3, ~0x10 ;[054]
264 in x1, USBIN ;[055] <-- bit 4 again
265 ori shift, 0x10 ;[056]
266 rjmp didUnstuff4 ;[057]
271 eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
272 in x1, USBIN ;[000] <-- bit 0
278 in r0, USBIN ;[006] <-- phase
280 bst x2, USBMINUS ;[008]
282 andi shift, 0xf9 ;[010]
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
291 in r0, USBIN ;[017] <-- phase
293 bst x1, USBMINUS ;[019]
295 andi shift, 0xf3 ;[021]
297 in x1, USBIN ;[022] <-- bit 2
298 breq unstuff1 ;[023] *** unstuff escape
301 subi cnt, 1 ;[026] overflow check
303 in r0, USBIN ;[028] <-- phase
305 bst x2, USBMINUS ;[030]
307 andi shift, 0xe7 ;[032]
309 in x2, USBIN ;[033] <-- bit 3
310 breq unstuff2 ;[034] *** unstuff escape
314 bst x1, USBMINUS ;[038]
315 in r0, USBIN ;[039] <-- phase
317 andi shift, 0xcf ;[041]
319 breq unstuff3 ;[042] *** unstuff escape
321 in x1, USBIN ;[044] <-- bit 4
323 bst x2, USBMINUS ;[046]
328 in r0, USBIN ;[050] <-- phase
329 andi shift, 0x9f ;[051]
330 breq unstuff4 ;[052] *** unstuff escape
331 rjmp continueWithBit5;[053]
334 macro POP_STANDARD ; 16 cycles
344 macro POP_RETI ; 5 cycles
350 #include "asmcommon.inc"
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
362 nop2 ;[6] C is zero (brcc)
368 lpm ;[7] 3 cycle NOP, modifies r0
369 out USBOUT, x1 ;[10] <-- out
375 ldi cnt, USBPID_NAK ;[-19]
376 rjmp sendCntAndReti ;[-18]
378 ldi cnt, USBPID_ACK ;[-17]
381 ldi YL, 0 ;[-15] R0 address is 0
384 ; rjmp usbSendAndReti fallthrough
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
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
403 sbrs shift, 0 ;[8] [-3]
405 out USBOUT, x1 ;[10] [-1] <-- out
412 subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37
413 brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value
418 out USBOUT, x1 ;[10] <-- out
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
434 breq skipAddrAssign ;[2]
435 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
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]
442 cbr x2, USBMASK ;[8] set both pins to input
444 cbr x3, USBMASK ;[10] configure no pullup on both pins
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