?? usbdrvasm165.s
字號:
or phase, r0 ;[025] subi cnt, 1 ;[026] overflow check brcs overflow ;[027] in r0, USBIN ;[028] <-- phase eor x2, x1 ;[029] bst x2, USBMINUS ;[030] bld shift, 2 ;[031] andi shift, 0xe7 ;[032]didUnstuff2: ;[ ] in x2, USBIN ;[033] <-- bit 3 breq unstuff2 ;[034] *** unstuff escape eor r0, x2 ;[035] or phase, r0 ;[036] eor x1, x2 ;[037] bst x1, USBMINUS ;[038] in r0, USBIN ;[039] <-- phase bld shift, 3 ;[040] andi shift, 0xcf ;[041]didUnstuff3: ;[ ] breq unstuff3 ;[042] *** unstuff escape nop ;[043] in x1, USBIN ;[044] <-- bit 4 eor x2, x1 ;[045] bst x2, USBMINUS ;[046] bld shift, 4 ;[047]didUnstuff4: ;[ ] eor r0, x1 ;[048] or phase, r0 ;[049] in r0, USBIN ;[050] <-- phase andi shift, 0x9f ;[051] breq unstuff4 ;[052] *** unstuff escape rjmp continueWithBit5;[053]; [---] ;[054];----------------------------------------------------------------------------; Processing of received packet (numbers in brackets are cycles after center of SE0);----------------------------------------------------------------------------;This is the only non-error exit point for the software receiver loop;we don't check any CRCs here because there is no time left.#define token x1se0: subi cnt, USB_BUFSIZE ;[5] neg cnt ;[6] cpi cnt, 3 ;[7] ldi x2, 1<<USB_INTR_PENDING_BIT ;[8] out USB_INTR_PENDING, x2;[9] clear pending intr and check flag later. SE0 should be over. brlo doReturn ;[10] this is probably an ACK, NAK or similar packet sub YL, cnt ;[11] sbci YH, 0 ;[12] ld token, y ;[13] cpi token, USBPID_DATA0 ;[15] breq handleData ;[16] cpi token, USBPID_DATA1 ;[17] breq handleData ;[18] ldd x2, y+1 ;[19] ADDR and 1 bit endpoint number mov x3, x2 ;[21] store for endpoint number andi x2, 0x7f ;[22] x2 is now ADDR lds shift, usbDeviceAddr;[23] cp x2, shift ;[25]overflow: ; This is a hack: brcs overflow will never have Z flag set brne ignorePacket ;[26] packet for different address cpi token, USBPID_IN ;[27] breq handleIn ;[28] cpi token, USBPID_SETUP ;[29] breq handleSetupOrOut ;[30] cpi token, USBPID_OUT ;[31] breq handleSetupOrOut ;[32]; rjmp ignorePacket ;fallthrough, should not happen anyway.ignorePacket: clr shift sts usbCurrentTok, shiftdoReturn: pop cnt pop x4 pop x3 pop x2 pop x1 pop shift pop YH pop YLsofError: pop r0 out SREG, r0 pop r0 reti#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_HAVE_INTRIN_ENDPOINT3handleIn3: lds cnt, usbTxLen3 ;[43] sbrc cnt, 4 ;[45] rjmp sendCntAndReti ;[46] 48 + 16 = 64 until SOP sts usbTxLen3, x1 ;[47] x1 == USBPID_NAK from above ldi YL, lo8(usbTxBuf3) ;[49] ldi YH, hi8(usbTxBuf3) ;[50] rjmp usbSendAndReti ;[51] 53 + 12 = 65 until SOP#endif;Setup and Out are followed by a data packet two bit times (16 cycles) after;the end of SE0. The sync code allows up to 40 cycles delay from the start of;the sync pattern until the first bit is sampled. That's a total of 56 cycles.handleSetupOrOut: ;[34]#if USB_CFG_IMPLEMENT_FN_WRITEOUT /* if we have data for second OUT endpoint, set usbCurrentTok to -1 */ sbrc x3, 7 ;[34] skip if endpoint 0 ldi token, -1 ;[35] indicate that this is endpoint 1 OUT#endif sts usbCurrentTok, token;[36] pop cnt ;[38] pop x4 ;[40] pop x3 ;[42] pop x2 ;[44] pop x1 ;[46] pop shift ;[48] pop YH ;[50] pop YL ;[52] in r0, USB_INTR_PENDING;[54] sbrc r0, USB_INTR_PENDING_BIT;[55] check whether data is already arriving rjmp waitForJ ;[56] save the pops and pushes -- a new interrupt is aready pending rjmp sofError ;[57] not an error, but it does the pops and reti we wanthandleData: lds token, usbCurrentTok;[20] tst token ;[22] breq doReturn ;[23] lds x2, usbRxLen ;[24] tst x2 ;[26] brne sendNakAndReti ;[27]; 2006-03-11: The following two lines fix a problem where the device was not; recognized if usbPoll() was called less frequently than once every 4 ms. cpi cnt, 4 ;[28] zero sized data packets are status phase only -- ignore and ack brmi sendAckAndReti ;[29] keep rx buffer clean -- we must not NAK next SETUP sts usbRxLen, cnt ;[30] store received data, swap buffers sts usbRxToken, token ;[32] lds x2, usbInputBufOffset;[34] swap buffers ldi cnt, USB_BUFSIZE ;[36] sub cnt, x2 ;[37] sts usbInputBufOffset, cnt;[38] buffers now swapped rjmp sendAckAndReti ;[40] 42 + 17 = 59 until SOPhandleIn:;We don't send any data as long as the C code has not processed the current;input data and potentially updated the output data. That's more efficient;in terms of code size than clearing the tx buffers when a packet is received. lds x1, usbRxLen ;[30] cpi x1, 1 ;[32] negative values are flow control, 0 means "buffer free" brge sendNakAndReti ;[33] unprocessed input packet? ldi x1, USBPID_NAK ;[34] prepare value for usbTxLen#if USB_CFG_HAVE_INTRIN_ENDPOINT sbrc x3, 7 ;[35] x3 contains addr + endpoint rjmp handleIn1 ;[36]#endif lds cnt, usbTxLen ;[37] sbrc cnt, 4 ;[39] all handshake tokens have bit 4 set rjmp sendCntAndReti ;[40] 42 + 16 = 58 until SOP sts usbTxLen, x1 ;[41] x1 == USBPID_NAK from above ldi YL, lo8(usbTxBuf) ;[43] ldi YH, hi8(usbTxBuf) ;[44] rjmp usbSendAndReti ;[45] 47 + 12 = 59 until SOP; Comment about when to set usbTxLen to USBPID_NAK:; We should set it back when we receive the ACK from the host. This would; be simple to implement: One static variable which stores whether the last; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the; ACK. However, we set it back immediately when we send the package,; assuming that no error occurs and the host sends an ACK. We save one byte; RAM this way and avoid potential problems with endless retries. The rest of; the driver assumes error-free transfers anyway.#if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */handleIn1: ;[38]#if USB_CFG_HAVE_INTRIN_ENDPOINT3; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint ldd x2, y+2 ;[38] sbrc x2, 0 ;[40] rjmp handleIn3 ;[41]#endif lds cnt, usbTxLen1 ;[42] sbrc cnt, 4 ;[44] all handshake tokens have bit 4 set rjmp sendCntAndReti ;[45] 47 + 16 = 63 until SOP sts usbTxLen1, x1 ;[46] x1 == USBPID_NAK from above ldi YL, lo8(usbTxBuf1) ;[48] ldi YH, hi8(usbTxBuf1) ;[49] rjmp usbSendAndReti ;[50] 52 + 12 + 64 until SOP#endif; USB spec says:; idle = J; J = (D+ = 0), (D- = 1); K = (D+ = 1), (D- = 0); Spec allows 7.5 bit times from EOP to SOP for repliesbitstuff7: eor x1, x4 ;[4] ldi x2, 0 ;[5] nop2 ;[6] C is zero (brcc) rjmp didStuff7 ;[8]bitstuffN: eor x1, x4 ;[5] ldi x2, 0 ;[6] lpm ;[7] 3 cycle NOP, modifies r0 out USBOUT, x1 ;[10] <-- out rjmp didStuffN ;[0]#define bitStatus x3sendNakAndReti: ldi cnt, USBPID_NAK ;[-19] rjmp sendCntAndReti ;[-18]sendAckAndReti: ldi cnt, USBPID_ACK ;[-17]sendCntAndReti: mov r0, cnt ;[-16] ldi YL, 0 ;[-15] R0 address is 0 ldi YH, 0 ;[-14] ldi cnt, 2 ;[-13]; rjmp usbSendAndReti fallthrough;usbSend:;pointer to data in 'Y';number of bytes in 'cnt' -- including sync byte [range 2 ... 12];uses: x1...x4, shift, cnt, Y;Numbers in brackets are time since first bit of sync pattern is sentusbSendAndReti: ; 12 cycles until SOP in x2, USBDDR ;[-12] ori x2, USBMASK ;[-11] sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) in x1, USBOUT ;[-8] port mirror for tx loop out USBDDR, x2 ;[-7] <- acquire bus; need not init x2 (bitstuff history) because sync starts with 0 ldi x4, USBMASK ;[-6] exor mask ldi shift, 0x80 ;[-5] sync byte is first byte sent ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytesbyteloop:bitloop: sbrs shift, 0 ;[8] [-3] eor x1, x4 ;[9] [-2] out USBOUT, x1 ;[10] [-1] <-- out ror shift ;[0] ror x2 ;[1]didStuffN: cpi x2, 0xfc ;[2] brcc bitstuffN ;[3] nop ;[4] subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37 brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value sbrs shift, 0 ;[7] eor x1, x4 ;[8] ror shift ;[9]didStuff7: out USBOUT, x1 ;[10] <-- out ror x2 ;[0] cpi x2, 0xfc ;[1] brcc bitstuff7 ;[2] ld shift, y+ ;[3] dec cnt ;[5] brne byteloop ;[6];make SE0: cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles] lds x2, usbNewDeviceAddr;[8] out USBOUT, x1 ;[10] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm:;set address only after data packet was sent, not after handshake subi YL, 2 ;[0] sbci YH, 0 ;[1] breq skipAddrAssign ;[2] sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longerskipAddrAssign:;end of usbDeviceAddress transfer ldi x2, 1<<USB_INTR_PENDING_BIT;[4] int0 occurred during TX -- clear pending flag out USB_INTR_PENDING, x2;[5] ori x1, USBIDLE ;[6] in x2, USBDDR ;[7] cbr x2, USBMASK ;[8] set both pins to input mov x3, x1 ;[9] cbr x3, USBMASK ;[10] configure no pullup on both pins ldi x4, 4 ;[11]se0Delay: dec x4 ;[12] [15] [18] [21] brne se0Delay ;[13] [16] [19] [22] out USBOUT, x1 ;[23] <-- out J (idle) -- end of SE0 (EOP signal) out USBDDR, x2 ;[24] <-- release bus now out USBOUT, x3 ;[25] <-- ensure no pull-up resistors are active rjmp doReturn
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -