1 /* Name: usbdrvasm165.S
2 * Project: AVR USB driver
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) or proprietary (CommercialLicense.txt)
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: r0, SREG [sofError], YL, YH, shift, x1, x2, x3, x4, cnt
41 push r0 ;[-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 ;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
51 sbis USBIN, USBMINUS ;[-18] wait for D- == 1
54 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
55 sbis USBIN, USBMINUS ;[-15]
69 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
70 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
71 ;are cycles from center of first sync (double K) bit after the instruction
76 lds YL, usbInputBufOffset;[-8]
79 subi YL, lo8(-(usbRxBuf));[-5] [rx loop init]
80 sbci YH, hi8(-(usbRxBuf));[-4] [rx loop init]
81 mov r0, x2 ;[-3] [rx loop init]
82 sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
83 rjmp haveTwoBitsK ;[-1]
84 pop YH ;[0] undo the pushes from before
86 rjmp waitForK ;[4] this was not the end of sync, retry
87 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
88 ; bit times (= 22 cycles).
90 ;----------------------------------------------------------------------------
91 ; push more registers and initialize values while we sample the first bits:
92 ;----------------------------------------------------------------------------
98 ldi shift, 0xff ;[9] [rx loop init]
99 ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag
101 in x1, USBIN ;[11] <-- sample bit 0
102 bst x1, USBMINUS ;[12]
104 push x4 ;[14] == phase
108 ldi phase, 0 ;[18] [rx loop init]
109 ldi cnt, USB_BUFSIZE;[19] [rx loop init]
113 ;----------------------------------------------------------------------------
114 ; Receiver loop (numbers in brackets are cycles within byte after instr)
115 ;----------------------------------------------------------------------------
117 byte oriented operations done during loop:
120 bit 2: overflow check
122 bit 4: rjmp to achieve conditional jump range
125 bit 7: jump, fixup bitstuff
127 ------------------------------------------------------------------
130 in x2, USBIN ;[055] <-- bit 5
133 sbrc phase, USBMINUS ;[058]
134 lpm ;[059] optional nop3; modifies r0
135 in phase, USBIN ;[060] <-- phase
137 bst x1, USBMINUS ;[062]
139 andi shift, 0x3f ;[064]
140 in x1, USBIN ;[065] <-- bit 6
141 breq unstuff5 ;[066] *** unstuff escape
144 bst x2, USBMINUS ;[069]
147 in r0, USBIN ;[071] <-- phase
148 cpi shift, 0x02 ;[072]
149 brlo unstuff6 ;[073] *** unstuff escape
153 in x2, USBIN ;[076] <-- bit 7
155 bst x1, USBMINUS ;[078]
160 in r0, USBIN ;[082] <-- phase
161 cpi shift, 0x04 ;[083]
165 andi x3, ~0x80 ;[085]
166 ori shift, 0x80 ;[086]
167 in x2, USBIN ;[087] <-- sample stuffed bit 7
169 rjmp didUnstuff7 ;[089]
175 andi x3, ~0x20 ;[069]
176 ori shift, 0x20 ;[070]
177 in r0, USBIN ;[071] <-- phase
182 in x1, USBIN ;[076] <-- bit 6
186 bst x2, USBMINUS ;[080]
187 bld shift, 6 ;[081] no need to check bitstuffing, we just had one
188 in r0, USBIN ;[082] <-- phase
189 rjmp didUnstuff5 ;[083]
194 andi x3, ~0x40 ;[075]
195 in x1, USBIN ;[076] <-- bit 6 again
196 ori shift, 0x40 ;[077]
199 rjmp didUnstuff6 ;[080]
206 andi x2, USBMASK ;[016] check for SE0
207 in r0, USBIN ;[017] <-- phase
208 breq didUnstuff0 ;[018] direct jump to se0 would be too long
209 andi x3, ~0x01 ;[019]
210 ori shift, 0x01 ;[020]
211 mov x1, x2 ;[021] mov existing sample
212 in x2, USBIN ;[022] <-- bit 1 again
213 rjmp didUnstuff0 ;[023]
220 andi x3, ~0x02 ;[027]
221 in r0, USBIN ;[028] <-- phase
222 ori shift, 0x02 ;[029]
224 rjmp didUnstuff1 ;[031]
231 andi x3, ~0x04 ;[038]
232 in r0, USBIN ;[039] <-- phase
233 ori shift, 0x04 ;[040]
235 rjmp didUnstuff2 ;[042]
240 in x2, USBIN ;[044] <-- bit 3 again
243 andi x3, ~0x08 ;[047]
244 ori shift, 0x08 ;[048]
246 in r0, USBIN ;[050] <-- phase
247 rjmp didUnstuff3 ;[051]
252 andi x3, ~0x10 ;[054]
253 in x1, USBIN ;[055] <-- bit 4 again
254 ori shift, 0x10 ;[056]
255 rjmp didUnstuff4 ;[057]
260 eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
261 in x1, USBIN ;[000] <-- bit 0
267 in r0, USBIN ;[006] <-- phase
269 bst x2, USBMINUS ;[008]
271 andi shift, 0xf9 ;[010]
273 in x2, USBIN ;[011] <-- bit 1
274 breq unstuff0 ;[012] *** unstuff escape
275 andi x2, USBMASK ;[013] SE0 check for bit 1
276 didUnstuff0: ;[ ] Z only set if we detected SE0 in bitstuff
280 in r0, USBIN ;[017] <-- phase
282 bst x1, USBMINUS ;[019]
284 andi shift, 0xf3 ;[021]
286 in x1, USBIN ;[022] <-- bit 2
287 breq unstuff1 ;[023] *** unstuff escape
290 subi cnt, 1 ;[026] overflow check
292 in r0, USBIN ;[028] <-- phase
294 bst x2, USBMINUS ;[030]
296 andi shift, 0xe7 ;[032]
298 in x2, USBIN ;[033] <-- bit 3
299 breq unstuff2 ;[034] *** unstuff escape
303 bst x1, USBMINUS ;[038]
304 in r0, USBIN ;[039] <-- phase
306 andi shift, 0xcf ;[041]
308 breq unstuff3 ;[042] *** unstuff escape
310 in x1, USBIN ;[044] <-- bit 4
312 bst x2, USBMINUS ;[046]
317 in r0, USBIN ;[050] <-- phase
318 andi shift, 0x9f ;[051]
319 breq unstuff4 ;[052] *** unstuff escape
320 rjmp continueWithBit5;[053]
323 ;----------------------------------------------------------------------------
324 ; Processing of received packet (numbers in brackets are cycles after center of SE0)
325 ;----------------------------------------------------------------------------
326 ;This is the only non-error exit point for the software receiver loop
327 ;we don't check any CRCs here because there is no time left.
330 subi cnt, USB_BUFSIZE ;[5]
333 ldi x2, 1<<USB_INTR_PENDING_BIT ;[8]
334 out USB_INTR_PENDING, x2;[9] clear pending intr and check flag later. SE0 should be over.
335 brlo doReturn ;[10] this is probably an ACK, NAK or similar packet
339 cpi token, USBPID_DATA0 ;[15]
340 breq handleData ;[16]
341 cpi token, USBPID_DATA1 ;[17]
342 breq handleData ;[18]
343 ldd x2, y+1 ;[19] ADDR and 1 bit endpoint number
344 mov x3, x2 ;[21] store for endpoint number
345 andi x2, 0x7f ;[22] x2 is now ADDR
346 lds shift, usbDeviceAddr;[23]
348 overflow: ; This is a hack: brcs overflow will never have Z flag set
349 brne ignorePacket ;[26] packet for different address
350 cpi token, USBPID_IN ;[27]
352 cpi token, USBPID_SETUP ;[29]
353 breq handleSetupOrOut ;[30]
354 cpi token, USBPID_OUT ;[31]
355 breq handleSetupOrOut ;[32]
356 ; rjmp ignorePacket ;fallthrough, should not happen anyway.
360 sts usbCurrentTok, shift
376 #if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_HAVE_INTRIN_ENDPOINT3
378 lds cnt, usbTxLen3 ;[43]
380 rjmp sendCntAndReti ;[46] 48 + 16 = 64 until SOP
381 sts usbTxLen3, x1 ;[47] x1 == USBPID_NAK from above
382 ldi YL, lo8(usbTxBuf3) ;[49]
383 ldi YH, hi8(usbTxBuf3) ;[50]
384 rjmp usbSendAndReti ;[51] 53 + 12 = 65 until SOP
387 ;Setup and Out are followed by a data packet two bit times (16 cycles) after
388 ;the end of SE0. The sync code allows up to 40 cycles delay from the start of
389 ;the sync pattern until the first bit is sampled. That's a total of 56 cycles.
390 handleSetupOrOut: ;[34]
391 #if USB_CFG_IMPLEMENT_FN_WRITEOUT /* if we have data for second OUT endpoint, set usbCurrentTok to -1 */
392 sbrc x3, 7 ;[34] skip if endpoint 0
393 ldi token, -1 ;[35] indicate that this is endpoint 1 OUT
395 sts usbCurrentTok, token;[36]
404 in r0, USB_INTR_PENDING;[54]
405 sbrc r0, USB_INTR_PENDING_BIT;[55] check whether data is already arriving
406 rjmp waitForJ ;[56] save the pops and pushes -- a new interrupt is aready pending
407 rjmp sofError ;[57] not an error, but it does the pops and reti we want
411 lds token, usbCurrentTok;[20]
414 lds x2, usbRxLen ;[24]
416 brne sendNakAndReti ;[27]
417 ; 2006-03-11: The following two lines fix a problem where the device was not
418 ; recognized if usbPoll() was called less frequently than once every 4 ms.
419 cpi cnt, 4 ;[28] zero sized data packets are status phase only -- ignore and ack
420 brmi sendAckAndReti ;[29] keep rx buffer clean -- we must not NAK next SETUP
421 sts usbRxLen, cnt ;[30] store received data, swap buffers
422 sts usbRxToken, token ;[32]
423 lds x2, usbInputBufOffset;[34] swap buffers
424 ldi cnt, USB_BUFSIZE ;[36]
426 sts usbInputBufOffset, cnt;[38] buffers now swapped
427 rjmp sendAckAndReti ;[40] 42 + 17 = 59 until SOP
430 ;We don't send any data as long as the C code has not processed the current
431 ;input data and potentially updated the output data. That's more efficient
432 ;in terms of code size than clearing the tx buffers when a packet is received.
433 lds x1, usbRxLen ;[30]
434 cpi x1, 1 ;[32] negative values are flow control, 0 means "buffer free"
435 brge sendNakAndReti ;[33] unprocessed input packet?
436 ldi x1, USBPID_NAK ;[34] prepare value for usbTxLen
437 #if USB_CFG_HAVE_INTRIN_ENDPOINT
438 sbrc x3, 7 ;[35] x3 contains addr + endpoint
441 lds cnt, usbTxLen ;[37]
442 sbrc cnt, 4 ;[39] all handshake tokens have bit 4 set
443 rjmp sendCntAndReti ;[40] 42 + 16 = 58 until SOP
444 sts usbTxLen, x1 ;[41] x1 == USBPID_NAK from above
445 ldi YL, lo8(usbTxBuf) ;[43]
446 ldi YH, hi8(usbTxBuf) ;[44]
447 rjmp usbSendAndReti ;[45] 47 + 12 = 59 until SOP
449 ; Comment about when to set usbTxLen to USBPID_NAK:
450 ; We should set it back when we receive the ACK from the host. This would
451 ; be simple to implement: One static variable which stores whether the last
452 ; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
453 ; ACK. However, we set it back immediately when we send the package,
454 ; assuming that no error occurs and the host sends an ACK. We save one byte
455 ; RAM this way and avoid potential problems with endless retries. The rest of
456 ; the driver assumes error-free transfers anyway.
458 #if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
460 #if USB_CFG_HAVE_INTRIN_ENDPOINT3
461 ; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
466 lds cnt, usbTxLen1 ;[42]
467 sbrc cnt, 4 ;[44] all handshake tokens have bit 4 set
468 rjmp sendCntAndReti ;[45] 47 + 16 = 63 until SOP
469 sts usbTxLen1, x1 ;[46] x1 == USBPID_NAK from above
470 ldi YL, lo8(usbTxBuf1) ;[48]
471 ldi YH, hi8(usbTxBuf1) ;[49]
472 rjmp usbSendAndReti ;[50] 52 + 12 + 64 until SOP
478 ; J = (D+ = 0), (D- = 1)
479 ; K = (D+ = 1), (D- = 0)
480 ; Spec allows 7.5 bit times from EOP to SOP for replies
485 nop2 ;[6] C is zero (brcc)
491 lpm ;[7] 3 cycle NOP, modifies r0
492 out USBOUT, x1 ;[10] <-- out
498 ldi cnt, USBPID_NAK ;[-19]
499 rjmp sendCntAndReti ;[-18]
501 ldi cnt, USBPID_ACK ;[-17]
504 ldi YL, 0 ;[-15] R0 address is 0
507 ; rjmp usbSendAndReti fallthrough
510 ;pointer to data in 'Y'
511 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
512 ;uses: x1...x4, shift, cnt, Y
513 ;Numbers in brackets are time since first bit of sync pattern is sent
514 usbSendAndReti: ; 12 cycles until SOP
516 ori x2, USBMASK ;[-11]
517 sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
518 in x1, USBOUT ;[-8] port mirror for tx loop
519 out USBDDR, x2 ;[-7] <- acquire bus
520 ; need not init x2 (bitstuff history) because sync starts with 0
521 ldi x4, USBMASK ;[-6] exor mask
522 ldi shift, 0x80 ;[-5] sync byte is first byte sent
523 ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes
526 sbrs shift, 0 ;[8] [-3]
528 out USBOUT, x1 ;[10] [-1] <-- out
535 subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37
536 brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value
541 out USBOUT, x1 ;[10] <-- out
549 cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles]
550 lds x2, usbNewDeviceAddr;[8]
551 out USBOUT, x1 ;[10] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
552 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
553 ;set address only after data packet was sent, not after handshake
556 breq skipAddrAssign ;[2]
557 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
559 ;end of usbDeviceAddress transfer
560 ldi x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag
561 out USB_INTR_PENDING, x2;[5]
564 cbr x2, USBMASK ;[8] set both pins to input
566 cbr x3, USBMASK ;[10] configure no pullup on both pins
569 dec x4 ;[12] [15] [18] [21]
570 brne se0Delay ;[13] [16] [19] [22]
571 out USBOUT, x1 ;[23] <-- out J (idle) -- end of SE0 (EOP signal)
572 out USBDDR, x2 ;[24] <-- release bus now
573 out USBOUT, x3 ;[25] <-- ensure no pull-up resistors are active