⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 int.s

📁 This is a software implementation of the USB low-speed protocol for the Atmel ATtiny microcontrolle
💻 S
字号:
; ======================================================================; USB interrupt handler;; This is the handler for the interrupt caused by the initial rising edge; on the D+ USB signal. The NRZI encoding and bit stuffing are removed,; and the packet is saved in one of the two input buffers. In some cases,; a reply packet is sent right away.;; When a DATA0/DATA1 packet directly follows a SETUP or OUT packet, while; this interrupt handler is not yet finished, there would be no time to; return and take another interrupt. In that case, the second packet is; decoded directly in the same invocation.;; This code is *extremely* time critical. For instance, there is not a; single spare cycle in the receiver loop, and only two in the transmitter; loop. In addition, the various code paths are laid out in such a way that; the various USB timeouts are not violated, in particular the maximum time; between the reception of a packet and the reply, which is 7.5 bit times; (TRSPIPD2) for the captive cable that is mandatory for a low-speed USB; device. The worst-case delay here is 55 cycles, which is well below the; 60 cycles limit.;; The interrupt handler must be reached within 34 cycles after D+ goes high; for the first time, so the interrupts should not be disabled for longer; than 34-4-2=28 cycles.;; The end-of-packet (EOP) is sampled in the second bit, because the USB; standard allows the EOP to be delayed by up to one bit. As the EOP; duration is two bits, this is not a problem.;; Stack usage including the return address: 11 bytes.;; Copyright 2006-2008 Dick Streefland;; This is free software, licensed under the terms of the GNU General; Public License as published by the Free Software Foundation.; ======================================================================#include "def.h"; ----------------------------------------------------------------------; local data; ----------------------------------------------------------------------	.datatx_ack:	.byte	USB_PID_ACK		; ACK packettx_nak:	.byte	USB_PID_NAK		; NAK packet	.lcomm	token_pid, 1		; PID of most recent token packet; ----------------------------------------------------------------------; register definitions; ----------------------------------------------------------------------// receiver:#define	count		r16#define	usbmask		r17#define	odd		r18#define	byte		r19#define	fixup		r20#define	even		r22// transmitter:#define	output		odd#define	done		fixup#define	next		even// control:#define	pid		odd#define	addr		usbmask#define	tmp		fixup#define	nop2		rjmp	.+0	// not .+2 for some strange reason; ----------------------------------------------------------------------; interrupt handler; ----------------------------------------------------------------------	.text	.global	USB_INT_VECTOR	.type	USB_INT_VECTOR, @function; ----------------------------------------------------------------------; This handler must be reached no later than 34 cycles after D+ goes high; for the first time.; ----------------------------------------------------------------------USB_INT_VECTOR:	; save registers	push	count	push	usbmask	push	odd	push	YH	push	YL	in	count, SREG	push	count; ----------------------------------------------------------------------; Synchronize to the pattern 10101011 on D+. This code must be reached; no later than 47 cycles after D+ goes high for the first time.; ----------------------------------------------------------------------sync:	; wait until D+ == 0	sbic	USB_IN, USBTINY_DPLUS	rjmp	sync			; jump if D+ == 1resync:	; sync on 0-->1 transition on D+ with a 2 cycle resolution	sbic	USB_IN, USBTINY_DPLUS	rjmp	sync6			; jump if D+ == 1	sbic	USB_IN, USBTINY_DPLUS	rjmp	sync6			; jump if D+ == 1	sbic	USB_IN, USBTINY_DPLUS	rjmp	sync6			; jump if D+ == 1	sbic	USB_IN, USBTINY_DPLUS	rjmp	sync6			; jump if D+ == 1	sbic	USB_IN, USBTINY_DPLUS	rjmp	sync6			; jump if D+ == 1	ldi	count, 1<<USB_INT_PENDING_BIT	out	USB_INT_PENDING, count	rjmp	return			; ==> false start, bail outsync6:	; we are now between -1 and +1 cycle from the center of the bit	; following the 0-->1 transition	lds	YL, usb_rx_off	clr	YH	subi	YL, lo8(-(usb_rx_buf))	; Y = & usb_rx_buf[usb_rx_off]	sbci	YH, hi8(-(usb_rx_buf))	ldi	count, USB_BUFSIZE	; limit on number of bytes to receive	ldi	usbmask, USB_MASK	; why is there no eori instruction?	ldi	odd, USB_MASK_DPLUSsync7:	; the last sync bit should also be 1	sbis	USB_IN, USBTINY_DPLUS	; bit 7 of sync byte?	rjmp	resync			; no, wait for next transition	push	byte	push	fixup	push	even; ----------------------------------------------------------------------; receiver loop; ----------------------------------------------------------------------	in	even, USB_IN		; sample bit 0	ldi	byte, 0x80		; load sync byte for correct unstuffing	rjmp	rxentry			; 2 cyclesrxloop:	in	even, USB_IN		; sample bit 0	or	fixup, byte	st	Y+, fixup		; 2 cyclesrxentry:	clr	fixup	andi	even, USB_MASK	eor	odd, even	subi	odd, 1	in	odd, USB_IN		; sample bit 1	andi	odd, USB_MASK	breq	eop			; ==> EOP detected	ror	byte	cpi	byte, 0xfc	brcc	skip0skipped0:	eor	even, odd	subi	even, 1	in	even, USB_IN		; sample bit 2	andi	even, USB_MASK	ror	byte	cpi	byte, 0xfc	brcc	skip1skipped1:	eor	odd, even	subi	odd, 1	ror	byte	in	odd, USB_IN		; sample bit 3	andi	odd, USB_MASK	cpi	byte, 0xfc	brcc	skip2	eor	even, odd	subi	even, 1	ror	byteskipped2:	cpi	byte, 0xfc	in	even, USB_IN		; sample bit 4	andi	even, USB_MASK	brcc	skip3	eor	odd, even	subi	odd, 1	ror	byteskipped4:	cpi	byte, 0xfcskipped3:	brcc	skip4	in	odd, USB_IN		; sample bit 5	andi	odd, USB_MASK	eor	even, odd	subi	even, 1	ror	byteskipped5:	cpi	byte, 0xfc	brcc	skip5	dec	count	in	even, USB_IN		; sample bit 6	brmi	overflow		; ==> overflow	andi	even, USB_MASK	eor	odd, even	subi	odd, 1	ror	byteskipped6:	cpi	byte, 0xfc	brcc	skip6	in	odd, USB_IN		; sample bit 7	andi	odd, USB_MASK	eor	even, odd	subi	even, 1	ror	byte	cpi	byte, 0xfc	brcs	rxloop			; 2 cycles	rjmp	skip7eop:	rjmp	eop2overflow:	rjmp	ignore; ----------------------------------------------------------------------; out-of-line code to skip stuffing bits; ----------------------------------------------------------------------skip0:					; 1+6 cycles	eor	even, usbmask	in	odd, USB_IN		; resample bit 1	andi	odd, USB_MASK	cbr	byte, (1<<7)	sbr	fixup, (1<<0)	rjmp	skipped0skip1:					; 2+5 cycles	cbr	byte, (1<<7)	sbr	fixup, (1<<1)	in	even, USB_IN		; resample bit 2	andi	even, USB_MASK	eor	odd, usbmask	rjmp	skipped1skip2:					; 3+7 cycles	cbr	byte, (1<<7)	sbr	fixup, (1<<2)	eor	even, usbmask	in	odd, USB_IN		; resample bit 3	andi	odd, USB_MASK	eor	even, odd	subi	even, 1	ror	byte	rjmp	skipped2skip3:					; 4+7 cycles	cbr	byte, (1<<7)	sbr	fixup, (1<<3)	eor	odd, usbmask	ori	byte, 1	in	even, USB_IN		; resample bit 4	andi	even, USB_MASK	eor	odd, even	subi	odd, 1	ror	byte	rjmp	skipped3skip4:					; 5 cycles	cbr	byte, (1<<7)	sbr	fixup, (1<<4)	eor	even, usbmask	rjmp	skipped4skip5:					; 5 cycles	cbr	byte, (1<<7)	sbr	fixup, (1<<5)	eor	odd, usbmask	rjmp	skipped5skip6:					; 5 cycles	cbr	byte, (1<<7)	sbr	fixup, (1<<6)	eor	even, usbmask	rjmp	skipped6skip7:					; 7 cycles	cbr	byte, (1<<7)	sbr	fixup, (1<<7)	eor	odd, usbmask	nop2	rjmp	rxloop; ----------------------------------------------------------------------; end-of-packet detected (worst-case: 3 cycles after end of SE0); ----------------------------------------------------------------------eop2:	; clear pending interrupt (SE0+3)	ldi	byte, 1<<USB_INT_PENDING_BIT	out	USB_INT_PENDING, byte	; clear pending bit at end of packet	; ignore packets shorter than 3 bytes	subi	count, USB_BUFSIZE	neg	count			; count = packet length	cpi	count, 3	brlo	ignore	; get PID	sub	YL, count	ld	pid, Y	; check for DATA0/DATA1 first, as this is the critical path (SE0+12)	cpi	pid, USB_PID_DATA0	breq	is_data			; handle DATA0 packet	cpi	pid, USB_PID_DATA1	breq	is_data			; handle DATA1 packet	; check ADDR (SE0+16)	ldd	addr, Y+1	andi	addr, 0x7f	lds	tmp, usb_address	cp	addr, tmp		; is this packet for me?	brne	ignore			; no, ignore	; check for other PIDs (SE0+23)	cpi	pid, USB_PID_IN	breq	is_in			; handle IN packet	cpi	pid, USB_PID_SETUP	breq	is_setup_out		; handle SETUP packet	cpi	pid, USB_PID_OUT	breq	is_setup_out		; handle OUT packet; ----------------------------------------------------------------------; exit point for ignored packets; ----------------------------------------------------------------------ignore:	clr	tmp	sts	token_pid, tmp	pop	even	pop	fixup	pop	byte	rjmp	return; ----------------------------------------------------------------------; Handle SETUP/OUT (SE0+30); ----------------------------------------------------------------------is_setup_out:	sts	token_pid, pid		; save PID of token packet	pop	even	pop	fixup	pop	byte	in	count, USB_INT_PENDING	; next packet already started?	sbrc	count, USB_INT_PENDING_BIT	rjmp	sync			; yes, get it right away (SE0+42); ----------------------------------------------------------------------; restore registers and return from interrupt; ----------------------------------------------------------------------return:	pop	count	out	SREG, count	pop	YL	pop	YH	pop	odd	pop	usbmask	pop	count	reti; ----------------------------------------------------------------------; Handle IN (SE0+26); ----------------------------------------------------------------------is_in:	lds	count, usb_tx_len	tst	count			; data ready?	breq	nak			; no, reply with NAK	lds	tmp, usb_rx_len	tst	tmp			; unprocessed input packet?	brne	nak			; yes, don't send old data for new packet	sts	usb_tx_len, tmp		; buffer is available again (after reti)	lds	tmp, usb_new_address	sts	usb_address, tmp	; assign new address at end of transfer	ldi	YL, lo8(usb_tx_buf)	ldi	YH, hi8(usb_tx_buf)	rjmp	send_packet		; SE0+44, SE0 --> SOP <= 55; ----------------------------------------------------------------------; Handle DATA0/DATA1 (SE0+17); ----------------------------------------------------------------------is_data:	lds	pid, token_pid	tst	pid			; data following our SETUP/OUT	breq	ignore			; no, ignore	lds	tmp, usb_rx_len	tst	tmp			; buffer free?	brne	nak			; no, reply with NAK	sts	usb_rx_len, count	; pass buffer length	sts	usb_rx_token, pid	; pass PID of token (SETUP or OUT)	lds	count, usb_rx_off	; switch to other input buffer	ldi	tmp, USB_BUFSIZE	sub	tmp, count	sts	usb_rx_off, tmp; ----------------------------------------------------------------------; send ACK packet (SE0+35); ----------------------------------------------------------------------ack:	ldi	YL, lo8(tx_ack)	ldi	YH, hi8(tx_ack)	rjmp	send_token; ----------------------------------------------------------------------; send NAK packet (SE0+36); ----------------------------------------------------------------------nak:	ldi	YL, lo8(tx_nak)	ldi	YH, hi8(tx_nak)send_token:	ldi	count, 1		; SE0+40, SE0 --> SOP <= 51; ----------------------------------------------------------------------; acquire the bus and send a packet (11 cycles to SOP); ----------------------------------------------------------------------send_packet:	in	output, USB_OUT	cbr	output, USB_MASK	ori	output, USB_MASK_DMINUS	in	usbmask, USB_DDR	ori	usbmask, USB_MASK	out	USB_OUT, output		; idle state	out	USB_DDR, usbmask	; acquire bus	ldi	usbmask, USB_MASK	ldi	byte, 0x80		; start with sync byte; ----------------------------------------------------------------------; transmitter loop; ----------------------------------------------------------------------txloop:	sbrs	byte, 0	eor	output, usbmask	out	USB_OUT, output		; output bit 0	ror	byte	ror	donestuffed0:	cpi	done, 0xfc	brcc	stuff0	sbrs	byte, 0	eor	output, usbmask	ror	bytestuffed1:	out	USB_OUT, output		; output bit 1	ror	done	cpi	done, 0xfc	brcc	stuff1	sbrs	byte, 0	eor	output, usbmask	ror	byte	nopstuffed2:	out	USB_OUT, output		; output bit 2	ror	done	cpi	done, 0xfc	brcc	stuff2	sbrs	byte, 0	eor	output, usbmask	ror	byte	nopstuffed3:	out	USB_OUT, output		; output bit 3	ror	done	cpi	done, 0xfc	brcc	stuff3	sbrs	byte, 0	eor	output, usbmask	ld	next, Y+		; 2 cycles	out	USB_OUT, output		; output bit 4	ror	byte	ror	donestuffed4:	cpi	done, 0xfc	brcc	stuff4	sbrs	byte, 0	eor	output, usbmask	ror	bytestuffed5:	out	USB_OUT, output		; output bit 5	ror	done	cpi	done, 0xfc	brcc	stuff5	sbrs	byte, 0	eor	output, usbmask	ror	bytestuffed6:	ror	done	out	USB_OUT, output		; output bit 6	cpi	done, 0xfc	brcc	stuff6	sbrs	byte, 0	eor	output, usbmask	ror	byte	mov	byte, nextstuffed7:	ror	done	out	USB_OUT, output		; output bit 7	cpi	done, 0xfc	brcc	stuff7	dec	count	brpl	txloop			; 2 cycles	rjmp	gen_eop; ----------------------------------------------------------------------; out-of-line code to insert stuffing bits; ----------------------------------------------------------------------stuff0:					; 2+3	eor	output, usbmask	clr	done	out	USB_OUT, output	rjmp	stuffed0stuff1:					; 3	eor	output, usbmask	rjmp	stuffed1stuff2:					; 3	eor	output, usbmask	rjmp	stuffed2stuff3:					; 3	eor	output, usbmask	rjmp	stuffed3stuff4:					; 2+3	eor	output, usbmask	clr	done	out	USB_OUT, output	rjmp	stuffed4stuff5:					; 3	eor	output, usbmask	rjmp	stuffed5stuff6:					; 3	eor	output, usbmask	rjmp	stuffed6stuff7:					; 3	eor	output, usbmask	rjmp	stuffed7; ----------------------------------------------------------------------; generate EOP, release the bus, and return from interrupt; ----------------------------------------------------------------------gen_eop:	cbr	output, USB_MASK	out	USB_OUT, output		; output SE0 for 2 bit times	pop	even	pop	fixup	pop	byte	ldi	count, 1<<USB_INT_PENDING_BIT	out	USB_INT_PENDING, count	; interrupt was triggered by transmit	pop	YH			; this is the saved SREG	pop	YL	in	usbmask, USB_DDR	mov	count, output	ori	output, USB_MASK_DMINUS	out	USB_OUT, output		; output J state for 1 bit time	cbr	usbmask, USB_MASK	out	SREG, YH	pop	YH	pop	odd			; is the same register as output!	nop	out	USB_DDR, usbmask	; release bus	out	USB_OUT, count		; disable D- pullup	pop	usbmask	pop	count	reti

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -