FPGA外接FT232H配置FIFO实现USB通信回环测试

USB英文全称 Universal Serial Bus,即通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。

FTDI 公司的USB2.0 芯片FT232H 进行USB 通信

FH232H芯片在内部不仅完成了USB 硬件接口差分电平转换,还封装了USB 的相关协议,留出数据交互接口

FH232H可以默认配置为UART模式,还可配置为JTAG,FIFO,IIC,SPI,本次将其配置为FIFO进行实验。

作为FPGA开发者只需要关注数据交互接口的时序即可实现USB功能。

 MPSSE/Multi_purpose UART/FIFO controler:该模块为多功能UART/FIFO 控制器,它集成了面向用户的IO,直接负责与用户端(FPGA)进行数据交互。当把FT232H 配置成不同的模式时,管脚会有不同的含义

 (I/O是对于FT232H来说)

ADBUS[7:0]: (I/O) 数据端口,双向IO接口(读写不能同时发生

RD:      (IN)           FT232H中的数据输出使能,由FPGA发送给FT232H,低电平有效

WR:     (IN)            FT232H中的数据输入使能,由FPGA发送给FT232H,低电平有效

RXF:   (OUT)         FT232H中的FIFO数据可读标志位,低电平有效

TXE:    (OUT)        FT232H中的FIFO数据可写标志位,低电平有效

OE:     (IN)             FT232H中的数据输出,低电平有效

CLKOUT: (OUT)    60MHz时钟信号,由FT232H产生并传递给FPGA作为本次实验主时钟

SIWU:   (OUT)       FT232H中的数据立即发送使能,低电平有效

读时序:232拉低RXF表示有数据可读 > FPGA拉低OE使能输出 > 等待数据有效 > FPGA拉低RD > 有效数据 > 232拉高RXF > 读空 > FPGA需要同时拉高RD和OE

写时序:232中FIFO未满 > 232拉低TXE > FPGA拉低WR > 向232写入数据 > 232拉高TXE > 写满

硬件设计:参考https://github.com/WangXuan95/FPGA-ftdi245fifo,正点原子达芬奇Pro

        连接好硬件后进行FT232H模式修改:

官网下载ft_prog

安装后运行,去掉其他FT器件,按如图所示操作

编写代码实现回环(参考正点原子源码)

配置管脚,按硬件连接配置管脚

xilinx vivado FIFO IP核配置:

顶层模块

module usb_loopback (
    input        usb_clk_60m,  //FT232输出的60M时钟
    input        sys_rst_n,    //系统复位 ,低电平
    input        usb_rxf_n,    //FT232H中FIFO数据的可读标
    input        usb_txe_n,    //FT232H中FIFO数据的可写标
    output       usb_oe_n,     //FT232H数据输出使能
    output       usb_rd_n,     //FT232H读使能信号
    output       usb_wr_n,     //FT232H写使能信号
    output       usb_siwu_n,   //send immediate/wake up
    output       c7,   //send immediate/wake up
    inout  [7:0] usb_data      //FT232H双向数据总线
);
    //wire define
    wire [7:0] fifo_data_in;  //从FT232进到FPGA的数据
    wire [7:0] fifo_data_out;  //从FPGA输出到FT232的数据
    wire       wr_en;  //FPGA FIFO写使能
    wire       rd_en;  //FPGA FIFO读使能
    wire       full;  //FPGA FIFO写满信号
    wire       empty;  //FPGA FIFO读空信号
    //*****************************************************
    //** main code
    //*****************************************************
    assign usb_siwu_n = 1'b1;  //立即发送,唤醒
    assign c7 = 1'b1;  //立即发送,唤醒
    //USB 同步FIFO读写
    usb_rw u_usb_rw (
        .usb_clk_60m(usb_clk_60m),
        .rst_n      (sys_rst_n),
        .usb_rxf_n  (usb_rxf_n),
        .usb_txe_n  (usb_txe_n),
        .usb_oe_n   (usb_oe_n),
        .usb_rd_n   (usb_rd_n),
        .usb_wr_n   (usb_wr_n),
        .fifo_wr_en (wr_en),
        .fifo_rd_en (rd_en),
        .empty      (empty),
        .usb_data   (usb_data),

        .fifo_data_in (fifo_data_in),
        .fifo_data_out(fifo_data_out)
    );
    //FPGA FIFO调用
    fifo_generator_0 u_fifo_generator_0 (
        .clk  (usb_clk_60m),    // input wire clk
        .srst (1'b0),           // input wire srst
        .din  (fifo_data_in),   // input wire [7 : 0] din
        .wr_en(wr_en),          // input wire wr_en
        .rd_en(rd_en),          // input wire rd_en
        .dout (fifo_data_out),  // output wire [7 : 0] dout
        .full (full),           // output wire full
        .empty(empty)           // output wire empty
    );


    
// ila_0 u_ila_0 (
// 	.clk(usb_clk_60m), // input wire clk


// 	.probe0(fifo_data_out), // input wire [7:0]  probe0  
// 	.probe1(fifo_data_in), // input wire [7:0]  probe1 
// 	.probe2({usb_rxf_n,usb_txe_n,usb_oe_n,usb_rd_n,usb_wr_n}), // input wire [7:0]  probe2 
// 	.probe3(0) // input wire [7:0]  probe3
// );
endmodule

USB模块:

module usb_rw (
    input            usb_clk_60m,  //FT232 输出的60M 时钟
    input            rst_n,        //系统复位 ,低电平
    //FT232H
    input            usb_rxf_n,    //FT232H 中FIFO 数据的可读标志
    input            usb_txe_n,    //FT232H 中FIFO 数据的可写标志
    output reg       usb_oe_n,     //FT232H 数据输出使能
    output reg       usb_rd_n,     //FT232H 读使能信号
    output reg       usb_wr_n,     //FT232H 写使能信号
    inout      [7:0] usb_data,     //FT232H 双向数据总线
    //FPGA FIFO

    output reg       fifo_wr_en,     //FPGA FIFO写使能
    output reg       fifo_rd_en,     //FPGA FIFO读使能
    input            empty,          //FPGA FIFO读空信号
    input      [7:0] fifo_data_out,  //FPGA FIFO中读出的数据
    output reg [7:0] fifo_data_in    //写入FPGA FIFO的数据
);
    // localparam define
    localparam IDLE = 4'b001;  //FT232H 空闲
    localparam READ = 4'b010;  //FT232H 读状态,此时数据从FT232H发送到FPGA
    localparam WRITE = 4'b100;  //FT232H 写状态,此时数据从FPGA发送到FT232H


    //reg define
    reg [2:0] cur_state;  //读写现状态
    reg [2:0] next_state;  //读写次状态
    reg       usb_oe_n_d1;  //usb_oe_n下一拍
    //*****************************************************
    //** main code
    //*****************************************************
    //在FT232H写状态,将FIFO的数据输出赋值给将USB数据总线,其他时候为高阻态
    assign usb_data = (next_state == WRITE) ? fifo_data_out : 8'hzz;


    //产生FT232H数据输出使能usb_oe_n
    always @(posedge usb_clk_60m or negedge rst_n) begin
        if (!rst_n) usb_oe_n <= 1'b1;
        else if (!usb_rxf_n) usb_oe_n <= 1'b0;
        else usb_oe_n <= 1'b1;
    end
    //FT232H数据输出使能usb_oe_n打一拍
    always @(posedge usb_clk_60m or negedge rst_n) begin
        if (!rst_n) usb_oe_n_d1 <= 1'b1;
        else usb_oe_n_d1 <= usb_oe_n;
    end

    //状态跳转
    always @(posedge usb_clk_60m or negedge rst_n) begin
        if (!rst_n) cur_state <= IDLE;
        else cur_state <= next_state;
    end
    //读写状态跳转条件
    always @(*) begin
        case (cur_state)
            IDLE: begin
                if (usb_rxf_n == 1'b0)  //usb_rxf_n拉低,,ft232中数据可读,下一时钟进入去读FT232H数据
                    next_state <= READ;  //usb_txe_n拉低且FPGA FIFO不空进入FT232H写
                else if ((usb_txe_n == 1'b0) && (empty == 1'b0)) next_state <= WRITE;//ft232可写且本地fifo不为空
                else next_state <= IDLE;
            end
            READ: begin  //usb_rxf_n拉高,ft232数据读空,从FT232H读回到空闲状态
                if ((usb_oe_n_d1 == 1'b1) && (usb_rxf_n == 1'b1)) next_state <= IDLE;
                else next_state <= READ;
            end
            WRITE: begin  //usb_txe_n拉高或者FPGA FIFO被读空,回到空闲状态
                if ((usb_txe_n == 1'b1) || (empty == 1'b1)) next_state <= IDLE;
                else next_state <= WRITE;
            end
            default: next_state <= IDLE;
        endcase
    end

    //状态赋值
    always @(*) begin
        case (next_state)
            IDLE: begin
                fifo_data_in <= 8'hzz;
                usb_rd_n <= 1'b1;
                usb_wr_n <= 1'b1;
                fifo_wr_en <= 1'b0;
                fifo_rd_en <= 1'b0;
            end

            //读状态时,将usb数据赋值给fifo_data_in
            READ: begin
                fifo_data_in <= usb_data;
                usb_wr_n <= 1'b1;
                fifo_rd_en <= 1'b0;
                //在usb_oe_n为低且在usb_oe_n下一拍也为低时拉低usb_rd_n,其他时候为高
                if ((usb_oe_n_d1 == 0) && (usb_oe_n == 0)) usb_rd_n <= 1'b0;//拉低读取标志位,开始读取ft232数据
                else usb_rd_n <= 1'b1;
                //在usb_oe_n下一拍为低,且usb_rxf_n也为低时使能FIFO写
                if ((usb_oe_n_d1 == 0) && (usb_rxf_n == 0)) fifo_wr_en <= 1'b1;//使能本地fifo写入数据
                else fifo_wr_en <= 1'b0;
            end

            //写状态时,使能fifo_rd_en和usb_wr_n
            WRITE: begin
                fifo_data_in <= 8'hzz;
                usb_rd_n <= 1'b1;
                fifo_wr_en <= 1'b0;
                usb_wr_n <= 1'b0;
                fifo_rd_en <= 1'b1;
            end
            
            default: begin
                fifo_data_in <= 8'hzz;
                usb_rd_n <= 1'b1;
                usb_wr_n <= 1'b1;

                fifo_wr_en <= 1'b0;
                fifo_rd_en <= 1'b0;
            end
        endcase
    end
endmodule

下载完成后断开下载线,只保留USB连接线,使用串口助手 ATK-FUSB测试:

成功的话会在接收窗口看到同样的数据返回。

  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值