本文基于前面写的SLAVE FIFO模式,然后再根据fx2lafw官方开源码进行修改,得到我们fx2lafw-8ch的逻辑分析仪源码。
硬件连接方法:FIFOADR0 拉低 FIFOADR1 拉低 SLRD 拉高关闭读 SLOE 拉高关闭读数据总线 SLWR 拉低使能写,记住此处的RDY0其实是真实的SLWR,丝印标记错误。
需要修改Fw.c中的 void SetupCommand(void) 函数
void SetupCommand(void)
{
switch(SETUPDAT[1])
{
case SC_GET_STATUS: // *** Get Status
DR_GetStatus();
break;
case SC_CLEAR_FEATURE: // *** Clear Feature
DR_ClearFeature();
break;
case SC_SET_FEATURE: // *** Set Feature
DR_SetFeature();
case SC_GET_DESCRIPTOR: // *** Get Descriptor
DR_GetDescriptor();
break;
case SC_GET_CONFIGURATION: // *** Get Configuration
DR_GetConfiguration();
break;
case SC_SET_CONFIGURATION: // *** Set Configuration
DR_SetConfiguration();
break;
case SC_GET_INTERFACE: // *** Get Interface
DR_GetInterface();
break;
case SC_SET_INTERFACE: // *** Set Interface
DR_SetInterface();
break;
default: // *** Verdor Command
DR_VendorCmnd();
}
EP0CS |= bmHSNAK;
}
外设文件periph.c,需要修改以下函数
BOOL DR_GetDescriptor(void);
BOOL DR_SetConfiguration(void);
BOOL DR_GetConfiguration(void);
BOOL DR_SetInterface(void);
BOOL DR_GetInterface(void);
BOOL DR_GetStatus(void);
BOOL DR_ClearFeature(void);
BOOL DR_SetFeature(void);
BOOL DR_VendorCmnd(void);
void TD_Poll(void) // Called repeatedly while the device is idle
{
if(G_u32_Cnt < 60000)
{
G_u32_Cnt ++;
}
else
{
G_u32_Cnt = 0;
if(EP2468STAT & bmEP6EMPTY) /* 如果 INEP2FIFO 为空 PA1-LED就翻转 */
{
PA1 = ~PA1;
}
if(!(EP2468STAT & bmEP2FULL)) /* 如果 INEP6FIFO 不满 PA0-LED就翻转 */
{
PA0 = ~PA0;
}
}
}
void DSLogic_Init(void)
{
//设置8051的工作频率为48MHz
CPUCS = 0x12; // CLKSPD[1:0]=10, for 48MHz operation, output CLKOUT
SYNCDELAY;
//Slave使用内部48MHz的时钟
IFCONFIG = 0xE3; //对从设备 FIFO 接口进行配置,使之使用 48 MHz 的内部时钟
SYNCDELAY;
/***************************************************
配置变址寻址方式
PINFLAGSAB = 0x00
PINFLAGSCD = 0x00
报告当前FIFO数据端口(由FIFOADR[I:0]引脚选择)的的状态
FLAGA报告"可编程级"状态
FLAGB报告"满"状态为 0 非满为1 FLAGB 报告“已满”状态
FLAGC报告"空"状态为 0 非空为1 FLAGC 报告“空”状态
外部主服务器通常监视
OUT 端点的“空”标志 (EF)
IN 端点的完整 (FF) 标志
***************************************************/
#if 0
PINFLAGSAB = 0x00;
SYNCDELAY;
PINFLAGSCD = 0x00;
SYNCDELAY;
#else
PINFLAGSAB = 0xE0; /* FLAGB 被配置为 EP6 OUT FIFO 的空标志 EP2EF 非空为1 PC发送数据到CY7C68013->FPGA(MCU) Check 此标志为1则按照时序进行读取 */
SYNCDELAY;
PINFLAGSCD = 0x08; /* FLAGC 被配置为 EP2 IN FIFO 的满标志 EP6FF 非满为1 PC从CY7C68013读取数据<-FPGA(MCU) Check 此标志为1则按照时序进行写入 */
SYNCDELAY;
#endif
FIFOPINPOLAR = 0x00; //Slave FIFO标志位低电平有效
PORTACFG |= 0x80; // FLAGD, set alt. func. of PA7 pin
/*********************************************************************************
从属FIFO控制引脚为
SLOE(输出使能)
SLRD(读)
SLWR(写)
PKTEND(包结束)
"读"和"写"来自外部主控制器的外引线;外部主控制器从OUT端点读,向IN端点写。
读:
在同步方式下(IFCONFIG.3=0),当FIFO指针在SLRD有效时,IFCLK的每一个上升沿累加。
在异步方式下(IFCoNFIG.3=1),FIFO指针在每次SLRD激活到撤销激活变化时累加。
SLOE引脚提供FD输出使能信号。默认情况下,SLOE和SLRD低电平有效。
写:
在同步方式下(IFCONFIG.3=O),当SLWR被激活时,FD总线上的数据在每个时钟信号IFCLK上升沿来到时被写入FIFO(并且FIFO指针被加1)。
在异步方式下(IFCONFIG.3=1),FD总路线上的数据在每次SLWR激活到撤销激活变化时被写入FIFO(并且FIFO指针被加1)。
默认情况下,SLWR低电平有效。
如果FIFO被设置为允许零长度包(EPXFIFOCFG.2=1),则可激活PKTEND脚,当FIFO为空时,提交零长度包。
PKTEND默认为低电平有效
*********************************************************************************/
SYNCDELAY;
EP6CFG = 0xA0; // OUT, 512-bytes, 4x, bulk
SYNCDELAY;
EP2CFG = 0xE0; // IN, 512-bytes, 4x, bulk
SYNCDELAY;
EP4CFG = 0x02; //禁止EP4
SYNCDELAY;
EP8CFG = 0x02; //禁止EP8
SYNCDELAY;
//复位FIFO
FIFORESET = 0x80; // activate NAK-ALL to avoid race conditions
SYNCDELAY; // see TRM section 15.14
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
SYNCDELAY;
// 分别将端点 2 FIFO 和端点 6 配置为自动输出模式和自动输入模式 同时使用8位接口
EP6FIFOCFG = 0x00; // AUTOOUT=0, WORDWIDE=0
// core needs to see AUTOOUT=0 to AUTOOUT=1 switch to arm endp's
SYNCDELAY; //
EP6FIFOCFG = 0x10; // AUTOOUT=1, WORDWIDE=0
SYNCDELAY; //
EP2FIFOCFG = 0x0C; // AUTOIN=1, ZEROLENIN=1, WORDWIDE=0
SYNCDELAY;
OEA|=0x03; //Declare PA.1 PA.0 as output
SYNCDELAY;
IOA|=0x01; //output 0 on PA.1 1 on PA.0
SYNCDELAY;
}
void DSLogic_Poll(void)
{
struct cmd_start *cmd;
switch(vendor_command)
{
case CMD_START:
{
if ((EP0CS & bmEPBUSY) != 0)
break;
if (EP0BCL == sizeof(struct cmd_start))
{
cmd = (struct cmd_start *)EP0BUF;
if (cmd->flags & CMD_START_FLAGS_SAMPLE_16BIT)
EP2FIFOCFG = bmAUTOIN | bmWORDWIDE;
else
EP2FIFOCFG = bmAUTOIN;
SYNCDELAY;
/* Set IFCONFIG to the correct clock source. */
if (cmd->flags & CMD_START_FLAGS_CLK_48MHZ)
{
IFCONFIG = bmIFCLKSRC | bm3048MHZ | bmIFCLKOE | bmBIT1 | bmBIT0;
}
else
{
IFCONFIG = bmIFCLKSRC | bmIFCLKOE | bmBIT1 | bmBIT0;
}
}
vendor_command = 0;
break;
}
default:
vendor_command = 0;
break;
}
TD_Poll();
}
//-----------------------------------------------------------------------------
// Device Request hooks
// The following hooks are called by the end point 0 device request parser.
//-----------------------------------------------------------------------------
BOOL DR_GetDescriptor(void)
{
void *dscr_ptr;
switch(SETUPDAT[3])
{
case GD_DEVICE: // Device
SUDPTRH = MSB(pDeviceDscr);
SUDPTRL = LSB(pDeviceDscr);
break;
case GD_CONFIGURATION: // Configuration
SUDPTRH = MSB(pConfigDscr);
SUDPTRL = LSB(pConfigDscr);
break;
case GD_STRING: // String
if(dscr_ptr = (void *)EZUSB_GetStringDscr(SETUPDAT[2]))
{
SUDPTRH = MSB(dscr_ptr);
SUDPTRL = LSB(dscr_ptr);
}
else
EZUSB_STALL_EP0(); // Stall End Point 0
break;
case GD_DEVICE_QUALIFIER: // Device Qualifier
SUDPTRH = MSB(pDeviceQualDscr);
SUDPTRL = LSB(pDeviceQualDscr);
break;
case GD_OTHER_SPEED_CONFIGURATION: // Other Speed Configuration
SUDPTRH = MSB(pOtherConfigDscr);
SUDPTRL = LSB(pOtherConfigDscr);
break;
default: // Invalid request
EZUSB_STALL_EP0(); // Stall End Point 0
}
return(TRUE);
}
BOOL DR_SetConfiguration(void) // Called when a Set Configuration command is received
{
Configuration = SETUPDAT[2];
return(TRUE); // Handled by user code
}
BOOL DR_GetConfiguration(void) // Called when a Get Configuration command is received
{
EP0BUF[0] = Configuration;
EP0BCH = 0;
EP0BCL = 1;
return(TRUE); // Handled by user code
}
BOOL DR_SetInterface(void) // Called when a Set Interface command is received
{
AlternateSetting = SETUPDAT[2];
return(TRUE); // Handled by user code
}
BOOL DR_GetInterface(void) // Called when a Set Interface command is received
{
EP0BUF[0] = AlternateSetting;
EP0BCH = 0;
EP0BCL = 1;
return(TRUE); // Handled by user code
}
BOOL DR_GetStatus(void)
{
switch(SETUPDAT[0])
{
case GS_INTERFACE: // Interface
EP0BUF[0] = 0;
EP0BUF[1] = 0;
EP0BCH = 0;
EP0BCL = 2;
break;
case GS_DEVICE: // Device
EP0BUF[0] = ((BYTE)Rwuen << 1) | (BYTE)Selfpwr;
EP0BUF[1] = 0;
EP0BCH = 0;
EP0BCL = 2;
break;
case GS_ENDPOINT: // End Point
EP0BUF[0] = *(BYTE xdata *) epcs(SETUPDAT[4]) & bmEPSTALL;
EP0BUF[1] = 0;
EP0BCH = 0;
EP0BCL = 2;
break;
default: // Invalid Command
EZUSB_STALL_EP0(); // Stall End Point 0
}
return(TRUE);
}
BOOL DR_ClearFeature(void)
{
switch(SETUPDAT[0])
{
case FT_DEVICE: // Device
if(SETUPDAT[2] == 1)
Rwuen = FALSE; // Disable Remote Wakeup
else
EZUSB_STALL_EP0(); // Stall End Point 0
break;
case FT_ENDPOINT: // End Point
if(SETUPDAT[2] == 0)
{
*(BYTE xdata *) epcs(SETUPDAT[4]) &= ~bmEPSTALL;
EZUSB_RESET_DATA_TOGGLE( SETUPDAT[4] );
}
else
EZUSB_STALL_EP0(); // Stall End Point 0
break;
default:
return DR_VendorCmnd();
}
return(TRUE);
}
BOOL DR_SetFeature(void)
{
switch(SETUPDAT[0])
{
case FT_DEVICE: // Device
if(SETUPDAT[2] == 1)
Rwuen = TRUE; // Enable Remote Wakeup
else if(SETUPDAT[2] == 2)
break;
else
EZUSB_STALL_EP0(); // Stall End Point 0
break;
case FT_ENDPOINT: // End Point
*(BYTE xdata *) epcs(SETUPDAT[4]) |= bmEPSTALL;
break;
default:
return DR_VendorCmnd();
}
return(TRUE);
}
BOOL DR_VendorCmnd(void)
{
switch (SETUPDAT[1])
{
case CMD_GET_FW_VERSION:
{
EP0BUF[0] = FX2LAFW_VERSION_MAJOR;
EP0BUF[1] = FX2LAFW_VERSION_MINOR;
EP0BCH = 0;
EP0BCL = 2;
return TRUE;
break;
}
case CMD_GET_REVID_VERSION:
{
EP0BUF[0] = REVID;
EP0BCH = 0;
EP0BCL = 1;
return TRUE;
break;
}
case CMD_START:
{
vendor_command = SETUPDAT[1];
EP0BCL = 0;
SYNCDELAY;
return TRUE;
break;
}
default:
EZUSB_STALL_EP0(); // Stall End Point 0
return FALSE;
break;
}
}
//-----------------------------------------------------------------------------
// USB Interrupt Handlers
// The following functions are called by the USB interrupt jump table.
//-----------------------------------------------------------------------------
// Setup Data Available Interrupt Handler
void ISR_Sudav(void) interrupt 0
{
GotSUD = TRUE; // Set flag
EZUSB_IRQ_CLEAR();
USBIRQ = bmSUDAV; // Clear SUDAV IRQ
}
// Setup Token Interrupt Handler
void ISR_Sutok(void) interrupt 0
{
EZUSB_IRQ_CLEAR();
USBIRQ = bmSUTOK; // Clear SUTOK IRQ
}
void ISR_Sof(void) interrupt 0
{
EZUSB_IRQ_CLEAR();
USBIRQ = bmSOF; // Clear SOF IRQ
}
void ISR_Ures(void) interrupt 0
{
// whenever we get a USB reset, we should revert to full speed mode
pConfigDscr = pFullSpeedConfigDscr;
((CONFIGDSCR xdata *) pConfigDscr)->type = CONFIG_DSCR;
pOtherConfigDscr = pHighSpeedConfigDscr;
((CONFIGDSCR xdata *) pOtherConfigDscr)->type = OTHERSPEED_DSCR;
EZUSB_IRQ_CLEAR();
USBIRQ = bmURES; // Clear URES IRQ
}
void ISR_Susp(void) interrupt 0
{
EZUSB_IRQ_CLEAR();
USBIRQ = bmSUSP;
}
void ISR_Highspeed(void) interrupt 0
{
if (EZUSB_HIGHSPEED())
{
pConfigDscr = pHighSpeedConfigDscr;
((CONFIGDSCR xdata *) pConfigDscr)->type = CONFIG_DSCR;
pOtherConfigDscr = pFullSpeedConfigDscr;
((CONFIGDSCR xdata *) pOtherConfigDscr)->type = OTHERSPEED_DSCR;
}
EZUSB_IRQ_CLEAR();
USBIRQ = bmHSGRANT;
}
按照上述方法修改完成后再修改dscr.a51文件既可以完成fx2lafw_8CH_Firmware固件的修改。
测试如下:选择fx2lafw设备
板载小灯单灯闪烁,PA1引脚
选择48M采集,采集数据长度为1G:实际采集波形如下,由于实际硬件未连接任何接口所以都是高电平。
将PB引脚进行试触采集:
这里需要注意的是下载完源码后,接在电脑上会出现识别带叹号的问题,需要使用zadig-2.8.exe将驱动修改替换为通用usb总线既即可如下图
驱动替换完成后显示如下
其实也可以改成16通道的采集模式,只需要修改描述文件的VID PID,还有初始化部分的自动FIFO模式中的数据宽度。但是改成16通道后采集速率不知道为啥只能使用12M及以下的采集速率。高了提示错误。
源码链接: