📄 enumappnote_bf1.c
字号:
//---------------------------------------------------------------------------
// 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 + -