搜索
bottom↓
回复: 28

高手看看,能不能确定是FPGA板的问题?有代码有波形

[复制链接]

出0入0汤圆

发表于 2013-11-15 17:14:40 | 显示全部楼层 |阅读模式
本帖最后由 sme 于 2013-11-16 12:04 编辑

买了一块FPGA板,以前在spartan3/spartan6上好好的项目,弄到这块Artix-7上,出问题了。用片内逻辑分析仪抓了半天信号,发现是RAM问题,将电路反复复位(由上位机控制,在电路内部产生复位信号)、运行,RAM中的数据会变。
(RAM当程序ROM用,由上位机下载进去,下载完后不再更新。RAM速度为6~12MHz)。
1. 首选怀疑是不是电路有问题
  用100MHz的时钟来抓we信号,没有发现we有高电平。
2. 难道有毛刺?把we接成0,上位机不更新RAM,只在综合时将初始值置进去。
  仍然会出错。
3. 多放一片一样的RAM,地址、时钟、we全接一样,两片RAM的输出做个比较电路,以检测ROM内容是否发生变化。
  结果:会发生变化。即使we接0,也会。

我个人觉得,一片RAM,WE接地,但是初始化进去的数据却会随机改变,硬说是我电路的设计问题,我是无法接受的。

结论在16、21、22楼。

高手在民间啊。

厂家的技术,一会是软件问题,一会是IO问题,另外又是代码问题:
不要用parameter!
U_DLY的延时,仿真和综合结果会不一样!
1<<ADDR_WIDTH,这种写法不对!
mem文件和RAM深度不一致!

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2013-11-15 17:17:26 | 显示全部楼层


看图,两片RAM的输出,u_irom/dout和u_irom_ref/dout和code对比,有不一致的。



这个错得更多

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-11-15 17:23:21 | 显示全部楼层
本帖最后由 sme 于 2013-11-15 17:27 编辑

为了简单,我又做了实验,单独做了个工程,就放两片RAM和比较电路,并把它发给了厂家的技术人员。


附件里是源代码,高手可以看下。

使用这个电路,按板上的复位键,会随机出错(rom_err=1)

为了验证是不是我的板子有缺陷,让厂家也用他们手头的板子了试验,结果是:按复位键,rom_err会随机出现1。
和我的结果一样。

证明至少两边的板子是一样的现象。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-11-15 17:24:46 | 显示全部楼层


我的工程,用片内逻辑分析仪抓到的,两个RAM的输出出现不一致。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-11-15 17:25:50 | 显示全部楼层
厂家的答复是:

用他们自己的代码不会出现问题,我的问题是随机现象,是设计问题。

在这里高手看一下,我的设计到底有什么问题?

出0入0汤圆

 楼主| 发表于 2013-11-15 17:29:25 | 显示全部楼层
rom的描述:

`define        U_DLY        1
`timescale        1ns/1ns

module        c8051f_irom (
        clk,
        addr,
        di,
        we,
        oe,
        ce,
        dout
        );

        parameter        ADDR_W        =        14;
        parameter        BUS_W        =        8;
        parameter        ROM_FILE        =        "HIDtoUART.mem";
       
        input                        clk;
        input        [ADDR_W-1:0]        addr;
        input        [BUS_W-1:0]        di;
        input                        we;
        input                        oe;
        input                        ce;
        output        [BUS_W-1:0]        dout;

`ifdef        ASIC

`else
        reg                [BUS_W-1:0]        mem        [(1<<ADDR_W)-1:0];
        reg                [ADDR_W-1:0]        rd_addr;

        initial
        begin
                $readmemh(ROM_FILE,mem);
                $display("**************************************************************");
                $display("*                                                                                                                           *");
                $display("*  Read code file from file %s *",ROM_FILE);
                $display("*                                                                                                                           *");
                $display("**************************************************************");
    end

        always @(posedge clk)
        begin
                if (ce & we)
                        mem[addr]        <=        #`U_DLY di;
                rd_addr        <=        #`U_DLY addr;
        end
        assign        #`U_DLY        dout        =        (ce & oe) ? mem[rd_addr] : 8'h00;
`endif

endmodule

出0入0汤圆

发表于 2013-11-15 17:29:51 | 显示全部楼层
帮顶,等高手。。。

出0入0汤圆

 楼主| 发表于 2013-11-15 17:30:07 | 显示全部楼层
本帖最后由 sme 于 2013-11-15 17:32 编辑

rom的调用:

        wire        [7:0]        irom_read_data;
        wire        [7:0]        irom_ref_data;
       
        c8051f_irom #(`ROM_ADDR_WIDTH) u_irom (
                .clk                        (rom_clk),
                .addr                        (irom_addr[`ROM_ADDR_WIDTH-1:0]),
                .di                                (8'h00),        //        irom_addr[7:0]),
                .we                                (xween),   //      这引脚接到FPGA的引脚,用拔动开关,控制写信号是否有效。如果外部接到高电平,则ram内容全被全写成0,可以看到rom_err为高;当外部接低电平时,当ROM用
                .oe                                (1'b1),
                .ce                                (1'b1),
                .dout                        (irom_read_data)
        );
       
        c8051f_irom #(`ROM_ADDR_WIDTH) u_irom_ref (
                .clk                        (rom_clk),
                .addr                        (irom_addr[`ROM_ADDR_WIDTH-1:0]),
                .di                                (8'h00),
                .we                                (1'b0),    //      这个接成0,当ROM用
                .oe                                (1'b1),
                .ce                                (1'b1),
                .dout                        (irom_ref_data)
        );

出0入0汤圆

 楼主| 发表于 2013-11-15 17:30:47 | 显示全部楼层
两个rom 的输出进行比较:

`ifdef        ASYNC_RESET               
        always @(negedge rst_n2 or posedge rom_clk)
`else
        always @(posedge rom_clk)
`endif
        begin
                if (!rst_n2)
                        rom_err        <=        1'b0;
                else
                        rom_err        <=        irom_read_data != irom_ref_data;
        end

出0入0汤圆

发表于 2013-11-15 17:30:57 | 显示全部楼层
本来不想回帖,回了也是灌水。。。

出0入0汤圆

 楼主| 发表于 2013-11-15 17:34:46 | 显示全部楼层
WM_CH 发表于 2013-11-15 17:30
本来不想回帖,回了也是灌水。。。

电路很简单,用心去看,一定能了解。

出0入8汤圆

发表于 2013-11-16 00:53:00 | 显示全部楼层
除了Verilog,Waveform. FPGA还有很多东西,比如你这个问题需要赶紧看timing report.
我个人猜测主要问题出在:
reg                [BUS_W-1:0]        mem        [(1<<ADDR_W)-1:0];

这种写法,导致mem逻辑巨大。跑不到12M。

建议有三个:
  • 减小RAM尺寸,减小到1KBYE,从新实验,如果过了,那说明猜的没错。
  • 给CLK增加一条Clock约束,约到大于12M,然后再用12M做测试。
  • 芯片自带ROM/RAM的IP要用起来。

出0入0汤圆

 楼主| 发表于 2013-11-16 09:08:13 | 显示全部楼层
本帖最后由 sme 于 2013-11-16 09:10 编辑
uindex 发表于 2013-11-16 00:53
除了Verilog,Waveform. FPGA还有很多东西,比如你这个问题需要赶紧看timing report.
我个人猜测主要问题出 ...


谢谢你的回复,个人认为并不是以上原因。

1. 关于mem的写法,这个是没有问题的,只是定义了两个参数而已,用参数没理由就导致RAM巨大。
下面是xilinx的Language Template的写法:
   parameter RAM_WIDTH = <ram_width>;
   parameter RAM_ADDR_BITS = <ram_addr_bits>;
   
   (* RAM_STYLE="{AUTO | BLOCK |  BLOCK_POWER1 | BLOCK_POWER2}" *)
   reg [RAM_WIDTH-1:0] <ram_name> [(2**RAM_ADDR_BITS)-1:0];
   reg [RAM_WIDTH-1:0] <output_data>;

   <reg_or_wire> [RAM_ADDR_BITS-1:0] <address>;
   <reg_or_wire> [RAM_WIDTH-1:0] <input_data>;

   //  The following code is only necessary if you wish to initialize the RAM
   //  contents via an external file (use $readmemb for binary data)
   initial
      $readmemh("<data_file_name>", <rom_name>, <begin_address>, <end_address>);

   always @(posedge <clock>)
      if (<ram_enable>) begin
         if (<write_enable>)
            <ram_name>[<address>] <= <input_data>;
         <output_data> <= <ram_name>[<address>];
      end

由上可见,同样是使用的参数定义。
定义参是为了调用方便,没有规定不能用参数吧?1<<n 和2**n是一样的。我给的ADDR_W是的14,综合出来的就是16KB,结果并没有错。

2. 减小RAM尺寸
这个上班了我会再试。

3. 增加约束。
我是从spartan3/spartan6换到artix-7,这种跑1、20M时钟的电路,很轻易。
并且,我估的这个测试工程,就2片RAM,没有理由连12M都跑不到。

再,你看我在二楼的图片,我是用的100MHz的时钟来找取ROM的信号,ROM的速度完全没有问题。

4. 用IP
之所以不用IP,是为了移值方便。我自己做的东西,除了跟物理特性有关的,像DCM、PLL等,能不用IP尽量不用IP,这样换型号最方便。


做的这个测试工程,已经是精简至极,我觉得只要RAM的WE是无效的,没有理由RAM内容会变化。

之前我是整个项目出错,找了好久才发现是RAM的问题。通过片内逻辑分析仪可以确定,时序、速度都没问题,百思不得其解,然后才想到调用两次来比较结果,确认不是电路会存在误写导致数据出错。

出0入0汤圆

发表于 2013-11-16 10:47:08 | 显示全部楼层
这个地方 应该是时钟有毛刺引起的,你给了一个分频时钟,然后这个时钟可能有毛刺,导致ram的地址出现了亚稳态,然后ram里面的数据被修改了,ram应用中即使是不写使能不为1,只要是读写地址出现了亚稳态都会修改ram里面的数据,我建议LZ把时钟修改成时钟使能,而不是直接用作时钟

出0入0汤圆

 楼主| 发表于 2013-11-16 10:55:04 | 显示全部楼层
Fourier00 发表于 2013-11-16 10:47
这个地方 应该是时钟有毛刺引起的,你给了一个分频时钟,然后这个时钟可能有毛刺,导致ram的地址出现了亚稳 ...

嗯,兄弟这句话确实有一定的道理。

我有两个疑问:
1. 分频时钟有毛刺
个人认为这不太可能。不管是用同步分频,还是使用2分频的异步串联,只要最后抽出来的时钟,是从寄存器出来,都不可能有毛刺。

2. 分频电路如下:
`ifdef        ASYNC_RESET       
        always @(negedge rst_n or posedge clk100m)
`else
        always @(posedge clk100m)
`endif
        begin
                if (!rst_n)
                        div        <=        8'h00;
                else
                        div        <=        div + 1;
        end
        assign        rom_clk        =        div[2];                //        100MHz/8

这种除8的电路,应该是没有毛刺的。

出0入0汤圆

发表于 2013-11-16 10:59:55 | 显示全部楼层
还有一种可能就是你的异步复位没有做同步化引起的,同时时钟也不稳定,导致ram里面的数据被改写

出0入0汤圆

发表于 2013-11-16 11:00:39 | 显示全部楼层

  1. `define        ROM_ADDR_WIDTH        14
  2. `define        ASYNC_RESET                1

  3. module top (
  4.         input                        clk100m,
  5.         input                        rst,
  6.         input                        xween                /*        synthesis xc_pulldown = 1 */,
  7.         output                        rom_clk,
  8.         output        reg                rom_err
  9.         );
  10.        
  11.         reg                [7:0]        div;
  12.         reg                [2:0]        rst_n_ff;
  13.         wire                        rst_n;
  14.        
  15.        
  16.         reg   rst_1syn;
  17.         reg   rst_2syn;
  18.         wire  rst_n   ;
  19.         wire  rom_clk ;
  20.         always @(posedge clk100m)
  21.         begin
  22.                 rst_1syn <= ~rst;
  23.                 rst_2syn <= rst_1syn;
  24.         end
  25.         assign        rst_n        =rst_2syn;
  26.         always @(negedge rst_n or posedge clk100m)
  27.         begin
  28.                 if (!rst_n)
  29.                         div        <=        8'h00;
  30.                 else
  31.                         div        <=        div + 1;
  32.         end
  33.        
  34.         assign        rom_clk        =        (div[2:0] == 3'd0)?1'b1:1'b0;                //        100MHz/8
  35.        
  36.         reg                [`ROM_ADDR_WIDTH-1:0]        irom_addr;
  37.        
  38.         always @(negedge rst_n or posedge clk100m)
  39.         begin
  40.                 if (!rst_n)
  41.                         irom_addr        <=        0;
  42.                 else if(rom_clk == 1'b1)
  43.                         irom_addr        <=        irom_addr + 1;
  44.         end

  45.         wire        [7:0]        irom_read_data;
  46.         wire        [7:0]        irom_ref_data;
  47.        
  48.         c8051f_irom #(`ROM_ADDR_WIDTH) u_irom (
  49.                 .clk                        (clk),
  50.                 .addr                        (irom_addr[`ROM_ADDR_WIDTH-1:0]),
  51.                 .di                                (8'h00),        //        irom_addr[7:0]),
  52.                 .we                                (xween),
  53.                 .oe                                (1'b1),
  54.                 .ce                                (1'b1),
  55.                 .dout                        (irom_read_data)
  56.         );
  57.        
  58.         c8051f_irom #(`ROM_ADDR_WIDTH) u_irom_ref (
  59.                 .clk                        (clk),
  60.                 .addr                        (irom_addr[`ROM_ADDR_WIDTH-1:0]),
  61.                 .di                                (8'h00),
  62.                 .we                                (1'b0),
  63.                 .oe                                (1'b1),
  64.                 .ce                                (1'b1),
  65.                 .dout                        (irom_ref_data)
  66.         );
  67.        
  68.         always @(negedge rst_n or posedge clk100m)
  69.         begin
  70.                 if (!rst_n)
  71.                         rom_err        <=        1'b0;
  72.                 else
  73.                         rom_err        <=        irom_read_data != irom_ref_data;
  74.         end
  75.        
  76. endmodule
复制代码

出0入0汤圆

 楼主| 发表于 2013-11-16 11:01:44 | 显示全部楼层
Fourier00 发表于 2013-11-16 10:59
还有一种可能就是你的异步复位没有做同步化引起的,同时时钟也不稳定,导致ram里面的数据被改写
...

这个可能说到点子上了,我想想。

出0入0汤圆

 楼主| 发表于 2013-11-16 11:05:33 | 显示全部楼层
Fourier00 发表于 2013-11-16 11:00

我明白你的意思,使用使能的方式,有两个问题:
1. 与我的IC不符。
做IC时是有不少分频时钟的,做FPGA是为了ASIC的前期验证。

2. 这种方式,耗电会大不少,因为整个电路都是以最高频率在运行。当然,FPGA耗电大点无所谓。

出0入0汤圆

发表于 2013-11-16 11:15:48 | 显示全部楼层
sme 发表于 2013-11-16 11:05
我明白你的意思,使用使能的方式,有两个问题:
1. 与我的IC不符。
做IC时是有不少分频时钟的,做FPGA是 ...

FPGA 里面不推荐使用分频时钟的,做ASIC验证 应该有一定的规则来处理这种分频时钟的吧,比如说时钟使能,或者说分频出去在上锁相环然后上全局,我没有做过ASIC验证,所以不知道你们这些是怎么处理的,还有就是分频时钟其实分频了反转率降低了,动态功耗会下降,但是相比与直接的时钟降频来说,静态功耗还是会要高些

出0入0汤圆

 楼主| 发表于 2013-11-16 11:18:38 | 显示全部楼层
本帖最后由 sme 于 2013-11-16 11:32 编辑
Fourier00 发表于 2013-11-16 10:59
还有一种可能就是你的异步复位没有做同步化引起的,同时时钟也不稳定,导致ram里面的数据被改写
...


你说的这点,可能要从RAM的电路结构入手。

我曾经反向过由foundry提供的memory compiler出来的RAM,其原理、结构可能和FPGA里的block RAM一样。

同步RAM的信号,通常是CLK、CE、OE、WE、ADDR、DI。
OE在这里不考虑,只控制输出的buffer。
其它的信号,利用CLK来采样。
CLK的处理,最为关键。我看到的电路,是利用CLK产生一极窄的单击脉冲,来锁存输入信号。
ADDR、DI等输入信号的变化,在CLK边沿无效时,是不会影响电路的任何功能。
但在CLK的单击脉冲这段时间内,如果WE无效,是作读操作,由ADDR来确定选中的RAM单元。
一个RAM单元一般都是6T结构,同一时刻,其bit line选中的同一列中,只能选中一行,如果选中了多行,就可能会改写数据。
如果此时ADDR在变化,就会出现word line选择的毛刺,可能有多行被选中。

回到我的电路:
rom_clk是12.5MHz,其地址线也是由rom_clk计数产生,因此不管地址和时钟是用同一沿,或是分别用上升、下降沿,其setup/hold都满足。
并且,rom_clk应该也无毛刺。

问题出在复位上。
当异步复位发生时,有可能正好发生在rom_clk的有效沿,而此时ADDR也会复位。这一组ADDR在此时的变化,会导致Setup/hold不满足,从而使RAM的WE即使无效,其数据也有可能被改。

出0入0汤圆

发表于 2013-11-16 11:45:49 | 显示全部楼层
亚稳态修改ram

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-11-16 11:54:48 | 显示全部楼层
Fourier00 发表于 2013-11-16 11:45
亚稳态修改ram

嗯,应该就是这个问题。

出0入0汤圆

发表于 2013-11-16 16:16:06 | 显示全部楼层
菜鸟一枚,只是来学习的!谢谢高手分享~

出0入0汤圆

发表于 2013-11-16 22:33:45 | 显示全部楼层
楼主公布一下修改后的测试结果把;

出0入0汤圆

 楼主| 发表于 2013-11-17 08:06:59 | 显示全部楼层
jm2011 发表于 2013-11-16 22:33
楼主公布一下修改后的测试结果把;

已经通过测试,就是异步复位的原因。

出0入0汤圆

发表于 2013-11-17 08:26:28 | 显示全部楼层
菜鸟观摩了!

出0入0汤圆

发表于 2013-11-17 09:09:43 | 显示全部楼层
呵呵,异步复位同步释放。话说楼主不是在广告区做mcu ic定制的那位?

出0入0汤圆

 楼主| 发表于 2013-11-17 09:32:52 | 显示全部楼层
winster321 发表于 2013-11-17 09:09
呵呵,异步复位同步释放。话说楼主不是在广告区做mcu ic定制的那位?

嗯,是的。

这个问题,异步复位、同步释放,也是解决不了的。和异步复位、异步释放比起来,只是将出错机率减少了50%。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 05:24

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表