USB3.0通信入门QT上位机简单读写FPGA

在我们完成“初探USB3.0极简方案FT601Q芯片方案”后,我们需要编写自己的上位机软件,实现对FPGA的访问。本文中,笔者编写了一个简单的应用程序,可以实现对开发板上LED的控制,以及读取开发板按键值。

 

1、USB3.0 FPGA 程序设计,在以下程序中,我们实现上位机发送的数据控制LED,以及上位机读取按键数据。

module ft60x_top(

// system control

input                  Rstn_i,//fpga reset

output                 USBSS_EN,//power enable   

// FIFO interface    

input                  CLK_i,

inout [31:0]           DATA_io,

inout [3:0]            BE_io,

input                  RXF_N_i,   // ACK_N

input                  TXE_N_i,

output                 OE_N_o,

output                 WR_N_o,    // REQ_N

output                 SIWU_N_o,

output                 RD_N_o,

output                 WAKEUP_o,

output [1:0]           GPIO_o,

// led

output reg            [3:0]LED,

input                 [3:0]BTN

);

 

assign USBSS_EN = 1'b1;   

assign WAKEUP_o = 1'b1;

assign GPIO_o   = 2'b00;   

assign SIWU_N_o = 1'b0;

 

wire rstn;

(*mark_debug = "true"*) wire            RXF_N_i;   // ACK_N

(*mark_debug = "true"*) wire            TXE_N_i;

(*mark_debug = "true"*) reg             OE_N_o;

(*mark_debug = "true"*) reg             WR_N_o;    // REQ_N

(*mark_debug = "true"*) reg             RD_N_o;

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *)wire [31:0] rd_data;

(*mark_debug = "true"*) (* KEEP = "TRUE" *)wire [31:0] wr_data;

(*mark_debug = "true"*) wire [3 :0] BE_RD;

(*mark_debug = "true"*) wire [3 :0] BE_WR;

(*mark_debug = "true"*) reg [1:0] USB_S;

 

wire data_rd_valid,data_wr_valid;

assign data_rd_valid = (RD_N_o==1'b0)&&(RXF_N_i==1'b0);

assign data_wr_valid = (WR_N_o==1'b0)&&(TXE_N_i==1'b0);

//read or write flag

assign rd_data  =  data_rd_valid ? DATA_io : 32'd0;//read data dir

assign DATA_io  =  data_wr_valid ? wr_data : 32'bz;// write data dir

assign BE_RD    =  data_rd_valid ? BE_io   : 4'd0; //read data dir

assign BE_io    =  data_wr_valid ? BE_WR   : 4'bz;// write data dir

assign BE_WR    =  4'b1111;

 

assign wr_data = {8'h00,8'haa,8'hff,4'h0,BTN};

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *) reg [15:0]rd_cnt;

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        rd_cnt <= 16'd0;

    end

    else if(data_rd_valid) begin

        rd_cnt <= rd_cnt + 1'b1;

    end

    else begin

       rd_cnt  <= 16'd0;

    end

end

 

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        LED <= 4'b0000;

    end

    else if(data_rd_valid) begin

        LED <= rd_data[3:0];

    end

end

 

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        USB_S <= 2'd0;

        OE_N_o <= 1'b1;

        RD_N_o <= 1'b1;

        WR_N_o <= 1'b1;

    end

    else begin

        case(USB_S)

        0:begin

            OE_N_o <= 1'b1;

            RD_N_o <= 1'b1;

            WR_N_o <= 1'b1;

            if((!RXF_N_i)) begin

                USB_S  <= 2'd1;

                OE_N_o <= 1'b0;  

            end

            else if(!TXE_N_i)begin

                USB_S  <= 2'd2;

            end

        end

        1:begin

            RD_N_o <= 1'b0;  

            if(RXF_N_i) begin

                USB_S  <= 2'd0;

                RD_N_o <= 1'b1;

                OE_N_o <= 1'b1;     

            end

        end

        2:begin

            WR_N_o <= 1'b0;

            if(TXE_N_i) begin

                USB_S  <= 2'd0;

                WR_N_o <= 1'b1;

             end

        end

        3:begin

            USB_S <= 2'd0;

        end

        endcase                

    end

end

 

 

Delay_rst #(

    .num(20'hffff0)

)

Delay_rst_inst

(

    .clk_i(CLK_i),

    .rstn_i(Rstn_i),

    .rst_o(rstn)

 );

2、人机界面

USB3.0通信入门QT上位机简单读写FPGA_第1张图片

3、上位机分析

3.1、Mainwindow.c

此程序中关键就打开USB设备,以及发送写数据操作和读数据操作

1)、UsbManager::getInstance();中会调用并且打开USB设备

2)、由于GPIO控制不需要非常高的速度,因此定时每100ms用定时器更新一次数据

3)、在定时器read_one_time函数中首先把需要设置的LED值发送给USB设备,FPGA会根据读取到的数据设置LED的状态;然后再读取按键的状态,之后更新上位机按键的显示状态

#include "mainwindow.h"

#include "ui_mainwindow.h"

#include

#include "UsbManager.h"

 

uint32_t m_io_val;

 

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    this->setWindowTitle(tr("MSXBO USB GPIO Test(V1.00)"));

 

    UsbManager::getInstance();

    m_io_val=0;

    m_QTimer_btn = new QTimer(this);

    connect(m_QTimer_btn,SIGNAL(timeout()),this,SLOT(read_one_time()));

    m_QTimer_btn->start(100);

}

 

MainWindow::~MainWindow()

{

 

    delete ui;

}

 

void MainWindow::read_one_time()

{

    uchar val;

    uchar buff[4];

    buff[0]=m_io_val;

    buff[1]=0xff;

    buff[2]=0xaa;

    buff[3]=0x00;

 

    long len=4;

 

    USBMANAGER->sendData(0,buff,len);

 

    USBMANAGER->recvData(0,buff,len);

    val = buff[0];

 

    if(val&0x1) ui->ch_btn_0->setCheckState(Qt::Unchecked);

     else ui->ch_btn_0->setCheckState(Qt::Checked);

 

    if(val&0x2) ui->ch_btn_1->setCheckState(Qt::Unchecked);

     else ui->ch_btn_1->setCheckState(Qt::Checked);

 

    if(val&0x4) ui->ch_btn_2->setCheckState(Qt::Unchecked);

     else ui->ch_btn_2->setCheckState(Qt::Checked);

 

    if(val&0x8) ui->ch_btn_3->setCheckState(Qt::Unchecked);

     else ui->ch_btn_3->setCheckState(Qt::Checked);

 

}

 

void MainWindow::on_ch_led_0_stateChanged(int arg1)

{

    if(arg1==Qt::Checked) m_io_val|=0x1;

    else m_io_val&=0xe;

 

}

 

void MainWindow::on_ch_led_1_stateChanged(int arg1)

{

    if(arg1==Qt::Checked) m_io_val|=0x2;

    else m_io_val&=0xd;

}

 

 

void MainWindow::on_ch_led_2_stateChanged(int arg1)

{

    if(arg1==Qt::Checked) m_io_val|=0x4;

    else m_io_val&=0xb;

}

 

void MainWindow::on_ch_led_3_stateChanged(int arg1)

{

    if(arg1==Qt::Checked) m_io_val|=0x8;

    else m_io_val&=0x7;

}

 

3.2 UsbManager.c

在此程序中实际上定义了2个类分别是UsbManager和UsbDevice故名思意,UsbManager是对UsbDevice进一步的管理。在上面的UsbManager::getInstance();函数调用的时候就会首先打开USB设备。这里注意驱动inf文件里面的gui需要和程序里面的GUID一致,否作无法正常打开设备。

#include

#include "UsbManager.h"

#include "UsbCommon.h"

#include

#include "QThread"

#include

#include

DEFINE_GUID(GUID_DEVINTERFACE_FOR_FTDI_DEVICES,

         0x219d0508, 0x57a8, 0x4ff5, 0x97, 0xa1, 0xbd, 0x86, 0x58, 0x7c, 0x6c, 0x7e);

 

 

 

UsbManager* UsbManager::mInstance = NULL;

 

 

UsbManager::UsbManager(void)

{

         UsbDevice *device = new UsbDevice(NULL);

         device->openDevice(0);

         mDeviceList.push_back(device);

 

}

 

UsbManager::~UsbManager(void)

{

         for (int i = 0; i < mDeviceList.size(); i++)

         {

                   delete mDeviceList.at(i);

         }

}

 

UsbManager * UsbManager::getInstance()

{

         if (mInstance==NULL)

         {

                   mInstance = new UsbManager();

         }

         return mInstance;

}

 

 

bool UsbManager::sendData( int device /*=0*/, uchar *data, long& length )

{

 

    UCHAR buff[4096];

    memcpy(buff,data,length);

 

    if (device

    {

        bool result = mDeviceList.at(device)->sendData(data,length);

        return result;

    }

    return false;

}

 

bool UsbManager::recvData( int device /*=0*/,uchar* buff, long& length )

{

         if (device

         {

                   return mDeviceList.at(device)->recvData(buff,length);

         }

         return false;

}

 

bool UsbManager::deviceIsOpen( int device )

{

         if (device

         {

                   return mDeviceList.at(device)->isOpen();

         }

         return false;

}

 

void UsbManager::resetDevice( int device )

{

         if (device

         {

                   mDeviceList.at(device)->reset();

         }

}

 

void UsbManager::destoryInstance()

{

         if (mInstance)

         {

                   delete mInstance;

                   mInstance = NULL;

         }

}

 

void UsbManager::openUsbDevice( int device )

{

         if (device

         {

                   mDeviceList.at(device)->reOpen();

         }

}

 

UsbDevice::UsbDevice( QObject *parent )

    :ftHandle(NULL)

         ,ftStatus(FT_INVALID_HANDLE)

{

        

}

 

UsbDevice::~UsbDevice()

{

         FT_Close(ftHandle);

}

 

void UsbDevice::openDevice( int dev )

{

//FT_INVALID_HANDLE

         USHORT uwVID = 0;

         USHORT uwPID = 0;

 

         GUID DeviceGUID[2] = { 0 };

         memcpy(&DeviceGUID[0], &GUID_DEVINTERFACE_FOR_FTDI_DEVICES, sizeof(GUID));

         ftStatus = FT_Create(&DeviceGUID[0], FT_OPEN_BY_GUID, &ftHandle);

 

         if (FT_FAILED(ftStatus))

         {

                   std::cout << "open fail" << std::endl;

                   return ;

         }

 

         ftStatus = FT_GetVIDPID(ftHandle, &uwVID, &uwPID);

         if (FT_FAILED(ftStatus))

         {

                   FT_Close(ftHandle);

         }

}

 

bool UsbDevice::sendData( uchar *data, long& length )

{

         if (ftStatus != FT_OK)

         {

                   return false;

         }

         unsigned long writenLen;

 

         ftStatus = FT_WritePipe(ftHandle, 0x02, data, length, &writenLen, NULL);

 

         bool result = true;

         if (FT_FAILED(ftStatus) || writenLen != length)

         {

                   result = false;

         }

         return result;

}

 

bool UsbDevice::recvData( uchar* buff, long& length )

{

         if (ftStatus != FT_OK)

         {

                   return false;

         }

         unsigned long readLen;

         ftStatus = FT_ReadPipe(ftHandle, 0x82, buff, length, &readLen, NULL);

 

         bool result = true;

         if (FT_FAILED(ftStatus) || readLen != length)

         {

                   result = false;

         }

         length = readLen;

         return result;

}

 

bool UsbDevice::isOpen()

{

         return ftStatus == FT_OK;

}

 

void UsbDevice::reset()

{

         if (isOpen())

         {

 

         }

}

 

void UsbDevice::reOpen()

{

         FT_Close(ftHandle);

         openDevice(0);

}

 

4、通过FPGA内嵌的逻辑分析仪查看数据,点亮LED0 LED1

USB3.0通信入门QT上位机简单读写FPGA_第2张图片

在线逻辑分析抓到的数据

在线逻辑分析抓到的数据

USB3.0通信入门QT上位机简单读写FPGA_第3张图片

 

 

转载于:https://my.oschina.net/msxbo/blog/3101072

你可能感兴趣的:(USB3.0通信入门QT上位机简单读写FPGA)