基于PXI总线的高速数字传输模块设计及正交解调的实现(三)

来源:岁月联盟 作者:陈国斌 时间:2010-08-21

  5.3  PXI数字传输模块软件面板的设计和测试结果

  本课题上层应用程序是通过VC++工具进行开发的。之所以选择VC++是因为驱动程序也是在该软件平台上编写与实现的,这样便于应用程序与底层驱动的调用与衔接。应用程序访问设备驱动程序,一般由两种方法,一种是在应用程序中直接编程访问驱动程序,第二种方法是先利用 VC 等语言编写与驱动程序的接口,将函数封装成动态链接库供其它应用程序调用。这两种方法各有利弊,前一种方法比较灵活,应用程序几乎可实现对硬件的全面操作,但这种办法需应用程序开发工具支持与驱动程序的接口,并且开发者要全面了解驱动程序和硬件结构。后一种方法灵活性差,但动态连接库写好后上层应用程序可以用几乎任何一种高级语言写。并且由于应用程序和驱动程序之间隔了一层动态连接库,因此用户可以不用太关心驱动程序的情况和硬件结构。本课题选用直接接口设计。

  直接接口与通过动态连接库实现接口,除了在接口上有区别之外,在打开设备,读写设备等方面两者是一样的。下面介绍一下接口和界面的实现步骤[40]。

  (1)定义应用程序与设备驱动程序接口所需的唯一标识号GUID。

  (2)编写接口函数。

  (3)得到与对应GUID相关的信息。

  (4)获取接口数据。

  (5)获取符号连接名长度。

  (6)获取符号连接名。

  (7)创建文件,由于任何设备在Windows中都被认为是一个文件,所以从创建完文件开始,对该设备的操作将都使用文件读写函数完成。

  (8)应用程序通过写文件函数,向设备驱动程序发送读写请求。

  根据上述步骤设计的软面板如图5-5所示。通过软面板可以实现各种模式下的数据读写功能。

  最后对设计出来的板卡进行了硬件测试,在应用程序中编写如下简单程序:

  void CPDC4000DemoDlg::OnBlockDmaPciToLocalDemo()//DMA模式输出数据

{

      unsigned char pData[0x100];//待输出的数组

      for (int i = 0; i < 0x100; i ++)

      {

                           pData[i] = i + 0x0;

      }

      m_iStatus = STATUS_BLOCK_WRITE;

      BlockDmaPciToLocal(pData, 0x100);

}

  通过逻辑分析仪测量板卡的输出波形,得到输出低8位结果见图5-6。在源程序中写入的数据为pData数组,它的取值是从0开始依次加1,因此从最低位开始往上一位走,依次为2分频。而从输出波形可以看出,输出完全符合写入的数据,数据输出的速率为16 MHz。

图5-5  PXI卡软件面板

图5-6  低8位输出结果

  5.4  本章小结

  本章详细的介绍了PCI/PXI设备驱动程序特点,以及DDK开发驱动程序的主要技术内容。本课题用DDK成功的开发出了基于PCI9054的设备驱动,并成功安装到硬件上且板卡能正常工作。

  本设计中最突出的优点是采用DDK设计驱动程序,而没有采用DS(Driver Studio)和Windriver ,因为DDK是基于汇编语言的编程方式的,其优点是可以开发核心态的真正意义上的驱动程序,开发出来的驱动程序效率是最高的。

[1]         马嘉. PXI模块仪器系统. 机系统测试与控制, 1999, 7(1): 28~30

[2]         周琴. GPIB总线及应用技术. 低压电器, 2008, 1(9): 16~17

[3]         张世箕. 自动测试系统. 第一版. 成都: 科技大学出版社, 1990: 21~23

[4]         孙家琪. 自动测试系统. 第一版. 北京: 机械出版社, 1990: 36~40

[5]         Subbarao V, Wunnava, Peter Hoo. Remote Instrumentation Access&Control (RIAC)Through Inter-Networking. IEEE Instrumentation and Measurement Technology c- onference 1999: 118~119

[6]         马怀俭. 自动测试系统. 第一版. 哈尔滨: 哈尔滨理工大学出版社, 1994: 41~45

[7]         K. Chipperfield. Exploring VXIbus Systems and Instrumentation. IEEE,1995: 217~224

[8]         马怀俭. VXI总线讲座. 电测与仪表, 1990(4): 12

[9]         万鹏. 自动测试与VXI总线自动测试系统. 山东大学学报, 1997(3):85~86

[10]     杨乐平. 一种新的模块化仪器总线标准PXI. . 测控技术, 1998(5):62~63

[11]     National Instruments. PXI Specification PCI eXtensions for Instrumentation An I- mplementation of CompactPCI, 1997:1~50

[12]     Arlene Meadows, Grey Hill. VXI技术现状及其技术规范. 国外电子测量技术, 1998(6): 3~4

[13]     杨乐平, 曾敏. VXI仪器软件技术新-IVI. 第八届VXI技术研讨会集, 1999. 25~31

[14]     席成洲. 一种开放的工业计算机标准-CompactPCI. 测控技术, 1998(1): 7~11

[15]     马永杰, 杨志民. 100MHz高速数据采集卡研制中关键技术的探讨. 西北师范大学学报(版), 1999(1): 37~37

[16]     方慧, 王飞, 何配琨等. TMS320C6000系列DSPs的原理与应用, 第2版. 北京: 电子工业出版社, 2001. 53~62

[17]     Exas Instruments Inc: TMS320C6416T FIXED-POINT DIGITAL SIGNAL PRO- CESSORS Data Sheet. Texas Instruments Inc:2004

[18]     苏涛, 蔡建隆. DSP接口电路设计与编程. 西安: 西安电子科技大学出版社, 2003. 21~56

[19]     黎向阳, 刘光平, 梁甸农. 宽带正交解调器幅相一致性测量. 国防科技大学学报, 2002(2): 60~63

[20]     向民, 张辉. 一种用于信号分析的数字正交解调电路设计. 电视技术,  2006(2): 65~69

[21]     立君, 马骏. 一种宽带正交解调器的试验研究. 电子, 2000(4): 30~32

[22]     崔勇, 王宏远. 基于SystemView的正交系统仿真与分析: 船舶电子工程, 2006(6): 90-92.

[23]     James Kimery.PXI测量系统面对今天的测试挑战.Electronic Products China, 2000(5): 18

[24]     王鲁平, 李飚. 基于EPLD技术的PCI总线接口设计. 电子技术应用,2001(3): 5

[25]     Finkelstein, Ehud, Weiss, Shlomo. PCI-based systems using CPLDand FPGA dev- ices. Proceedings of the Mediterranean Electrotechnical Conference-MELECON v2 1998 (3): 18~20

[26]     Plx technology, PCI9054 Data Book, Version 2. 1, January,2000:15~60

[27]     振勇, 翁木云. FPGA设计及应用. 第一版. 西安: 西安电子科技大学出版社, 2002. 1~22, 111~140, 195~218

[28]     DA先锋工作室, 吴继华, 王城. Altera FPGA/CPLD设计(基础篇)第一版. 北京: 人民邮电出版社, 2005. 1~116

[29]     ltera. CycloneII Device Handbook. San Jose: Altera Corporation ,2006: 1~484

[30]     任爱锋, 初秀琴, 常存等. 基于FPGA的嵌入式系统设计. 第一版. 西安: 西安电子科技大学出版社,2004. 9~126

[31]     Integrated Device Technology, Inc. IDT72V205/72V215/72V225/72V235/72V245 Data Sheet. Datasheet. FEBRUARY 2006:1~25

[32]     梅杰, 曹以龙, 许明东. 基于VerilogHDL语言的USB收发器设计. 电子技术,  2003, 12: 19~21

[33]     李玉柏, 彭启琮, 管庆. 基于VXI总线的虚拟仪器平台. 测控技术,1997, 16(3): 45~47

[34]     VXI Plug & play System Alliance. The VISA Library. Texas: VXI Plug& play Sy- stem Alliance, 1996:121~256

[35]     VXI Plug & play System Alliance. VISA Implementation Specificationfor Textual Languages. Texas:VXI Plug & play System Alliance, 1996:57~146

[36]     Chris Cant . Windows WDM设备驱动程序开发指南(美)北京: 机械工业出版社, 2000. 1~100

[37]     Walter Oney, Programming the Windows Model Driver. Microsoft Press, 1999: 35~71

[38]     Microsoft,Windows 2000 DDK Documents, 1999: 20~54

[39]     Walter O. Programming the microsoft windows driver model[M] . USA ,1999: 21~50

[40]     VXI Plug & play System Alliance. Soft Front Panel Specification. Texas: VXI Plug & play System Alliance, 1996: 12~39

  附录1  攻读学位期间发表的论文

[1]            陈国斌, 汤清华, 汤丁诚. 基于PXI总线高速数字I/O卡设计. 电子技术应用, 2008, 33(1): 59~61

 

  附录2  FPGA控制程序

`define     COUNTERSIZE  129

`define     COUNTERSIZE_INT    10

module Statemachine (

                   …)//由于篇幅限制,端口定义省略


always @ (GCLK0)

        if(LHOLD)

          LHOLDA<=LHOLD;

        else

          LHOLDA<=1'b0;


always@(posedge GCLK0  or negedge LRSTo_)

begin

  if(LRSTo_==1'b0)

          begin

            LRS_I_<=1'b0;

            LRS_O_  <=1'b0;

           

          end

   else

      begin

            LRS_I_<=1'b1;

            LRS_O_  <=1'b1;

          end

end

        //output logic

always @ (posedge GCLK0)

        begin

              casex (State)

              1'b0:

              begin

                     if (!LADS_)

                     begin

                           

                            LREADY_ <= 1'b0;

                            if (LWR_==1'b0)

                              begin

                                     LREN_I_ <=1'b0;  

                                     WEN_O_  <=1'b1;

       

                       begin

                              LREADY_ <=1'b0;

 

                              if (LWR_== 0)

                                begin

                                       LREN_I_ <=1'b0;     

                                       WEN_O_  <=1'b1;

                                end

                          else

                               begin

                                       LREN_I_ <=1'b1;     

                                       WEN_O_  <=1'b0;

                                end

                    

                              State <= 1'b1;


                       end

                     else               //Cycle Last

                       begin

                               LREADY_ <=1'b1;

                                   LREN_I_ <=1'b1;      

                                   WEN_O_  <=1'b1;

                               State <=1'b0;

                   end

              end

              default:

                     State <=1'b0;

                            endcase

        end


assign  LOE_O_ =(LRSTo_)?1'b0:1'b1;

assign  LOE_I_ =(LRSTo_)?1'b0:1'b1;

//assign LLINT_=1'b1;      


always@(posedge GCLK0  or negedge LRSTo_)//or negedge LGCLK

begin

  if(LRSTo_==1'b0)

          begin

            counter<=6'b0;

            WCLK_reg  <=1'b0;

          end

  else

    if(counter==`COUNTERSIZE)

      begin

        WCLK_reg<=!WCLK_reg;

        counter<=6'b0;

      end

    else

      counter<=counter+6'b000001; 

end

assign  WCLK_O=(`COUNTERSIZE==129)?GCLK0:WCLK_reg;

always@(posedge GCLK0)

begin

        LHF_I_buf1<=LHF_I_;

        LHF_I_buf2<=LHF_I_buf1;

end

        

always@(posedge GCLK0 or negedge LRSTo_)

begin

  if(LRSTo_==1'b0)

    begin

          counter_int<=8'b0;

          LLINT_<=1'b1;

          sub_state<=3'b000;

    end

  else

    begin

          case(sub_state)

            3'b000:

              begin

                LLINT_<=1'b1;

                    if(!LHF_I_buf1&&LHF_I_buf2)

                      sub_state<=3'b001;

                    else

                      sub_state<=3'b000;

              end

             

            3'b001:

              begin

                    counter_int<=counter_int+8'b00000001;

                    LLINT_<=1'b0;

                    if(counter_int==`COUNTERSIZE_INT)

                      sub_state<=3'b000;

                    else

                      sub_state<=3'b001;

              end

            default  sub_state<=3'b000;

          endcase

    end

end 

 

   if(!LRSTo_)

       count<=0;

    else if(count_flag)

       count<=count+1;

     else count<=0;

 

always@(posedge GCLK0  or negedge LRSTo_)

  if(!LRSTo_)

     LRE_ENA_<=1'b1;

  else if(count>15)

     LRE_ENA_<=1'b0;

  else

     LRE_ENA_<=1'b1;

 endmodule

       

 

附录3  PXI部分驱动程序代码
PXI驱动部分代码

/************************************************************************

* Function   :  DispatchRead

* Description:  Handle IRP_MJ_READ, which is not implemented by this driver ReadFile

************************************************************************/

NTSTATUS DispatchRead(IN PDEVICE_OBJECT fdo,

                                     IN PIRP pIrp)

{                                                                                         //DispatchRead

        KdPrint((DBG_NAME "Read Device Start./n"));

        ULONG ReturnedValue;

        NTSTATUS status = STATUS_SUCCESS;

        //将从硬件采集到的数据送给应用程序, 如果不能很快处理,将IRP进行串行化,交给StartIo处理。

        IoMarkIrpPending(pIrp);

        IoStartPacket(fdo, pIrp, NULL, CancelIrp);

        KdPrint((DBG_NAME "Read Device End./n"));

    return STATUS_PENDING;

}                                                                                         //DispatchRead

/************************************************************************

* Function   :  DispatchWrite

* Description:  Handle the IRP_MJ_WRITE, which is not implemented by this driver

WriteFile

************************************************************************/

NTSTATUS DispatchWrite(IN PDEVICE_OBJECT fdo,

                                      IN PIRP pIrp)

{                                                                                  //DispatchWrite

        KdPrint((DBG_NAME "Write File Start./n"));

        //将应用程序的数据送到硬件, 将IRP串行化,交给StartIo处理

        IoMarkIrpPending(pIrp);

        IoStartPacket(fdo, pIrp, NULL, CancelIrp);

        KdPrint((DBG_NAME "Write File End./n"));

        return STATUS_PENDING;

}                                

/************************************************************************

* Function   :  DispatchIoControl

* Description:  Processes the IOCTL IRPs sent to this device.

************************************************************************/

{            case IOCTL_PDC4000_REGISTER_EVENT://注册Event变量          

status= bReferenceObjectByHandle(*(PHANDLE)pIrp->AssociatedIrp.SystemBuffer,

                                   EVENT_MODIFY_STATE, *ExEventObjectType,

                                   pIrp->RequestorMode, (PVOID*)&pdx->pWaitEvent, NULL);

              if (!NT_SUCCESS(status))

              {

                     pdx->bSetWaitEvent = FALSE;

                     KdPrint((DBG_NAME "WARNNING - ObReferenceObjectByHandle failed/n"));

              }

              else

              {

                     pdx->bSetWaitEvent = TRUE;

                     KdPrint((DBG_NAME "OK - ObReferenceObjectByHandle succeed/n"));

              }

              lReturnedValue = 0;

              break;

        case IOCTL_PDC4000_UNREGISTER_EVENT:     //反注册Event变量

              pdx->pWaitEvent = NULL;

              pdx->bSetWaitEvent = FALSE;

              lReturnedValue = 0;

              break;

        case IOCTL_PDC4000_READ_DATA:      

              ULONG Num, Buffer;

              lPdcAddress = (ULONG)pdx->PdcMemBase0;

              RtlCopyMemory(&Num, pIrp->AssociatedIrp.SystemBuffer, sizeof(ULONG));

              KdPrint((DBG_NAME "Input Value is %x.", Num));

              Buffer = READ_REGISTER_UCHAR((unsigned char *)(lPdcAddress + Num));

              KdPrint((DBG_NAME "Read Data Value is %x./n", Buffer));

              RtlCopyMemory( pIrp->AssociatedIrp.SystemBuffer, &Buffer, sizeof(ULONG));

              lReturnedValue = sizeof(ULONG);

              break;

        case IOCTL_PDC4000_WRITE_DATA:

              ULONG dwWriteBuffer[2];

              lPdcAddress = (ULONG)pdx->PdcMemBase0;

              RtlCopyMemory(dwWriteBuffer, pIrp->AssociatedIrp.SystemBuffer, 2 * sizeofpIrpStack->Parameters.DeviceIoControl.InputBufferLength;//0x10;

              RtlCopyMemory(pdx->DmaInfo[0].vaCommonBuffer, pIrp->AssociatedIrp.SystemBuffer, lDMAPciToLocalTransferSize);

              KdPrint((DBG_NAME "The vaCommonBuffer is %X./n", *(unsigned char *)(pdx->DmaInfo[0].vaCommonBuffer)));

              lPdcAddress = (ULONG)pdx->LocalRegisterMemBase;

dcd.BTERMInputEnable    = 1;

              dcd.DACChainLoad          = 0;

              dcd.DemandMode                    = 0;

              dcd.DmaChannelPriority     = Rotational;

              dcd.DmaEOTPinEnable             = 0;

              dcd.DoneInterrputEnable = 1;

              dcd.EnableTransferCountClear = 0;  //For sgl DMA

              dcd.FastSlowTerminateModeSelect = 0;

              dcd.InternalWaitStates = 0;

              dcd.InterrputSelect             = 1;

              dcd.LocalAddressingMode = 0;

              dcd.LocalBurstEnable  = 1;

              dcd.LocalBusWidth            = 0;

              dcd.MemoryWriteAndInvalidateMode = 0;

              dcd.ReadyInputEnable = 1;

              dcd.ScatterGatherMODE   = 0;

              //DMA threshold

              dte.DirectionOfTransfer = 0;

              dte.EndOfChain = 0;

              dte.InterruptAfterTerminalCount = 0;

              dte.NextDescriptorAddress = 0;

              KdPrint((DBG_NAME "The lDMAPciToLocalTransferSize is 0x%X./n", lDMAPciToLocalTransferSize));

             rc = DmaBlockTransfer(pdx, 0, &dte);

              if (rc != RC_SUCCESS)

              {                   KdPrint((DBG_NAME "Can't DmaBlockTransfer./n"));          }

              KdPrint((DBG_NAME "IOCTL_PDC4000_BLOCK_DMA_PCI_TO_LOCAL End./n"));

              break;

        case IOCTL_PDC4000_BLOCK_DMA_LOCAL_TO_PCI:

              IoMarkIrpPending(pIrp);

              IoStartPacket(fdo, pIrp, NULL, CancelIrp);