📄 usbdrvasm15.s
字号:
;-----------------------------------------------------unstuff7: ;- [08] andi x3, ~0x80 ;1 [09] in x2, USBIN ;1 [00] [10] <-- sample stuffed bit 7 andi x2, USBMASK ;1 [01] breq se0 ;1 [02] SE0 check for stuffed bit 7 ori shift, 0x80 ;1 [03] rjmp didUnstuff7 ;2 [04];----------------------------------------------------------------------------; 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: ;- [04] subi cnt, USB_BUFSIZE ;1 [05] neg cnt ;1 [06] cpi cnt, 3 ;1 [07] ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [08] USB_STORE_PENDING(x2) ;1 [09] clear pending intr and check flag later. SE0 should be over. brlo doReturn ;1 [10] this is probably an ACK, NAK or similar packet sub YL, cnt ;1 [11] sbci YH, 0 ;1 [12] ld token, y ;2 [13+14] cpi token, USBPID_DATA0 ;1 [15] breq handleData ;1 [16] cpi token, USBPID_DATA1 ;1 [17] breq handleData ;1 [18] ldd x2, y+1 ;2 [19+20] ADDR and 1 bit endpoint number mov x3, x2 ;1 [21] store for endpoint number andi x2, 0x7f ;1 [22] x2 is now ADDR lds shift, usbDeviceAddr ;2 [23+24] cp x2, shift ;1 [25] brne ignorePacket ;1 [26] packet for different address cpi token, USBPID_IN ;1 [27] breq handleIn ;1 [28] cpi token, USBPID_SETUP ;1 [29] breq handleSetupOrOut ;1 [30] cpi token, USBPID_OUT ;1 [31] breq handleSetupOrOut ;1 [32]; rjmp ignorePacket ; fallthrough, should not happen anyway.ignorePacket: ;- [32] clr shift ;1 [33] sts usbCurrentTok, shift ;2 [34+35]doReturn: pop x4 pop cnt pop bitcnt pop x3 pop x2 pop x1 pop shift pop YHsofError: pop YL out SREG, YL pop YL reti;-------------------------------------------------------------------------#if USB_CFG_HAVE_INTRIN_ENDPOINT && USB_CFG_HAVE_INTRIN_ENDPOINT3handleIn3: ;- [42] lds cnt, usbTxLen3 ;2 [43+44] sbrc cnt, 4 ;1 [45] rjmp sendCntAndReti ;1 [46] 46 + 16 = 62 until SOP sts usbTxLen3, x1 ;2 [47+48] x1 == USBPID_NAK from above ldi YL, lo8(usbTxBuf3) ;1 [49] ldi YH, hi8(usbTxBuf3) ;1 [50] rjmp usbSendAndReti ;1 [51] 51 + 13 = 64 until SOP#endif;Setup and Out are followed by a data packet two bit times (20 cycles) after;the end of SE0. The sync code allows up to 50 cycles delay from the start of;the sync pattern until the first bit is sampled. That's a total of 70 cycles.handleSetupOrOut: ;[31/33]#if USB_CFG_IMPLEMENT_FN_WRITEOUT /* if we have data for second OUT endpoint, set usbCurrentTok to -1 */ sbrc x3, 7 ;[32] skip if endpoint 0 ldi token, -1 ;[33] indicate that this is endpoint 1 OUT#endif sts usbCurrentTok, token ;[34+35] pop x4 ;[36+37] pop cnt ;[38+39] pop bitcnt ;[40+41] pop x3 ;[42+43] pop x2 ;[44+45] pop x1 ;[46+47] pop shift ;[48+49] pop YH ;[50+51] USB_LOAD_PENDING(YL) ;[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 want;--------------------------------------------------------------------handleData: ;- [16/18] lds token, usbCurrentTok ;2 [19+20] tst token ;1 [21] breq doReturn ;1 [22] lds x2, usbRxLen ;2 [23+24] tst x2 ;1 [25] brne sendNakAndReti ;1 [26]; 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 ;1 [27] 0 sized data packets are status phase only -- ignore and ack brmi sendAckAndReti ;1 [28] keep rx buffer clean -- we must not NAK next SETUP sts usbRxLen, cnt ;2 [29+30] store received data, swap buffers sts usbRxToken, token ;2 [31+23] lds x2, usbInputBufOffset ;2 [33+34] swap buffers ldi cnt, USB_BUFSIZE ;1 [35] sub cnt, x2 ;1 [36] sts usbInputBufOffset, cnt ;2 [37+38] buffers now swapped rjmp sendAckAndReti ;1 [39] 39 + 17 = 56 until SOP;--------------------------------------------------------------------;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.handleIn: ;- [29] lds x1, usbRxLen ;2 [30+31] cpi x1, 1 ;1 [32] negative values are flow control, 0 means "buffer free" brge sendNakAndReti ;1 [33] unprocessed input packet? ldi x1, USBPID_NAK ;1 [34] prepare value for usbTxLen#if USB_CFG_HAVE_INTRIN_ENDPOINT sbrc x3, 7 ;1 [35] x3 contains addr + endpoint rjmp handleIn1 ;1 [36]#endif lds cnt, usbTxLen ;2 [37+38] sbrc cnt, 4 ;2 [39] all handshake tokens have bit 4 set rjmp sendCntAndReti ;1 [40] 42 + 16 = 58 until SOP sts usbTxLen, x1 ;2 [41+42] x1 == USBPID_NAK from above ldi YL, lo8(usbTxBuf) ;1 [43] ldi YH, hi8(usbTxBuf) ;1 [44] rjmp usbSendAndReti ;1 [45] 45 + 13 = 58 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: ;- [37]#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 ;2 [38+39] sbrc x2, 0 ;2 [40] rjmp handleIn3 ;1 [41]#endif lds cnt, usbTxLen1 ;2 [42+43] sbrc cnt, 4 ;2 [44] all handshake tokens have bit 4 set rjmp sendCntAndReti ;1 [45] 45 + 16 = 61 until SOP sts usbTxLen1, x1 ;2 [46+47] x1 == USBPID_NAK from above ldi YL, lo8(usbTxBuf1) ;1 [48] ldi YH, hi8(usbTxBuf1) ;1 [49] rjmp usbSendAndReti ;1 [50] 50 + 13 + 63 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 replies;---------------------------------------------------------------------------bitstuffN: ;- [04] eor x1, x4 ;1 [05] clr x2 ;1 [06] nop ;1 [07] rjmp didStuffN ;1 [08];--------------------------------------------------------------------------- bitstuff6: ;- [04] eor x1, x4 ;1 [05] clr x2 ;1 [06] rjmp didStuff6 ;1 [07];---------------------------------------------------------------------------bitstuff7: ;- [02] eor x1, x4 ;1 [03] clr x2 ;1 [06] nop ;1 [05] rjmp didStuff7 ;1 [06];---------------------------------------------------------------------------sendNakAndReti: ;- [-19] ldi x3, USBPID_NAK ;1 [-18] rjmp sendX3AndReti ;1 [-17];---------------------------------------------------------------------------sendAckAndReti: ;- [-17] ldi cnt, USBPID_ACK ;1 [-16]sendCntAndReti: ;- [-16] mov x3, cnt ;1 [-15]sendX3AndReti: ;- [-15] ldi YL, 20 ;1 [-14] x3==r20 address is 20 ldi YH, 0 ;1 [-13] ldi cnt, 2 ;1 [-12]; 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 need not to match the transfer rate exactly because the spec demands ;only 1.5% precision anyway.usbSendAndReti: ;- [-13] 13 cycles until SOP in x2, USBDDR ;1 [-12] ori x2, USBMASK ;1 [-11] sbi USBOUT, USBMINUS ;2 [-09-10] prepare idle state; D+ and D- must have been 0 (no pullups) in x1, USBOUT ;1 [-08] port mirror for tx loop out USBDDR, x2 ;1 [-07] <- acquire bus ; need not init x2 (bitstuff history) because sync starts with 0 ldi x4, USBMASK ;1 [-06] exor mask ldi shift, 0x80 ;1 [-05] sync byte is first byte sent ldi bitcnt, 6 ;1 [-04] txBitLoop: ;- [-04] [06] sbrs shift, 0 ;1 [-03] [07] eor x1, x4 ;1 [-02] [08] ror shift ;1 [-01] [09] didStuffN: ;- [09] out USBOUT, x1 ;1 [00] [10] <-- out N ror x2 ;1 [01] cpi x2, 0xfc ;1 [02] brcc bitstuffN ;1 [03] dec bitcnt ;1 [04] brne txBitLoop ;1 [05] sbrs shift, 0 ;1 [06] eor x1, x4 ;1 [07] ror shift ;1 [08]didStuff6: ;- [08] nop ;1 [09] out USBOUT, x1 ;1 [00] [10] <-- out 6 ror x2 ;1 [01] cpi x2, 0xfc ;1 [02] brcc bitstuff6 ;1 [03] sbrs shift, 0 ;1 [04] eor x1, x4 ;1 [05] ror shift ;1 [06] ror x2 ;1 [07]didStuff7: ;- [07] ldi bitcnt, 6 ;1 [08] cpi x2, 0xfc ;1 [09] out USBOUT, x1 ;1 [00] [10] <-- out 7 brcc bitstuff7 ;1 [01] ld shift, y+ ;2 [02+03] dec cnt ;1 [04] brne txBitLoop ;1 [05]makeSE0: cbr x1, USBMASK ;1 [06] prepare SE0 [spec says EOP may be 19 to 23 cycles] lds x2, usbNewDeviceAddr;2 [07+08];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 ;1 [09] out USBOUT, x1 ;1 [00] [10] <-- out SE0-- from now 2 bits==20 cycl. until bus idle sbci YH, 0 ;1 [01] breq skipAddrAssign ;1 [02] sts usbDeviceAddr, x2 ;2 [03+04] if not skipped: SE0 is one cycle longer;----------------------------------------------------------------------------;end of usbDeviceAddress transferskipAddrAssign: ;- [03/04] ldi x2, 1<<USB_INTR_PENDING_BIT ;1 [04] int0 occurred during TX -- clear pending flag USB_STORE_PENDING(x2) ;1 [05] ori x1, USBIDLE ;1 [06] in x2, USBDDR ;1 [07] cbr x2, USBMASK ;1 [08] set both pins to input mov x3, x1 ;1 [09] cbr x3, USBMASK ;1 [10] configure no pullup on both pins ldi x4, 3 ;1 [11]se0Delay: ;- [11] [14] dec x4 ;1 [12] [15] brne se0Delay ;1 [13] [16] nop2 ;2 [17+18] out USBOUT, x1 ;1 [19] <--out J (idle) -- end of SE0 (EOP sig.) out USBDDR, x2 ;1 [20] <--release bus now out USBOUT, x3 ;1 [21] <--ensure no pull-up resistors are active rjmp doReturn ;1 [22];---------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -