📄 max3421e_reading_keypad.c
字号:
//
// THIS EXAMPLE CODE IS PRELIMINARY AND NOT WARRANTEED IN ANY WAY.
// IT IS TO BE USED FOR REFERENCE ONLY.
// 3-19-06 LTH
//
// Host_Talking_To_Keypad.C. Tested with Targus & Micro Innovations USB keypads.
// Targus and Micro Innovations keypads send 8 byte HID reports, with
// the data in the third byte. This program knows this in
// advance, and therefore does not need to fully enumerate the device, or
// read & parse its HID report descriptor.
//
// The code assumes a keypad is plugged in when the code runs.
//
// To make this code independent of any particular interrupt system, the code directlypolls
// and clears individual IRQ bits.
//
#include "maxq2000.h" // Rowley CrossStudio for the MAXQ
#include "maxq2000_LTH.H" // added bit masks for a few MAXQ registers
#include "MAX3421E_Host_Regs_and_Bits.h" // MAX3421E registers and bit names
#include "MAX3421E_MACROS.h" // macros to turn LEDS on and off
//
#define SS_HI PO5 |= 0x10; // MAXQ2000 SPI hardware does not have a SS (slave select)
#define SS_LO PO5 &= ~0x10; // so we use a GPO pin (P05).
// Prototypes
void Reset_MAX(WORD time); // Reset the MAX3421E. Good to do this when starting a new debug session.
void SPI_Init(void); // Initialize the MAXQ2000 SPI unit to talk to the MAX3421E
void check_LEDS(void); // Single step this to verify LED operation
void wreg(BYTE reg, BYTE dat);// Write a MAX3421E register
BYTE rreg(BYTE reg); // Read a MAX3421E register.
void readbytes(BYTE reg, BYTE N, BYTE *p); // read N bytes from MAX3421E FIFO 'reg' into p.
void writebytes(BYTE reg, BYTE N, BYTE *p); // write N bytes from p to MAX3421E fifo 'reg'.
BYTE CTL_Write_ND(void); // Launch a CONTROL-WRITE request with no data stage
void waitframes(BYTE num); // Wait num frames (SOF or KA interrupts)
// Send these 8 setup bytes for three enumeration requests to the keypad.
static BYTE Set_Address_to_25[8] = {0x00,0x05,0x19,0x00,0x00,0x00,0x00,0x00};
static BYTE Set_Config_to_1[8] = {0x00,0x09,0x01,0x00,0x00,0x00,0x00,0x00};
static BYTE Set_Idle[8] = {0x21,0x0A,0x00,0x00,0x00,0x00,0x00,0x00};
//********************
void main(void)
{
BYTE HR1,HR2,HR3,rxnum,newkey;
BYTE KB_data[8];
WORD Wdum;
//
SPI_Init(); // set up the MAXQ2000 to use its SPI port as a master
wreg(rPINCTL,(bmFDUPSPI|bmPOSINT)); // MAX3421E: INTLEVEL=0, POSINT=1 for pos edge interrupt pin
check_LEDS(); // single step this to check the 8 LEDS connected to MAX3421E GP-OUT pins
PD0 = 0xFF; // Set MAXQ2000 board port 0 to outputs (LED bar graph)
PO0 = rreg(rRevision); // Show 3421 rev number in bargraph LEDS
// Reset the MAX3421E. Done here to help debugging, so chip always initialized to a known state,
// with no carryover from the previous debug session.
//
wreg(rUSBCTL,bmCHIPRES); // chip reset This stops the oscillator
wreg(rUSBCTL,0x00); // remove the reset
while(!(rreg(rUSBIRQ) & bmOSCOKIRQ)) ; // hang until the PLL stabilizes
// Turn on Vbus
wreg(rIOPINS2,0x08); // A MAX4793 switches (and current protects) Vbus power to the peripheral.
// Set up the host
wreg(rMODE,(bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED)); // make the MAX3421E a low speed host
// Issue a USB bus reset
wreg(rHCTL,bmBUSRST); // initiate the 50 msec bus reset
while(rreg(rHCTL) & bmBUSRST); // Wait for the bus reset to complete
// Turn on the frame markers (low speed keep-alives). The MAX3421E automatically generates these.
wreg(rMODE,(bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB|bmLOWSPEED)); // start the frame markers
// Wait one frame before programming any transfers.
wreg(rHIRQ,bmFRAMEIRQ); // clear the IRQ bit
while(!(rreg(rHIRQ)&bmFRAMEIRQ)) ; // wait for the MAX3421E to generate one SOF packet (FRAMEIRQ)
// Set_Address to 25
wreg(rPERADDR,0); // Set_Address request goes to address 0
writebytes(rSUDFIFO,8,Set_Address_to_25); // Load the SUDFIFO with Set_Address=4 request
HR1 = CTL_Write_ND(); // CTL-Write transfer with no data.
// Configure the keypad (set configuration to 1)
wreg(rPERADDR,25); // keypad is now at address 25 (0x19)
writebytes (rSUDFIFO,8,Set_Config_to_1);
HR2 = CTL_Write_ND();
//
// In an endless loop, send IN tokens to EP1, once every 10 frames.
// If the keypad responds with a NAK handshake, continue to send IN tokens.
// If ACK, read the 8 keyboard data bytes in RCVFIFO and clear the RCVDAVIRQ bit.
// Then show the pressed key (0-9 only) in the lights.
//
wreg(rHCTL,bmRCVTOG0); // very first data toggle should be DATA0
while(1)
{
waitframes(10); // don't be a bus hog--ping the KB every 10 frames (10 msec)
wreg(rHIRQ,bmHXFRDNIRQ); // clear the transfer done IRQ
wreg(rHXFR,tokIN|0x01); // send an IN token to EP1
while(!(rreg(rHIRQ) & bmHXFRDNIRQ)); // wait for the completion IRQ
HR3 = rreg(rHRSL) & (BYTE)0x0F; // get the 4 HRSLT bits
if(HR3==hrNAK)
continue; // loop back and after 10 frames, send another IN
else if (HR3==hrSUCCESS)
{
rxnum = rreg(rRCVBC); // (should always be 8)
readbytes(rRCVFIFO,rxnum,KB_data); // read "rxnum" bytes from the RCVFIFO, clear RCVDAVIRQ.
newkey = KB_data[2]; // third byte has the data for this keypad
if (newkey==0x00)
{
PO0 = 0x00; // if key up, all MAXQ2000 EVKIT bargraph lights off
wreg(rIOPINS1,0); // and the LEDS connected to MAX3421E GPOUT[3:0] off
L4_OFF
}
else if (newkey >= 0x59 && newkey <= 0x62) // 89 is 1-key, 98 is 0-key
{
L4_ON
newkey -= 0x58; // now 1-10
if (newkey == 0x0A) newkey=0; // 10 is actually zero
PO0 = newkey; // show it in the LEDS
wreg(rIOPINS1,newkey); // and on the MAX3421E board
}
} // else if (HR3==hrSUCCESS)
else // any other completion code is an error. Normally we'd
// put an error checker here and take appropriate action.
{
PO0=0xFF; // all bar LEDS on
wreg(rIOPINS1,0); // all MAX3421E board lights off
while(1); // hang here and examine error code
}
} // while(1)
}
// *************** Subroutines *******************
//
// Control-Write with no data stage. Assumes PERADDR is set and the SUDFIFO contains
// the 8 setup bytes. Returns with result code = HRSLT[3:0] (HRSL register).
//
BYTE CTL_Write_ND(void)
{
BYTE resultcode;
// 1. Send the SETUP token and 8 setup bytes. Device should immediately ACK.
wreg(rHXFR,tokSETUP); // Launch the SETUP packet
while((rreg(rHIRQ)& bmHXFRDNIRQ) != bmHXFRDNIRQ) ; // Wait for completion
wreg(rHIRQ,bmHXFRDNIRQ); // clear the IRQ
resultcode = (rreg(rHRSL) & 0x0F);
if (resultcode) return (10+resultcode); // should be 0, indicating ACK
// 2. No data stage, so the last operation is to send an IN token to the peripheral
// as the STATUS (handshake) stage of this control transfer. We should get NAK or the
// DATA1 PID. When we get the DATA1 PID the 3421 automatically sends the closing ACK.
do
{
wreg(rHXFR,tokINHS); // Send IN token as a Control Transfer Handshake
while((rreg(rHIRQ)& bmHXFRDNIRQ) != bmHXFRDNIRQ) ; // Poll bit for completion
wreg(rHIRQ,bmHXFRDNIRQ); // got it--clear the IRQ
resultcode=(rreg(rHRSL)&0x0F);
}
while (resultcode == hrNAK); // Try again if a NAK
if(resultcode) return (0x20+resultcode);
else return(0);
}
void Reset_MAX(WORD time) // applies to MAX3420E or MAX3421E
{
WORD k;
wreg(rUSBCTL,0x20); // chip reset
for(k=0; k<time; k++) ;
wreg(rUSBCTL,0x00); // remove the reset
}
void SPI_Init(void)
{
// MAXQ2000 SPI port
CKCN = 0x00; // system clock divisor is 1
SS_HI // CS# high
PD5 |= 0x070; // Set SPI output pins (CS, SCLK, DOUT) as output.
PD5 &= ~0x080; // Set SPI input pin (DIN) as input.
SPICK = 0x00; // fastest SPI clock--div by 2
SPICF = 0x00; // mode(0,0), 8 bit data
SPICN |= bmMSTM; // Set SPI controller as master
SPICN |= bmSPIEN; // Enable the SPI controller
// MAX3410E INT pin is tied to MAXQ2000 P60
PD6 &= ~0x01; // PD6.0=0 (turn off output)
}
void check_LEDS(void)
{
wreg(rIOPINS1,0x01);
wreg(rIOPINS1,0x02);
wreg(rIOPINS1,0x04);
wreg(rIOPINS1,0x08);
wreg(rIOPINS2,0x01);
wreg(rIOPINS2,0x02);
wreg(rIOPINS2,0x04);
wreg(rIOPINS2,0x08);
//
wreg(rIOPINS1,0x00); // LEDS off
wreg(rIOPINS2,0x00);
}
void wreg(BYTE reg, BYTE dat)
{
SS_LO // Set CS# low
SPIB = reg+2; // send the register number with the DIR bit (b1) set to WRITE
while (SPICN & bmSTBY); // loop if data still being sent
SPIB = dat; // send the data
while (SPICN & bmSTBY); // loop if data still being sent
SS_HI // set CS# high
}
// Read a register, return its value.
BYTE rreg(BYTE reg)
{
BYTE dum;
SS_LO
SPIB = reg; // reg number w. dir=0 (IN)
while (SPICN & bmSTBY); // loop if data still being sent
dum = SPIB; // NECESSARY TO RE-ENABLE THE INPUT BUFFER in BYTE MODE
SPIB=0x00; // data is don't care, we're clocking in MISO bits
while (SPICN & bmSTBY); // loop if data still being sent
SS_HI
return(SPIB);
}
void readbytes(BYTE reg, BYTE N, BYTE *p)
{
BYTE j;
SS_LO
SPIB = reg; // write bit b1=0 to command a read operation
while (SPICN & bmSTBY); // loop if data still being sent
j = SPIB; // NECESSARY TO RE-ENABLE THE INPUT BUFFER in BYTE MODE
for(j=0; j<N; j++)
{
SPIB = 0x00; // dummy value to get the next read byte
while (SPICN & bmSTBY); // loop if data still being received
*p = SPIB; // store it in the data array
p++; // bump the pointer
}
SS_HI
wreg(rHIRQ,bmRCVDAVIRQ); // clear the data available IRQ to switch the double buffers
}
void writebytes(BYTE reg, BYTE N, BYTE *p)
{
BYTE j,wd;
SS_LO
SPIB = reg+2; // write bit b1=1 to command a write operation
while (SPICN & bmSTBY); // loop if data still being sent
for(j=0; j<N; j++)
{
wd = *p; // write the array value
SPIB = wd;
while (SPICN & bmSTBY); // loop if data still being sent
p++; // bump the pointer
}
SS_HI
}
void waitframes(BYTE num)
{
BYTE k;
wreg(rHIRQ,bmFRAMEIRQ); // clear any pending
k=0;
while(k!=num) // do this at least once
{
while(!(rreg(rHIRQ)& bmFRAMEIRQ));
wreg(rHIRQ,bmFRAMEIRQ); // clear the IRQ
k++;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -