USB检测工具V1.5——下环路测试模块设计

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/snaking616/article/details/88579423

目录

1. 模块界面与功能介绍

1.1 测试环境

1.2 界面控件介绍

1.3 模块功能介绍

2. 模块代码设计

2.1 程序流程图设计

2.2 核心代码

2.3 控件函数小结

3. 下环路速度测试

3.1 勾选“显示传输状态”复选框

3.2 不勾选“显示传输状态”复选框

3.3 数据分析

4. 上位机工程文件

5. 参考


1. 模块界面与功能介绍

1.1 测试环境

        图1为上位机的硬件测试环境,USB芯片CY7C68013A被设置为SlaveFIFO工作模式,分别使用EP6和EP2作为上位机的输入和输出端点,端点的大小为512byte,端点缓存大小为2Kbyte。EP6带有一个满标志位,EP2带有一个空标志位,FPGA通过判断端点的状态标志位来控制数据的读和写。

        下环路测试中,FPGA为主端,上位机为从端,FPGA首先向USB写数据并判断EP6是否写满,写满后就停止写操作并切换至读操作,当EP2被读空时,就进行下一个写操作。上位机端不断的从EP6接收数据,当接收数据的数量达到指定值时,将指定数量的数据输出至EP2中。

图1 下环路测试的硬件框图

本次功能验证的软硬件环境为:

项目

说明

电脑系统

Win7 64位旗舰版

上位机开发软件

Visual Studio 2008

USB固件开发软件

keil uVision2

FPGA编程软件

Quartus II

USB开发板

易津USB开发板(USB型号CY7C68013A

FPGA下载工具

USB Blaster 下载器

1.2 界面控件介绍

        如图2所示,下环路测试模块包括的控件资源有:4个按钮、3个静态文本框、1个复选框、1个下拉选择框和2个编辑框(可读不可写)。下拉框包含8个可选项:0.5K、1K、2K、3K、4K、5K、8K和10K,默认选择第7项8K。复选框“显示传输状态”默认不勾选,勾选时会影响速度测试结果,当需要查看被成功或失败传输的数据大小时才勾选。

图2 下环路测试界面布局

1.3 模块功能介绍

        模块主要包括3个功能:单次数据的接收与发送、下环路速度测试和下环路循环收发测试。

(1)单次数据的接收与发送

        图3为单次数据的收发测试的功能验证,在接收单次数据环节,上位机接收指定数量的数据并将其前512字节进行显示,接着统计本次接收耗时,最后提示可以进行发生数据测试。在发送已接收数据环节,上位机仅显示发送完指定大小数据消耗的时间。单次数据的接收与发送模块用于FPGA代码的调试,通过对比FPGA指定发送的数据和上位机接收到的数据就可以判断FPGA的发送时序逻辑是否有误。

图3. 单次数据收发测试

(2)下环路速度测试

        在进行速度测试时,单向传输的数据量为20MB,上位机先接收20MB数据再发送给FPGA,同一时刻数据仅进行单向传输。图4为下环路速度测试的功能验证,显示框记录了最近两次速度测试的结果,第一次测试单次接收数据量为8KB,一共接收了2560次,接收与发送共耗时1.37s,平均传输速度达29.29MB/s。第二次测试单次接收数据量为10KB,一共接收了2048次,接收与发送共耗时1.39s,平均传输速度达28.83MB/s。

图4 下环路速度测试

(3)下环路循环收发测试

        下环路循环测试与速度测试模块共用同一个线程函数,不同点在于循环测试环节,代码屏蔽掉了速度统计和数据显示功能,此时的上位机会循环的接收指定大小数据并发送给FPGA。

图5 下环路循环收发测试

2. 模块代码设计

2.1 程序流程图设计

(1)单次数据的接收与发送模块

图6 单次数据收发程序流程图

(2)下环路速度测试与循环收发模块

        下环路速度测试与循环收发模块的程序流程图如图7所示,两个模块共用同一个进程函数UINT XferLoop_FPGA( LPVOID params ) ,pXfer_IN_FPGA为线程指针,loop_FPGA_key为测速开关变量,为真的时候才进行速度测试,bLooping_FPGA为收发函数的循环变量,为真是进行循环收发数据,为假时停止数据收发。

        在进行速度测试时,测速开关变量loop_FPGA_key为true,当接次数R_S_num达到LOOP_FPGA_xfer_num时,停止速度测试,统计接收并发送20M数据所需的时间和平均速度信息。LOOP_FPGA_xfer_num为上位机接收20MB数据需要的接收次数,它的计算公式为:

LOOP_FPGA_xfer_num=20*1024*1024/LOOP_FPGA_Xfer_size,

其中,LOOP_FPGA_Xfer_size为上位机单次接收数据的长度)。

