1 / 33

World’s Simplest USB Host Application

World’s Simplest USB Host Application. Lane Hauck lth@cypress.Com. Question. How simple can embedded host firmware be? Let’s figure out a really simple (but useful) interface and write the code. EZ-USB. SL-811. Development. USB Host. Board. Controller. USB. Keypad. D[7..0]. CS#.

Download Presentation

World’s Simplest USB Host Application

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. World’s Simplest USB Host Application Lane Hauck lth@cypress.Com

  2. Question • How simple can embedded host firmware be? • Let’s figure out a really simple (but useful) interface and write the code.

  3. EZ-USB SL-811 Development USB Host Board Controller USB Keypad D[7..0] CS# CS# RD# RD# 8051 USB D+D- WR# WR# A0 A0 PB1 M/S# PB0 RES# PA0 Scope Trigger A USB “Point Solution” Host Firmware Demo

  4. USB Enumeration • Detect device • Detect speed • Issue USB bus reset • Get Descriptor: Device • Set Address • Get Descriptor: Configuration • Get String: Product • Set Configuration

  5. Assumptions save codeInitial conditions are known • Detect deviceIt’s plugged in • Detect speedLow speed • Issue USB bus reset • Get Descriptor: Device • Set Address • Get Descriptor: Configuration • Get String: Product • Set Configuration

  6. How about the descriptors? • They’re fixed (hardwired) in the keypad • They are the same every time we ask for them • With a “Get_Descriptor” request • If we know them in advance, we can save the code that asks for and interprets them • Device assumptions save code • But limit our code to a specific device

  7. Assumptions save codeThe keypad’s device descriptor

  8. Assumptions save codeThe keypad’s device descriptor

  9. Assumptions save codeConfig. & interface descriptors

  10. Assumptions save codeConfig. & interface descriptors

  11. Assumptions save codeEndpoint & HID descriptors Note: In HID version 1.1 the order of these descriptors is HID, Endpoint.

  12. Assumptions save codeEndpoint & HID descriptors Note: In HID version 1.1 the order of these descriptors is HID, Endpoint.

  13. Assumptions save codeHID Report descriptor • It’s complicated • The HID spec is 100 pages long and handles such issues as how to report controls attached to various body parts. • It helps an application discover the capabilities of any Human-Interface Device attached to a PC without prior knowledge of the device. • All we really need to know: • Keystroke data is delivered in 3-byte packets, with the keypress code in the third byte. • We could deduce this by deciphering the HID descriptor, or by watching a little bus traffic.

  14. What we know in advance • It’s a low-speed HID (keypad) • It reports data on EP1-IN • Which is an INTERRUPT endpoint with an 8-byte MaxPacketSize • It responds to IN requests with a 3-byte payload. • The keycode is in the third byte

  15. Init. code simplifies to this • Detect device • Detect speed • Issue USB bus reset • Get Descriptor: Device • Set Address • Get Descriptor: Configuration • Get String: Product • Set Configuration

  16. Operation code is simple • Send 1 msec “keep alive” pulses (EOP) so the keypad doesn’t suspend. • Automatic, just initialize the 811H chip • Whenever we feel like it, send an IN token. • If the keypad has a new keycode to report, it responds with a DATA PID and 3 bytes of data. • If it doesn’t, it sends a NAK PID. • If we get data, use it. • 811H chip automatically ACKS the transfer

  17. Our IN RequestKeypad has no new data Sync IN AD EP CRC5 Host (us) 00000001 10010110 0000001 0001 xy Sync NAK Keypad 00000001 10100101

  18. Our IN RequestKeypad reports a new keystroke Sync IN AD EP CRC5 Host (us) 00000001 10010110 0000001 0001 xy Data Sync DATA0/1 CRC16 Keypad 00000001 10010110 A B C wxyz Sync ACK Host (us) 00000001 01001011

  19. Code-1Initialize the 811H and USB void main(void) { BYTE result; // set up the EZ-USB chip to talk to the 811 chip and provide a scope trigger PORTCCFG = 0xC0; // enable RD, WR pins OEB = 0x03; // PB0 is SL811 RESET, PB1 is Host/Slave pin) OEA = 0x01; // PA0 is scope trigger SCOPE_LO; // initialize scope trigger // Reset the SL811H chip OUTB = 0x00; // PB1=0 means we're the host delay(1000); OUTB = 0x01; // remove reset, keep PB1 LOW for SLAVE // SL811 initialization wr811(BUFADR,0x10); // start of SETUP/IN internal data buffer wr811(BUFLEN,0x08); // reserve 8 bytes // (1) Reset the USB device. This makes it listen to address 0. wr811(CTL1,USB_RESET); // Speed=1(L), JKFORCE=1, SOFEN=1 delay(10000); // about 18 milliseconds wr811(CTL1,USB_OPERATE); // Enable sending 1 msec EOP's (the low-speed version of SOF's) wr811(SOFCT_L, 0xE0); // Set the SOF generator time constant wr811(SOFCT_H, 0x2E | 0xC0); // 1 msec SOF rate, b7=HOST, b6=POLSWAP

  20. H H P S D C A E C E A 8 bytes R A H is Host P is Peripheral D N R SETUP T T Setup C C D D C U A Data 1 K R P 5 P 0 6 Data Packet Token Packet H/S Pkt H P H D C A E C A R A I D N R Payload DATA T C C N D D C Data A 1 K R P 5 1 6 Token Packet H/S Pkt Data Packet H H P H H P D D C C A E C A E C O A O A R N R A D N R D N R U T U T C A C C HANDSHAKE D D C D D C T A T A 1 K 1 K R P 5 R P 5 1 1 6 6 TokenPacket H/S Pkt H/S Pkt Token Packet Data Pkt Data Pkt (Operation not completed) (Operation completed) Review:CONTROL (CTL) transfer Set_Address & Set_Configuration data is contained in the SETUP stage, so no DATA stage is required.

  21. Code-2Issue Set_Address CTL transfer // (2) Issue a SET_ADDRESS USB request, setting the peripheral address to 1 // From the USB spec, Chapter 9, here is the data for a "SET_ADDRESS" request: // Note: every SL811_DATA load increments an internal SL811 address pointer SL811_ADDR = 0x10; // next SL811_DATA byte goes here SL811_DATA = 0x00; // bmRequestType (h->d,std request,device is recipient) SL811_DATA = 0x05; // bRequest (SET_ADDRESS) SL811_DATA = 0x01; // wValueL (device address)--we're setting it to ONE SL811_DATA = 0x00; // wValueH (zero) SL811_DATA = 0x00; // wIndexL (zero) SL811_DATA = 0x00; // wIndexH (zero) SL811_DATA = 0x00; // wLengthL (zero) SL811_DATA = 0x00; // wLengthH (zero) wr811(FNADDR,0x00); // USB address zero wr811(PID_EP,SETUP_PID | 0x00); // SETUP PID, EP0 result=go(0x07); // DIREC=1(out), ENAB=1, ARM=1 // STATUS stage is a no-data IN to EP0 wr811(PID_EP,IN_PID | 0x00); // IN PID, EP0 result=go(0x03); // Don't sync to SOF, DIREC=0(in), ENAB, ARM

  22. Code-2On the wire // (2) Issue a SET_ADDRESS USB request, setting the peripheral address to 1 // From the USB spec, Chapter 9, here is the data for a "SET_ADDRESS" request: // Note: every SL811_DATA load increments an internal SL811 address pointer SL811_ADDR = 0x10; // next SL811_DATA byte goes here SL811_DATA = 0x00; // bmRequestType (h->d,std request,device is recipient) SL811_DATA = 0x05; // bRequest (SET_ADDRESS) SL811_DATA = 0x01; // wValueL (device address)--we're setting it to ONE SL811_DATA = 0x00; // wValueH (zero) SL811_DATA = 0x00; // wIndexL (zero) SL811_DATA = 0x00; // wIndexH (zero) SL811_DATA = 0x00; // wLengthL (zero) SL811_DATA = 0x00; // wLengthH (zero) wr811(FNADDR,0x00); // USB address zero wr811(PID_EP,SETUP_PID | 0x00); // SETUP PID, EP0 result=go(0x07); // DIREC=1(out), ENAB=1, ARM=1 // STATUS stage is a no-data IN to EP0 wr811(PID_EP,IN_PID | 0x00); // IN PID, EP0 result=go(0x03); // Don't sync to SOF, DIREC=0(in), ENAB, ARM D- PA0

  23. Code-2CATC trace // (2) Issue a SET_ADDRESS USB request, setting the peripheral address to 1 // From the USB spec, Chapter 9, here is the data for a "SET_ADDRESS" request: // Note: every SL811_DATA load increments an internal SL811 address pointer SL811_ADDR = 0x10; // next SL811_DATA byte goes here SL811_DATA = 0x00; // bmRequestType (h->d,std request,device is recipient) SL811_DATA = 0x05; // bRequest (SET_ADDRESS) SL811_DATA = 0x01; // wValueL (device address)--we're setting it to ONE SL811_DATA = 0x00; // wValueH (zero) SL811_DATA = 0x00; // wIndexL (zero) SL811_DATA = 0x00; // wIndexH (zero) SL811_DATA = 0x00; // wLengthL (zero) SL811_DATA = 0x00; // wLengthH (zero) wr811(FNADDR,0x00); // USB address zero wr811(PID_EP,SETUP_PID | 0x00); // SETUP PID, EP0 result=go(0x07); // DIREC=1(out), ENAB=1, ARM=1 // STATUS stage is a no-data IN to EP0 wr811(PID_EP,IN_PID | 0x00); // IN PID, EP0 result=go(0x03); // Don't sync to SOF, DIREC=0(in), ENAB, ARM

  24. Code-3Issue Set_Config. CTL Transfer // (3) Send a CONTROL transfer to select configuration #1. Until we do this // the device is in an "unconfigured" state and probably won't send data. // Again, from USB spec Chapter 9: SL811_ADDR = 0x10; // reset pointer to beginning of internal buffer. SL811_DATA = 0x00; // bmRequestType (h->d,std request,device is recipient) SL811_DATA = 0x09; // bRequest (SET_CONFIGURATION) SL811_DATA = 0x01; // wValueL (configuration = 1) SL811_DATA = 0x00; // wValueH (zero) SL811_DATA = 0x00; // wIndexL (zero) SL811_DATA = 0x00; // wIndexH (zero) SL811_DATA = 0x00; // wLengthL (zero) SL811_DATA = 0x00; // wLengthH (zero) wr811(FNADDR,0x01); // now talking to USB device at address 1 wr811(PID_EP,SETUP_PID | 0x00); // OR in the endpoint (zero) result=go(0x07); // DIREC=1(out), ENAB=1, ARM=1 // STATUS stage is a no-data IN to EP0 wr811(PID_EP,IN_PID | 0x00); // IN PID, EP0 result=go(0x03); // DIREC=0(in), ENAB=1, ARM=1

  25. Code-3On the wire // (3) Send a CONTROL transfer to select configuration #1. Until we do this // the device is in an "unconfigured" state and probably won't send data. // Again, from USB spec Chapter 9: SL811_ADDR = 0x10; // reset pointer to beginning of internal buffer. SL811_DATA = 0x00; // bmRequestType (h->d,std request,device is recipient) SL811_DATA = 0x09; // bRequest (SET_CONFIGURATION) SL811_DATA = 0x01; // wValueL (configuration = 1) SL811_DATA = 0x00; // wValueH (zero) SL811_DATA = 0x00; // wIndexL (zero) SL811_DATA = 0x00; // wIndexH (zero) SL811_DATA = 0x00; // wLengthL (zero) SL811_DATA = 0x00; // wLengthH (zero) wr811(FNADDR,0x01); // now talking to USB device at address 1 wr811(PID_EP,SETUP_PID | 0x00); // OR in the endpoint (zero) result=go(0x07); // DIREC=1(out), ENAB=1, ARM=1 // STATUS stage is a no-data IN to EP0 wr811(PID_EP,IN_PID | 0x00); // IN PID, EP0 result=go(0x03); // DIREC=0(in), ENAB=1, ARM=1 D- PA0

  26. Code-3CATC trace // (3) Send a CONTROL transfer to select configuration #1. Until we do this // the device is in an "unconfigured" state and probably won't send data. // Again, from USB spec Chapter 9: SL811_ADDR = 0x10; // reset pointer to beginning of internal buffer. SL811_DATA = 0x00; // bmRequestType (h->d,std request,device is recipient) SL811_DATA = 0x09; // bRequest (SET_CONFIGURATION) SL811_DATA = 0x01; // wValueL (configuration = 1) SL811_DATA = 0x00; // wValueH (zero) SL811_DATA = 0x00; // wIndexL (zero) SL811_DATA = 0x00; // wIndexH (zero) SL811_DATA = 0x00; // wLengthL (zero) SL811_DATA = 0x00; // wLengthH (zero) wr811(FNADDR,0x01); // now talking to USB device at address 1 wr811(PID_EP,SETUP_PID | 0x00); // OR in the endpoint (zero) result=go(0x07); // DIREC=1(out), ENAB=1, ARM=1 // STATUS stage is a no-data IN to EP0 wr811(PID_EP,IN_PID | 0x00); // IN PID, EP0 result=go(0x03); // DIREC=0(in), ENAB=1, ARM=1

  27. Code-4Ping the keypad, display new data // (4) Send constant IN requests to Addr 1, EP1 wr811(PID_EP,IN_PID | 0x01); // set up for IN PIDS to endpoint 1 while(1) { SL811_ADDR = 0x10; // reset pointer to beginning of internal buffer waitframes(4); // send the IN requests every n milliseconds result=go(0x03); // DIREC=0(in), ENAB=1, ARM=1 if (result & 0x01) // look only for ACK display_hex(rd811(0x12)); } // KB value is in third byte of 3-byte packet

  28. Entire startup sequence D- EOP PA0 Set Address Handshake IN: Dev=1, EP=1 Handshake Set Config

  29. Keypad NAKS, then ready

  30. Code-5Housekeeping void wr811(BYTE address, BYTE value) { SL811_ADDR = address; SL811_DATA = value; } BYTE rd811(BYTE address) { SL811_ADDR = address; return SL811_DATA; } BYTE go(BYTE cmd) { // Launch an 811H operation. SCOPE_HI; wr811(INTSTATUS,0x01); // clear the DONE bit wr811(CTL,cmd); // start the operation delay(100); while(rd811(INTSTATUS) & 0x01==0) { } // spin while "done" bit is low SCOPE_LO; return rd811(PKTSTAT); } // return the status of this transfer

  31. * * * * * * * C O D E M E M O R Y * * * * * * * CODE 0000H 0003H ABSOLUTE 0003H 00FDH *** GAP *** CODE 0100H 00DDH UNIT ?PR?MAIN?MINHOST CODE 01DDH 008CH UNIT ?C_C51STARTUP CODE 0269H 003FH UNIT ?PR?_DISPLAY_HEX?MINHOST CODE 02A8H 0037H UNIT ?PR?_WAITFRAMES?MINHOST CODE 02DFH 0027H UNIT ?PR?_GO?MINHOST CODE 0306H 0014H UNIT ?C_INITSEG CODE 031AH 000FH UNIT ?PR?_WR811?MINHOST CODE 0329H 000BH UNIT ?PR?_DELAY?MINHOST CODE 0334H 0009H UNIT ?PR?_RD811?MINHOST 350 bytes Code Size

  32. Creeping Elegance • Detect device plug-in • Put the device to sleep (suspend) • Easy—just disable 1 msec EOP’s • Wake up the device (resume) • Start sending EOP’s again • Operate through a hub • Keep track of more than one device address

  33. Resources: www.usb.org • Tools • USBCV Beta 2 - Windows 2000 and Windows XP only • The installation utility, USBCVBeta2.msi (11 MB), contains USB Command Verifier (USBCV) version 0.9.0.6. USBCV is the new compliance test tool which evaluates High, Full and Low-speed USB devices for conformance to the USB Device Framework (Chapter 9), Hub device class (Chapter 11), and HID specifications. USBCV is a replacement for USBCheck and is the preferred compliance tool to be used at this time. The final release of USBCV is expected to occur no later than Q2 2002. At that time USBCheck will be made obsolete and removed from this site. Users are encouraged to immediately use USBCV along with or instead of USBCheck. Until USBCheck is made obsolete, test results from either tool are considered by the compliance team to have equal weight. This version of USBCV was posted on 1/22/02. This software release will only work on Windows 2000 and Windows XP. Please check the release notes and accompanying documentations for details on using USBCV and how to provide the USB-IF feedback on issues and suggestions. This software is provided courtesy of Intel Corporation.

More Related