mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
first commit
This commit is contained in:
commit
e238472454
8 changed files with 1633 additions and 0 deletions
5
README
Normal file
5
README
Normal 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
385
Usb.cpp
Normal 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
181
Usb.h
Normal 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
376
avrpins.h
Normal 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
1
diff.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Comparing files usbhost.h and USBHOST.H2
|
223
max3421e.h
Normal file
223
max3421e.h
Normal 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
169
usb_ch9.h
Normal 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
293
usbhost.h
Normal 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_
|
Loading…
Reference in a new issue