1 /* Name: usbdrvasm16.inc
2 * Project: AVR USB driver
3 * Author: Christian Starkjohann
4 * Creation Date: 2007-06-15
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: usbdrvasm16.inc 692 2008-11-07 15:07:40Z cs $
11 /* Do not link this file! Link usbdrvasm.S instead, which includes the
12 * appropriate implementation!
17 This file is the 16 MHz version of the asssembler part of the USB driver. It
18 requires a 16 MHz crystal (not a ceramic resonator and not a calibrated RC
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 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
29 ;nominal frequency: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte
30 ; Numbers in brackets are clocks counted from center of last sync bit
31 ; when instruction starts
34 ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt
35 push YL ;[-25] push only what is necessary to sync with edge ASAP
39 ;----------------------------------------------------------------------------
40 ; Synchronize with sync pattern:
41 ;----------------------------------------------------------------------------
42 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
43 ;sync up with J to K edge during sync pattern -- use fastest possible loops
44 ;The first part waits at most 1 bit long since we must be in sync pattern.
45 ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to
46 ;waitForJ, ensure that this prerequisite is met.
50 brne waitForJ ; just make sure we have ANY timeout
52 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
53 sbis USBIN, USBMINUS ;[-15]
69 #endif /* USB_COUNT_SOF */
75 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
76 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
77 ;are cycles from center of first sync (double K) bit after the instruction
80 lds YL, usbInputBufOffset;[-10]
83 subi YL, lo8(-(usbRxBuf));[-7] [rx loop init]
84 sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init]
87 ldi bitcnt, 0x55 ;[-3] [rx loop init]
88 sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
89 rjmp haveTwoBitsK ;[-1]
90 pop shift ;[0] undo the push from before
91 pop bitcnt ;[2] undo the push from before
92 rjmp waitForK ;[4] this was not the end of sync, retry
93 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
94 ; bit times (= 21 cycles).
96 ;----------------------------------------------------------------------------
97 ; push more registers and initialize values while we sample the first bits:
98 ;----------------------------------------------------------------------------
104 ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that
107 in x1, USBIN ;[11] <-- sample bit 0
108 andi x1, USBMASK ;[12]
109 bst x1, USBMINUS ;[13]
112 ldi leap, 0 ;[17] [rx loop init]
113 ldi cnt, USB_BUFSIZE;[18] [rx loop init]
114 rjmp rxbit1 ;[19] arrives at [21]
116 ;----------------------------------------------------------------------------
117 ; Receiver loop (numbers in brackets are cycles within byte after instr)
118 ;----------------------------------------------------------------------------
121 andi x2, USBMASK ;[03]
122 ori x3, 1<<6 ;[04] will not be shifted any more
123 andi shift, ~0x80;[05]
124 mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6
125 subi leap, 3 ;[07] since this is a short (10 cycle) bit, enforce leap bit
126 rjmp didUnstuff6 ;[08]
129 ori x3, 1<<7 ;[09] will not be shifted any more
130 in x2, USBIN ;[00] [10] re-sample bit 7
131 andi x2, USBMASK ;[01]
132 andi shift, ~0x80;[02]
133 subi leap, 3 ;[03] since this is a short (10 cycle) bit, enforce leap bit
134 rjmp didUnstuff7 ;[04]
137 ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0
138 in x1, USBIN ;[00] [10]
139 andi shift, ~0x80;[01]
140 andi x1, USBMASK ;[02]
142 subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit
144 rjmp didUnstuffE ;[06]
147 ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1
148 in x2, USBIN ;[00] [10]
149 andi shift, ~0x80;[01]
150 andi x2, USBMASK ;[02]
152 subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit
154 rjmp didUnstuffO ;[06]
157 andi x1, USBMASK ;[03]
161 subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte
167 cpi shift, 0xfc ;[10]
168 in x2, USBIN ;[00] [11] <-- sample bit 7
170 andi x2, USBMASK ;[02]
175 cpi shift, 0xfc ;[06]
177 eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others
178 st y+, x3 ;[09] store data
180 in x1, USBIN ;[00] [11] <-- sample bit 0/2/4
181 andi x1, USBMASK ;[01]
183 andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7
186 cpi shift, 0xfc ;[06]
187 brcc unstuffEven ;[07]
192 in x2, USBIN ;[00] [10] <-- sample bit 1/3/5
193 andi x2, USBMASK ;[01]
198 cpi shift, 0xfc ;[06]
199 brcc unstuffOdd ;[07]
201 subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3
205 in x1, USBIN ;[00] [11] <-- sample bit 6
206 brcc rxByteLoop ;[01]
209 macro POP_STANDARD ; 14 cycles
218 macro POP_RETI ; 7 cycles
225 #include "asmcommon.inc"
229 ; J = (D+ = 0), (D- = 1)
230 ; K = (D+ = 1), (D- = 0)
231 ; Spec allows 7.5 bit times from EOP to SOP for replies
238 out USBOUT, x1 ;[10] <-- out
243 ldi x2, 0 ;[6] Carry is zero due to brcc
244 rol shift ;[7] compensate for ror shift at branch destination
248 ldi x2, 0 ;[2] Carry is zero due to brcc
253 ldi x3, USBPID_NAK ;[-18]
254 rjmp sendX3AndReti ;[-17]
256 ldi cnt, USBPID_ACK ;[-17]
260 ldi YL, 20 ;[-15] x3==r20 address is 20
263 ; rjmp usbSendAndReti fallthrough
266 ;pointer to data in 'Y'
267 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
268 ;uses: x1...x4, btcnt, shift, cnt, Y
269 ;Numbers in brackets are time since first bit of sync pattern is sent
270 ;We don't match the transfer rate exactly (don't insert leap cycles every third
271 ;byte) because the spec demands only 1.5% precision anyway.
272 usbSendAndReti: ; 12 cycles until SOP
274 ori x2, USBMASK ;[-11]
275 sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
276 in x1, USBOUT ;[-8] port mirror for tx loop
277 out USBDDR, x2 ;[-7] <- acquire bus
278 ; need not init x2 (bitstuff history) because sync starts with 0
279 ldi x4, USBMASK ;[-6] exor mask
280 ldi shift, 0x80 ;[-5] sync byte is first byte sent
282 ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101
284 sbrs shift, 0 ;[-3] [7]
286 out USBOUT, x1 ;[-1] [9] <-- out N
299 out USBOUT, x1 ;[-1] [9] <-- out 6
311 out USBOUT, x1 ;[-1][10] <-- out 7
312 brcc bitstuff7 ;[0] [11]
317 cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles]
318 lds x2, usbNewDeviceAddr;[6]
319 lsl x2 ;[8] we compare with left shifted address
320 subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3
322 out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
323 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
324 ;set address only after data packet was sent, not after handshake
325 breq skipAddrAssign ;[0]
326 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
328 ;end of usbDeviceAddress transfer
329 ldi x2, 1<<USB_INTR_PENDING_BIT;[2] int0 occurred during TX -- clear pending flag
330 USB_STORE_PENDING(x2) ;[3]
333 cbr x2, USBMASK ;[6] set both pins to input
335 cbr x3, USBMASK ;[8] configure no pullup on both pins
338 dec x4 ;[10] [13] [16] [19]
339 brne se0Delay ;[11] [14] [17] [20]
340 out USBOUT, x1 ;[21] <-- out J (idle) -- end of SE0 (EOP signal)
341 out USBDDR, x2 ;[22] <-- release bus now
342 out USBOUT, x3 ;[23] <-- ensure no pull-up resistors are active