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
00030
00031
00032
00033
00034
00035
00036 ;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
00037 ;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
00038 ;max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable
00039 ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes
00040 ;Numbers in brackets are maximum cycles since SOF.
00041 USB_INTR_VECTOR:
00042 ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt
00043 push YL ;2 [35] push only what is necessary to sync with edge ASAP
00044 in YL, SREG ;1 [37]
00045 push YL ;2 [39]
00046 ;----------------------------------------------------------------------------
00047 ; Synchronize with sync pattern:
00048 ;----------------------------------------------------------------------------
00049 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
00050 ;sync up with J to K edge during sync pattern -- use fastest possible loops
00051 ;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
00052 waitForJ:
00053 sbis USBIN, USBMINUS ;1 [40] wait for D- == 1
00054 rjmp waitForJ ;2
00055 waitForK:
00056 ;The following code results in a sampling window of 1/4 bit which meets the spec.
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:
00074 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 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 YH ;2 [2]
00078 lds YL, usbInputBufOffset;2 [4]
00079 clr YH ;1 [5]
00080 subi YL, lo8(-(usbRxBuf));1 [6]
00081 sbci YH, hi8(-(usbRxBuf));1 [7]
00082
00083 sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early]
00084 rjmp haveTwoBitsK ;2 [10]
00085 pop YH ;2 [11] undo the push from before
00086 rjmp waitForK ;2 [13] this was not the end of sync, retry
00087 haveTwoBitsK:
00088 ;----------------------------------------------------------------------------
00089 ; push more registers and initialize values while we sample the first bits:
00090 ;----------------------------------------------------------------------------
00091 push shift ;2 [16]
00092 push x1 ;2 [12]
00093 push x2 ;2 [14]
00094
00095 in x1, USBIN ;1 [17] <-- sample bit 0
00096 ldi shift, 0xff ;1 [18]
00097 bst x1, USBMINUS ;1 [19]
00098 bld shift, 0 ;1 [20]
00099 push x3 ;2 [22]
00100 push cnt ;2 [24]
00101
00102 in x2, USBIN ;1 [25] <-- sample bit 1
00103 ser x3 ;1 [26] [inserted init instruction]
00104 eor x1, x2 ;1 [27]
00105 bst x1, USBMINUS ;1 [28]
00106 bld shift, 1 ;1 [29]
00107 ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction]
00108 rjmp rxbit2 ;2 [32]
00109
00110 ;----------------------------------------------------------------------------
00111 ; Receiver loop (numbers in brackets are cycles within byte after instr)
00112 ;----------------------------------------------------------------------------
00113
00114 unstuff0: ;1 (branch taken)
00115 andi x3, ~0x01 ;1 [15]
00116 mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit
00117 in x2, USBIN ;1 [17] <-- sample bit 1 again
00118 ori shift, 0x01 ;1 [18]
00119 rjmp didUnstuff0 ;2 [20]
00120
00121 unstuff1: ;1 (branch taken)
00122 mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit
00123 andi x3, ~0x02 ;1 [22]
00124 ori shift, 0x02 ;1 [23]
00125 nop ;1 [24]
00126 in x1, USBIN ;1 [25] <-- sample bit 2 again
00127 rjmp didUnstuff1 ;2 [27]
00128
00129 unstuff2: ;1 (branch taken)
00130 andi x3, ~0x04 ;1 [29]
00131 ori shift, 0x04 ;1 [30]
00132 mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit
00133 nop ;1 [32]
00134 in x2, USBIN ;1 [33] <-- sample bit 3
00135 rjmp didUnstuff2 ;2 [35]
00136
00137 unstuff3: ;1 (branch taken)
00138 in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late]
00139 andi x3, ~0x08 ;1 [35]
00140 ori shift, 0x08 ;1 [36]
00141 rjmp didUnstuff3 ;2 [38]
00142
00143 unstuff4: ;1 (branch taken)
00144 andi x3, ~0x10 ;1 [40]
00145 in x1, USBIN ;1 [41] <-- sample stuffed bit 4
00146 ori shift, 0x10 ;1 [42]
00147 rjmp didUnstuff4 ;2 [44]
00148
00149 unstuff5: ;1 (branch taken)
00150 andi x3, ~0x20 ;1 [48]
00151 in x2, USBIN ;1 [49] <-- sample stuffed bit 5
00152 ori shift, 0x20 ;1 [50]
00153 rjmp didUnstuff5 ;2 [52]
00154
00155 unstuff6: ;1 (branch taken)
00156 andi x3, ~0x40 ;1 [56]
00157 in x1, USBIN ;1 [57] <-- sample stuffed bit 6
00158 ori shift, 0x40 ;1 [58]
00159 rjmp didUnstuff6 ;2 [60]
00160
00161 ; extra jobs done during bit interval:
00162 ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs]
00163 ; bit 1: se0 check
00164 ; bit 2: overflow check
00165 ; bit 3: recovery from delay [bit 0 tasks took too long]
00166 ; bit 4: none
00167 ; bit 5: none
00168 ; bit 6: none
00169 ; bit 7: jump, eor
00170 rxLoop:
00171 eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others
00172 in x1, USBIN ;1 [1] <-- sample bit 0
00173 st y+, x3 ;2 [3] store data
00174 ser x3 ;1 [4]
00175 nop ;1 [5]
00176 eor x2, x1 ;1 [6]
00177 bst x2, USBMINUS;1 [7]
00178 bld shift, 0 ;1 [8]
00179 in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed)
00180 andi x2, USBMASK ;1 [10]
00181 breq se0 ;1 [11] SE0 check for bit 1
00182 andi shift, 0xf9 ;1 [12]
00183 didUnstuff0:
00184 breq unstuff0 ;1 [13]
00185 eor x1, x2 ;1 [14]
00186 bst x1, USBMINUS;1 [15]
00187 bld shift, 1 ;1 [16]
00188 rxbit2:
00189 in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed)
00190 andi shift, 0xf3 ;1 [18]
00191 breq unstuff1 ;1 [19] do remaining work for bit 1
00192 didUnstuff1:
00193 subi cnt, 1 ;1 [20]
00194 brcs overflow ;1 [21] loop control
00195 eor x2, x1 ;1 [22]
00196 bst x2, USBMINUS;1 [23]
00197 bld shift, 2 ;1 [24]
00198 in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed)
00199 andi shift, 0xe7 ;1 [26]
00200 breq unstuff2 ;1 [27]
00201 didUnstuff2:
00202 eor x1, x2 ;1 [28]
00203 bst x1, USBMINUS;1 [29]
00204 bld shift, 3 ;1 [30]
00205 didUnstuff3:
00206 andi shift, 0xcf ;1 [31]
00207 breq unstuff3 ;1 [32]
00208 in x1, USBIN ;1 [33] <-- sample bit 4
00209 eor x2, x1 ;1 [34]
00210 bst x2, USBMINUS;1 [35]
00211 bld shift, 4 ;1 [36]
00212 didUnstuff4:
00213 andi shift, 0x9f ;1 [37]
00214 breq unstuff4 ;1 [38]
00215 nop2 ;2 [40]
00216 in x2, USBIN ;1 [41] <-- sample bit 5
00217 eor x1, x2 ;1 [42]
00218 bst x1, USBMINUS;1 [43]
00219 bld shift, 5 ;1 [44]
00220 didUnstuff5:
00221 andi shift, 0x3f ;1 [45]
00222 breq unstuff5 ;1 [46]
00223 nop2 ;2 [48]
00224 in x1, USBIN ;1 [49] <-- sample bit 6
00225 eor x2, x1 ;1 [50]
00226 bst x2, USBMINUS;1 [51]
00227 bld shift, 6 ;1 [52]
00228 didUnstuff6:
00229 cpi shift, 0x02 ;1 [53]
00230 brlo unstuff6 ;1 [54]
00231 nop2 ;2 [56]
00232 in x2, USBIN ;1 [57] <-- sample bit 7
00233 eor x1, x2 ;1 [58]
00234 bst x1, USBMINUS;1 [59]
00235 bld shift, 7 ;1 [60]
00236 didUnstuff7:
00237 cpi shift, 0x04 ;1 [61]
00238 brsh rxLoop ;2 [63] loop control
00239 unstuff7:
00240 andi x3, ~0x80 ;1 [63]
00241 ori shift, 0x80 ;1 [64]
00242 in x2, USBIN ;1 [65] <-- sample stuffed bit 7
00243 nop ;1 [66]
00244 rjmp didUnstuff7 ;2 [68]
00245
00246 macro POP_STANDARD ; 12 cycles
00247 pop cnt
00248 pop x3
00249 pop x2
00250 pop x1
00251 pop shift
00252 pop YH
00253 endm
00254 macro POP_RETI ; 5 cycles
00255 pop YL
00256 out SREG, YL
00257 pop YL
00258 endm
00259
00260 #include "asmcommon.inc"
00261
00262 ;----------------------------------------------------------------------------
00263 ; Transmitting data
00264 ;----------------------------------------------------------------------------
00265
00266 bitstuff0: ;1 (for branch taken)
00267 eor x1, x4 ;1
00268 ldi x2, 0 ;1
00269 out USBOUT, x1 ;1 <-- out
00270 rjmp didStuff0 ;2 branch back 2 cycles earlier
00271 bitstuff1: ;1 (for branch taken)
00272 eor x1, x4 ;1
00273 rjmp didStuff1 ;2 we know that C is clear, jump back to do OUT and ror 0 into x2
00274 bitstuff2: ;1 (for branch taken)
00275 eor x1, x4 ;1
00276 rjmp didStuff2 ;2 jump back 4 cycles earlier and do out and ror 0 into x2
00277 bitstuff3: ;1 (for branch taken)
00278 eor x1, x4 ;1
00279 rjmp didStuff3 ;2 jump back earlier and ror 0 into x2
00280 bitstuff4: ;1 (for branch taken)
00281 eor x1, x4 ;1
00282 ldi x2, 0 ;1
00283 out USBOUT, x1 ;1 <-- out
00284 rjmp didStuff4 ;2 jump back 2 cycles earlier
00285
00286 sendNakAndReti: ;0 [-19] 19 cycles until SOP
00287 ldi x3, USBPID_NAK ;1 [-18]
00288 rjmp usbSendX3 ;2 [-16]
00289 sendAckAndReti: ;0 [-19] 19 cycles until SOP
00290 ldi x3, USBPID_ACK ;1 [-18]
00291 rjmp usbSendX3 ;2 [-16]
00292 sendCntAndReti: ;0 [-17] 17 cycles until SOP
00293 mov x3, cnt ;1 [-16]
00294 usbSendX3: ;0 [-16]
00295 ldi YL, 20 ;1 [-15] 'x3' is R20
00296 ldi YH, 0 ;1 [-14]
00297 ldi cnt, 2 ;1 [-13]
00298 ; rjmp usbSendAndReti fallthrough
00299
00300 ; USB spec says:
00301 ; idle = J
00302 ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
00303 ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
00304 ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
00305
00306 ;usbSend:
00307 ;pointer to data in 'Y'
00308 ;number of bytes in 'cnt' -- including sync byte
00309 ;uses: x1...x4, shift, cnt, Y
00310 ;Numbers in brackets are time since first bit of sync pattern is sent
00311 usbSendAndReti: ;0 [-13] timing: 13 cycles until SOP
00312 in x2, USBDDR ;1 [-12]
00313 ori x2, USBMASK ;1 [-11]
00314 sbi USBOUT, USBMINUS;2 [-9] prepare idle state; D+ and D- must have been 0 (no pullups)
00315 in x1, USBOUT ;1 [-8] port mirror for tx loop
00316 out USBDDR, x2 ;1 [-7] <- acquire bus
00317 ; need not init x2 (bitstuff history) because sync starts with 0
00318 push x4 ;2 [-5]
00319 ldi x4, USBMASK ;1 [-4] exor mask
00320 ldi shift, 0x80 ;1 [-3] sync byte is first byte sent
00321 txLoop: ; [62]
00322 sbrs shift, 0 ;1 [-2] [62]
00323 eor x1, x4 ;1 [-1] [63]
00324 out USBOUT, x1 ;1 [0] <-- out bit 0
00325 ror shift ;1 [1]
00326 ror x2 ;1 [2]
00327 didStuff0:
00328 cpi x2, 0xfc ;1 [3]
00329 brsh bitstuff0 ;1 [4]
00330 sbrs shift, 0 ;1 [5]
00331 eor x1, x4 ;1 [6]
00332 ror shift ;1 [7]
00333 didStuff1:
00334 out USBOUT, x1 ;1 [8] <-- out bit 1
00335 ror x2 ;1 [9]
00336 cpi x2, 0xfc ;1 [10]
00337 brsh bitstuff1 ;1 [11]
00338 sbrs shift, 0 ;1 [12]
00339 eor x1, x4 ;1 [13]
00340 ror shift ;1 [14]
00341 didStuff2:
00342 ror x2 ;1 [15]
00343 out USBOUT, x1 ;1 [16] <-- out bit 2
00344 cpi x2, 0xfc ;1 [17]
00345 brsh bitstuff2 ;1 [18]
00346 sbrs shift, 0 ;1 [19]
00347 eor x1, x4 ;1 [20]
00348 ror shift ;1 [21]
00349 didStuff3:
00350 ror x2 ;1 [22]
00351 cpi x2, 0xfc ;1 [23]
00352 out USBOUT, x1 ;1 [24] <-- out bit 3
00353 brsh bitstuff3 ;1 [25]
00354 nop2 ;2 [27]
00355 ld x3, y+ ;2 [29]
00356 sbrs shift, 0 ;1 [30]
00357 eor x1, x4 ;1 [31]
00358 out USBOUT, x1 ;1 [32] <-- out bit 4
00359 ror shift ;1 [33]
00360 ror x2 ;1 [34]
00361 didStuff4:
00362 cpi x2, 0xfc ;1 [35]
00363 brsh bitstuff4 ;1 [36]
00364 sbrs shift, 0 ;1 [37]
00365 eor x1, x4 ;1 [38]
00366 ror shift ;1 [39]
00367 didStuff5:
00368 out USBOUT, x1 ;1 [40] <-- out bit 5
00369 ror x2 ;1 [41]
00370 cpi x2, 0xfc ;1 [42]
00371 brsh bitstuff5 ;1 [43]
00372 sbrs shift, 0 ;1 [44]
00373 eor x1, x4 ;1 [45]
00374 ror shift ;1 [46]
00375 didStuff6:
00376 ror x2 ;1 [47]
00377 out USBOUT, x1 ;1 [48] <-- out bit 6
00378 cpi x2, 0xfc ;1 [49]
00379 brsh bitstuff6 ;1 [50]
00380 sbrs shift, 0 ;1 [51]
00381 eor x1, x4 ;1 [52]
00382 ror shift ;1 [53]
00383 didStuff7:
00384 ror x2 ;1 [54]
00385 cpi x2, 0xfc ;1 [55]
00386 out USBOUT, x1 ;1 [56] <-- out bit 7
00387 brsh bitstuff7 ;1 [57]
00388 mov shift, x3 ;1 [58]
00389 dec cnt ;1 [59]
00390 brne txLoop ;1/2 [60/61]
00391 ;make SE0:
00392 cbr x1, USBMASK ;1 [61] prepare SE0 [spec says EOP may be 15 to 18 cycles]
00393 pop x4 ;2 [63]
00394 ;brackets are cycles from start of SE0 now
00395 out USBOUT, x1 ;1 [0] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle
00396 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
00397 ;set address only after data packet was sent, not after handshake
00398 lds x2, usbNewDeviceAddr;2 [2]
00399 lsl x2; ;1 [3] we compare with left shifted address
00400 subi YL, 20 + 2 ;1 [4] Only assign address on data packets, not ACK/NAK in x3
00401 sbci YH, 0 ;1 [5]
00402 breq skipAddrAssign ;2 [7]
00403 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
00404 skipAddrAssign:
00405 ;end of usbDeviceAddress transfer
00406 ldi x2, 1<<USB_INTR_PENDING_BIT;1 [8] int0 occurred during TX -- clear pending flag
00407 USB_STORE_PENDING(x2) ;1 [9]
00408 ori x1, USBIDLE ;1 [10]
00409 in x2, USBDDR ;1 [11]
00410 cbr x2, USBMASK ;1 [12] set both pins to input
00411 mov x3, x1 ;1 [13]
00412 cbr x3, USBMASK ;1 [14] configure no pullup on both pins
00413 out USBOUT, x1 ;1 [15] <-- out J (idle) -- end of SE0 (EOP signal)
00414 out USBDDR, x2 ;1 [16] <-- release bus now
00415 out USBOUT, x3 ;1 [17] <-- ensure no pull-up resistors are active
00416 rjmp doReturn
00417
00418 bitstuff5: ;1 (for branch taken)
00419 eor x1, x4 ;1
00420 rjmp didStuff5 ;2 same trick as in bitstuff1...
00421 bitstuff6: ;1 (for branch taken)
00422 eor x1, x4 ;1
00423 rjmp didStuff6 ;2 same trick as above...
00424 bitstuff7: ;1 (for branch taken)
00425 eor x1, x4 ;1
00426 rjmp didStuff7 ;2 same trick as above...
00427