?? usbdrvasm16.s
字號:
doReturn: pop cnt pop x4 pop x3 pop x2 pop x1 pop shift pop bitcntsofError: pop YH pop YL out SREG, YL pop YL 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 bitcnt ;[50] in YL, USB_INTR_PENDING;[52] sbrc YL, USB_INTR_PENDING_BIT;[53] check whether data is already arriving rjmp waitForJ ;[54] save the pops and pushes -- a new interrupt is aready pending rjmp sofError ;[55] 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 repliesbitstuffN: eor x1, x4 ;[5] ldi x2, 0 ;[6] nop2 ;[7] nop ;[9] out USBOUT, x1 ;[10] <-- out rjmp didStuffN ;[0] bitstuff6: eor x1, x4 ;[4] ldi x2, 0 ;[5] nop2 ;[6] C is zero (brcc) rjmp didStuff6 ;[8]bitstuff7: eor x1, x4 ;[3] ldi x2, 0 ;[4] rjmp didStuff7 ;[5]sendNakAndReti: ldi x3, USBPID_NAK ;[-18] rjmp sendX3AndReti ;[-17]sendAckAndReti: ldi cnt, USBPID_ACK ;[-17]sendCntAndReti: mov x3, cnt ;[-16]sendX3AndReti: ldi YL, 20 ;[-15] x3==r20 address is 20 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, btcnt, shift, cnt, Y;Numbers in brackets are time since first bit of sync pattern is sent;We don't match the transfer rate exactly (don't insert leap cycles every third;byte) because the spec demands only 1.5% precision anyway.usbSendAndReti: ; 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 senttxByteLoop: ldi bitcnt, 0x2a ;[-4] [6] binary 00101010txBitLoop: sbrs shift, 0 ;[-3] [7] eor x1, x4 ;[-2] [8] out USBOUT, x1 ;[-1] [9] <-- out N ror shift ;[0] [10] ror x2 ;[1]didStuffN: cpi x2, 0xfc ;[2] brcc bitstuffN ;[3] lsr bitcnt ;[4] brcc txBitLoop ;[5] brne txBitLoop ;[6] sbrs shift, 0 ;[7] eor x1, x4 ;[8] ror shift ;[9]didStuff6: out USBOUT, x1 ;[-1] [10] <-- out 6 ror x2 ;[0] [11] cpi x2, 0xfc ;[1] brcc bitstuff6 ;[2] sbrs shift, 0 ;[3] eor x1, x4 ;[4] ror shift ;[5] ror x2 ;[6]didStuff7: nop ;[7] nop2 ;[8] out USBOUT, x1 ;[-1][10] <-- out 7 cpi x2, 0xfc ;[0] [11] brcc bitstuff7 ;[1] ld shift, y+ ;[2] dec cnt ;[4] brne txByteLoop ;[4];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
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -