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 ;max stack usage: [ret(2), YL, SREG, YH, bitcnt, shift, x1, x2, x3, x4, cnt] = 12 bytes
00029 ;nominal frequency: 16 MHz -> 10.6666666 cycles per bit, 85.333333333 cycles per byte
00030 ; Numbers in brackets are clocks counted from center of last sync bit
00031 ; when instruction starts
00032
00033 USB_INTR_VECTOR:
00034 ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt
00035 push YL ;[-25] push only what is necessary to sync with edge ASAP
00036 in YL, SREG ;[-23]
00037 push YL ;[-22]
00038 push YH ;[-20]
00039 ;----------------------------------------------------------------------------
00040 ; Synchronize with sync pattern:
00041 ;----------------------------------------------------------------------------
00042 ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
00043 ;sync up with J to K edge during sync pattern -- use fastest possible loops
00044 ;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
00045 waitForJ:
00046 sbis USBIN, USBMINUS ;[-18] wait for D- == 1
00047 rjmp waitForJ
00048 waitForK:
00049 ;The following code results in a sampling window of < 1/4 bit which meets the spec.
00050 sbis USBIN, USBMINUS ;[-15]
00051 rjmp foundK ;[-14]
00052 sbis USBIN, USBMINUS
00053 rjmp foundK
00054 sbis USBIN, USBMINUS
00055 rjmp foundK
00056 sbis USBIN, USBMINUS
00057 rjmp foundK
00058 sbis USBIN, USBMINUS
00059 rjmp foundK
00060 sbis USBIN, USBMINUS
00061 rjmp foundK
00062 #if USB_COUNT_SOF
00063 lds YL, usbSofCount
00064 inc YL
00065 sts usbSofCount, YL
00066 #endif
00067 rjmp sofError
00068 foundK: ;[-12]
00069 ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling]
00070 ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets
00071 ;are cycles from center of first sync (double K) bit after the instruction
00072 push bitcnt ;[-12]
00073 ; [---] ;[-11]
00074 lds YL, usbInputBufOffset;[-10]
00075 ; [---] ;[-9]
00076 clr YH ;[-8]
00077 subi YL, lo8(-(usbRxBuf));[-7] [rx loop init]
00078 sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init]
00079 push shift ;[-5]
00080 ; [---] ;[-4]
00081 ldi bitcnt, 0x55 ;[-3] [rx loop init]
00082 sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early)
00083 rjmp haveTwoBitsK ;[-1]
00084 pop shift ;[0] undo the push from before
00085 pop bitcnt ;[2] undo the push from before
00086 rjmp waitForK ;[4] this was not the end of sync, retry
00087 ; The entire loop from waitForK until rjmp waitForK above must not exceed two
00088 ; bit times (= 21 cycles).
00089
00090 ;----------------------------------------------------------------------------
00091 ; push more registers and initialize values while we sample the first bits:
00092 ;----------------------------------------------------------------------------
00093 haveTwoBitsK:
00094 push x1 ;[1]
00095 push x2 ;[3]
00096 push x3 ;[5]
00097 ldi shift, 0 ;[7]
00098 ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that
00099 push x4 ;[9] == leap
00100
00101 in x1, USBIN ;[11] <-- sample bit 0
00102 andi x1, USBMASK ;[12]
00103 bst x1, USBMINUS ;[13]
00104 bld shift, 7 ;[14]
00105 push cnt ;[15]
00106 ldi leap, 0 ;[17] [rx loop init]
00107 ldi cnt, USB_BUFSIZE;[18] [rx loop init]
00108 rjmp rxbit1 ;[19] arrives at [21]
00109
00110 ;----------------------------------------------------------------------------
00111 ; Receiver loop (numbers in brackets are cycles within byte after instr)
00112 ;----------------------------------------------------------------------------
00113
00114 unstuff6:
00115 andi x2, USBMASK ;[03]
00116 ori x3, 1<<6 ;[04] will not be shifted any more
00117 andi shift, ~0x80;[05]
00118 mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6
00119 subi leap, 3 ;[07] since this is a short (10 cycle) bit, enforce leap bit
00120 rjmp didUnstuff6 ;[08]
00121
00122 unstuff7:
00123 ori x3, 1<<7 ;[09] will not be shifted any more
00124 in x2, USBIN ;[00] [10] re-sample bit 7
00125 andi x2, USBMASK ;[01]
00126 andi shift, ~0x80;[02]
00127 subi leap, 3 ;[03] since this is a short (10 cycle) bit, enforce leap bit
00128 rjmp didUnstuff7 ;[04]
00129
00130 unstuffEven:
00131 ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0
00132 in x1, USBIN ;[00] [10]
00133 andi shift, ~0x80;[01]
00134 andi x1, USBMASK ;[02]
00135 breq se0 ;[03]
00136 subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit
00137 nop ;[05]
00138 rjmp didUnstuffE ;[06]
00139
00140 unstuffOdd:
00141 ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1
00142 in x2, USBIN ;[00] [10]
00143 andi shift, ~0x80;[01]
00144 andi x2, USBMASK ;[02]
00145 breq se0 ;[03]
00146 subi leap, 3 ;[04] since this is a short (10 cycle) bit, enforce leap bit
00147 nop ;[05]
00148 rjmp didUnstuffO ;[06]
00149
00150 rxByteLoop:
00151 andi x1, USBMASK ;[03]
00152 eor x2, x1 ;[04]
00153 subi leap, 1 ;[05]
00154 brpl skipLeap ;[06]
00155 subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte
00156 nop ;1
00157 skipLeap:
00158 subi x2, 1 ;[08]
00159 ror shift ;[09]
00160 didUnstuff6:
00161 cpi shift, 0xfc ;[10]
00162 in x2, USBIN ;[00] [11] <-- sample bit 7
00163 brcc unstuff6 ;[01]
00164 andi x2, USBMASK ;[02]
00165 eor x1, x2 ;[03]
00166 subi x1, 1 ;[04]
00167 ror shift ;[05]
00168 didUnstuff7:
00169 cpi shift, 0xfc ;[06]
00170 brcc unstuff7 ;[07]
00171 eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others
00172 st y+, x3 ;[09] store data
00173 rxBitLoop:
00174 in x1, USBIN ;[00] [11] <-- sample bit 0/2/4
00175 andi x1, USBMASK ;[01]
00176 eor x2, x1 ;[02]
00177 andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7
00178 subi x2, 1 ;[04]
00179 ror shift ;[05]
00180 cpi shift, 0xfc ;[06]
00181 brcc unstuffEven ;[07]
00182 didUnstuffE:
00183 lsr x3 ;[08]
00184 lsr x3 ;[09]
00185 rxbit1:
00186 in x2, USBIN ;[00] [10] <-- sample bit 1/3/5
00187 andi x2, USBMASK ;[01]
00188 breq se0 ;[02]
00189 eor x1, x2 ;[03]
00190 subi x1, 1 ;[04]
00191 ror shift ;[05]
00192 cpi shift, 0xfc ;[06]
00193 brcc unstuffOdd ;[07]
00194 didUnstuffO:
00195 subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3
00196 brcs rxBitLoop ;[09]
00197
00198 subi cnt, 1 ;[10]
00199 in x1, USBIN ;[00] [11] <-- sample bit 6
00200 brcc rxByteLoop ;[01]
00201 rjmp overflow
00202
00203 macro POP_STANDARD ; 14 cycles
00204 pop cnt
00205 pop x4
00206 pop x3
00207 pop x2
00208 pop x1
00209 pop shift
00210 pop bitcnt
00211 endm
00212 macro POP_RETI ; 7 cycles
00213 pop YH
00214 pop YL
00215 out SREG, YL
00216 pop YL
00217 endm
00218
00219 #include "asmcommon.inc"
00220
00221 ; USB spec says:
00222 ; idle = J
00223 ; J = (D+ = 0), (D- = 1)
00224 ; K = (D+ = 1), (D- = 0)
00225 ; Spec allows 7.5 bit times from EOP to SOP for replies
00226
00227 bitstuffN:
00228 eor x1, x4 ;[5]
00229 ldi x2, 0 ;[6]
00230 nop2 ;[7]
00231 nop ;[9]
00232 out USBOUT, x1 ;[10] <-- out
00233 rjmp didStuffN ;[0]
00234
00235 bitstuff6:
00236 eor x1, x4 ;[5]
00237 ldi x2, 0 ;[6] Carry is zero due to brcc
00238 rol shift ;[7] compensate for ror shift at branch destination
00239 rjmp didStuff6 ;[8]
00240
00241 bitstuff7:
00242 ldi x2, 0 ;[2] Carry is zero due to brcc
00243 rjmp didStuff7 ;[3]
00244
00245
00246 sendNakAndReti:
00247 ldi x3, USBPID_NAK ;[-18]
00248 rjmp sendX3AndReti ;[-17]
00249 sendAckAndReti:
00250 ldi cnt, USBPID_ACK ;[-17]
00251 sendCntAndReti:
00252 mov x3, cnt ;[-16]
00253 sendX3AndReti:
00254 ldi YL, 20 ;[-15] x3==r20 address is 20
00255 ldi YH, 0 ;[-14]
00256 ldi cnt, 2 ;[-13]
00257 ; rjmp usbSendAndReti fallthrough
00258
00259 ;usbSend:
00260 ;pointer to data in 'Y'
00261 ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12]
00262 ;uses: x1...x4, btcnt, shift, cnt, Y
00263 ;Numbers in brackets are time since first bit of sync pattern is sent
00264 ;We don't match the transfer rate exactly (don't insert leap cycles every third
00265 ;byte) because the spec demands only 1.5% precision anyway.
00266 usbSendAndReti: ; 12 cycles until SOP
00267 in x2, USBDDR ;[-12]
00268 ori x2, USBMASK ;[-11]
00269 sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups)
00270 in x1, USBOUT ;[-8] port mirror for tx loop
00271 out USBDDR, x2 ;[-7] <- acquire bus
00272 ; need not init x2 (bitstuff history) because sync starts with 0
00273 ldi x4, USBMASK ;[-6] exor mask
00274 ldi shift, 0x80 ;[-5] sync byte is first byte sent
00275 txByteLoop:
00276 ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101
00277 txBitLoop:
00278 sbrs shift, 0 ;[-3] [7]
00279 eor x1, x4 ;[-2] [8]
00280 out USBOUT, x1 ;[-1] [9] <-- out N
00281 ror shift ;[0] [10]
00282 ror x2 ;[1]
00283 didStuffN:
00284 cpi x2, 0xfc ;[2]
00285 brcc bitstuffN ;[3]
00286 lsr bitcnt ;[4]
00287 brcc txBitLoop ;[5]
00288 brne txBitLoop ;[6]
00289
00290 sbrs shift, 0 ;[7]
00291 eor x1, x4 ;[8]
00292 didStuff6:
00293 out USBOUT, x1 ;[-1] [9] <-- out 6
00294 ror shift ;[0] [10]
00295 ror x2 ;[1]
00296 cpi x2, 0xfc ;[2]
00297 brcc bitstuff6 ;[3]
00298 ror shift ;[4]
00299 didStuff7:
00300 ror x2 ;[5]
00301 sbrs x2, 7 ;[6]
00302 eor x1, x4 ;[7]
00303 nop ;[8]
00304 cpi x2, 0xfc ;[9]
00305 out USBOUT, x1 ;[-1][10] <-- out 7
00306 brcc bitstuff7 ;[0] [11]
00307 ld shift, y+ ;[1]
00308 dec cnt ;[3]
00309 brne txByteLoop ;[4]
00310 ;make SE0:
00311 cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles]
00312 lds x2, usbNewDeviceAddr;[6]
00313 lsl x2 ;[8] we compare with left shifted address
00314 subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3
00315 sbci YH, 0 ;[10]
00316 out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle
00317 ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:
00318 ;set address only after data packet was sent, not after handshake
00319 breq skipAddrAssign ;[0]
00320 sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer
00321 skipAddrAssign:
00322 ;end of usbDeviceAddress transfer
00323 ldi x2, 1<<USB_INTR_PENDING_BIT;[2] int0 occurred during TX -- clear pending flag
00324 USB_STORE_PENDING(x2) ;[3]
00325 ori x1, USBIDLE ;[4]
00326 in x2, USBDDR ;[5]
00327 cbr x2, USBMASK ;[6] set both pins to input
00328 mov x3, x1 ;[7]
00329 cbr x3, USBMASK ;[8] configure no pullup on both pins
00330 ldi x4, 4 ;[9]
00331 se0Delay:
00332 dec x4 ;[10] [13] [16] [19]
00333 brne se0Delay ;[11] [14] [17] [20]
00334 out USBOUT, x1 ;[21] <-- out J (idle) -- end of SE0 (EOP signal)
00335 out USBDDR, x2 ;[22] <-- release bus now
00336 out USBOUT, x3 ;[23] <-- ensure no pull-up resistors are active
00337 rjmp doReturn