xilinx FPGA usb模块的使用(VHDL)

此次实例中,使用的是小梅哥的xilinx a7系列200t的开发板,其中自带一个usb2.0模块,然后根据他的基于slave fifo的fpga数据回环实验改编,主要是小梅哥的例程是基于verilog的,以及是自己编写的一个fifo模块,然后我改成了基于vhdl以及fifo ip核的工程,有需要的小伙伴可以参考参考。

1 首先是根据小梅哥的例程,改成vhdl程序

1.1 第一点,是对fifo0_rd_en ,fx2_slwr,fx2_fdata_out的使能不一样

--fifo0_rd_en <= ((not fx2_slwr_reg ) and (not fifo0_empty ));
--之所以不像小梅哥里面写的去使能fifo0的读使能,是因为小梅哥自己写的fifo好像不会存在延时,所以他的fx2_slwr和fifo_rd(fifo_pop)是同时有效的,根据fx2的原理可以知道,当fx2_slwr为0时,就可以将fifo里面相应的数据传输给fx_data,然后发送到上位机,这个前提是fx2和fifo的时钟是一致的。因为fx2用的是同步(同步就是在IFCLK时钟沿进行数据读写,SLWR和SLRD是作为使能信号。异步就是在SLWR和SLRD下降沿进行数据读写,不需要IFCLK。),而fifo也是根据时钟信号去实现功能的。

--------------------------------------------写一下关于时钟的影响-------------------------------------------------------

在小梅哥的usb模块当中使用的fx2,并且配置成了同步传输,所以最好是关于使用该部分的数据,都使用该时钟,不然会有一些问题。

首先我们来看一下fx2的同步传输的时序图:数据都是使能信号有效时,然后在ifclk的上升沿的时候进行传输的

 然后我们来看一下fx2的异步传输的时序图:数据都是使能信号的下降沿时进行传输的

下面我们来看一下,如果对传输数据使用不同时钟去使能传输的话,我们收到的数据有什么区别

第一种,我们任然使用fx的输出时钟(这里配置的是48MHZ),然后可以看到上位机收到的数据和发出的数据是一样的:

 第二种,我们使用fpga的输出时钟(这里配置的是50MHZ),然后可以看到上位机收到的数据和发出的数据就会有一些误差的:就是有的数据可能会持续两三个时钟

  第二种,我们使用2倍的ifclk的输出时钟(这里配置的是96MHZ),然后可以看到上位机收到的数据和发出的数据就会有一些误差的:就是每个数据会持续两个时钟

 ---------------------------------------------------------end----------------------------------------------------------------------

基于 FPGA 的 SlaveFIFO 回送测试

基于 SlaveFIFO 接口的数据回环测试,能够实现 PC 通过 FX2 发往 FPGA 的数据再通

FX2 芯片发回到 PC。整个系统的数据链路如下所示。

我们将输入数据从上位机传输给fpga的fifo,缓存之后就可以接收数据,进行处理,最后再把结果送给fxdata,就可以通过fx2的ep6端点把数据传输到上位机了。

调试过程中可能遇到的问题:

第一个问题,可能datain可以收到fxdata的数据,但是dataout一直没有数据

可能是fpga缓存的fifo没有进行读使能,或者使用fifo ip核的时候设置了复位,但那是高电平复位,而fx2的芯片是低电平复位,所以要注意一下这点

 第二个问题,fxdata收到的数据跟fifodataout的数据不一致,是因为小梅哥的程序里面是自己写的fifo,那么他的fxslwr和fiforden是同时有效的,而且dataout和rden也是一致的。

而正常使用fifo时,会信号延迟,首先当rd_en拉高之后,是要等下一个时钟来时,才会有数据读出,即rd_en下一个时钟,vaild和data_out才有效,所以根据上面的原理,因为是把fifo的data_out给fxdata,所以要等到vaild有效时才能去使能fx2_slwr

新增:其实通过先通过rd_en再去使能slwr,还存在一个问题,就是slwr有效之后,数据才会写入usb,然后flagc的full信号才会有反应,但是这个过程中,rd_en还在使能,所以在这个间隙的时候,就会造成数据丢失,将这部分程序改一下:(2022.11.13)

process (fx2_ifclk,rst_n,fx2_flagc,fifo2_empty,state_c)  --usb in状态机
begin
if(rst_n = '0') then    --低电平复位
   state_c <= s0_wait_flagc;
elsif(rising_edge(fx2_ifclk)) then
    case state_c is
        when s0_wait_flagc => 
            if (fx2_flagc = '1')  then
                state_c <= s1_wirte;
            else
                state_c <= s0_wait_flagc;
            end if;
        when s1_wirte => 
            if ((fx2_flagc = '0') or (fifo2_empty='1'))  then    --or (fifo0_empty='1')
                state_c <= s0_wait_flagc;
            else
                state_c <= s1_wirte;
            end if;
        when others =>
			state_c <= s0_wait_flagc;
    end case;
end if;
end process;

--------------------------------------------------------------------------------------------------------------------------------------------------------------
--因为fxdata要在slwr为0且flagc为1时输出,但是fxdata的数据又是从fifo当中读出来的,读的时候会有时间的延迟,也就是要在valid为1时,数据才有效,也就是在valid为1时,slwr和fxdata的使能,但又要保证在flagc为1的情况下,所以就可以在flagc为1时,使能rd_en,然后马上拉低,在输出fxdata之后,再去判断flagc有没有满,然后再决定是否使能rd_en。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
process (fx2_ifclk,rst_n,state_c,fx2_flagc,fifo2_empty,cnt2,state1)  --fifo2_rd_en
begin
if(rst_n = '0') then    --低电平复位
   state1 <= s0;
   fifo2_rd_en <= '0';
   cnt2  <=  (others => '0');
elsif(rising_edge(fx2_ifclk)) then
case state1 is
    when s0 => 
        fifo2_rd_en <= '0';
        if ((state_c = s1_wirte) and (fx2_flagc = '1') and (fifo2_empty='0'))  then    --or (fifo0_empty='1')
            state1 <= s1;
        else
            state1 <= s0;
        end if;
    when s1 => 
        if ((state_c = s1_wirte) and (fx2_flagc = '1') and (fifo2_empty='0'))  then    --or (fifo0_empty='1')
            fifo2_rd_en <= '1';
            cnt2 <= cnt2 +'1';
            state1 <= s2;
        else
            fifo2_rd_en <= '0';
            cnt2 <= cnt2 ;
            state1 <= s0;
        end if;
    when s2 => 
        fifo2_rd_en <= '0';
        state1 <= s0;
   when others =>
        state1 <= s0;
    end case;
end if;
end process;

process(fifo2_valid)  --fx2_slwr_reg  fx2_fdata_out
begin
    if( fifo2_valid='1' ) then  --not full
        fx2_slwr_reg <= '0';
        fx2_fdata_out  <=  fifo2_data_out(15 downto 0);
    else
        fx2_slwr_reg <= '1';
        fx2_fdata_out  <= (others =>'Z');
    end if;
end process;

第三个问题,fifodatain 和fifo dataout都是0,没有收到fxdata,可能是因为process里面的敏感信号没有写完整,因为小梅哥的程序里面是用的verilog,always(*),他就把所有敏感信号都包含了,但是vhdl里面不可以这样写,我就只写了输入的影响信号,比如我没有写fx2_fdata,结果就是下面这样

process(fx2_slrd_reg)
begin
    if(fx2_slrd_reg = '0')  then
        fifo_data_in <= fx2_fdata;
    else
        fifo_data_in  <=  (others => '0');
    end if;
end process;

 添加上fx2_fdata敏感信号之后,就可以传输正常了:

process(fx2_slrd_reg,fx2_fdata)
begin
    if(fx2_slrd_reg = '0')  then
        fifo_data_in <= fx2_fdata;
    else
        fifo_data_in  <=  (others => '0');
    end if;
end process;

2.更改ila的部分

vhdl的语法会比verilog严格很多,例如同样是ila调用,verilog可以直接使用,但是vhdl里面由于ila ip核会把只有一位的信号定义成STD_LOGIC_VECTOR(0 DOWNTO 0),而我们一般在程序里面会直接定义成STD_LOGIC,这就导致了不能直接观测改信号,会报错说信号类型不一致。那么有两种解决办法,一是将程序中要观测的信号都改成STD_LOGIC_VECTOR(0 DOWNTO 0),但是这很麻烦,因为要将该信号的赋值都改成“0”或“1”,就是要把单引号都改成双引号;二是重新定义一个信号,即st_ila :STD_LOGIC_VECTOR(0 DOWNTO 0); st :STD_LOGIC;  st_ila <= conv_std_logic_vector(st,1); 然后观测时,连接到st_ila就可以了,其中conv_std_logic_vector函数要包含一个库文件use ieee.std_logic_arith.all;

具体的代码分析,我录了一个是视频,大家感兴趣的话,可以看看:基于 FPGA 的 SlaveFIFO 回送测试(VHDL)_哔哩哔哩_bilibili

(ps:不管是fpga烧录eprom文件 还是fx2烧录eprom文件 烧录完成后 一定要掉电 才会进行相应功能)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值