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 勾选“显示传输状态”复选框

扫描二维码关注公众号,回复: 6583935 查看本文章

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