基于Spartan-6的高速数据采集、处理和实时传输研究

时间:2016-12-06来源:网络

择一种最佳的设计方案。表 1为不同抽取倍数下的带宽和混叠衰减规格:

  最后确定选择CIC2滤波器抽取倍数为15,CIC5抽取倍数为2,RCF抽取倍数为2就可以满足系统设计的要求。

  3.2.3 可变系数RCF滤波器参数设置

  根据2.2.1节设计得到的RCF抽取倍数为30,可以根据式来计算得到抽取滤波器的抽头数为150。

  

  其中,为60MHz,为15,为CIC5滤波器抽取降速后的频率也即2MHz,当输入通道模式时单通道实模式时为1。对可变系数的RCF滤波器进行编程设置时需要先向地址0x30C写入整数 149(=59)。然后滤波器的响应逐一写入到地址0x000~0xFF中。这样就完成了RCF寄存器的编程设置。

  3.2.4 AD6620工作模式寄存器编程

  对频率变换单元、固定系数的CIC2和CIC5以及RCF滤波器变化进行编程设置后,要使AD6620正常工作还需要对其工作方式和相关寄存器进行配置。AD6620的工作方式主要由地址0x300H的寄存器中低四位决定,其中,bit0=1时系统处于软复位状态,bit0=0则处于正常状态;bit1=1时系统处于双通道实数输入模式;bit2=1时系统处于单通道复数输入模式;如果bit0~bit2都是0,那么系统处于单通道实数输入模式;bit3=1/0为时钟主从工作模式。因此,当各寄存器配置完成后需要将寄存器bit0拉低,也即置为0状态使其脱离软复位状态,进入正常工作模式。另外,在本文中AD6620读写内部寄存器是采用的异步读写时序,数据输出是并行16位输出模式。  总的来说,采用FPGA实现AD6620初始化的过程如下:

  1)首先判断AD6620有没有经过硬件复位,如果没有经过硬件复位而又要实现系统复位,那么可以通过程序去编程地址0x300H的寄存器的bit0位置为1,使得AD6620处于软件复位状态,这样就可以对非动态的寄存器进行相关编程;

  2)对NCO单元、CIC2、CIC5滤波器的抽取倍数和系数进行编程,将相应的控制系数写入相对应的地址寄存器中;

  3)对RCF滤波器系数进行编程,分别向地址0x000H~0xFF中写入这150个抽头系数,剩下的写入0。

  4)对AD6620所有配置工作完成后,必须向地址0x300H的bit0写入0,使其脱离软复位状态,这样AD6620才可以在所配置工作方式下对输入的数据进行处理。  

  4.实时数据传输模块

  基于USB2.0的数据传输设计主要包括以下几个部分:(1)基于EZ-USB FX2的硬件电路设计(2)EZ-USB FX2系列器件CY7C68013A的固件程序(设置CY7C68013A工作模式、传输方式等,需要对其内部寄存器进行相关配置),主要通过Keil C51软件进行开发。

  4.1 实时数据传输部分的硬件设计

  实时数据传输部分(USB2.0的数据传输)的硬件设计方案如图10所示,USB模块与FPGA间的连线如图11所示。

  在高速数据传输部分采用了Cypress公司的EZ-USB FX2 CY7C68013A芯片,采用单片USB 2.0外设可以避免用FPGA直接实现USB通信协议时可靠性低的问题。在数据采集、传输以及测试过程中,CY7C68013A作为从机,负责将FPGA发送给它的基带数据,利用其16位SLAVE FIFO(关于SLAVE FIFO的传输示意图如图所示)将数据缓冲发送给上位机。在SLAVE FIFO数据传输中,上位机应用程序、固件程序和FPGA程序都非常关键,要配合好才能完成数据的高速数据传输。在这个系统中,FPGA起着主控制器作用,CY7C68013A则相当于一个从设备。具体的工作流程是:FPGA把接收过来的16位数字基带信号发送给CY7C68013A,CY7C68013A以SLAVE FIFO的方式将这些数据缓冲,并以批量数据传输的方式发送给上位机,上位机接收到这些数据后加以存储和显示。

  4.2 CY7C68013A的固件程序设计

  固件程序是指运行在设备CPU中的程序,只有在该程序运行时,外设才能称之为具有给定功能的外部设备。固件程序负责初始化单元,重新设置设备。主要包括设备描述符信息、设备功能代码。设备描述信息描述USB设备的一半特性和配置,如设备类别、接口配置、VID和PID等。主机在设备列举时要获取USB设备的描述符,从而获得设备的配置信息和相关驱动信息。用户可以通过修改固件中的描述符来改变设备的特性。设备功能代码有设备的功能需求决定。通信控制功能代码执行主机请求分析处理和数据交换处理功能。

  采用ARM公司的Keil C51 uVision4.02开发CY7C68013A的固件程序。为了简化固件编程,CYPRESS提供了固件编程框架,在此基础上添加我们所需要的配置代码即可完成软件编程。  

  复位上电时,固件先初始化一些全局变量,然后调用初始化函数ID_Init(),初始化设备一直到没有配置的状态和打开中断,循环1s后枚举,直到端点0接收到SETUP包退出循环,进入循环语句while,执行任务函数,函数包括:

  (a)TD_POLL()用户任务调度函数;

  (b)如果发现USB设备请求,则执行对应的USB请求;

  (c)如果发现USB空闲置位,则调用TD_Suspend()这个挂起函数,调用成功后则内核挂起,直到出现USB远程唤醒信号,调用TD_Resume(),内核唤醒后重新进入while循环。

  固件框架程序需要以下几个文件:

  (1)FX2.h:库函数申明,以及变量、宏定义、数据类型定义;

  (2)Fxregs.h:FX2LP寄存器头文件;

  (3)Fw.c:固件框架源文件;

  (4)Periph.c:用户调度函数、用户可以修改,在不同的应用中文件名不一样;

  (5)Dscr.a51:USB描述符列表,用户可以修改;

  (6)Ezusb.lib:EZUSB库文件;

  (7)USBJmpTb.OBJ:中断跳转函数目标文件

  这种情况下,需要在固件程序中,进行相应的修改。在SLAVE FIFO中,特别是自动传输(CY7C68013A单片机不干预数据传输),固件程序主要完成各个端口的初始化。因此我们要修改两个地方:(1)USB设备描述符列表Dscr.a51,根据实际情况修改里面的端口数和传输方式等;(2)初始化函数void TD_Init(void)。在SLAVE FIFO这种方式下,设置EP2为4缓冲的输出端口,EP6为4缓冲的输入端口。

  5. 上位机软件设计

  上位机应用程序是系统与用户之间交流的接口,它通过通用驱动程序完成对外设的控制和通信。主机端应用程序负责向FX2的FIFO发送或者接收数据。本报告中采用的固件架构是EZ-USB FX2/FX2LP(CY7C68013, 驱动程序是Cyusb.sys。用Visual Studio2008软件进行上位机开发,利用C++/MFC来开发基于对话框的应用程序,系统的主要功能模块有:打开USB设备、复位USB设备、系统数据测试与显示等。

  在VS2008中建立一个MFC 单文档/对话框应用程序后,在路径项目中包含头文件cyapi.h和cyapi.lib所在的路径。然后手动导入cyapi.lib,注意是CV6_7的lib,不要导入BCB的。

  开发USB应用程序的一般工作流程如下。

  1)首先要创建一个USB设备对象

  CCyUSBDevice *USBDevice = new CCyUSBDev(Handle);括号中的Handle是USB所关联对象的句柄,一般在MFC中直接就是m_hwnd。

  2)打开USB设备。

  可以用到两个函数open();isopen()这两个都可以用来打开USB设备,isopen()还可以判断能否获得USB设备句柄,一般来说,如果只有一个USB设备连接,可以这样打开:

  USBDevice->open(0)//打开0号USB设备;如果要判断,可以:

  if(!USBDevice->open(0)) //打开失败

  {messagebox("USB未连接");}

  或者if(!USBDevice->Isopen())

  如果连接有多个USB设备,那么可以枚举所有的USB,用到DeviceCount()函数;具体的可以参考cybulk的例子。执行USBDevice->DeviceCount()后,返回所连接的USB设备个数:

  if (USBDevice->DeviceCount()) //保证至少有一个USB设备连接

  {

  for (i = 0; i DeviceCount(); i++) //枚举所有USB设备

  {

  USBDevice->Open(i);//打开第i号USB设备

  m_DeviceListComBox.AddString(USBDevice->DeviceName);//所选择的当前设备名}

  }

  3)端点枚举

  在cybulk的例子中介绍了如何枚举固件中使用的所有端点,也就是使用多个端点的情况,其枚举步骤主要包括一下几个端点:

  (1)创建USB设备并打开该设备

  CCyUSBDevice *USBDevice=new CCyUSBDevice(m_hWnd);//USB设备USBDevice->Open(0);//打开0号USB设备。

  (2)获取所用的端点数目

  intepts = USBDevice->EndPointCount();

  EndPointCount();函数返回当前所用的端点数+1,也就是包含了控制端点。例如在固件接口描述符Interface Descriptor中设置Number of end points项(第5项)的值为4,则epts的值为4+1=5。

  (3)定义端点指针

  CCyUSBEndPoint *endpt;CCyUSBEndPoint建立一个端点对象,可建立所有的端点类型,控制端点,bulk端点,ISO端点等;

  (4)枚举端点,并获得其属性:端点号,传输方向

  for (i=1; i

  {

  endpt = USBDevice->EndPoints[i];//EndPoints-端点列表,最大16.EndPoints[0]指向控制端点(CCyControlEndPoint),未使用的端点设置为NULL。

  if (endpt->Attributes == 2) // Bulk Attributes 判断传输类型bulk,control,等。

  {

  sprintf(s, "0x%02x", endpt->Address);

  if (endpt->Address & 0x80) //Address--判断传输方向in or out 0x8_-in;0x0_-out

  {

  m_InEndptComBox.AddString(s); //最高位为8,in端点,添加到in组合框m_InEndptComBox.SetItemData(m_InEndptComBox.GetCount()-1,i);

  else

  {

  m_OutEndptComBox.AddString(s); //否则,最高位为0,out端点,添加到out组合框m_OutEndptComBox.SetItemData(m_OutEndptComBox.GetCount()-1,i);

  }}}  这样,就完成了某个具体端点的选择。如果只需要使用一个端点的话,那上面的代码无疑就显得冗长不够简洁了。仅使用一个端点,可以使用EndPointOf()函数,该函数直接使用指定的端点,返回其指针;例如,要使用端点2,in传输,那么,可以这样:

  CCyUSBDevice *USBDevice=new CCyUSBDevice(m_hWnd); //USB设备

USBDevice->Open(0); //打

1 2 3

关键词: Spartan-6高速数

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW

或用微信扫描左侧二维码

相关文章

查看电脑版