the 18f2550 usb connection

advertisement
THE 18F2550 USB CONNECTION
(005)
Keep in mind that this documents, about the 18F2550 connection are intended as a
guide to visualize the steps performed for USB initialization with the 18F2550; it is
not intended as a firmware instruction by instruction analysis, or a USB protocol
analysis.
The reader is assumed to have a proper domain of USB concepts and software
development.
As stated before knowledge of USB is expected, but anyway it is of help to recall some
important points:
USB is a host centric bus. The host initiates all transactions.
Each USB transaction consists of a
• Token Packet (Header defining what it expects to follow), an
• Optional Data Packet, (Containing the payload) and a
• Status Packet (Used to acknowledge transactions and to provide a means of error
correction)
But this happens right after the HOST has completed the speed identification process
(D+ and D- lines, to see where the resistor was placed).
This is the way the HOST sees that a device has been attached. The USBEN bit
(number 3 of UCON) must be enabled so that the USB module and supporting circuitry
is enabled (device attached). That´s why the USBEN bit (UCON<3>) can be used as a
soft attach/detach to the USB (no need to disconnect/connect the cable).
Once the speed identification process has succeeded, ENUMERATION takes place.
Enumeration is the process of determining what device has just been connected to the
bus and what parameters it requires such as power consumption, number and type of
endpoint(s), class of product etc. The host will then assign the device an address and
enable a configuration allowing the device to transfer data on the bus.
A common Windows enumeration involves the following steps:
1. The host or hub detects the connection of a new device via the device's pull up
resistors on the data pair. The host waits for at least 100ms allowing for the plug to be
inserted fully and for power to stabilise on the device.
2. Host issues a reset placing the device is the default state. The device may now
respond to the default address zero.
3. The MS Windows host asks for the first bytes of the Device Descriptor.
4. After receiving the first 8 bytes of the Device Descriptor, it immediately issues
another bus reset.
5. The host now issues a Set Address command, placing the device in the addressed
state.
6. The host asks for the entire 18 bytes of the Device Descriptor.
7. It then asks for 9 bytes of the Configuration Descriptor to determine the overall size.
8. The host asks for the remaining bytes of the Configuration Descriptor.
9. Host asks for any String Descriptors if they were specified.
At the end of Step 9, Windows will ask for a driver for your device (if the driver to be
used is different from the HID one normally used by Windows).
If the speed identification succeeds but the enumeration process does not, a USB not
recognized device message will show up.
Normally when something is wrong with a descriptor or how it is being sent, the host
will attempt to read it three times with long pauses in between requests. After the third
attempt, the host gives up reporting an error with your device.
The usb_defs.inc
file contains appropriate information to be filled in the
Descriptor_begin sector of the code
Examples:
db
0x12, DEVICE
; bLength, bDescriptorType
The 0x12 is the bLength (18 bytes), and the bDescriptorType is taken from
usb_defs.inc:
; standard descriptor types
#define
DEVICE
1
#define
CONFIGURATION 2
#define
STRING
3
#define
INTERFACE 4
#define
ENDPOINT 5
db
0x09, CONFIGURATION ; bLength, bDescriptorType
The 0x09 is the bLength (9 bytes), and the bDescriptorType is taken from usb_defs.inc:
; standard descriptor types
#define
DEVICE
1
#define
CONFIGURATION 2
#define
STRING
3
#define
INTERFACE 4
#define
ENDPOINT 5
The “USBSTUFF code” has the db (Data Bytes <Reserve program memory words with
8-bit values. Multiple expressions continue to fill bytes consecutively until the end of
expressions>) which contain the descriptors values, and they’re accessed of course
making use of the TBLPTRU, TBLPTRH, TBLPTRL, and TABLAT registers.
USBSTUFF
code
Descriptor
movlw
upper Descriptor_begin
movwf
TBLPTRU, ACCESS
movlw
high Descriptor_begin
movwf
TBLPTRH, ACCESS
movlw
low Descriptor_begin
banksel
USB_desc_ptr
addwf
USB_desc_ptr, W, BANKED
ifset STATUS, C, ACCESS
incf
TBLPTRH, F, ACCESS
ifset STATUS, Z, ACCESS
incf
TBLPTRU, F, ACCESS
endi
endi
movwf
TBLPTRL, ACCESS
tblrd*
movf
TABLAT, W
return
Descriptor_begin
USB has a start of frame packet or keep alive sent periodically on the bus. This prevents
an idle bus from entering suspend mode in the absence of data.
A full speed bus will have a frame sent down each 1.000 ms ±500 ns. Start of frame
packets, indicate the start of a new frame. Frames are the way the HOST checks out and
understands a device request is present (once the device is configured).
bInterval is the Interval for polling endpoint data transfers. Value in frame counts, but it
is ignored for Control Endpoints.
The control endpoint must be armed with the appropriate values:
; Define the states for Control EndPoints
#define EP_IDLE_STATE
#define EP_SETUP_STATE
#define EP_DISABLED_STATE
0x00
0x01
0xff
#define ENDPT_DISABLED
#define ENDPT_IN_ONLY
#define ENDPT_OUT_ONLY
#define ENDPT_CONTROL
#define ENDPT_NON_CONTROL
0x00
0x12
0x14
0x16
0x1E
#define INT_STAT_MASK_RESET
0x01
#define INT_STAT_MASK_ERROR
0x02
#define INT_STAT_MASK_TOKEN_DONE
#define INT_STAT_MASK_SLEEP
0x08
#define INT_STAT_MASK_STALL
0x10
; enable for in, out and setup
; enable for in, and out
0x04
#define TOKEN_OUT
(0x01<<2)
#define TOKEN_ACK
(0x02<<2)
#define TOKEN_IN (0x09<<2)
#define TOKEN_SETUP
(0x0D<<2)
The setup state takes place (Service USB sector of code) and once the HOST can
communicate with the device (UOWN=1) the process of acquiring the first device
descriptors data begins, right after the reset (enumeration: Host issues a reset placing the
device is the default state. The device may now respond to the default address zero). At
this very moment the USB ADDRESS REGISTER (UADDR) is still zero (0; UADDR
is reset to 00h when a USB Reset is received).
Once the first 8 bytes of the device descriptor are received by the HOST, it (HOST)
immediately issues another bus reset, and the host now issues a Set Address command,
placing the device
USB_address_pending)
in
the
addressed
state
(case
ADDRESS_STATE;
The host then asks for the entire 18 bytes of the Device Descriptor.
It is known that USB_buffer_data locations are just eight (0064 to 006B); so to be able
to send the whole 18 bytes, the information has to be chunked.
When the Host wants to request a device descriptor during enumeration the packets
which are sent are as follows.
The host will send the Setup token telling the function that the following packet is a
Setup packet. The Address field will hold the address of the device the host is
requesting the descriptor from. The endpoint number should be zero, specifying the
default pipe. The host will then send a DATA0 packet. This will have an 8 byte payload
which is the Device Descriptor Request as outlined in Chapter 9 of the USB
Specification. The USB function then acknowledges the setup packet has been read
correctly with no errors.
The above three packets represent the first USB transaction. The USB device will now
decode the 8 bytes received, and determine it was a device descriptor request. The
device will then attempt to send the Device Descriptor, which will be the next USB
transaction.
As the maximum packet size is 8 bytes, we must split up the 18 bytes device
descriptor into chunks to send. Each chunk must be 8 bytes except for the last
transaction. The host acknowledges every data packet we send it.
Once the device descriptor is sent, a status transaction follows.
An example of a code sector accessing USB_buffer_data:
ProcessSetupToken
banksel
movf
movwf
movf
movwf
movf
movwf
movf
movwf
movf
movwf
movf
movwf
movf
movwf
movf
movwf
movf
movwf
movf
movwf
banksel
movlw
movwf
movwf
banksel
ifl
movlw
otherwise
movlw
endi
banksel
movwf
bcf
banksel
movlw
movwf
movf
andlw
USB_buffer_data
USB_buffer_desc+ADDRESSH, W, BANKED
FSR0H, ACCESS
USB_buffer_desc+ADDRESSL, W, BANKED
FSR0L, ACCESS
POSTINC0, W
USB_buffer_data, BANKED
POSTINC0, W
USB_buffer_data+1, BANKED
POSTINC0, W
USB_buffer_data+2, BANKED
POSTINC0, W
USB_buffer_data+3, BANKED
POSTINC0, W
USB_buffer_data+4, BANKED
POSTINC0, W
USB_buffer_data+5, BANKED
POSTINC0, W
USB_buffer_data+6, BANKED
POSTINC0, W
USB_buffer_data+7, BANKED
BD0OBC
0x08
BD0OBC, BANKED ; reset the byte count
BD0IST, BANKED ; return the in buffer to us (dequeue any pending
; requests)
USB_buffer_data+bmRequestType
USB_buffer_data+bmRequestType, ==, 0x21
0xC8
0x88
BD0OST
BD0OST, BANKED ; set EP0 OUT UOWN back to USB and
; DATA0/DATA1 packet according to request type
UCON, PKTDIS, ACCESS
; assuming there is nothing to dequeue,
; clear the packet disable bit
USB_dev_req
NO_REQUEST
USB_dev_req, BANKED
; clear the device request in process
USB_buffer_data+bmRequestType, W, BANKED
0x60
; extract request type bits
*********************************************************************
1
1
0
movlw
otherwise
movlw
1
0
0
0
1
0
0
0
1
0
0
0
0xC8
0x88
0
**********************************************************************
Download