/Designs/Tools/i2c_AVR_USB/SW/firmware/usbtiny/int.S
9,20 → 9,26
; 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.
; decoded directly in the same invocation. A packet immediately following
; an ignored packet is also decoded directly.
;
; 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 6.5 bit times
; for a detachable cable (TRSPIPD1), and 7.5 bit times for a captive cable
; (TRSPIPD2). The worst-case delay here is 51 cycles, which is just below
; the 52 cycles for a detachable cable.
; between the reception of a packet and the reply, which is 7.5 bit times
; (TRSPIPD2) for a low-speed USB captive cable. The worst-case delay here
; is 51 cycles, which is well below the 60 cycles limit, and even below the
; 6.5 bit times limit for a detachable cable (TRSPIPD1).
;
; 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.
; for the first time. The interrupt response time is 4 cycles, and the RJMP
; in the vector table takes 2 cycles. Therefore, the interrupts should not
; be disabled for longer than: 34 - 4 - 2 = 28 cycles. When the I-bit is
; reenabled, a single instruction is always executed before a pending
; interrupt is served, so this instruction should be included in the
; calculation. For RETI, the next instruction can be anything, so we
; should assume the worst-case of 4 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
30,7 → 36,7
;
; Stack usage including the return address: 11 bytes.
;
; Copyright (C) 2006 Dick Streefland
; Copyright 2006-2010 Dick Streefland
;
; This is free software, licensed under the terms of the GNU General
; Public License as published by the Free Software Foundation.
45,6 → 51,7
tx_ack: .byte USB_PID_ACK ; ACK packet
tx_nak: .byte USB_PID_NAK ; NAK packet
.lcomm token_pid, 1 ; PID of most recent token packet
.global __do_copy_data
 
; ----------------------------------------------------------------------
; register definitions
291,46 → 298,51
; 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
; calculate packet length
subi count, USB_BUFSIZE
neg count ; count = packet length
cpi count, 3
brlo ignore
; get PID
sub YL, count
sbci YH, 0
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)
; separate out the non-Token packets (SE0+11)
sbrc pid, 1
rjmp is_data_handshake ; jump for Data or Handshake packet
; check ADDR of Token packet (SE0+13)
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)
; dispatch Token packets (SE0+20)
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
brne is_setup_out ; handle SETUP and OUT packets
 
; ----------------------------------------------------------------------
; exit point for ignored packets
; Handle IN (SE0+22)
; ----------------------------------------------------------------------
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+40, SE0 --> SOP <= 51
 
; ----------------------------------------------------------------------
; exit point for ignored packets (SE0+21)
; ----------------------------------------------------------------------
ignore:
clr tmp
sts token_pid, tmp
pop even
pop fixup
pop byte
rjmp return
clr pid
ignore0:
 
; ----------------------------------------------------------------------
; Handle SETUP/OUT (SE0+30)
; Handle SETUP/OUT (SE0+23)
; ----------------------------------------------------------------------
is_setup_out:
sts token_pid, pid ; save PID of token packet
339,10 → 351,10
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)
rjmp sync ; yes, get it right away (SE0+35)
 
; ----------------------------------------------------------------------
; restore registers and return from interrupt
; restore registers and return from interrupt (SE0+34)
; ----------------------------------------------------------------------
return:
pop count
355,27 → 367,26
reti
 
; ----------------------------------------------------------------------
; Handle IN (SE0+26)
; send NAK packet (SE0+31)
; ----------------------------------------------------------------------
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)
ldi YL, lo8(usb_tx_buf)
ldi YH, hi8(usb_tx_buf)
rjmp send_packet ; SE0+40, SE0 --> SOP <= 51
nak:
ldi YL, lo8(tx_nak)
ldi YH, hi8(tx_nak)
rjmp send_token
 
; ----------------------------------------------------------------------
; Handle DATA0/DATA1 (SE0+17)
; Handle Data and Handshake packets (SE0+14)
; ----------------------------------------------------------------------
is_data:
is_data_handshake:
andi pid, 0x01
breq ignore0 ; ignore ACK/NAK/STALL
 
; ----------------------------------------------------------------------
; Handle DATA0/DATA1 (SE0+16)
; ----------------------------------------------------------------------
lds pid, token_pid
tst pid ; data following our SETUP/OUT
breq ignore ; no, ignore
breq ignore0 ; no, ignore
lds tmp, usb_rx_len
tst tmp ; buffer free?
brne nak ; no, reply with NAK
387,21 → 398,12
sts usb_rx_off, tmp
 
; ----------------------------------------------------------------------
; send ACK packet (SE0+35)
; send ACK packet (SE0+34)
; ----------------------------------------------------------------------
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
ldi count, 1 ; SE0+37, SE0 --> SOP <= 48
 
; ----------------------------------------------------------------------
; acquire the bus and send a packet (11 cycles to SOP)