数据的平均速度计算公式为:

rate=(double)2*((LOOP_FPGA_Xfer_num*LOOP_FPGA_Xfer_size)/1024/1024)/t。

在循环收发测试中,测速开关变量loop_FPGA_key为false,只要循环变量bLooping_FPGA不为false,上位机就不停的收发数据。

图7 下环路速度测试与循环收发模块程序流程图

2.2 核心代码

(1)单次数据的接收与发送模块

UINT Xfer_OUT_FPGA( LPVOID params ) 
{
	OVERLAPPED outOvLap; 
    CUSBprojDlg *pDlg = (CUSBprojDlg *) params;
	CString str;	
	LONG xfer=pDlg->LOOP_FPGA_Xfer_size;
    outOvLap.hEvent  = CreateEvent(NULL, false, false, _T("CYUSB_OUT"));    	
	bool success_out;
    pDlg->pOutEndpt->TimeOut = 2000;
	
	LARGE_INTEGER BegainTime;               //记录测速开始之前时钟计数数值
	LARGE_INTEGER EndTime;					//记录测速结束之后时钟计数数值
	LARGE_INTEGER Frequency;				//记录1s内系统时钟计数次数
                                            //测速耗时t=(EndTime-BegainTime)/Frequency
	QueryPerformanceFrequency(&Frequency); //获取1s内系统时钟计数次数
	QueryPerformanceCounter(&BegainTime);//获取当前系统时钟计数的数值

	UCHAR  *outContext = pDlg->pOutEndpt->BeginDataXfer(pDlg->R_512B,xfer,&outOvLap);
	if(!pDlg->pOutEndpt->WaitForXfer(&outOvLap,2000))
	{
		pDlg->pOutEndpt->Abort();
		WaitForSingleObject(outOvLap.hEvent, 2000);
	}
	success_out = pDlg->pOutEndpt->FinishDataXfer(pDlg->R_512B,xfer, &outOvLap,outContext);

	QueryPerformanceCounter(&EndTime);//16组数据传输完后,记录系统时钟计数的数值
	double t=(double)( EndTime.QuadPart - BegainTime.QuadPart )/Frequency.QuadPart;
	t=t*1000000;
    	
    CloseHandle(outOvLap.hEvent); 
	//str.Format(_T("状态提示:%d 字节数据已发送\r\n"),xfer);
	//pDlg->data_display += str;
	str.Format(_T("本次发送%d字节数据耗时:%.2f uS\r\n"),xfer,t);
	pDlg->data_display +=str;
	pDlg->m_data_receive_display.SetWindowTextW(pDlg->data_display);
	
	pDlg->pXfer_OUT_FPGA = NULL;   	
	return true;
}
UINT Xfer_IN_FPGA( LPVOID params ) 
{
	CUSBprojDlg *pDlg = (CUSBprojDlg *) params;
	pDlg->FPGA_512B_OK=true;//已接收1组数据(数量不一定为512字节),所以置true!
	OVERLAPPED inOvLap; 
	LONG xfer=pDlg->LOOP_FPGA_Xfer_size;
	CString str;	

    inOvLap.hEvent  = CreateEvent(NULL, false, false, _T("CYUSB_IN"));    	
	bool success_in;
    pDlg->pInEndpt->TimeOut = 2000;

	LARGE_INTEGER BegainTime;               //记录测速开始之前时钟计数数值
	LARGE_INTEGER EndTime;					//记录测速结束之后时钟计数数值
	LARGE_INTEGER Frequency;				//记录1s内系统时钟计数次数
                                            //测速耗时t=(EndTime-BegainTime)/Frequency
	QueryPerformanceFrequency(&Frequency); //获取1s内系统时钟计数次数
	QueryPerformanceCounter(&BegainTime);//获取当前系统时钟计数的数值
	
	UCHAR  *inContext = pDlg->pInEndpt->BeginDataXfer(pDlg->R_512B,xfer,&inOvLap);
	if(!pDlg->pInEndpt->WaitForXfer(&inOvLap,2000))
	{
		pDlg->pInEndpt->Abort();
		WaitForSingleObject(inOvLap.hEvent, 2000);
	}
	success_in = pDlg->pInEndpt->FinishDataXfer(pDlg->R_512B,xfer, &inOvLap,inContext);

	QueryPerformanceCounter(&EndTime);//16组数据传输完后,记录系统时钟计数的数值
	double t=(double)( EndTime.QuadPart - BegainTime.QuadPart )/Frequency.QuadPart;
	t=t*1000000;

    if(success_in)
	{
		pDlg->Matrix_to_String(pDlg->R_512B);
		str.Format(_T("\r\n本次接收%d字节数据耗时:%.2f uS\r\n请开始发送测试!\r\n"),xfer,t);
		pDlg->data_display+=str;
		pDlg->m_data_receive_display.SetWindowTextW(pDlg->data_display);
	}
	else 
	{
		str.Format(_T("\r\n FPGA端数据接收失败,请检查FPGA端烧写的程序是否正确!\r\n"));
		pDlg->data_display+=str;
		pDlg->m_data_receive_display.SetWindowTextW(pDlg->data_display);
	
	}
    CloseHandle(inOvLap.hEvent);      
	
	pDlg->pXfer_IN_FPGA = NULL;   	
	return true;

}

(2)下环路速度测试与循环收发模块

UINT XferLoop_FPGA( LPVOID params ) {
    OVERLAPPED outOvLap, inOvLap; 
    CUSBprojDlg *pDlg = (CUSBprojDlg *) params;
	CString str;	
	LONG xfer = pDlg->LOOP_FPGA_Xfer_size;
	int R_S_num=0;
	PUCHAR data = new UCHAR[pDlg->LOOP_FPGA_Xfer_size];	ZeroMemory(data,pDlg->LOOP_FPGA_Xfer_size);	
    outOvLap.hEvent  = CreateEvent(NULL, false, false, _T("CYUSB_OUT")); 
    inOvLap.hEvent   = CreateEvent(NULL, false, false, _T("CYUSB_IN")); 	
	bool success_in, success_out;
	int nSuc=0,nErr=0;
    pDlg->pOutEndpt->TimeOut = 2000;
	pDlg->pInEndpt->TimeOut = 2000;
	pDlg->m_Semaphore.Lock();
    LARGE_INTEGER BegainTime;               //记录测速开始之前时钟计数数值
	LARGE_INTEGER EndTime;					//记录测速结束之后时钟计数数值
	LARGE_INTEGER Frequency;				//记录1s内系统时钟计数次数
                                            //测速耗时t=(EndTime-BegainTime)/Frequency
	QueryPerformanceFrequency(&Frequency); //获取1s内系统时钟计数次数
	QueryPerformanceCounter(&BegainTime);//获取当前系统时钟计数的数值

	pDlg->data_display+=_T("++++++++当前测试环节:下环路测试+++++++++\r\n\r\n状态提示:正在进行下环路测试!\r\n\r\n");
	str.Format(_T("单次传输数据量:%d byte\r\n\r\n"),xfer);
	pDlg->data_display+=str;
	str.Format(_T("单向传输20M数据需要的次数:%d \r\n\r\n测试中,请等待!\r\n\r\n"),pDlg->LOOP_FPGA_Xfer_num);
	pDlg->data_display+=str;
	pDlg->m_data_receive_display.SetWindowTextW(pDlg->data_display);
	pDlg->m_data_receive_display.SetSel(-1);             //使数据显示框拉到最低下
	while(pDlg->bLooping_FPGA) 
	{
		//先接收512字节数据
		UCHAR  *inContext = pDlg->pInEndpt->BeginDataXfer(data,xfer,&inOvLap);
		if(!pDlg->pInEndpt->WaitForXfer(&inOvLap,2000))
			{
				pDlg->pInEndpt->Abort();
				WaitForSingleObject(inOvLap.hEvent, 2000);
			}
		success_in = pDlg->pInEndpt->FinishDataXfer(data,xfer, &inOvLap,inContext);
	
		//再发送512字节数据			
		UCHAR  *outContext = pDlg->pOutEndpt->BeginDataXfer(data,xfer,&outOvLap);
		if(!pDlg->pOutEndpt->WaitForXfer(&outOvLap,2000))
			{
				pDlg->pOutEndpt->Abort();
				WaitForSingleObject(outOvLap.hEvent, 2000);
			}
		success_out = pDlg->pOutEndpt->FinishDataXfer(data, xfer, &outOvLap,outContext);
		//判断本次下环路的接收和发送环节是否通过
		if(success_in==true)//
		{			
			if(pDlg->loop_FPGA_key) R_S_num++;        //如果要进行速度测试,收发计数变量R_S_num开始计数,累积传输10M数据停止测试
			
			if(success_out==true) 
				nSuc++;
			else
				nErr++;
		}	
		else 
		{	if(pDlg->bLooping_FPGA)	
			{
			pDlg->data_display+=_T("状态提示:等待FPGA端发送数据!\r\n");
			pDlg->m_data_receive_display.SetWindowTextW(pDlg->data_display);
			}
		}
		if(pDlg->m_LOOP_FPGA_STATUS.GetCheck()==1) //判断是否要显示传输数据的状态,打开
		{
			str.Format(_T("%d"),(nSuc*pDlg->LOOP_FPGA_Xfer_size)/1024);
			pDlg->m_Success2.SetWindowTextW(str);
			str.Format(_T("%d"),(nErr*pDlg->LOOP_FPGA_Xfer_size)/1024);
			pDlg->m_Failure2.SetWindowTextW(str);
		}
		if(R_S_num==pDlg->LOOP_FPGA_Xfer_num)
		{
			QueryPerformanceCounter(&EndTime);//16组数据传输完后,记录系统时钟计数的数值
			double t=(double)( EndTime.QuadPart - BegainTime.QuadPart )/Frequency.QuadPart;
			double rate=(double)2*((pDlg->LOOP_FPGA_Xfer_num*xfer)/1024/1024)/t;
			pDlg->bLooping_FPGA=NULL;

			pDlg->data_display +=_T("++++++++当前测试环节:下环路测试+++++++++\r\n\r\n");
			pDlg->data_display+=_T("状态提示:下环路速度测速已完成。\r\n\r\n");
			str.Format(_T("单向传输字节数:%d MB。\r\n\r\n"),(xfer*pDlg->LOOP_FPGA_Xfer_num)/1024/1024);
			pDlg->data_display+=str;
			str.Format(_T("平均传输速度达:%.2f MB/s\r\n\r\n"),rate);
			pDlg->data_display+=str;
			str.Format(_T("本次传输总耗时:%.2f s\r\n\r\n"),t);
			pDlg->data_display+=str;
			pDlg->m_data_receive_display.SetWindowTextW(pDlg->data_display);
			pDlg->m_data_receive_display.SetSel(-1);             //使数据显示框拉到最低下
			pDlg->m_Startloop_FPGA.EnableWindow(true);	

			pDlg->m_loop_FPGA_key.SetWindowText(_T("下环路速度测试"));
			pDlg->m_LOOP_R_512B.EnableWindow(true);
			pDlg->m_LOOP_T_512B.EnableWindow(true);
			pDlg->m_loop_FPGA_key.EnableWindow(true);
			pDlg->m_LOOP_FPGA_STATUS.EnableWindow(true);

			pDlg->loop_FPGA_key=false; //关闭测速开关			
		}
	} 
	pDlg->m_Semaphore.Unlock();
	//if(R_S_num==pDlg->LOOP_FPGA_Xfer_num)
	//R_S_num=0;
    CloseHandle(outOvLap.hEvent); 
    CloseHandle(inOvLap.hEvent); 
	delete [] data;	
	pDlg->pXferThread_FPGA = NULL;
   	return true;
}

2.3 控件函数小结

(1)控件使能与禁用

m_LOOP_R_512B.EnableWindow(true); //使能按钮“接收单次数据”

m_LOOP_R_512B.EnableWindow(false); //禁用按钮“接收单次数据”

(2)更改控件名称

m_Startloop_FPGA.SetWindowText(_T("Stop"));        //将下环路速度测试按钮名称改为“stop”

m_loop_FPGA_key.SetWindowText(_T("下环路速度测试")); //将下环路速度测试按钮名称改为“下环路速度测试

(3)示例编辑框相关操作

m_data_receive_display.SetWindowTextW(data_display); //将字符串data_display显示在编辑框IDC_data_receive_display上

m_data_receive_display.SetSel(-1);                   //使数据显示框拉到最低下

(4)复选框相关操作

int n=m_LOOP_FPGA_NUM.GetCurSel();              //获取下环路单次传输的数据量

3. 下环路速度测试

3.1 勾选“显示传输状态”复选框

单向数据量

单次传输数据量

循环次数

总耗时

平均速度

20M

0.5K

40960

11.35 s

3.52 MB/s

20M

1K

20480

5.95 s

6.73 MB/s

20M

2K

10240

3.60 s

11.12 MB/s

19 MB

3K

6826

2.72 s

13.96 MB/s

