📄 usbdrvasm.s
字号:
lds YL, usbInputBuf ;2 reposition to buffer start sub cnt, YL ;1 length of message ldi x1, 1<<USB_INTR_PENDING_BIT ;1 cpi cnt, 3 ;1 out USB_INTR_PENDING, x1;1 clear pending intr and check flag later. SE0 must be over. {,10} into next frame brlo rxDoReturn ;1 ensure valid packet size, ignore others ld x1, y ;2 PID ldd x2, y+1 ;2 ADDR + 1 bit endpoint number mov x3, x2 ;1 store for endpoint number andi x2, 0x7f ;1 mask endpoint number bit lds shift, usbDeviceId ;2 cpi x1, USBPID_SETUP ;1 breq isSetupOrOut ;2 -> 19 = {13, 21} from SE0 end cpi x1, USBPID_OUT ;1 breq isSetupOrOut ;2 -> 22 = {16, 24} from SE0 end / {,24} into next frame cpi x1, USBPID_IN ;1 breq handleIn ;1 cpi x1, USBPID_DATA0 ;1 breq isData ;1 cpi x1, USBPID_DATA1 ;1 brne rxDoReturn ;1 ignore all other PIDsisData: lds x2, usbCurrentTok ;2 tst x2 ;1 breq rxDoReturn ;1 for other device or spontaneous data -- ignore lds x1, usbRxLen ;2 cpi x1, 0 ;1 brne sendNakAndReti ;1 no buffer space available / {30, 38} from SE0 end sts usbRxLen, cnt ;2 store received data, swap buffers sts usbRxToken, x2 ;2 lds x1, usbAppBuf ;2 sts usbAppBuf, YL ;2 sts usbInputBuf, x1 ;2 buffers now swapped rjmp sendAckAndReti ;2 -> {42, 50} from SE0 endhandleIn: ; {18, 26} from SE0 end cp x2, shift ;1 shift contains our device ID brne rxDoReturn ;1 other device#if USB_CFG_HAVE_INTRIN_ENDPOINT sbrc x3, 7 ;2 rjmp handleIn1 ;0#endif lds cnt, usbTxLen ;2 cpi cnt, -1 ;1 breq sendNakAndReti ;1 -> {27, 35} from SE0 end ldi x1, -1 ;1 sts usbTxLen, x1 ;2 buffer is now free ldi YL, lo8(usbTxBuf) ;1 ldi YH, hi8(usbTxBuf) ;1 rjmp usbSendAndReti ;2 -> {34, 43} from SE0 end; Comment about when to set usbTxLen to -1:; We should set it back to -1 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 to -1 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.otherOutOrSetup: clr x1 sts usbCurrentTok, x1rxDoReturn: pop x3 ;2 pop YL ;2 pop YH ;2 rjmp sofError ;2isSetupOrOut: ; we must be fast here -- a data package may follow / {,24} into next frame cp x2, shift ;1 shift contains our device ID brne otherOutOrSetup ;1 other device -- ignore sts usbCurrentTok, x1 ;2#if 0 /* we implement only one rx endpoint */ sts usbRxEndp, x3 ;2 only stored if we may have to distinguish endpoints#endif;A transmission can still have data in the output buffer while we receive a;SETUP package with an IN phase. To avoid that the old data is sent as a reply,;we abort transmission. ### This mechanism assumes that NO OUT OR SETUP package;is ever sent to endpoint 1. We would abort transmission for endpoint 0;in this case. ldi x1, -1 ;1 sts usbMsgLen, x1 ;2 sts usbTxLen, x1 ;2 abort transmission pop x3 ;2 pop YL ;2 in x1, USB_INTR_PENDING;1 sbrc x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame rjmp shortcutToStart ;2 save the pops and pushes -- a new interrupt is aready pending;If the jump above was not taken, we can be at {,2} into the next frame here pop YH ;2sofError: ; error in start of frame -- ignore frame ldi x1, 1<<USB_INTR_PENDING_BIT;1 many int0 events occurred during our processing -- clear pending flag out USB_INTR_PENDING, x1;1 pop shift ;2 pop cnt ;2 pop x2 ;2 pop x1 ;2 out SREG, x1 ;1 pop x1 ;2 reti ;4 -> {,21} into next frame -> up to 3 sync bits missedsendNakAndReti: ; 21 cycles until SOP ldi YL, lo8(usbNakBuf) ;1 ldi YH, hi8(usbNakBuf) ;1 rjmp usbSendToken ;2sendAckAndReti: ; 19 cycles until SOP ldi YL, lo8(usbAckBuf) ;1 ldi YH, hi8(usbAckBuf) ;1usbSendToken: ldi cnt, 2 ;1;;;;rjmp usbSendAndReti fallthrough; USB spec says:; idle = J; J = (D+ = 0), (D- = 1) or USBOUT = 0x01; K = (D+ = 1), (D- = 0) or USBOUT = 0x02; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles);usbSend:;pointer to data in 'Y';number of bytes in 'cnt';uses: x1...x4, shift, cnt, YusbSendAndReti: ; SOP starts 16 cycles after call push x4 ;2 in x1, USBOUT ;1 cbr x1, USBMASK ;1 mask out data bits ori x1, USBIDLE ;1 idle out USBOUT, x1 ;1 prepare idle state ldi x4, USBMASK ;1 exor mask in x2, USBDDR ;1 ori x2, USBMASK ;1 set both pins to output out USBDDR, x2 ;1 <-- acquire bus now; need not init x2 (bitstuff history) because sync starts with 0 ldi shift, 0x80 ;1 sync byte is first byte sent rjmp txLoop ;2 -> 13 + 3 = 16 cycles until SOP#if USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */handleIn1: lds cnt, usbTxLen1 cpi cnt, -1 breq sendNakAndReti ldi x1, -1 sts usbTxLen1, x1 ldi YL, lo8(usbTxBuf1) ldi YH, hi8(usbTxBuf1) rjmp usbSendAndReti#endifbitstuff0: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 out USBOUT, x1 ;1 <-- out rjmp didStuff0 ;2 branch back 2 cycles earlierbitstuff1: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 sec ;1 set carry so that brsh will not jump out USBOUT, x1 ;1 <-- out rjmp didStuff1 ;2 jump back 1 cycle earlerbitstuff2: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 rjmp didStuff2 ;2 jump back 3 cycles earlier and do outbitstuff3: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 rjmp didStuff3 ;2 jump back earliertxLoop: sbrs shift, 0 ;1 eor x1, x4 ;1 out USBOUT, x1 ;1 <-- out ror shift ;1 ror x2 ;1didStuff0: cpi x2, 0xfc ;1 brsh bitstuff0 ;1 sbrs shift, 0 ;1 eor x1, x4 ;1 ror shift ;1 out USBOUT, x1 ;1 <-- out ror x2 ;1 cpi x2, 0xfc ;1didStuff1: brsh bitstuff1 ;1 sbrs shift, 0 ;1 eor x1, x4 ;1 ror shift ;1 ror x2 ;1didStuff2: out USBOUT, x1 ;1 <-- out cpi x2, 0xfc ;1 brsh bitstuff2 ;1 sbrs shift, 0 ;1 eor x1, x4 ;1 ror shift ;1 ror x2 ;1didStuff3: cpi x2, 0xfc ;1 out USBOUT, x1 ;1 <-- out brsh bitstuff3 ;1 nop2 ;2 ld x3, y+ ;2 sbrs shift, 0 ;1 eor x1, x4 ;1 out USBOUT, x1 ;1 <-- out ror shift ;1 ror x2 ;1didStuff4: cpi x2, 0xfc ;1 brsh bitstuff4 ;1 sbrs shift, 0 ;1 eor x1, x4 ;1 ror shift ;1 out USBOUT, x1 ;1 <-- out ror x2 ;1 cpi x2, 0xfc ;1didStuff5: brsh bitstuff5 ;1 sbrs shift, 0 ;1 eor x1, x4 ;1 ror shift ;1 ror x2 ;1didStuff6: out USBOUT, x1 ;1 <-- out cpi x2, 0xfc ;1 brsh bitstuff6 ;1 sbrs shift, 0 ;1 eor x1, x4 ;1 ror shift ;1 ror x2 ;1didStuff7: cpi x2, 0xfc ;1 out USBOUT, x1 ;1 <-- out brsh bitstuff7 ;1 mov shift, x3 ;1 dec cnt ;1 brne txLoop ;2 | 1 cbr x1, USBMASK ;1 prepare SE0 pop x4 ;2 out USBOUT, x1 ;1 <-- out SE0 ldi cnt, 4 ;1 two bits = 16 cyclesse0Delay: dec cnt ;1 brne se0Delay ;2 | 1 ori x1, USBIDLE ;1 in x2, USBDDR ;1 cbr x2, USBMASK ;1 set both pins to input out USBOUT, x1 ;1 <-- out J (idle) cbr x1, USBMASK ;1 configure no pullup on both pins pop x3 ;2 pop YL ;2 out USBDDR, x2 ;1 <-- release bus now out USBOUT, x1 ;1 set pullup state pop YH ;2 rjmp sofError ;2 [we want to jump to rxDoReturn, but this saves cycles]bitstuff4: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 out USBOUT, x1 ;1 <-- out rjmp didStuff4 ;2 jump back 2 cycles earlierbitstuff5: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 sec ;1 set carry so that brsh is not taken out USBOUT, x1 ;1 <-- out rjmp didStuff5 ;2 jump back 1 cycle earlierbitstuff6: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 rjmp didStuff6 ;2 jump back 3 cycles earlier and do out therebitstuff7: ;1 (for branch taken) eor x1, x4 ;1 ldi x2, 0 ;1 rjmp didStuff7 ;2 jump back 4 cycles earlier; ######################## utility functions ########################; extern unsigned usbCrc16(unsigned char *data, unsigned char len);; data: r24/25; len: r22; temp variables:; r18: data byte; r19: bit counter; r20/21: polynomial; r23: scratch; r24/25: crc-sum; r26/27=X: ptr.global usbCrc16usbCrc16: mov XL, r24 mov XH, r25 ldi r24, 0xff ldi r25, 0xff ldi r20, lo8(0xa001) ldi r21, hi8(0xa001)crcByteLoop: subi r22, 1 brcs crcReady ld r18, x+ ldi r19, 8crcBitLoop: mov r23, r18 eor r23, r24 lsr r25 ror r24 lsr r18 sbrs r23, 0 rjmp crcNoXor eor r24, r20 eor r25, r21crcNoXor: dec r19 brne crcBitLoop rjmp crcByteLoopcrcReady: com r24 com r25 ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -