⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 enumappnote_bf1.c

📁 BR1 source code
💻 C
📖 第 1 页 / 共 2 页
字号:
//---------------------------------------------------------------------------
// Copyright (C) 2005 Maxim Integrated Products, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL MAXIM INTEGRATED PRODUCTS INC. BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//---------------------------------------------------------------------------
// EnumAppNote_BF1.C	2-9-06. Changes the include file "MAX3420E.h" to "MAX3420#-BF1.h".
//			To incorporate a bug fix that did not correctly issue a USB stall handshake
//
// This code demonstrates enumeration using the MAXIM MAX3420E USB Peripheral Controller.
// The code handles all host enumeration requests, as well as suspend/resume. The USB device
// implemented with this code reports itself as capable of signaling remote wakeup (RWU), and
// the code supports this operation by checking a RWU pushbutton while the bus is suspended.
//
//  The code requires pushbuttons on GPIN0 and GPIN2. Connect the other side of the pushbutton to GND 
//    (No pullups necessary--they're inside the MAX3420E.)
//  The code supports 4 LEDS connected to the GPOUT pins. These are programmed as 
//    active high, so the LED anodes go to the GPOUT pin and the cathodes go to GND.
//    Use series resistors of about 150 Ohms for VL=3.3V.
//            Pushbuttons                 LED's
//    GPIN0   Send Keystrokes   GPOUT0    Sending Keystrokes
//    GPIN1   ---               GPOUT1    Bus Reset
//    GPIN2   Remote Wakeup     GPOUT2    SUSPEND
//    GPIN3   ---               GPOUT3    Program Loop Active
//
//  The code runs fine without the LEDS or pushbutton (it enumerates)
//  but it requires the pushbuttons to function as a USB device and to signal remote wakeup.
//
//  After enumerating as a USB HID class device, the code implements a one-button keyboard
//  using the button attached to GPIN0. When this button is pressed the program types the 
//  character string defined in "EnumApp_enum_data.h". 
//
//  Because the I/O is implemented using MAX3420E IO pins, I/O code is portable across processors.
//
//  The code enables certain interrupts and the MAX3420E INT pin, but it does not assume any particular
//  uC or compiler for implementing vectored interrupts. It accomplishes this by polling the INT pin for
//  an active low level instead of having the INT pin trigger a particular uC hardware interrupt. This
//  makes the code as generic as possible since it does not assume any particular uC interrupt system
//  or compiler interrupt handler syntax.
//
#include "MAX3420E_BF1.h"       // MAX3420E registers (rREGNAME), bits (bmBITNAME), and some handy macros
#include "EnumApp_enum_data.h"  // HID keyboard enumeration data

typedef unsigned char BYTE;     // these save typing
typedef unsigned short WORD;

// function prototypes
void SPI_Init(void);            // Configure MAXQ2000 and MAX3420E IO pins for SPI
void Reset_MAX(void);           // Reset the MAX3420E
void wreg(BYTE r,BYTE v);       // Write a MAX3420E register byte
void wregAS(BYTE r,BYTE v);     // Same as 'wreg' but also set the ACKSTAT bit in the SPI command byte
BYTE rreg(BYTE r);              // Read a MAX3420E register byte
BYTE rregAS(BYTE r);            // Same as 'rreg' but also set the ACKSTAT bit
void readbytes(BYTE reg, BYTE N, BYTE *p);  // Read N MAX3420E FIFO bytes into the array p
void writebytes(BYTE reg, BYTE N, BYTE *p); // Write N MAX3420E FIFO bytes into the array p
BYTE MAX_Int_Pending(void);     // Poll the MAX3420E INT pin (set for active low level)

// USB functions
void std_request(void);
void class_request(void);
void vendor_request(void);
void send_descriptor(void);
void send_keystroke(BYTE);
void feature(BYTE);
void get_status(void);
void set_interface(void);
void get_interface(void);
void set_configuration(void);
void get_configuration(void);

// Application code
void do_SETUP(void);      // Handle a USB SETUP transfer
void do_IN3(void);        // Send keyboard characters over Endpoint 3-IN
void check_for_resume(void);
void service_irqs(void);
void initialize_MAX(void);

//Global variables
BYTE SUD[8];		// Local copy of the 8 setup data read from the MAX3420E SUDFIFO
BYTE msgidx,msglen;	// Text string in EnumApp_enum_data.h--index and length
BYTE configval;		// Set/Get_Configuration value
BYTE ep3stall;		// Flag for EP3 Stall, set by Set_Feature, reported back in Get_Status
BYTE interfacenum;      // Set/Get interface value
BYTE inhibit_send;	// Flag for the keyboard character send routine
BYTE RWU_enabled;       // Set by Set/Clear_Feature RWU request, sent back for Get_Status-RWU
BYTE Suspended;         // Tells the main loop to look for host resume and RWU pushbutton
WORD msec_timer;        // Count off time in the main loop
WORD blinktimer;        // Count milliseconds to blink the "loop active" light
BYTE send3zeros;        // EP3-IN function uses this to send HID (key up) codes between keystrokes
//
#define ENABLE_IRQS wreg(rEPIEN,(bmSUDAVIE+bmIN3BAVIE)); wreg(rUSBIEN,(bmURESIE+bmURESDNIE));
// Note: the SUSPEND IRQ will be enabled later, when the device is configured.
// This prevents repeated SUSPEND IRQ's

void initialize_MAX(void)
{
ep3stall=0;			// EP3 inintially un-halted (no stall) (CH9 testing)
msgidx = 0;			// start of KB Message[]
msglen = sizeof(Message);     // so we can check for the end of the message
inhibit_send = 0x01;		// 0 means send, 1 means inhibit sending
send3zeros=1;
msec_timer=0;
blinktimer=0;
// software flags
configval=0;                    // at pwr on OR bus reset we're unconfigured
Suspended=0;
RWU_enabled=0;                  // Set by host Set_Feature(enable RWU) request
//
SPI_Init();                     // set up MAXQ2000 to use its SPI port as a master
//
// Always set the FDUPSPI bit in the PINCTL register FIRST if you are using the SPI port in 
// full duplex mode. This configures the port properly for subsequent SPI accesses.
//
wreg(rPINCTL,(bmFDUPSPI+bmINTLEVEL+gpxSOF)); // MAX3420: SPI=full-duplex, INT=neg level, GPX=SOF
Reset_MAX();
wreg(rGPIO,0x00);                   // lites off (Active HIGH)
// This is a self-powered design, so the host could turn off Vbus while we are powered.
// Therefore set the VBGATE bit to have the MAX3420E automatically disconnect the D+
// pullup resistor in the absense of Vbus. Note: the VBCOMP pin must be connected to Vbus
// or pulled high for this code to work--a low on VBCOMP will prevent USB connection.
wreg(rUSBCTL,(bmCONNECT+bmVBGATE)); // VBGATE=1 disconnects D+ pullup if host turns off VBUS
ENABLE_IRQS
wreg(rCPUCTL,bmIE);                 // Enable the INT pin
}

#define TWENTY_MSEC 14200           // adjust this constant for 20 msec button checks
#define BLINKTIME 25                // blink every 500 msec

// ************************************************************************************
// This endless loop checks for two high priority events (every time through the loop):
// 1. USB suspend ("Suspended" flag = 1). If suspended, checks for resume signaling.
// 2. A MAX3420E pending interrupt. 
//
// Every 20 msec, it reads the "SEND" pushbutton. Every half second, it blinks
// the "Loop Active" light.
//
// *********************************** MAIN *******************************************
void main(void)
{
initialize_MAX();
while(1)		// endless loop
  {
  if(Suspended)
    check_for_resume();
  if (MAX_Int_Pending())
    service_irqs();
  msec_timer++;
  if(msec_timer==TWENTY_MSEC)
    {
    msec_timer=0;
    if((rreg(rGPIO) & 0x10) == 0) // Check the pushbutton on GPI-0
        {
        inhibit_send = 0x00;      // Tell the "do_IN3" function to send the text string
        L0_ON                     // Turn on the SEND light
        }
    blinktimer++;                 // blink the loop active light every half second
    if(blinktimer==BLINKTIME)
        {
        blinktimer=0;
        L3_BLINK
        }
    }// msec_timer==ONE_MSEC
  } // while(1)
}// main
      
void check_for_resume(void)         
{
  if(rreg(rUSBIRQ) & bmBUSACTIRQ)     // THE HOST RESUMED BUS TRAFFIC
      {
      L2_OFF
      Suspended=0;                    // no longer suspended
      }
  else if(RWU_enabled)                // Only if the host enabled RWU
      {
      if((rreg(rGPIO)&0x40)==0)       // See if the Remote Wakeup button was pressed
        {
        L2_OFF                        // turn off suspend light
        Suspended=0;                  // no longer suspended
        SETBIT(rUSBCTL,bmSIGRWU)      // signal RWU
        while ((rreg(rUSBIRQ)&bmRWUDNIRQ)==0) ;	// spin until RWU signaling done
        CLRBIT(rUSBCTL,bmSIGRWU)      // remove the RESUME signal 
        wreg(rUSBIRQ,bmRWUDNIRQ);     // clear the IRQ
        while((rreg(rGPIO)&0x40)==0) ;  // hang until RWU button released
        wreg(rUSBIRQ,bmBUSACTIRQ);    // wait for bus traffic -- clear the BUS Active IRQ
        while((rreg(rUSBIRQ) & bmBUSACTIRQ)==0) ; // & hang here until it's set again...
        }
      }
} 
//

void service_irqs(void)
{
BYTE itest1,itest2;
itest1 = rreg(rEPIRQ);            // Check the EPIRQ bits
itest2 = rreg(rUSBIRQ);           // Check the USBIRQ bits
if(itest1 & bmSUDAVIRQ) 
    {
     wreg(rEPIRQ,bmSUDAVIRQ);     // clear the SUDAV IRQ
     do_SETUP();
    }
if(itest1 & bmIN3BAVIRQ)          // Was an EP3-IN packet just dispatched to the host?
    {
    do_IN3();                     // Yes--load another keystroke and arm the endpoint
    }                             // NOTE: don't clear the IN3BAVIRQ bit here--loading the EP3-IN byte
                                  // count register in the do_IN3() function does it.
if((configval != 0) && (itest2&bmSUSPIRQ))   // HOST suspended bus for 3 msec
    {
    wreg(rUSBIRQ,(bmSUSPIRQ+bmBUSACTIRQ));  // clear the IRQ and bus activity IRQ
    L2_ON                         // turn on the SUSPEND light
    L3_OFF                        // turn off blinking light (in case it's on)
    Suspended=1;                  // signal the main loop
    }
if(rreg(rUSBIRQ)& bmURESIRQ)
    {
    L1_ON                         // turn the BUS RESET light on 
    L2_OFF                        // Suspend light off (if on)
    wreg(rUSBIRQ,bmURESIRQ);      // clear the IRQ
    }
if(rreg(rUSBIRQ) & bmURESDNIRQ)
    {
    L1_OFF                        // turn the BUS RESET light off
    wreg(rUSBIRQ,bmURESDNIRQ);    // clear the IRQ bit
    Suspended=0;                  // in case we were suspended
    ENABLE_IRQS                   // ...because a bus reset clears the IE bits
    }
} 

void do_SETUP(void)
{							
readbytes(rSUDFIFO,8,SUD);          // got a SETUP packet. Read 8 SETUP bytes
switch(SUD[bmRequestType]&0x60)     // Parse the SETUP packet. For request type, look only at b6&b5
    {
    case 0x00:	std_request();		break;
    case 0x20:	class_request();	break;  // just a stub in this program
    case 0x40:	vendor_request();	break;  // just a stub in this program
    default:	STALL_EP0                       // unrecognized request type
    }
}

void do_IN3(void)
{
if (inhibit_send==0x01)
        {
	wreg(rEP3INFIFO,0);			// send the "keys up" code
	wreg(rEP3INFIFO,0);
	wreg(rEP3INFIFO,0);
	}
else
  if (send3zeros==0x01)                         // precede every keycode with the "no keys" code
        {
	wreg(rEP3INFIFO,0);			// send the "keys up" code
	wreg(rEP3INFIFO,0);
	wreg(rEP3INFIFO,0);
        send3zeros=0;                           // next time through this function send the keycode
	}
  else
	{
        send3zeros=1;
        wreg(rEP3INFIFO,Message[msgidx++]);	// load the next keystroke (3 bytes)
	wreg(rEP3INFIFO,Message[msgidx++]);
	wreg(rEP3INFIFO,Message[msgidx++]);
	if(msgidx >= msglen)                    // check for message wrap
            {
            msgidx=0;
            L0_OFF
            inhibit_send=1;                     // send the string once per pushbutton press
            }
	}
wreg(rEP3INBC,3);				// arm it
}

//*******************
void std_request(void)
{
switch(SUD[bRequest])			
	{
	case	SR_GET_DESCRIPTOR:	send_descriptor();    break;
	case	SR_SET_FEATURE:		feature(1);           break;
	case	SR_CLEAR_FEATURE:	feature(0);           break;
	case	SR_GET_STATUS:		get_status();         break;
	case	SR_SET_INTERFACE:	set_interface();      break;
	case	SR_GET_INTERFACE:	get_interface();      break;
	case	SR_GET_CONFIGURATION:   get_configuration();  break;
	case	SR_SET_CONFIGURATION:   set_configuration();  break;
	case	SR_SET_ADDRESS:         rregAS(rFNADDR);      break;  // discard return value
	default:  STALL_EP0
	}
}

//**************************
void set_configuration(void)
{
configval=SUD[wValueL];           // Store the config value
if(configval != 0)                // If we are configured, 
  SETBIT(rUSBIEN,bmSUSPIE);       // start looking for SUSPEND interrupts
rregAS(rFNADDR);                  // dummy read to set the ACKSTAT bit
}

void get_configuration(void)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -