first commit

This commit is contained in:
Oleg Mazurov 2011-01-18 23:27:20 -07:00
commit e238472454
8 changed files with 1633 additions and 0 deletions

5
README Normal file
View file

@ -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

385
Usb.cpp Normal file
View file

@ -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
}

181
Usb.h Normal file
View file

@ -0,0 +1,181 @@
/* USB functions */
#ifndef _usb_h_
#define _usb_h_
#include <inttypes.h>
#include "avrpins.h"
#include "max3421e.h"
#include "usbhost.h"
#include "usb_ch9.h"
#include <WProgram.h>
/* 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<P10, P9> 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_

376
avrpins.h Normal file
View file

@ -0,0 +1,376 @@
/* copied from Konstantin Chizhov's AVR port templates */
#ifndef _avrpins_h_
#define _avrpins_h_
//#include "WProgram.h"
#include <avr/io.h>
#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<typename PORT, uint8_t PIN>
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<typename TCCR, uint8_t COM>
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<Porta, 0> Pa0;
typedef TPin<Porta, 1> Pa1;
typedef TPin<Porta, 2> Pa2;
typedef TPin<Porta, 3> Pa3;
typedef TPin<Porta, 4> Pa4;
typedef TPin<Porta, 5> Pa5;
typedef TPin<Porta, 6> Pa6;
typedef TPin<Porta, 7> Pa7;
#endif
#ifdef USE_PORTB
typedef TPin<Portb, 0> Pb0;
typedef TPin<Portb, 1> Pb1;
typedef TPin<Portb, 2> Pb2;
typedef TPin<Portb, 3> Pb3;
typedef TPin<Portb, 4> Pb4;
typedef TPin<Portb, 5> Pb5;
typedef TPin<Portb, 6> Pb6;
typedef TPin<Portb, 7> Pb7;
#endif
#ifdef USE_PORTC
typedef TPin<Portc, 0> Pc0;
typedef TPin<Portc, 1> Pc1;
typedef TPin<Portc, 2> Pc2;
typedef TPin<Portc, 3> Pc3;
typedef TPin<Portc, 4> Pc4;
typedef TPin<Portc, 5> Pc5;
typedef TPin<Portc, 6> Pc6;
typedef TPin<Portc, 7> Pc7;
#endif
#ifdef USE_PORTD
typedef TPin<Portd, 0> Pd0;
typedef TPin<Portd, 1> Pd1;
typedef TPin<Portd, 2> Pd2;
typedef TPin<Portd, 3> Pd3;
typedef TPin<Portd, 4> Pd4;
typedef TPin<Portd, 5> Pd5;
typedef TPin<Portd, 6> Pd6;
typedef TPin<Portd, 7> Pd7;
#endif
#ifdef USE_PORTE
typedef TPin<Porte, 0> Pe0;
typedef TPin<Porte, 1> Pe1;
typedef TPin<Porte, 2> Pe2;
typedef TPin<Porte, 3> Pe3;
typedef TPin<Porte, 4> Pe4;
typedef TPin<Porte, 5> Pe5;
typedef TPin<Porte, 6> Pe6;
typedef TPin<Porte, 7> Pe7;
#endif
#ifdef USE_PORTF
typedef TPin<Portf, 0> Pf0;
typedef TPin<Portf, 1> Pf1;
typedef TPin<Portf, 2> Pf2;
typedef TPin<Portf, 3> Pf3;
typedef TPin<Portf, 4> Pf4;
typedef TPin<Portf, 5> Pf5;
typedef TPin<Portf, 6> Pf6;
typedef TPin<Portf, 7> Pf7;
#endif
#ifdef USE_PORTG
typedef TPin<Portg, 0> Pg0;
typedef TPin<Portg, 1> Pg1;
typedef TPin<Portg, 2> Pg2;
typedef TPin<Portg, 3> Pg3;
typedef TPin<Portg, 4> Pg4;
typedef TPin<Portg, 5> Pg5;
typedef TPin<Portg, 6> Pg6;
typedef TPin<Portg, 7> Pg7;
#endif
#ifdef USE_PORTH
typedef TPin<Porth, 0> Ph0;
typedef TPin<Porth, 1> Ph1;
typedef TPin<Porth, 2> Ph2;
typedef TPin<Porth, 3> Ph3;
typedef TPin<Porth, 4> Ph4;
typedef TPin<Porth, 5> Ph5;
typedef TPin<Porth, 6> Ph6;
typedef TPin<Porth, 7> Ph7;
#endif
#ifdef USE_PORTJ
typedef TPin<Portj, 0> Pj0;
typedef TPin<Portj, 1> Pj1;
typedef TPin<Portj, 2> Pj2;
typedef TPin<Portj, 3> Pj3;
typedef TPin<Portj, 4> Pj4;
typedef TPin<Portj, 5> Pj5;
typedef TPin<Portj, 6> Pj6;
typedef TPin<Portj, 7> Pj7;
#endif
#ifdef USE_PORTK
typedef TPin<Portk, 0> Pk0;
typedef TPin<Portk, 1> Pk1;
typedef TPin<Portk, 2> Pk2;
typedef TPin<Portk, 3> Pk3;
typedef TPin<Portk, 4> Pk4;
typedef TPin<Portk, 5> Pk5;
typedef TPin<Portk, 6> Pk6;
typedef TPin<Portk, 7> Pk7;
#endif
#ifdef USE_PORTQ
typedef TPin<Portq, 0> Pq0;
typedef TPin<Portq, 1> Pq1;
typedef TPin<Portq, 2> Pq2;
typedef TPin<Portq, 3> Pq3;
typedef TPin<Portq, 4> Pq4;
typedef TPin<Portq, 5> Pq5;
typedef TPin<Portq, 6> Pq6;
typedef TPin<Portq, 7> Pq7;
#endif
#ifdef USE_PORTR
typedef TPin<Portr, 0> Pr0;
typedef TPin<Portr, 1> Pr1;
typedef TPin<Portr, 2> Pr2;
typedef TPin<Portr, 3> Pr3;
typedef TPin<Portr, 4> Pr4;
typedef TPin<Portr, 5> Pr5;
typedef TPin<Portr, 6> Pr6;
typedef TPin<Portr, 7> Pr7;
#endif
#ifdef USE_TCCR0A
typedef TCom<Tccr0a, COM0A1> Tc0a; //P6
typedef TCom<Tccr0a, COM0B1> Tc0b; //P5
#endif
#ifdef USE_TCCR1A
typedef TCom<Tccr1a, COM1A1> Tc1a; //P9
typedef TCom<Tccr1a, COM1B1> Tc1b; //P10
#endif
#ifdef USE_TCCR2A
typedef TCom<Tccr2a, COM2A1> Tc2a; //P11
typedef TCom<Tccr2a, COM2B1> Tc2b; //P3
#endif
template<typename Tp_pin, typename Tc_bit>
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<Pd3, Tc2b> P3; //Arduino pin 3
//typedef Tp_Tc<Pd5, Tc0b> P5; //Arduino pin 5
//typedef Tp_Tc<Pd6, Tc0a> P6; //Arduino pin 6
//typedef Tp_Tc<Pb1, Tc1a> P9; //Arduino pin 9
//typedef Tp_Tc<Pb2, Tc1b> P10; //Arduino pin 10
//typedef Tp_Tc<Pb3, Tc2a> 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_

1
diff.txt Normal file
View file

@ -0,0 +1 @@
Comparing files usbhost.h and USBHOST.H2

223
max3421e.h Normal file
View file

@ -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_

169
usb_ch9.h Normal file
View file

@ -0,0 +1,169 @@
/* USB chapter 9 structures */
#ifndef _ch9_h_
#define _ch9_h_
#include <inttypes.h>
/* 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_

293
usbhost.h Normal file
View file

@ -0,0 +1,293 @@
/* MAX3421E-based USB Host Library header file */
#ifndef _USBHOST_H_
#define _USBHOST_H_
#include <WProgram.h>
#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_