20M

4K

5120

2.45 s

16.32 MB/s

20M

5K

4096

2.76 s

14.50 MB/s

20M

8K

2560

2.38 s

16.82 MB/s

20M

10K

2048

1.89 s

21.16 MB/s

3.2 不勾选“显示传输状态”复选框

单向数据量

单次传输数据量

循环次数

总耗时

平均速度

20M

0.5K

40960

5.92 s

6.76 MB/s

20M

1K

20480

3.37 s

11.88 MB/s

20M

2K

10240

2.14 s

18.73 MB/s

19 MB

3K

6826

1.76 s

21.53 MB/s

20M

4K

5120

1.48 s

27.01 MB/s

20M

5K

4096

1.81 s

22.14 MB/s

20M

8K

2560

1.38 s

29.04 MB/s

20M

10K

2048

1.45 s

27.61 MB/s

3.3 数据分析

(1)速度测试时,单次传输的数据量越大传输速度越高,在单次传输量为4K的时候出现了一个速度峰值。

(2)勾选“显示传输状态”复选框时会明显降低平均速度的大小,因为数据统计与显示增加了额外的时间开销。

(3)为了增加数据的传输速度,在传输进程的处理函数中,要尽量避免与数据传输无关代码的时间开销。

4. 上位机工程文件

https://download.csdn.net/download/snaking616/11026480

5. 参考

[1] 基于MFC的USB上位机开发(5)下环路模块 - 瓜儿不甜的博客 - CSDN博客

猜你喜欢

转载自blog.csdn.net/snaking616/article/details/88579423