?? dynout_m.c
字號:
#pragma NOIV // Do not generate interrupt vectors
//-----------------------------------------------------------------------------
// File: dynout_m.c
// Contents: Hooks required to implement USB peripheral function.
// Code written for EZUSB FX2 128-pin REVE...
// Firmware tested on EZUSB FX2 128-pin (CY3681 DK)
// Copyright (c) 2001 Cypress Semiconductor All rights reserved
//-----------------------------------------------------------------------------
#include "fx2.h"
#include "fx2regs.h"
#include "fx2sdly.h" // SYNCDELAY macro
extern BOOL GotSUD; // Received setup data flag
extern BOOL Sleep;
extern BOOL Rwuen;
extern BOOL Selfpwr;
BYTE Configuration; // Current configuration
BYTE AlternateSetting; // Alternate settings
// proto's from "gpif.c"
void GpifInit( void );
// ...debug LEDs: accessed via movx reads only ( through CPLD )
xdata volatile const BYTE LED0_ON _at_ 0x8000;
xdata volatile const BYTE LED0_OFF _at_ 0x8100;
xdata volatile const BYTE LED1_ON _at_ 0x9000;
xdata volatile const BYTE LED1_OFF _at_ 0x9100;
xdata volatile const BYTE LED2_ON _at_ 0xA000;
xdata volatile const BYTE LED2_OFF _at_ 0xA100;
xdata volatile const BYTE LED3_ON _at_ 0xB000;
xdata volatile const BYTE LED3_OFF _at_ 0xB100;
// it may be worth noting here that the default monitor loads at 0xC000
// use this global variable when (de)asserting debug LEDs...
BYTE ledX_rdvar = 0x00;
// 512 for high speed, 64 for full speed
static WORD enum_pkt_size = 0x0000;
// when set firmware running in TD_Poll( ); handles data transfers
BOOL td_poll_handles_transfers = 0;
// when set cpu is out of the data path
BOOL endp_auto_mode_enabled = 0;
//-----------------------------------------------------------------------------
// Task Dispatcher hooks
// The following hooks are called by the task dispatcher.
//-----------------------------------------------------------------------------
void TD_Init( void )
{ // Called once at startup
CPUCS = 0x10; // CLKSPD[1:0]=10, for 48MHz operation
// CLKOE=0, don't drive CLKOUT
GpifInit( ); // init GPIF engine via GPIFTool output file
// Registers which require a synchronization delay, see section 15.14
// FIFORESET FIFOPINPOLAR
// INPKTEND OUTPKTEND
// EPxBCH:L REVCTL
// GPIFTCB3 GPIFTCB2
// GPIFTCB1 GPIFTCB0
// EPxFIFOPFH:L EPxAUTOINLENH:L
// EPxFIFOCFG EPxGPIFFLGSEL
// PINFLAGSxx EPxFIFOIRQ
// EPxFIFOIE GPIFIRQ
// GPIFIE GPIFADRH:L
// UDMACRCH:L EPxGPIFTRIG
// GPIFTRIG
// Note: The pre-REVE EPxGPIFTCH/L register are affected, as well...
// ...these have been replaced by GPIFTC[B3:B0] registers
SYNCDELAY; // see TRM section 15.14
REVCTL = 0x02; // REVCTL.1=1; use "dynamic OUT automaticity"
// An explaination of what all happens when REVCTL.1=1
// - dynamic out automaticity
// - enabled via REVCTL.1=1 (DYN_OUT)
// - means block auto arming of OUT endp's when turning on "auto mode"
// - allows cpu intervention when switching between AUTO and MANUAL modes
// - without having to reset the fifo
// - this feature is useful for applications that edit packet data...
// - REVCTL.1=0 not recommended for applications that "touch" data...
// EP2 512 BULK OUT 4x
SYNCDELAY; // see TRM section 15.14
EP2CFG = 0xA0; // BUF[1:0]=00 for 4x buffering
// EP6 512 BULK IN 4x
SYNCDELAY; //
EP6CFG = 0xE0; // BUF[1:0]=00 for 4x buffering
// EP4 and EP8 are not used in this implementation...
SYNCDELAY; //
EP4CFG = 0x20; // clear valid bit
SYNCDELAY; //
EP8CFG = 0x60; // clear valid bit
SYNCDELAY; //
FIFORESET = 0x80; // activate NAK-ALL to avoid race conditions
SYNCDELAY; //
FIFORESET = 0x02; // reset, FIFO 2
SYNCDELAY; //
FIFORESET = 0x04; // reset, FIFO 4
SYNCDELAY; //
FIFORESET = 0x06; // reset, FIFO 6
SYNCDELAY; //
FIFORESET = 0x08; // reset, FIFO 8
SYNCDELAY; //
FIFORESET = 0x00; // deactivate NAK-ALL
// 8-bit bus (WORDWIDE=0)...
SYNCDELAY; //
EP2FIFOCFG = 0x00;
SYNCDELAY; //
EP6FIFOCFG = 0x04;
// OUT endp's come up "unarmed" in the cpu domain
// ...to "arm" the endp's when AUTOOUT=0 the cpu write's
// (1)...OUTPKTEND w/skip=1 (N times) when REVCTL.0=1 (ENH_PKT)
// ...true even when AUTOOUT=1 for REVCTL.0=1
// SYNCDELAY; //
// OUTPKTEND = 0x82; // arm first buffer
// SYNCDELAY; //
// OUTPKTEND = 0x82; // arm second buffer
// SYNCDELAY; //
// OUTPKTEND = 0x82; // arm third buffer
// SYNCDELAY; //
// OUTPKTEND = 0x82; // arm fourth buffer
// SYNCDELAY; //
// (2)...EPxBCL w/skip=1 (N times) when REVCTL.0=0 (ENH_PKT)
SYNCDELAY; //
EP2BCL = 0x80; // arm first buffer
SYNCDELAY; //
EP2BCL = 0x80; // arm second buffer
SYNCDELAY; //
EP2BCL = 0x80; // arm third buffer
SYNCDELAY; //
EP2BCL = 0x80; // arm fourth buffer
SYNCDELAY; //
// Note: had we choosen to use AUTOOUT=1 initially, then...
// (1)...when REVCTL.1=0, the core must see MANUAL-AUTO switch of AUTO bit
// ...to properly "arm" OUT buffers...
//
// SYNCDELAY;
// EP2FIFOCFG = 0x00; // AUTOOUT=0 (manual OUT mode)
// SYNCDELAY;
// EP6FIFOCFG = 0x04;
// then,
// SYNCDELAY;
// EP2FIFOCFG = 0x10; // AUTOOUT=1 (auto OUT mode)
// SYNCDELAY;
// EP6FIFOCFG = 0x04;
//
// ...this might not be obvious because the default is AUTOOUT=0
// ...power static back to back firmware downloads may be subject to
// ...the above scheme.when the application's last status was AUTOOUT=1
//
// (2)...when REVCTL.1=1, core blocks auto arming of OUT endp's
// ...see above EPxBCL/OUTPKTEND sequence(s)
// ...sequence is as follows:
// ...(a) REVCTL.1=1
// ...(b) FIFORESET (as above)
// ...(c) EPxBCL/OUTPKTEND (as above)
// ...(d) AUTOOUT=1
// IN endp's come up in the cpu/peripheral domain
// setup INT4 as internal source for GPIF interrupts
// using INT4CLR (SFR), automatically enabled
INTSETUP |= 0x03; // Enable INT4 FIFO/GPIF Autovectoring
SYNCDELAY; // used here as "delay"
EXIF &= ~0x40; // just in case one was pending...
SYNCDELAY; // used here as "delay"
GPIFIRQ = 0x02;
SYNCDELAY; //
GPIFIE = 0x02; // Enable GPIFWF interrupt
SYNCDELAY; //
EIE |= 0x04; // Enable INT4 ISR, EIE.2(EIEX4=1)
// turn debug LED[3:0] off...
ledX_rdvar = LED0_OFF;
ledX_rdvar = LED1_OFF;
ledX_rdvar = LED2_OFF;
ledX_rdvar = LED3_OFF;
}
#define GPIFTRIGWR 0
#define GPIFTRIGRD 4
#define GPIF_EP2 0
#define GPIF_EP4 1
#define GPIF_EP6 2
#define GPIF_EP8 3
void TD_Poll( void )
{ // Called repeatedly while the device is idle
static WORD xFIFOTC_OUT = 0x0000;
static WORD xFIFOTC_IN = 0x0000;
// Registers which require a synchronization delay, see section 15.14
// FIFORESET FIFOPINPOLAR
// INPKTEND OUTPKTEND
// EPxBCH:L REVCTL
// GPIFTCB3 GPIFTCB2
// GPIFTCB1 GPIFTCB0
// EPxFIFOPFH:L EPxAUTOINLENH:L
// EPxFIFOCFG EPxGPIFFLGSEL
// PINFLAGSxx EPxFIFOIRQ
// EPxFIFOIE GPIFIRQ
// GPIFIE GPIFADRH:L
// UDMACRCH:L EPxGPIFTRIG
// GPIFTRIG
// Note: The pre-REVE EPxGPIFTCH/L register are affected, as well...
// ...these have been replaced by GPIFTC[B3:B0] registers
if( td_poll_handles_transfers )
{
// Handle OUT data...
if( endp_auto_mode_enabled )
{
// AUTOOUT=1, core handles transfers
// ...cpu is not in the data path...
ledX_rdvar = LED1_ON; // visual
}
else
{
// AUTOOUT=0, cpu handles transfers
// is the host sending data...
if( !( EP2468STAT & 0x01 ) )
{
// EP2EF=0, when endp buffer "not" empty
// ...at this point the pkt. switched from the usb domain to the cpu domain
// if the host sent a pkt... then a buffer was available
// AUTOOUT=0, so pass pkt. to peripheral domain - (GPIF)
// (1)...OUTPKTEND w/skip=0 when REVCTL.0=1 (ENH_PKT)
// SYNCDELAY;
// OUTPKTEND = 0x02; // endp#; w/skip=0
//
// ...additionally, the cpu may edit the packet data:
// - skip (OUTPKTEND = 0x82;)
// - modify data (via EPxFIFOBUF[i] and packet length (via EPxBCH/L)
// (2)...EPxBCL w/skip=0 when REVCTL.0=0 (ENH_PKT)
// SYNCDELAY;
// EP2BCL = 0x00; // w/skip=0
//
// ...additionally, the cpu may:
// - skip (EP2BCL = 0x80;)
// - modify data (via EPxFIFOBUF[i])
// - however, cpu can't modify the packet length
// REVCTL.0=0... so,
SYNCDELAY;
EP2BCL = 0x00; // w/skip=0
ledX_rdvar = LED0_ON; // visual
}
else
{
// host is "not" sending data...
}
}
// is the peripheral interface idle...
if( GPIFTRIG & 0x80 )
{
// DONE=1, when GPIF is "idle"
// check if there's a pkt in the peripheral domain...
if( EP24FIFOFLGS & 0x02 )
{
// ...EF=1 when buffer "empty", no more data to xfr.
}
else
{
// EF=0, when slave fifo is "not empty"
// ...the cpu passed the pkt. to the peripheral domain
// check if peripheral "not full"...
if( GPIFREADYSTAT & 0x02 )
{
// RDY1=1, when peripheral is "not" FULL (tied to peripheral "full" flag)
xFIFOTC_OUT = ( ( EP2FIFOBCH << 8 ) + EP2FIFOBCL );
// NOTE: typ. this is where we'd check if pkt. contains data...
// ...however:
// - the core doesn't notify the cpu of zero length OUT packets
// - this applies to both AUTO or MANUAL mode...
// - typ. this is handled "out-of-band" over endp0 or endp1...
// NOTE: we're using EPxGPIFTCH/L registers here to show backwards
// ...compatibility. New implementations should use the new
// ...unified GPIFTCB3, GPIFTCB2, GPIFTCB1, GPIFTCB0 registers
// ...these registers maintain a live update which the cpu can read
// ...at anytime to determine the status of a long transfer...
// setup GPIF transaction count
SYNCDELAY;
EP2GPIFTCH = EP2FIFOBCH;
SYNCDELAY;
EP2GPIFTCL = EP2FIFOBCL;
// trigger FIFO write transaction(s), using SFR
// R/W=0, EP[1:0]=00 for EP2 write(s)
SYNCDELAY;
GPIFTRIG = GPIFTRIGWR | GPIF_EP2;
// NOTE: 512 bytes transfers in ~75usec on 8-bit async bus
// ...once master (GPIF) drains OUT pkt, it (re)arms to usb domain
// ..."this" path is always auto, meaning core handles it...
if( xFIFOTC_OUT < enum_pkt_size )
{
// handle short pkt. to peripheral
// wait for the transaction to terminate naturally...
while( !( GPIFTRIG & 0x80 ) )
{
// should take <75usec @ 8-bit async.
; // poll GPIFTRIG.7, DONE bit...
}
// TODO: signal "shortpkt" to peripheral peripheral here...
}
else
{
// was max. pkt. size...
// ...let transaction terminate naturally...
}
ledX_rdvar = LED0_OFF; // visual
ledX_rdvar = LED1_OFF; // visual
}
else
{
// RDY1=0, when peripheral is FULL
}
}
}
else
{
// DONE=0 when GPIF is "not" IDLE...
}
// Handle IN data...
// is the peripheral interface idle...
if( GPIFTRIG & 0x80 )
{
// check if peripheral "not empty"...
if( GPIFREADYSTAT & 0x01 )
{
// RDY0=1, when peripheral "not" empty...
if( EP68FIFOFLGS & 0x01 )
{
// EP6FF=1, when fifo "full"
}
else
{
// EP6FF=0, when fifo "not full", buffer available...
// NOTE: we're using EPxGPIFTCH/L registers here to show backwards
// ...compatibility. New implementations should use the new
// ...unified GPIFTCB3, GPIFTCB2, GPIFTCB1, GPIFTCB0 registers
// ...these registers maintain a live update which the cpu can read
// ...at anytime to determine the status of a long transfer...
// setup GPIF transaction count
SYNCDELAY;
EP6GPIFTCH = 0x02;
SYNCDELAY;
EP6GPIFTCL = 0x00;
// trigger FIFO read transaction(s), using SFR
// R/W=1, EP[1:0]=FIFO_EpNum for EPx read(s)
SYNCDELAY;
GPIFTRIG = GPIFTRIGRD | GPIF_EP6;
// NOTE: 512 bytes transfers in ~75usec on 8-bit async bus
// NOTE: 64 bytes transfers in ~10usec on 8-bit async bus
// wait for the transaction to terminate naturally...
SYNCDELAY; //
while( !( GPIFTRIG & 0x80 ) )
{
// should take <75usec @ 8-bit async.
; // poll GPIFTRIG.7, DONE bit...
}
if( endp_auto_mode_enabled )
{
// AUTOOUT=1, core handles transfers
// ...cpu is not in the data path...
// ...however, cpu is responsible for committing "short packets"
xFIFOTC_IN = ( ( EP6FIFOBCH << 8 ) + EP6FIFOBCL );
if( xFIFOTC_IN < enum_pkt_size )
{
// handle short pkt. from peripheral
SYNCDELAY; //
INPKTEND = 0x06; // w/skip=0;.commit however many bytes in pkt.
SYNCDELAY; //
}
else
{
// core commits packet via EPxAUTOINLENH/L registers
}
}
else
{
// AUTOIN=0, so 8051 pass pkt. to host...
SYNCDELAY; //
INPKTEND = 0x06; // w/skip=0;.commit however many bytes in pkt.
SYNCDELAY; //
// ...NOTE: this also handles "shortpkt"
}
// NOTE: the cpu can optionally:
// ...- modify data (via EPxFIFOBUF[i] and packet length (via EPxBCH/L)
// ...
// ...when REVCTL.0=1
// ...- skip current packet;
// ...INPKTEND = 0x86; // w/skip=1, skip current packet
//
}
}
else
{
// master has all the data the peripheral sent...
}
}
else
{
// peripheral interface busy...
}
}
else
{
// handle data transfers via vend_ax cmnds...
}
}
BOOL TD_Suspend( void )
{ // Called before the device goes into suspend mode
return( TRUE );
}
BOOL TD_Resume( void )
{ // Called after the device resumes
return( TRUE );
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -