00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
00030 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
00031 ;max allowable interrupt latency: 59 cycles -> max 52 cycles interrupt disable
00032 ;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes
00033 ;nominal frequency: 16.5 MHz -> 11 cycles per bit
00034 ; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%)
00035 ; Numbers in brackets are clocks counted from center of last sync bit
00036 ; when instruction starts
00037
00038
00039 USB_INTR_VECTOR:
00040 ;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt
00041 push YL ;[-23] push only what is necessary to sync with edge ASAP
00042 in YL, SREG ;[-21]
00043 push YL ;[-20]
00044 ;----------------------------------------------------------------------------
00045 ; Synchronize with sync pattern:
00046 ;----------------------------------------------------------------------------
00047 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
00048 ;sync up with J to K edge during sync pattern -- use fastest possible loops
00049 ;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
00050 waitForJ:
00051 sbis USBIN, USBMINUS ;[-18] wait for D- == 1
00052 rjmp waitForJ
00053 waitForK:
00054 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
00055 sbis USBIN, USBMINUS ;[-15]
00056 rjmp foundK ;[-14]
00057 sbis USBIN, USBMINUS
00058 rjmp foundK
00059 sbis USBIN, USBMINUS
00060 rjmp foundK
00061 sbis USBIN, USBMINUS
00062 rjmp foundK
00063 sbis USBIN, USBMINUS
00064 rjmp foundK
00065 sbis USBIN, USBMINUS
00066 rjmp foundK
00067 #if USB_COUNT_SOF
00068 lds YL, usbSofCount
00069 inc YL
00070 sts usbSofCount, YL
00071 #endif /* USB_COUNT_SOF */
00072 rjmp sofError
00073 foundK: ;[-12]
00074 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
00075 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
00076 ;are cycles from center of first sync (double K) bit after the instruction
00077 push r0 ;[-12]
00078 ; [---] ;[-11]
00079 push YH ;[-10]
00080 ; [---] ;[-9]
00081 lds YL, usbInputBufOffset;[-8]
00082 ; [---] ;[-7]
00083 clr YH ;[-6]
00084 subi YL, lo8(-(usbRxBuf));[-5] [rx loop init]
00085 sbci YH, hi8(-(usbRxBuf));[-4] [rx loop init]
00086 mov r0, x2 ;[-3] [rx loop init]
00087 sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
00088 rjmp haveTwoBitsK ;[-1]
00089 pop YH ;[0] undo the pushes from before
00090 pop r0 ;[2]
00091 rjmp waitForK ;[4] this was not the end of sync, retry
00092 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
00093 ; bit times (= 22 cycles).
00094
00095 ;----------------------------------------------------------------------------
00096 ; push more registers and initialize values while we sample the first bits:
00097 ;----------------------------------------------------------------------------
00098 haveTwoBitsK: ;[1]
00099 push shift ;[1]
00100 push x1 ;[3]
00101 push x2 ;[5]
00102 push x3 ;[7]
00103 ldi shift, 0xff ;[9] [rx loop init]
00104 ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag
00105
00106 in x1, USBIN ;[11] <-- sample bit 0
00107 bst x1, USBMINUS ;[12]
00108 bld shift, 0 ;[13]
00109 push x4 ;[14] == phase
00110 ; [---] ;[15]
00111 push cnt ;[16]
00112 ; [---] ;[17]
00113 ldi phase, 0 ;[18] [rx loop init]
00114 ldi cnt, USB_BUFSIZE;[19] [rx loop init]
00115 rjmp rxbit1 ;[20]
00116 ; [---] ;[21]
00117
00118 ;----------------------------------------------------------------------------
00119 ; Receiver loop (numbers in brackets are cycles within byte after instr)
00120 ;----------------------------------------------------------------------------
00121 /*
00122 byte oriented operations done during loop:
00123 bit 0: store data
00124 bit 1: SE0 check
00125 bit 2: overflow check
00126 bit 3: catch up
00127 bit 4: rjmp to achieve conditional jump range
00128 bit 5: PLL
00129 bit 6: catch up
00130 bit 7: jump, fixup bitstuff
00131 ; 87 [+ 2] cycles
00132 ------------------------------------------------------------------
00133 */
00134 continueWithBit5:
00135 in x2, USBIN ;[055] <-- bit 5
00136 eor r0, x2 ;[056]
00137 or phase, r0 ;[057]
00138 sbrc phase, USBMINUS ;[058]
00139 lpm ;[059] optional nop3; modifies r0
00140 in phase, USBIN ;[060] <-- phase
00141 eor x1, x2 ;[061]
00142 bst x1, USBMINUS ;[062]
00143 bld shift, 5 ;[063]
00144 andi shift, 0x3f ;[064]
00145 in x1, USBIN ;[065] <-- bit 6
00146 breq unstuff5 ;[066] *** unstuff escape
00147 eor phase, x1 ;[067]
00148 eor x2, x1 ;[068]
00149 bst x2, USBMINUS ;[069]
00150 bld shift, 6 ;[070]
00151 didUnstuff6: ;[ ]
00152 in r0, USBIN ;[071] <-- phase
00153 cpi shift, 0x02 ;[072]
00154 brlo unstuff6 ;[073] *** unstuff escape
00155 didUnstuff5: ;[ ]
00156 nop2 ;[074]
00157 ; [---] ;[075]
00158 in x2, USBIN ;[076] <-- bit 7
00159 eor x1, x2 ;[077]
00160 bst x1, USBMINUS ;[078]
00161 bld shift, 7 ;[079]
00162 didUnstuff7: ;[ ]
00163 eor r0, x2 ;[080]
00164 or phase, r0 ;[081]
00165 in r0, USBIN ;[082] <-- phase
00166 cpi shift, 0x04 ;[083]
00167 brsh rxLoop ;[084]
00168 ; [---] ;[085]
00169 unstuff7: ;[ ]
00170 andi x3, ~0x80 ;[085]
00171 ori shift, 0x80 ;[086]
00172 in x2, USBIN ;[087] <-- sample stuffed bit 7
00173 nop ;[088]
00174 rjmp didUnstuff7 ;[089]
00175 ; [---] ;[090]
00176 ;[080]
00177
00178 unstuff5: ;[067]
00179 eor phase, x1 ;[068]
00180 andi x3, ~0x20 ;[069]
00181 ori shift, 0x20 ;[070]
00182 in r0, USBIN ;[071] <-- phase
00183 mov x2, x1 ;[072]
00184 nop ;[073]
00185 nop2 ;[074]
00186 ; [---] ;[075]
00187 in x1, USBIN ;[076] <-- bit 6
00188 eor r0, x1 ;[077]
00189 or phase, r0 ;[078]
00190 eor x2, x1 ;[079]
00191 bst x2, USBMINUS ;[080]
00192 bld shift, 6 ;[081] no need to check bitstuffing, we just had one
00193 in r0, USBIN ;[082] <-- phase
00194 rjmp didUnstuff5 ;[083]
00195 ; [---] ;[084]
00196 ;[074]
00197
00198 unstuff6: ;[074]
00199 andi x3, ~0x40 ;[075]
00200 in x1, USBIN ;[076] <-- bit 6 again
00201 ori shift, 0x40 ;[077]
00202 nop2 ;[078]
00203 ; [---] ;[079]
00204 rjmp didUnstuff6 ;[080]
00205 ; [---] ;[081]
00206 ;[071]
00207
00208 unstuff0: ;[013]
00209 eor r0, x2 ;[014]
00210 or phase, r0 ;[015]
00211 andi x2, USBMASK ;[016] check for SE0
00212 in r0, USBIN ;[017] <-- phase
00213 breq didUnstuff0 ;[018] direct jump to se0 would be too long
00214 andi x3, ~0x01 ;[019]
00215 ori shift, 0x01 ;[020]
00216 mov x1, x2 ;[021] mov existing sample
00217 in x2, USBIN ;[022] <-- bit 1 again
00218 rjmp didUnstuff0 ;[023]
00219 ; [---] ;[024]
00220 ;[014]
00221
00222 unstuff1: ;[024]
00223 eor r0, x1 ;[025]
00224 or phase, r0 ;[026]
00225 andi x3, ~0x02 ;[027]
00226 in r0, USBIN ;[028] <-- phase
00227 ori shift, 0x02 ;[029]
00228 mov x2, x1 ;[030]
00229 rjmp didUnstuff1 ;[031]
00230 ; [---] ;[032]
00231 ;[022]
00232
00233 unstuff2: ;[035]
00234 eor r0, x2 ;[036]
00235 or phase, r0 ;[037]
00236 andi x3, ~0x04 ;[038]
00237 in r0, USBIN ;[039] <-- phase
00238 ori shift, 0x04 ;[040]
00239 mov x1, x2 ;[041]
00240 rjmp didUnstuff2 ;[042]
00241 ; [---] ;[043]
00242 ;[033]
00243
00244 unstuff3: ;[043]
00245 in x2, USBIN ;[044] <-- bit 3 again
00246 eor r0, x2 ;[045]
00247 or phase, r0 ;[046]
00248 andi x3, ~0x08 ;[047]
00249 ori shift, 0x08 ;[048]
00250 nop ;[049]
00251 in r0, USBIN ;[050] <-- phase
00252 rjmp didUnstuff3 ;[051]
00253 ; [---] ;[052]
00254 ;[042]
00255
00256 unstuff4: ;[053]
00257 andi x3, ~0x10 ;[054]
00258 in x1, USBIN ;[055] <-- bit 4 again
00259 ori shift, 0x10 ;[056]
00260 rjmp didUnstuff4 ;[057]
00261 ; [---] ;[058]
00262 ;[048]
00263
00264 rxLoop: ;[085]
00265 eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others
00266 in x1, USBIN ;[000] <-- bit 0
00267 st y+, x3 ;[001]
00268 ; [---] ;[002]
00269 eor r0, x1 ;[003]
00270 or phase, r0 ;[004]
00271 eor x2, x1 ;[005]
00272 in r0, USBIN ;[006] <-- phase
00273 ser x3 ;[007]
00274 bst x2, USBMINUS ;[008]
00275 bld shift, 0 ;[009]
00276 andi shift, 0xf9 ;[010]
00277 rxbit1: ;[ ]
00278 in x2, USBIN ;[011] <-- bit 1
00279 breq unstuff0 ;[012] *** unstuff escape
00280 andi x2, USBMASK ;[013] SE0 check for bit 1
00281 didUnstuff0: ;[ ] Z only set if we detected SE0 in bitstuff
00282 breq se0 ;[014]
00283 eor r0, x2 ;[015]
00284 or phase, r0 ;[016]
00285 in r0, USBIN ;[017] <-- phase
00286 eor x1, x2 ;[018]
00287 bst x1, USBMINUS ;[019]
00288 bld shift, 1 ;[020]
00289 andi shift, 0xf3 ;[021]
00290 didUnstuff1: ;[ ]
00291 in x1, USBIN ;[022] <-- bit 2
00292 breq unstuff1 ;[023] *** unstuff escape
00293 eor r0, x1 ;[024]
00294 or phase, r0 ;[025]
00295 subi cnt, 1 ;[026] overflow check
00296 brcs overflow ;[027]
00297 in r0, USBIN ;[028] <-- phase
00298 eor x2, x1 ;[029]
00299 bst x2, USBMINUS ;[030]
00300 bld shift, 2 ;[031]
00301 andi shift, 0xe7 ;[032]
00302 didUnstuff2: ;[ ]
00303 in x2, USBIN ;[033] <-- bit 3
00304 breq unstuff2 ;[034] *** unstuff escape
00305 eor r0, x2 ;[035]
00306 or phase, r0 ;[036]
00307 eor x1, x2 ;[037]
00308 bst x1, USBMINUS ;[038]
00309 in r0, USBIN ;[039] <-- phase
00310 bld shift, 3 ;[040]
00311 andi shift, 0xcf ;[041]
00312 didUnstuff3: ;[ ]
00313 breq unstuff3 ;[042] *** unstuff escape
00314 nop ;[043]
00315 in x1, USBIN ;[044] <-- bit 4
00316 eor x2, x1 ;[045]
00317 bst x2, USBMINUS ;[046]
00318 bld shift, 4 ;[047]
00319 didUnstuff4: ;[ ]
00320 eor r0, x1 ;[048]
00321 or phase, r0 ;[049]
00322 in r0, USBIN ;[050] <-- phase
00323 andi shift, 0x9f ;[051]
00324 breq unstuff4 ;[052] *** unstuff escape
00325 rjmp continueWithBit5;[053]
00326 ; [---] ;[054]
00327
00328 macro POP_STANDARD ; 16 cycles
00329 pop cnt
00330 pop x4
00331 pop x3
00332 pop x2
00333 pop x1
00334 pop shift
00335 pop YH
00336 pop r0
00337 endm
00338 macro POP_RETI ; 5 cycles
00339 pop YL
00340 out SREG, YL
00341 pop YL
00342 endm
00343
00344 #include "asmcommon.inc"
00345
00346
00347 ; USB spec says:
00348 ; idle = J
00349 ; J = (D+ = 0), (D- = 1)
00350 ; K = (D+ = 1), (D- = 0)
00351 ; Spec allows 7.5 bit times from EOP to SOP for replies
00352
00353 bitstuff7:
00354 eor x1, x4 ;[4]
00355 ldi x2, 0 ;[5]
00356 nop2 ;[6] C is zero (brcc)
00357 rjmp didStuff7 ;[8]
00358
00359 bitstuffN:
00360 eor x1, x4 ;[5]
00361 ldi x2, 0 ;[6]
00362 lpm ;[7] 3 cycle NOP, modifies r0
00363 out USBOUT, x1 ;[10] <-- out
00364 rjmp didStuffN ;[0]
00365
00366 #define bitStatus x3
00367
00368 sendNakAndReti:
00369 ldi cnt, USBPID_NAK ;[-19]
00370 rjmp sendCntAndReti ;[-18]
00371 sendAckAndReti:
00372 ldi cnt, USBPID_ACK ;[-17]
00373 sendCntAndReti:
00374 mov r0, cnt ;[-16]
00375 ldi YL, 0 ;[-15] R0 address is 0
00376 ldi YH, 0 ;[-14]
00377 ldi cnt, 2 ;[-13]
00378 ; rjmp usbSendAndReti fallthrough
00379
00380 ;usbSend:
00381 ;pointer to data in 'Y'
00382 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
00383 ;uses: x1...x4, shift, cnt, Y
00384 ;Numbers in brackets are time since first bit of sync pattern is sent
00385 usbSendAndReti: ; 12 cycles until SOP
00386 in x2, USBDDR ;[-12]
00387 ori x2, USBMASK ;[-11]
00388 sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
00389 in x1, USBOUT ;[-8] port mirror for tx loop
00390 out USBDDR, x2 ;[-7] <- acquire bus
00391 ; need not init x2 (bitstuff history) because sync starts with 0
00392 ldi x4, USBMASK ;[-6] exor mask
00393 ldi shift, 0x80 ;[-5] sync byte is first byte sent
00394 ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes
00395 byteloop:
00396 bitloop:
00397 sbrs shift, 0 ;[8] [-3]
00398 eor x1, x4 ;[9] [-2]
00399 out USBOUT, x1 ;[10] [-1] <-- out
00400 ror shift ;[0]
00401 ror x2 ;[1]
00402 didStuffN:
00403 cpi x2, 0xfc ;[2]
00404 brcc bitstuffN ;[3]
00405 nop ;[4]
00406 subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37
00407 brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value
00408 sbrs shift, 0 ;[7]
00409 eor x1, x4 ;[8]
00410 ror shift ;[9]
00411 didStuff7:
00412 out USBOUT, x1 ;[10] <-- out
00413 ror x2 ;[0]
00414 cpi x2, 0xfc ;[1]
00415 brcc bitstuff7 ;[2]
00416 ld shift, y+ ;[3]
00417 dec cnt ;[5]
00418 brne byteloop ;[6]
00419 ;make SE0:
00420 cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles]
00421 lds x2, usbNewDeviceAddr;[8]
00422 lsl x2 ;[10] we compare with left shifted address
00423 out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
00424 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
00425 ;set address only after data packet was sent, not after handshake
00426 subi YL, 2 ;[0] Only assign address on data packets, not ACK/NAK in r0
00427 sbci YH, 0 ;[1]
00428 breq skipAddrAssign ;[2]
00429 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
00430 skipAddrAssign:
00431 ;end of usbDeviceAddress transfer
00432 ldi x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag
00433 USB_STORE_PENDING(x2) ;[5]
00434 ori x1, USBIDLE ;[6]
00435 in x2, USBDDR ;[7]
00436 cbr x2, USBMASK ;[8] set both pins to input
00437 mov x3, x1 ;[9]
00438 cbr x3, USBMASK ;[10] configure no pullup on both pins
00439 ldi x4, 4 ;[11]
00440 se0Delay:
00441 dec x4 ;[12] [15] [18] [21]
00442 brne se0Delay ;[13] [16] [19] [22]
00443 out USBOUT, x1 ;[23] <-- out J (idle) -- end of SE0 (EOP signal)
00444 out USBDDR, x2 ;[24] <-- release bus now
00445 out USBOUT, x3 ;[25] <-- ensure no pull-up resistors are active
00446 rjmp doReturn
00447