[X]关闭
0

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

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

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

    对于MA703FA开发板上IO有限,所以采用了FT600的芯片,FT600数据位宽是16bit是FT601Q 32bit的一半。因此程序上需要稍加改动后就能正常工作。

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

`timescale 1ns / 1ps

module ft60x_top(

// system control

output                 USBSS_EN,//power enable   

// FIFO interface    

input                  CLK_i,

inout [15:0]           DATA_io,

inout [1:0]            BE_io,

input                  RXF_N_i,   // ACK_N

input                  TXE_N_i,

output reg            OE_N_o,

output                 WR_N_o,    // REQ_N

output                 SIWU_N_o,

output reg            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 [15:0] rd_data;

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

(*mark_debug = "true"*) (* KEEP = "TRUE" *)reg  [31:0] rd_data_r;

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

(*mark_debug = "true"*) wire [1 :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  =  (USB_S==2'd1) ? DATA_io : 16'd0;//read data dir

assign BE_RD    =  (USB_S==2'd1) ? BE_io   : 2'd0;

assign DATA_io  =  (USB_S==2'd2) ? wr_data : 16'bz;// write data dir

assign BE_io    =  (USB_S==2'd2) ? BE_WR   : 2'bz;// write data dir

assign BE_WR    =  4'b1111;

 

assign wr_data = {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

 

(*mark_debug = "true"*) (* KEEP = "TRUE" *)reg data_en;

(*mark_debug = "true"*) (* KEEP = "TRUE" *)reg [1 :0] valid_r;

reg [31:0] rd_data_r;

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        LED <= 4'b0000;

    end

    else if(data_en&&valid_r[1]) begin

        LED <= rd_data_r[3:0];

    end

end

 

always @(posedge CLK_i)begin

    if(!rstn)begin

        rd_data_r <= 32'd0;

        valid_r   <=2'b10;

        data_en   <= 1'b0;

    end

    else if(data_rd_valid) begin

        data_en   <= 1'b1;

        valid_r   <= {valid_r[0],valid_r[1]};

        rd_data_r <= {rd_data,rd_data_r[31:16]};

    end

    else begin

        rd_data_r <= 32'd0;

        valid_r   <=2'b10;

        data_en   <= 1'b0;

    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(1'b1),

    .rst_o(rstn)

 );

 

  

endmodule

 

以上代码中,上位机往下发的数据是32bit但是FPGA和FT600用户接口的数据只有16bit所以需要完成一次16bit转32bit。

always @(posedge CLK_i)begin

    if(!rstn)begin

        rd_data_r <= 32'd0;

        valid_r   <=2'b10;

        data_en   <= 1'b0;

    end

    else if(data_rd_valid) begin

        data_en   <= 1'b1;

        valid_r   <= {valid_r[0],valid_r[1]};

        rd_data_r <= {rd_data,rd_data_r[31:16]};

    end

    else begin

        rd_data_r <= 32'd0;

        valid_r   <=2'b10;

        data_en   <= 1'b0;

    end

end

 

对于写数据到FT600依然可以采用默认的16bit,后面做传图的时候可以采用FIFO以16bit数据上传就可以了。

 

2、人机界面

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)

{





路过

雷人

握手

鲜花

鸡蛋

最新评论

本文作者
2019-9-14 13:55
  • 7
    粉丝
  • 5063
    阅读
  • 0
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
相关分类
热门评论
排行榜