commit e238472454ca183459fdd04f3e1e1badb711407a Author: Oleg Mazurov Date: Tue Jan 18 23:27:20 2011 -0700 first commit diff --git a/README b/README new file mode 100644 index 00000000..7328e500 --- /dev/null +++ b/README @@ -0,0 +1,5 @@ +This is Rev.2.0 of MAX3421E-based USB Host Library for Arduino. At the moment, this repo contains current development copy +of the code facilitating developer's exchange. For those not involved in the project, the code in its' current state doesn't bear any value. +In other words, nothing works yet. + +The code uses slightly modified Konstantin Chizhov's AVR pin templates, see the original here -> https://github.com/KonstantinChizhov/AvrProjects \ No newline at end of file diff --git a/Usb.cpp b/Usb.cpp new file mode 100644 index 00000000..2b5408b2 --- /dev/null +++ b/Usb.cpp @@ -0,0 +1,385 @@ +/* USB functions */ + +#include "avrpins.h" +#include "max3421e.h" +#include "usbhost.h" +#include "Usb.h" +#include "WProgram.h" + +static uint8_t usb_error = 0; +static uint8_t usb_task_state; +DEV_RECORD devtable[ USB_NUMDEVICES + 1 ]; +EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device + + +/* constructor */ + +USB::USB () +{ + usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine + init(); +} +/* Initialize data structures */ +void USB::init() +{ + uint8_t i; + for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) { + devtable[ i ].epinfo = NULL; //clear device table + devtable[ i ].devclass = 0; + } + devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device + // not necessary dev0ep.MaxPktSize = 8; //minimum possible + dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0 + dev0ep.rcvToggle = bmRCVTOG0; +} +uint8_t USB::getUsbTaskState( void ) +{ + return( usb_task_state ); +} +void USB::setUsbTaskState( uint8_t state ) +{ + usb_task_state = state; +} +EP_RECORD* USB::getDevTableEntry( uint8_t addr, uint8_t ep ) +{ + EP_RECORD* ptr; + ptr = devtable[ addr ].epinfo; + ptr += ep; + return( ptr ); +} +/* set device table entry */ +/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */ +void USB::setDevTableEntry( uint8_t addr, EP_RECORD* eprecord_ptr ) +{ + devtable[ addr ].epinfo = eprecord_ptr; + //return(); +} +/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */ +/* depending on request. Actual requests are defined as inlines */ +/* return codes: */ +/* 00 = success */ +/* 01-0f = non-zero HRSLT */ +uint8_t USB::ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, unsigned int wInd, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit ) +{ + boolean direction = false; //request direction, IN or OUT + uint8_t rcode; + SETUP_PKT setup_pkt; + + regWr( rPERADDR, addr ); //set peripheral address + if( bmReqType & 0x80 ) { + direction = true; //determine request direction + } + /* fill in setup packet */ + setup_pkt.ReqType_u.bmRequestType = bmReqType; + setup_pkt.bRequest = bRequest; + setup_pkt.wVal_u.wValueLo = wValLo; + setup_pkt.wVal_u.wValueHi = wValHi; + setup_pkt.wIndex = wInd; + setup_pkt.wLength = nbytes; + bytesWr( rSUDFIFO, 8, (uint8_t*)&setup_pkt ); //transfer to setup packet FIFO + rcode = dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet + //Serial.println("Setup packet"); //DEBUG + if( rcode ) { //return HRSLT if not zero + Serial.print("Setup packet error: "); + Serial.print( rcode, HEX ); + return( rcode ); + } + //Serial.println( direction, HEX ); + if( dataptr != NULL ) { //data stage, if present + rcode = ctrlData( addr, ep, nbytes, dataptr, direction ); + } + if( rcode ) { //return error + Serial.print("Data packet error: "); + Serial.print( rcode, HEX ); + return( rcode ); + } + rcode = ctrlStatus( ep, direction ); //status stage + return( rcode ); +} +/* Control transfer with status stage and no data stage */ +/* Assumed peripheral address is already set */ +uint8_t USB::ctrlStatus( uint8_t ep, boolean direction, unsigned int nak_limit ) +{ + uint8_t rcode; + if( direction ) { //GET + rcode = dispatchPkt( tokOUTHS, ep, nak_limit ); + } + else { + rcode = dispatchPkt( tokINHS, ep, nak_limit ); + } + return( rcode ); +} +/* Control transfer with data stage. Stages 2 and 3 of control transfer. Assumes preipheral address is set and setup packet has been sent */ +uint8_t USB::ctrlData( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, boolean direction, unsigned int nak_limit ) +{ + uint8_t rcode; + if( direction ) { //IN transfer + devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; + rcode = inTransfer( addr, ep, nbytes, dataptr, nak_limit ); + return( rcode ); + } + else { //OUT transfer + devtable[ addr ].epinfo[ ep ].sndToggle = bmSNDTOG1; + rcode = outTransfer( addr, ep, nbytes, dataptr, nak_limit ); + return( rcode ); + } +} +/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ +/* Keep sending INs and writes data to memory area pointed by 'data' */ +/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, + fe USB xfer timeout */ +uint8_t USB::inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit ) +{ + uint8_t rcode; + uint8_t pktsize; + uint8_t maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize; + unsigned int xfrlen = 0; + regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value + while( 1 ) { // use a 'return' to exit this loop + rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS. + if( rcode ) { + return( rcode ); //should be 0, indicating ACK. Else return error code. + } + /* check for RCVDAVIRQ and generate error if not present */ + /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */ + if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) { + return ( 0xf0 ); //receive error + } + pktsize = regRd( rRCVBC ); //number of received bytes + data = bytesRd( rRCVFIFO, pktsize, data ); + regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer + xfrlen += pktsize; // add this packet's byte count to total transfer length + /* The transfer is complete under two conditions: */ + /* 1. The device sent a short packet (L.T. maxPacketSize) */ + /* 2. 'nbytes' have been transferred. */ + if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes? + if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value + devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; + } + else { + devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0; + } + return( 0 ); + } + }//while( 1 ) +} +/* OUT transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ +/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */ +/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */ +/* major part of this function borrowed from code shared by Richard Ibbotson */ +uint8_t USB::outTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit ) +{ + uint8_t rcode, retry_count; + uint8_t* data_p = data; //local copy of the data pointer + unsigned int bytes_tosend, nak_count; + unsigned int bytes_left = nbytes; + uint8_t maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize; + unsigned long timeout = millis() + USB_XFER_TIMEOUT; + + if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64 + return 0xFE; + } + + regWr( rHCTL, devtable[ addr ].epinfo[ ep ].sndToggle ); //set toggle value + while( bytes_left ) { + retry_count = 0; + nak_count = 0; + bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left; + bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO + regWr( rSNDBC, bytes_tosend ); //set number of bytes + regWr( rHXFR, ( tokOUT | ep )); //dispatch packet + while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ + regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ + rcode = ( regRd( rHRSL ) & 0x0f ); + while( rcode && ( timeout > millis())) { + switch( rcode ) { + case hrNAK: + nak_count++; + if( nak_limit && ( nak_count == USB_NAK_LIMIT )) { + return( rcode); //return NAK + } + break; + case hrTIMEOUT: + retry_count++; + if( retry_count == USB_RETRY_LIMIT ) { + return( rcode ); //return TIMEOUT + } + break; + default: + return( rcode ); + }//switch( rcode... + /* process NAK according to Host out NAK bug */ + regWr( rSNDBC, 0 ); + regWr( rSNDFIFO, *data_p ); + regWr( rSNDBC, bytes_tosend ); + regWr( rHXFR, ( tokOUT | ep )); //dispatch packet + while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ + regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ + rcode = ( regRd( rHRSL ) & 0x0f ); + }//while( rcode && .... + bytes_left -= bytes_tosend; + data_p += bytes_tosend; + }//while( bytes_left... + devtable[ addr ].epinfo[ ep ].sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? bmSNDTOG1 : bmSNDTOG0; //update toggle + return( rcode ); //should be 0 in all cases +} +/* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */ +/* If NAK, tries to re-send up to nak_limit times */ +/* If nak_limit == 0, do not count NAKs, exit after timeout */ +/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */ +/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */ +uint8_t USB::dispatchPkt( uint8_t token, uint8_t ep, unsigned int nak_limit ) +{ + unsigned long timeout = millis() + USB_XFER_TIMEOUT; + uint8_t tmpdata; + uint8_t rcode; + unsigned int nak_count = 0; + char retry_count = 0; + + while( timeout > millis() ) { + regWr( rHXFR, ( token|ep )); //launch the transfer + rcode = 0xff; + while( millis() < timeout ) { //wait for transfer completion + tmpdata = regRd( rHIRQ ); + if( tmpdata & bmHXFRDNIRQ ) { + regWr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt + rcode = 0x00; + break; + }//if( tmpdata & bmHXFRDNIRQ + }//while ( millis() < timeout + if( rcode != 0x00 ) { //exit if timeout + return( rcode ); + } + rcode = ( regRd( rHRSL ) & 0x0f ); //analyze transfer result + switch( rcode ) { + case hrNAK: + nak_count ++; + if( nak_limit && ( nak_count == nak_limit )) { + return( rcode ); + } + break; + case hrTIMEOUT: + retry_count ++; + if( retry_count == USB_RETRY_LIMIT ) { + return( rcode ); + } + break; + default: + return( rcode ); + }//switch( rcode + }//while( timeout > millis() + return( rcode ); +} +/* USB main task. Performs enumeration/cleanup */ +void USB::Task( void ) //USB state machine +{ + uint8_t i; + uint8_t rcode; + static uint8_t tmpaddr; + uint8_t tmpdata; + static unsigned long delay = 0; + USB_DEVICE_DESCRIPTOR buf; + + //MAX3421E::Task(); + + tmpdata = getVbusState(); + /* modify USB task state if Vbus changed */ + + switch( tmpdata ) { + case SE1: //illegal state + usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL; + break; + case SE0: //disconnected + if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) { + usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; + } + break; + case FSHOST: //attached + case LSHOST: + if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) { + delay = millis() + USB_SETTLE_DELAY; + usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; + } + break; + }// switch( tmpdata + //Serial.print("USB task state: "); + //Serial.println( usb_task_state, HEX ); + switch( usb_task_state ) { + case USB_DETACHED_SUBSTATE_INITIALIZE: + init(); + usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE; + break; + case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here + break; + case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here + break; + case USB_ATTACHED_SUBSTATE_SETTLE: //setlle time for just attached device + if( delay < millis() ) { + usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; + } + break; + case USB_ATTACHED_SUBSTATE_RESET_DEVICE: + regWr( rHCTL, bmBUSRST ); //issue bus reset + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; + break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: + if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) { + tmpdata = regRd( rMODE ) | bmSOFKAENAB; //start SOF generation + regWr( rMODE, tmpdata ); +// regWr( rMODE, bmSOFKAENAB ); + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF; + delay = millis() + 20; //20ms wait after reset per USB spec + } + break; + case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order + if( regRd( rHIRQ ) & bmFRAMEIRQ ) { //when first SOF received we can continue + if( delay < millis() ) { //20ms passed + usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE; + } + } + break; + case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE: + // toggle( BPNT_0 ); + devtable[ 0 ].epinfo->MaxPktSize = 8; //set max.packet size to min.allowed + rcode = getDevDescr( 0, 0, 8, (uint8_t*)&buf ); + if( rcode == 0 ) { + devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0; + usb_task_state = USB_STATE_ADDRESSING; + } + else { + usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE; + usb_task_state = USB_STATE_ERROR; + } + break; + case USB_STATE_ADDRESSING: + for( i = 1; i < USB_NUMDEVICES; i++ ) { + if( devtable[ i ].epinfo == NULL ) { + devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize + //temporary record + //until plugged with real device endpoint structure + rcode = setAddr( 0, 0, i ); + if( rcode == 0 ) { + tmpaddr = i; + usb_task_state = USB_STATE_CONFIGURING; + } + else { + usb_error = USB_STATE_ADDRESSING; //set address error + usb_task_state = USB_STATE_ERROR; + } + break; //break if address assigned or error occured during address assignment attempt + } + } //for( i = 1; i < USB_NUMDEVICES; i++) + + if( usb_task_state == USB_STATE_ADDRESSING ) { //no vacant place in devtable + usb_error = 0xfe; + usb_task_state = USB_STATE_ERROR; + } + break; + case USB_STATE_CONFIGURING: + break; + case USB_STATE_RUNNING: + break; + case USB_STATE_ERROR: + break; + }// switch( usb_task_state +} diff --git a/Usb.h b/Usb.h new file mode 100644 index 00000000..b7bcc779 --- /dev/null +++ b/Usb.h @@ -0,0 +1,181 @@ +/* USB functions */ +#ifndef _usb_h_ +#define _usb_h_ + +#include +#include "avrpins.h" +#include "max3421e.h" +#include "usbhost.h" +#include "usb_ch9.h" +#include + +/* Common setup data constant combinations */ +#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type +#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface' +#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type +/* HID requests */ +#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE + +#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec +#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. o meand NAKs are not counted +#define USB_RETRY_LIMIT 3 //retry limit for a transfer +#define USB_SETTLE_DELAY 200 //settle delay in milliseconds +#define USB_NAK_NOWAIT 1 //used in Richard's PS2/Wiimote code + +#define USB_NUMDEVICES 2 //number of USB devices + +/* USB state machine states */ + +#define USB_STATE_MASK 0xf0 + +#define USB_STATE_DETACHED 0x10 +#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11 +#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12 +#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13 +#define USB_ATTACHED_SUBSTATE_SETTLE 0x20 +#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30 +#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40 +#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50 +#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60 +#define USB_STATE_ADDRESSING 0x70 +#define USB_STATE_CONFIGURING 0x80 +#define USB_STATE_RUNNING 0x90 +#define USB_STATE_ERROR 0xa0 + +// byte usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE + +/* USB Setup Packet Structure */ +typedef struct { + union { // offset description + uint8_t bmRequestType; // 0 Bit-map of request type + struct { + uint8_t recipient: 5; // Recipient of the request + uint8_t type: 2; // Type of request + uint8_t direction: 1; // Direction of data X-fer + }; + }ReqType_u; + uint8_t bRequest; // 1 Request + union { + unsigned int wValue; // 2 Depends on bRequest + struct { + uint8_t wValueLo; + uint8_t wValueHi; + }; + }wVal_u; + unsigned int wIndex; // 4 Depends on bRequest + unsigned int wLength; // 6 Depends on bRequest +} SETUP_PKT, *PSETUP_PKT; + +/* Endpoint information structure */ +/* bToggle of endpoint 0 initialized to 0xff */ +/* during enumeration bToggle is set to 00 */ +typedef struct { + uint8_t epAddr; //copy from endpoint descriptor. Bit 7 indicates direction ( ignored for control endpoints ) + uint8_t Attr; // Endpoint transfer type. + unsigned int MaxPktSize; // Maximum packet size. + uint8_t Interval; // Polling interval in frames. + uint8_t sndToggle; //last toggle value, bitmask for HCTL toggle bits + uint8_t rcvToggle; //last toggle value, bitmask for HCTL toggle bits + /* not sure if both are necessary */ +} EP_RECORD; +/* device record structure */ +typedef struct { + EP_RECORD* epinfo; //device endpoint information + uint8_t devclass; //device class +} DEV_RECORD; + + +typedef MAX3421e MAX3421E; + +class USB : public MAX3421E +{ +//data structures +/* device table. Filled during enumeration */ +/* index corresponds to device address */ +/* each entry contains pointer to endpoint structure */ +/* and device class to use in various places */ +//DEV_RECORD devtable[ USB_NUMDEVICES + 1 ]; +//EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device + +//byte usb_task_state; + + public: + USB( void ); + uint8_t getUsbTaskState( void ); + void setUsbTaskState( uint8_t state ); + EP_RECORD* getDevTableEntry( uint8_t addr, uint8_t ep ); + void setDevTableEntry( uint8_t addr, EP_RECORD* eprecord_ptr ); + uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, unsigned int wInd, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + /* Control requests */ + uint8_t getDevDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t getConfDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t conf, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t getStrDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t index, unsigned int langid, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t setAddr( uint8_t oldaddr, uint8_t ep, uint8_t newaddr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t setConf( uint8_t addr, uint8_t ep, uint8_t conf_value, unsigned int nak_limit = USB_NAK_LIMIT ); + /**/ + uint8_t setProto( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t protocol, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t getProto( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t getReportDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t setReport( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t getReport( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t getIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t reportID, uint8_t* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t setIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t reportID, uint8_t duration, unsigned int nak_limit = USB_NAK_LIMIT ); + /**/ + uint8_t ctrlData( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, boolean direction, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t ctrlStatus( uint8_t ep, boolean direction, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t inTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t outTransfer( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* data, unsigned int nak_limit = USB_NAK_LIMIT ); + uint8_t dispatchPkt( uint8_t token, uint8_t ep, unsigned int nak_limit = USB_NAK_LIMIT ); + void Task( void ); + //uint8_t nit() {}; + private: + void init(); +}; + +//get device descriptor +inline uint8_t USB::getDevDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr, nak_limit )); +} +//get configuration descriptor +inline uint8_t USB::getConfDescr( uint8_t addr, uint8_t ep, unsigned int nuint8_ts, uint8_t conf, uint8_t* dataptr, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nuint8_ts, dataptr, nak_limit )); +} +//get string descriptor +inline uint8_t USB::getStrDescr( uint8_t addr, uint8_t ep, unsigned int nuint8_ts, uint8_t index, unsigned int langid, uint8_t* dataptr, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr, nak_limit )); +} +//set address +inline uint8_t USB::setAddr( uint8_t oldaddr, uint8_t ep, uint8_t newaddr, unsigned int nak_limit ) { + return( ctrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL, nak_limit )); +} +//set configuration +inline uint8_t USB::setConf( uint8_t addr, uint8_t ep, uint8_t conf_value, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL, nak_limit )); +} +//class requests +inline uint8_t USB::setProto( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t protocol, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, interface, 0x0000, NULL, nak_limit )); +} +inline uint8_t USB::getProto( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t* dataptr, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, interface, 0x0001, dataptr, nak_limit )); +} +//get HID report descriptor +inline uint8_t USB::getReportDescr( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t* dataptr, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, dataptr, nak_limit )); +} +inline uint8_t USB::setReport( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit )); +} +inline uint8_t USB::getReport( uint8_t addr, uint8_t ep, unsigned int nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, unsigned int nak_limit ) { // ** RI 04/11/09 + return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit )); +} +/* returns one byte of data in dataptr */ +inline uint8_t USB::getIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t reportID, uint8_t* dataptr, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, interface, 0x0001, dataptr, nak_limit )); +} +inline uint8_t USB::setIdle( uint8_t addr, uint8_t ep, uint8_t interface, uint8_t reportID, uint8_t duration, unsigned int nak_limit ) { + return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, interface, 0x0000, NULL, nak_limit )); + } +#endif //_usb_h_ \ No newline at end of file diff --git a/avrpins.h b/avrpins.h new file mode 100644 index 00000000..e273d42b --- /dev/null +++ b/avrpins.h @@ -0,0 +1,376 @@ +/* copied from Konstantin Chizhov's AVR port templates */ + +#ifndef _avrpins_h_ +#define _avrpins_h_ + +//#include "WProgram.h" +#include + +#ifdef PORTA +#define USE_PORTA +#endif +#ifdef PORTB +#define USE_PORTB +#endif +#ifdef PORTC +#define USE_PORTC +#endif +#ifdef PORTD +#define USE_PORTD +#endif +#ifdef PORTE +#define USE_PORTE +#endif +#ifdef PORTF +#define USE_PORTF +#endif +#ifdef PORTG +#define USE_PORTG +#endif +#ifdef PORTH +#define USE_PORTH +#endif +#ifdef PORTJ +#define USE_PORTJ +#endif +#ifdef PORTK +#define USE_PORTK +#endif +#ifdef PORTQ +#define USE_PORTQ +#endif +#ifdef PORTR +#define USE_PORTR +#endif + +#ifdef TCCR0A +#define USE_TCCR0A +#endif +#ifdef TCCR1A +#define USE_TCCR1A +#endif +#ifdef TCCR2A +#define USE_TCCR2A +#endif + +//Port definitions for AtTiny, AtMega families. + +#define MAKE_PORT(portName, ddrName, pinName, className, ID) \ + class className{\ + public:\ + typedef uint8_t DataT;\ + public:\ + static void Write(DataT value){portName = value;}\ + static void ClearAndSet(DataT clearMask, DataT value){portName = (portName & ~clearMask) | value;}\ + static DataT Read(){return portName;}\ + static void DirWrite(DataT value){ddrName = value;}\ + static DataT DirRead(){return ddrName;}\ + static void Set(DataT value){portName |= value;}\ + static void Clear(DataT value){portName &= ~value;}\ + static void Toggle(DataT value){portName ^= value;}\ + static void DirSet(DataT value){ddrName |= value;}\ + static void DirClear(DataT value){ddrName &= ~value;}\ + static void DirToggle(DataT value){ddrName ^= value;}\ + static DataT PinRead(){return pinName;}\ + enum{Id = ID};\ + enum{Width=sizeof(DataT)*8};\ + }; + +// TCCR registers to set/clear Arduino PWM +#define MAKE_TCCR(TccrName, className) \ + class className{\ + public:\ + typedef uint8_t DataT;\ + public:\ + static void Write(DataT value){TccrName = value;}\ + static void ClearAndSet(DataT clearMask, DataT value){TccrName = (TccrName & ~clearMask) | value;}\ + static DataT Read(){return TccrName;}\ + static void Set(DataT value){TccrName |= value;}\ + static void Clear(DataT value){TccrName &= ~value;}\ + static void Toggle(DataT value){TccrName ^= value;}\ + enum{Width=sizeof(DataT)*8};\ + }; + +#ifdef USE_PORTA +MAKE_PORT(PORTA, DDRA, PINA, Porta, 'A') +#endif +#ifdef USE_PORTB +MAKE_PORT(PORTB, DDRB, PINB, Portb, 'B') +#endif +#ifdef USE_PORTC +MAKE_PORT(PORTC, DDRC, PINC, Portc, 'C') +#endif +#ifdef USE_PORTD +MAKE_PORT(PORTD, DDRD, PIND, Portd, 'D') +#endif +#ifdef USE_PORTE +MAKE_PORT(PORTE, DDRE, PINE, Porte, 'E') +#endif + +#ifdef USE_TCCR0A +MAKE_TCCR(TCCR0A, Tccr0a) +#endif +#ifdef USE_TCCR1A +MAKE_TCCR(TCCR1A, Tccr1a) +#endif +#ifdef USE_TCCR2A +MAKE_TCCR(TCCR2A, Tccr2a) +#endif + + // this class represents one pin in a IO port. + // It is fully static. + template + class TPin + { +// BOOST_STATIC_ASSERT(PIN < PORT::Width); + public: + typedef PORT Port; + enum{Number = PIN}; + + static void Set() { PORT::Set(1 << PIN); } + + static void Set(uint8_t val){ + if(val) + Set(); + else Clear();} + + static void SetDir(uint8_t val){ + if(val) + SetDirWrite(); + else SetDirRead();} + + static void Clear(){PORT::Clear(1 << PIN);} + + static void Toggle(){PORT::Toggle(1 << PIN);} + + static void SetDirRead(){PORT::DirClear(1 << PIN);} + + static void SetDirWrite(){PORT::DirSet(1 << PIN);} + + static uint8_t IsSet(){return PORT::PinRead() & (uint8_t)(1 << PIN);} + + static void WaiteForSet(){ while(IsSet()==0){} } + + static void WaiteForClear(){ while(IsSet()){} } + }; //class TPin... + + // this class represents one bit in TCCR port. + // used to set/clear TCCRx bits + // It is fully static. + template + class TCom + { +// BOOST_STATIC_ASSERT(PIN < PORT::Width); + public: + typedef TCCR Tccr; + enum{Com = COM}; + + static void Set() { TCCR::Set(1 << COM); } + + static void Clear() { TCCR::Clear(1 << COM); } + + static void Toggle() { TCCR::Toggle(1 << COM); } + }; //class TCom... + +//Short pin definitions +#ifdef USE_PORTA +typedef TPin Pa0; +typedef TPin Pa1; +typedef TPin Pa2; +typedef TPin Pa3; +typedef TPin Pa4; +typedef TPin Pa5; +typedef TPin Pa6; +typedef TPin Pa7; +#endif + +#ifdef USE_PORTB +typedef TPin Pb0; +typedef TPin Pb1; +typedef TPin Pb2; +typedef TPin Pb3; +typedef TPin Pb4; +typedef TPin Pb5; +typedef TPin Pb6; +typedef TPin Pb7; +#endif + +#ifdef USE_PORTC +typedef TPin Pc0; +typedef TPin Pc1; +typedef TPin Pc2; +typedef TPin Pc3; +typedef TPin Pc4; +typedef TPin Pc5; +typedef TPin Pc6; +typedef TPin Pc7; +#endif + +#ifdef USE_PORTD +typedef TPin Pd0; +typedef TPin Pd1; +typedef TPin Pd2; +typedef TPin Pd3; +typedef TPin Pd4; +typedef TPin Pd5; +typedef TPin Pd6; +typedef TPin Pd7; +#endif + +#ifdef USE_PORTE +typedef TPin Pe0; +typedef TPin Pe1; +typedef TPin Pe2; +typedef TPin Pe3; +typedef TPin Pe4; +typedef TPin Pe5; +typedef TPin Pe6; +typedef TPin Pe7; +#endif + +#ifdef USE_PORTF +typedef TPin Pf0; +typedef TPin Pf1; +typedef TPin Pf2; +typedef TPin Pf3; +typedef TPin Pf4; +typedef TPin Pf5; +typedef TPin Pf6; +typedef TPin Pf7; +#endif + +#ifdef USE_PORTG +typedef TPin Pg0; +typedef TPin Pg1; +typedef TPin Pg2; +typedef TPin Pg3; +typedef TPin Pg4; +typedef TPin Pg5; +typedef TPin Pg6; +typedef TPin Pg7; +#endif + +#ifdef USE_PORTH +typedef TPin Ph0; +typedef TPin Ph1; +typedef TPin Ph2; +typedef TPin Ph3; +typedef TPin Ph4; +typedef TPin Ph5; +typedef TPin Ph6; +typedef TPin Ph7; +#endif + +#ifdef USE_PORTJ +typedef TPin Pj0; +typedef TPin Pj1; +typedef TPin Pj2; +typedef TPin Pj3; +typedef TPin Pj4; +typedef TPin Pj5; +typedef TPin Pj6; +typedef TPin Pj7; +#endif + +#ifdef USE_PORTK +typedef TPin Pk0; +typedef TPin Pk1; +typedef TPin Pk2; +typedef TPin Pk3; +typedef TPin Pk4; +typedef TPin Pk5; +typedef TPin Pk6; +typedef TPin Pk7; +#endif + +#ifdef USE_PORTQ +typedef TPin Pq0; +typedef TPin Pq1; +typedef TPin Pq2; +typedef TPin Pq3; +typedef TPin Pq4; +typedef TPin Pq5; +typedef TPin Pq6; +typedef TPin Pq7; +#endif + +#ifdef USE_PORTR +typedef TPin Pr0; +typedef TPin Pr1; +typedef TPin Pr2; +typedef TPin Pr3; +typedef TPin Pr4; +typedef TPin Pr5; +typedef TPin Pr6; +typedef TPin Pr7; +#endif + +#ifdef USE_TCCR0A +typedef TCom Tc0a; //P6 +typedef TCom Tc0b; //P5 +#endif + +#ifdef USE_TCCR1A +typedef TCom Tc1a; //P9 +typedef TCom Tc1b; //P10 +#endif + +#ifdef USE_TCCR2A +typedef TCom Tc2a; //P11 +typedef TCom Tc2b; //P3 +#endif + +template + class Tp_Tc + { + public: + static void SetDir(uint8_t val){ + if(val) + SetDirWrite(); + else SetDirRead(); + } + static void SetDirRead(){ + Tp_pin::SetDirRead(); //set pin direction + Tc_bit::Clear(); //disconnect pin from PWM + } + static void SetDirWrite(){ + Tp_pin::SetDirWrite(); + Tc_bit::Clear(); + } + }; + +/* pin definitions for cases where it's necessary to clear compare output mode bits */ + +//typedef Tp_Tc P3; //Arduino pin 3 +//typedef Tp_Tc P5; //Arduino pin 5 +//typedef Tp_Tc P6; //Arduino pin 6 +//typedef Tp_Tc P9; //Arduino pin 9 +//typedef Tp_Tc P10; //Arduino pin 10 +//typedef Tp_Tc P11; //Arduino pin 11 + +//Arduino pin numbers + +#define P0 Pd0 +#define P1 Pd1 +#define P2 Pd2 +#define P3 Pd3 +#define P4 Pd4 +#define P5 Pd5 +#define P6 Pd6 +#define P7 Pd7 + +#define P8 Pb0 +#define P9 Pb1 +#define P10 Pb2 +#define P11 Pb3 +#define P12 Pb4 +#define P13 Pb5 + +#define P14 Pc0 +#define P15 Pc1 +#define P16 Pc2 +#define P17 Pc3 +#define P18 Pc4 +#define P19 Pc5 + +#endif //_avrpins_h_ diff --git a/diff.txt b/diff.txt new file mode 100644 index 00000000..21b456b3 --- /dev/null +++ b/diff.txt @@ -0,0 +1 @@ +Comparing files usbhost.h and USBHOST.H2 diff --git a/max3421e.h b/max3421e.h new file mode 100644 index 00000000..34d8bcab --- /dev/null +++ b/max3421e.h @@ -0,0 +1,223 @@ +/* MAX3421E register/bit names and bitmasks */ + +#ifndef _max3421e_h_ +#define _max3421e_h_ + +/* Arduino pin definitions */ + + +/* pin numbers to port numbers */ + +//#define MAX_SS 10 +#define MAX_INT 9 +#define MAX_GPX 8 +//#define MAX_RESET 7 +// +//#define BPNT_0 3 +//#define BPNT_1 2 +// +//#define Select_MAX3421E digitalWrite( MAX_SS,LOW ) +//#define Deselect_MAX3421E digitalWrite( MAX_SS,HIGH ) + +/* */ + +#define ON true +#define OFF false + +#define SE0 0 +#define SE1 1 +#define FSHOST 2 +#define LSHOST 3 + +/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */ +// +// MAX3421E Registers in HOST mode. +// +#define rRCVFIFO 0x08 //1<<3 +#define rSNDFIFO 0x10 //2<<3 +#define rSUDFIFO 0x20 //4<<3 +#define rRCVBC 0x30 //6<<3 +#define rSNDBC 0x38 //7<<3 + +#define rUSBIRQ 0x68 //13<<3 +/* USBIRQ Bits */ +#define bmVBUSIRQ 0x40 //b6 +#define bmNOVBUSIRQ 0x20 //b5 +#define bmOSCOKIRQ 0x01 //b0 + +#define rUSBIEN 0x70 //14<<3 +/* USBIEN Bits */ +#define bmVBUSIE 0x40 //b6 +#define bmNOVBUSIE 0x20 //b5 +#define bmOSCOKIE 0x01 //b0 + +#define rUSBCTL 0x78 //15<<3 +/* USBCTL Bits */ +#define bmCHIPRES 0x20 //b5 +#define bmPWRDOWN 0x10 //b4 + +#define rCPUCTL 0x80 //16<<3 +/* CPUCTL Bits */ +#define bmPUSLEWID1 0x80 //b7 +#define bmPULSEWID0 0x40 //b6 +#define bmIE 0x01 //b0 + +#define rPINCTL 0x88 //17<<3 +/* PINCTL Bits */ +#define bmFDUPSPI 0x10 //b4 +#define bmINTLEVEL 0x08 //b3 +#define bmPOSINT 0x04 //b2 +#define bmGPXB 0x02 //b1 +#define bmGPXA 0x01 //b0 +// GPX pin selections +#define GPX_OPERATE 0x00 +#define GPX_VBDET 0x01 +#define GPX_BUSACT 0x02 +#define GPX_SOF 0x03 + +#define rREVISION 0x90 //18<<3 + +#define rIOPINS1 0xa0 //20<<3 + +/* IOPINS1 Bits */ +#define bmGPOUT0 0x01 +#define bmGPOUT1 0x02 +#define bmGPOUT2 0x04 +#define bmGPOUT3 0x08 +#define bmGPIN0 0x10 +#define bmGPIN1 0x20 +#define bmGPIN2 0x40 +#define bmGPIN3 0x80 + +#define rIOPINS2 0xa8 //21<<3 +/* IOPINS2 Bits */ +#define bmGPOUT4 0x01 +#define bmGPOUT5 0x02 +#define bmGPOUT6 0x04 +#define bmGPOUT7 0x08 +#define bmGPIN4 0x10 +#define bmGPIN5 0x20 +#define bmGPIN6 0x40 +#define bmGPIN7 0x80 + +#define rGPINIRQ 0xb0 //22<<3 +/* GPINIRQ Bits */ +#define bmGPINIRQ0 0x01 +#define bmGPINIRQ1 0x02 +#define bmGPINIRQ2 0x04 +#define bmGPINIRQ3 0x08 +#define bmGPINIRQ4 0x10 +#define bmGPINIRQ5 0x20 +#define bmGPINIRQ6 0x40 +#define bmGPINIRQ7 0x80 + +#define rGPINIEN 0xb8 //23<<3 +/* GPINIEN Bits */ +#define bmGPINIEN0 0x01 +#define bmGPINIEN1 0x02 +#define bmGPINIEN2 0x04 +#define bmGPINIEN3 0x08 +#define bmGPINIEN4 0x10 +#define bmGPINIEN5 0x20 +#define bmGPINIEN6 0x40 +#define bmGPINIEN7 0x80 + +#define rGPINPOL 0xc0 //24<<3 +/* GPINPOL Bits */ +#define bmGPINPOL0 0x01 +#define bmGPINPOL1 0x02 +#define bmGPINPOL2 0x04 +#define bmGPINPOL3 0x08 +#define bmGPINPOL4 0x10 +#define bmGPINPOL5 0x20 +#define bmGPINPOL6 0x40 +#define bmGPINPOL7 0x80 + +#define rHIRQ 0xc8 //25<<3 +/* HIRQ Bits */ +#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume +#define bmRWUIRQ 0x02 +#define bmRCVDAVIRQ 0x04 +#define bmSNDBAVIRQ 0x08 +#define bmSUSDNIRQ 0x10 +#define bmCONDETIRQ 0x20 +#define bmFRAMEIRQ 0x40 +#define bmHXFRDNIRQ 0x80 + +#define rHIEN 0xd0 //26<<3 +/* HIEN Bits */ +#define bmBUSEVENTIE 0x01 +#define bmRWUIE 0x02 +#define bmRCVDAVIE 0x04 +#define bmSNDBAVIE 0x08 +#define bmSUSDNIE 0x10 +#define bmCONDETIE 0x20 +#define bmFRAMEIE 0x40 +#define bmHXFRDNIE 0x80 + +#define rMODE 0xd8 //27<<3 +/* MODE Bits */ +#define bmHOST 0x01 +#define bmLOWSPEED 0x02 +#define bmHUBPRE 0x04 +#define bmSOFKAENAB 0x08 +#define bmSEPIRQ 0x10 +#define bmDELAYISO 0x20 +#define bmDMPULLDN 0x40 +#define bmDPPULLDN 0x80 + +#define rPERADDR 0xe0 //28<<3 + +#define rHCTL 0xe8 //29<<3 +/* HCTL Bits */ +#define bmBUSRST 0x01 +#define bmFRMRST 0x02 +#define bmSAMPLEBUS 0x04 +#define bmSIGRSM 0x08 +#define bmRCVTOG0 0x10 +#define bmRCVTOG1 0x20 +#define bmSNDTOG0 0x40 +#define bmSNDTOG1 0x80 + +#define rHXFR 0xf0 //30<<3 +/* Host transfer token values for writing the HXFR register (R30) */ +/* OR this bit field with the endpoint number in bits 3:0 */ +#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1 +#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0 +#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0 +#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0 +#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0 +#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0 +#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0 + +#define rHRSL 0xf8 //31<<3 +/* HRSL Bits */ +#define bmRCVTOGRD 0x10 +#define bmSNDTOGRD 0x20 +#define bmKSTATUS 0x40 +#define bmJSTATUS 0x80 +#define bmSE0 0x00 //SE0 - disconnect state +#define bmSE1 0xc0 //SE1 - illegal state +/* Host error result codes, the 4 LSB's in the HRSL register */ +#define hrSUCCESS 0x00 +#define hrBUSY 0x01 +#define hrBADREQ 0x02 +#define hrUNDEF 0x03 +#define hrNAK 0x04 +#define hrSTALL 0x05 +#define hrTOGERR 0x06 +#define hrWRONGPID 0x07 +#define hrBADBC 0x08 +#define hrPIDERR 0x09 +#define hrPKTERR 0x0A +#define hrCRCERR 0x0B +#define hrKERR 0x0C +#define hrJERR 0x0D +#define hrTIMEOUT 0x0E +#define hrBABBLE 0x0F + +#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB) +#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB) + + +#endif //_max3421e_h_ diff --git a/usb_ch9.h b/usb_ch9.h new file mode 100644 index 00000000..e2b413c1 --- /dev/null +++ b/usb_ch9.h @@ -0,0 +1,169 @@ +/* USB chapter 9 structures */ +#ifndef _ch9_h_ +#define _ch9_h_ + +#include + +/* Misc.USB constants */ +#define DEV_DESCR_LEN 18 //device descriptor length +#define CONF_DESCR_LEN 9 //configuration descriptor length +#define INTR_DESCR_LEN 9 //interface descriptor length +#define EP_DESCR_LEN 7 //endpoint descriptor length + +/* Standard Device Requests */ + +#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS +#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE +#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE +#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS +#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR +#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR +#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION +#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION +#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE +#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE +#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME + +#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up +#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode + +/* Setup Data Constants */ + +#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer +#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer +#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard +#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class +#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor +#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device +#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface +#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint +#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other + +/* USB descriptors */ + +#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor. +#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor. +#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor. +#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor. +#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor. +#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier. +#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration. +#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power. +#define USB_DESCRIPTOR_OTG 0x09 // bDescriptorType for an OTG Descriptor. + +/* OTG SET FEATURE Constants */ +#define OTG_FEATURE_B_HNP_ENABLE 3 // SET FEATURE OTG - Enable B device to perform HNP +#define OTG_FEATURE_A_HNP_SUPPORT 4 // SET FEATURE OTG - A device supports HNP +#define OTG_FEATURE_A_ALT_HNP_SUPPORT 5 // SET FEATURE OTG - Another port on the A device supports HNP + +/* USB Endpoint Transfer Types */ +#define USB_TRANSFER_TYPE_CONTROL 0x00 // Endpoint is a control endpoint. +#define USB_TRANSFER_TYPE_ISOCHRONOUS 0x01 // Endpoint is an isochronous endpoint. +#define USB_TRANSFER_TYPE_BULK 0x02 // Endpoint is a bulk endpoint. +#define USB_TRANSFER_TYPE_INTERRUPT 0x03 // Endpoint is an interrupt endpoint. +#define bmUSB_TRANSFER_TYPE 0x03 // bit mask to separate transfer type from ISO attributes + + +/* Standard Feature Selectors for CLEAR_FEATURE Requests */ +#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient +#define USB_FEATURE_TEST_MODE 2 // Device recipient + +/* HID constants. Not part of chapter 9 */ +/* Class-Specific Requests */ +#define HID_REQUEST_GET_REPORT 0x01 +#define HID_REQUEST_GET_IDLE 0x02 +#define HID_REQUEST_GET_PROTOCOL 0x03 +#define HID_REQUEST_SET_REPORT 0x09 +#define HID_REQUEST_SET_IDLE 0x0A +#define HID_REQUEST_SET_PROTOCOL 0x0B + +/* Class Descriptor Types */ +#define HID_DESCRIPTOR_HID 0x21 +#define HID_DESCRIPTOR_REPORT 0x22 +#define HID_DESRIPTOR_PHY 0x23 + +/* Protocol Selection */ +#define BOOT_PROTOCOL 0x00 +#define RPT_PROTOCOL 0x01 +/* HID Interface Class Code */ +#define HID_INTF 0x03 +/* HID Interface Class SubClass Codes */ +#define BOOT_INTF_SUBCLASS 0x01 +/* HID Interface Class Protocol Codes */ +#define HID_PROTOCOL_NONE 0x00 +#define HID_PROTOCOL_KEYBOARD 0x01 +#define HID_PROTOCOL_MOUSE 0x02 + + +/* descriptor data structures */ + +/* Device descriptor structure */ +typedef struct { + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. +} USB_DEVICE_DESCRIPTOR; + +/* Configuration descriptor structure */ +typedef struct +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. +} USB_CONFIGURATION_DESCRIPTOR; + +/* Interface descriptor structure */ +typedef struct +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. +} USB_INTERFACE_DESCRIPTOR; + +/* Endpoint descriptor structure */ +typedef struct +{ + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. +} USB_ENDPOINT_DESCRIPTOR; + +/* HID descriptor */ +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescrType; + uint16_t wDescriptorLength; +} USB_HID_DESCRIPTOR; + +#endif // _ch9_h_ diff --git a/usbhost.h b/usbhost.h new file mode 100644 index 00000000..5702210e --- /dev/null +++ b/usbhost.h @@ -0,0 +1,293 @@ +/* MAX3421E-based USB Host Library header file */ +#ifndef _USBHOST_H_ +#define _USBHOST_H_ + +#include +#include "avrpins.h" +#include "max3421e.h" +#include "usb_ch9.h" + + +/* SPI initialization */ +template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi +{ + public: + static void init() { + uint8_t tmp; + CLK::SetDirWrite(); + MOSI::SetDirWrite(); + MISO::SetDirRead(); + SPI_SS::SetDirWrite(); + /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */ + SPCR = 0x50; + SPSR = 0x01; + /**/ + tmp = SPSR; + tmp = SPDR; + } +}; + +/* SPI pin definitions. see avrpins.h */ +#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) +typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi; +#endif +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) +typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi; +#endif + +template< typename SS, typename INTR > class MAX3421e /* : public spi */ +{ + static uint8_t vbusState; + + public: + MAX3421e(); + void regWr( uint8_t reg, uint8_t data ); + uint8_t* bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p ); + void gpioWr( uint8_t data ); + uint8_t regRd( uint8_t reg ); + uint8_t* bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p ); + uint8_t gpioRd(); + uint16_t reset(); + int8_t Init(); + uint8_t getVbusState( void ) { return vbusState; }; + void busprobe(); + uint8_t GpxHandler(); + uint8_t IntHandler(); + uint8_t Task(); +}; + +template< typename SS, typename INTR > +uint8_t MAX3421e< SS, INTR >::vbusState = 0; + +/* constructor */ +template< typename SS, typename INTR > +MAX3421e< SS, INTR >::MAX3421e() +{ + /* pin and peripheral setup */ + SS::SetDirWrite(); + SS::Set(); + /* For shield rev.1.xx uncomment following two lines */ + P7::SetDirWrite(); + P7::Set(); + + spi::init(); + INTR::SetDirRead(); + + /* MAX3421E - full-duplex SPI, level interrupt */ + regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL )); +}; +/* write single byte into MAX3421 register */ +template< typename SS, typename INTR > +void MAX3421e< SS, INTR >::regWr( uint8_t reg, uint8_t data ) +{ + SS::Clear(); + SPDR = ( reg | 0x02 ); + while(!( SPSR & ( 1 << SPIF ))); + SPDR = data; + while(!( SPSR & ( 1 << SPIF ))); + SS::Set(); + return; +}; +/* multiple-byte write */ +/* returns a pointer to memory position after last written */ +template< typename SS, typename INTR > +uint8_t* MAX3421e< SS, INTR >::bytesWr( uint8_t reg, uint8_t nbytes, uint8_t* data_p ) +{ + SS::Clear(); + SPDR = ( reg | 0x02 ); //set WR bit and send register number + while( nbytes-- ) { + while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent + SPDR = ( *data_p ); // send next data byte + data_p++; // advance data pointer + } + while(!( SPSR & ( 1 << SPIF ))); + SS::Set(); + return( data_p ); +} +/* GPIO write */ +/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */ +/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */ +template< typename SS, typename INTR > +void MAX3421e< SS, INTR >::gpioWr( uint8_t data ) +{ + regWr( rIOPINS1, data ); + data >>= 4; + regWr( rIOPINS2, data ); + return; +} +/* single host register read */ +template< typename SS, typename INTR > +uint8_t MAX3421e< SS, INTR >::regRd( uint8_t reg ) +{ + SS::Clear(); + SPDR = reg; + while(!( SPSR & ( 1 << SPIF ))); + SPDR = 0; //send empty byte + while(!( SPSR & ( 1 << SPIF ))); + SS::Set(); + return( SPDR ); +} +/* multiple-byte register read */ +/* returns a pointer to a memory position after last read */ +template< typename SS, typename INTR > +uint8_t* MAX3421e< SS, INTR >::bytesRd( uint8_t reg, uint8_t nbytes, uint8_t* data_p ) +{ + SS::Clear(); + SPDR = reg; + while(!( SPSR & ( 1 << SPIF ))); //wait + while( nbytes ) { + SPDR = 0; //send empty byte + nbytes--; + while(!( SPSR & ( 1 << SPIF ))); + *data_p = SPDR; + data_p++; + } + SS::Set(); + return( data_p ); +} +/* GPIO read. See gpioWr for explanation */ +/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */ +template< typename SS, typename INTR > +uint8_t MAX3421e< SS, INTR >::gpioRd() +{ + uint8_t gpin = 0; + gpin = regRd( rIOPINS2 ); //pins 4-7 + gpin &= 0xf0; //clean lower nibble + gpin |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation. + return( gpin ); +} +/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset + or zero if PLL haven't stabilized in 65535 cycles */ +template< typename SS, typename INTR > +uint16_t MAX3421e< SS, INTR >::reset() +{ + uint16_t i = 0; + regWr( rUSBCTL, bmCHIPRES ); + regWr( rUSBCTL, 0x00 ); + while( ++i ) { + if(( regRd( rUSBIRQ ) & bmOSCOKIRQ )) { + break; + } + } + return( i ); +} +///* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ +//template< typename SS, typename INTR > +//int8_t MAX3421e< SS, INTR >::Init() +//{ +// if( reset() == 0 ) { //OSCOKIRQ hasn't asserted in time +// return ( -1 ); +// } +// regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host +// +// return( 0 ); +//} +/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */ +template< typename SS, typename INTR > +int8_t MAX3421e< SS, INTR >::Init() +{ + if( reset() == 0 ) + { //OSCOKIRQ hasn't asserted in time + return ( -1 ); + } + regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST ); // set pull-downs, Host + + regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection + /* check if device is connected */ + regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus + while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish + busprobe(); //check if anything is connected + +// Serial.println(getVbusState(), HEX); + + regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt + regWr( rCPUCTL, 0x01 ); //enable interrupt pin + return( 0 ); +} + +/* probe bus to determine device presense and speed and switch host to this speed */ +template< typename SS, typename INTR > +void MAX3421e< SS, INTR >::busprobe() +{ + byte bus_sample; + bus_sample = regRd( rHRSL ); //Get J,K status + bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte + switch( bus_sample ) { //start full-speed or low-speed host + case( bmJSTATUS ): + if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { + regWr( rMODE, MODE_FS_HOST ); //start full-speed host + vbusState = FSHOST; + } + else { + regWr( rMODE, MODE_LS_HOST); //start low-speed host + vbusState = LSHOST; + } + break; + case( bmKSTATUS ): + if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { + regWr( rMODE, MODE_LS_HOST ); //start low-speed host + vbusState = LSHOST; + } + else { + regWr( rMODE, MODE_FS_HOST ); //start full-speed host + vbusState = FSHOST; + } + break; + case( bmSE1 ): //illegal state + vbusState = SE1; + break; + case( bmSE0 ): //disconnected state + vbusState = SE0; + break; + }//end switch( bus_sample ) +} +/* MAX3421 state change task and interrupt handler */ +template< typename SS, typename INTR > +uint8_t MAX3421e< SS, INTR >::Task( void ) +{ + uint8_t rcode = 0; + uint8_t pinvalue; + //Serial.print("Vbus state: "); + //Serial.println( vbusState, HEX ); + pinvalue = digitalRead( MAX_INT ); + if( pinvalue == LOW ) { + rcode = IntHandler(); + } + pinvalue = digitalRead( MAX_GPX ); + if( pinvalue == LOW ) { + GpxHandler(); + } +// usbSM(); //USB state machine + return( rcode ); +} +template< typename SS, typename INTR > +uint8_t MAX3421e< SS, INTR >::IntHandler() +{ + uint8_t HIRQ; + uint8_t HIRQ_sendback = 0x00; + HIRQ = regRd( rHIRQ ); //determine interrupt source + //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler + // HIRQ_sendback |= bmFRAMEIRQ; + //}//end FRAMEIRQ handling + if( HIRQ & bmCONDETIRQ ) { + busprobe(); + HIRQ_sendback |= bmCONDETIRQ; + } + /* End HIRQ interrupts handling, clear serviced IRQs */ + regWr( rHIRQ, HIRQ_sendback ); + return( HIRQ_sendback ); +} +template< typename SS, typename INTR > +uint8_t MAX3421e< SS, INTR >::GpxHandler() +{ + uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register +// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload +// vbusPwr( OFF ); //attempt powercycle +// delay( 1000 ); +// vbusPwr( ON ); +// regWr( rGPINIRQ, bmGPINIRQ7 ); +// } + return( GPINIRQ ); +} + +#endif //_USBHOST_H_