状态机跑飞的例子

来源:互联网 发布:手机淘宝卖东西怎么弄 编辑:程序博客网 时间:2024/05/19 23:53

例子1:

调这个nrf24l01模块差不多半个月的时间了,期间真是千难万阻,困难重重啊!每每以为调通了时候,一测试,不是发送不行了就是接收不行了,或者是时间一长就莫名其妙地断开了,再也不能自动连接上!

我将发送和接收写在同一个模块里,通过模式切换信号来切换,一开始就是用使能了自动应答的方式来调试的,代码前前后后改写了个无数版本。最痛苦的是刚开始就使用Signaltap II来调试的,谁知signaltap II并不如官方宣传的那么好用,简直是个大坑,会对需要进行采集的信号产生莫名其妙的影响,就算用增量编译好像也改善不了!我调试时用它采集一个通知spi模块开始写数据的使能信号en_singnal,结果工作就不正常了,从采集到的信号上看是在一个状态里其他的赋值语句都成功了,唯独en_signal不成功,由于是新手,根本就没怀疑到是singaltap ii的问题,还以为是射频模块会对FPGA芯片产生干扰,导致电路异常。

    不断的调,最后是在有些频道发送能成功,接收不成功;而在另一些频道接收能成功,发送不成功。真是一筹莫展啊!各种问题都想到了,包括状态机跑飞的情况!但还是疏忽了中断信号这个幕后的大boss,一切都是它在捣鬼。原以为只是在状态机里判断中断信号的电平而不是脉冲,所以不用寄存器打拍子进行同步应该是没问题的。结果问题就出在这,用寄存器试着打了三拍后再进行判断,问题解决了!

    哎,这种心情一言难尽啊!


例子2:

用的是xilinx的spatan 3a
发现有个状态机工作不正常:
1.当我用ont-hot编码的时候,用chipscope观察,出现全是0的现象,我在状态机的when others中也加了状态的回复,但是还是不行。
2.然后我换了gray编码,这次状态停到了“011”就不走了,而这个状态仅仅起到一个延迟作用,没有任何条件语句。


程序平时是没有问题的,大概运行300次左右就出现一次跑飞。用fpga1年了,属于初学者,从来没有遇到过这种问题。

请教个位高手,如何解决?
以下是代码
p_reg2:process(S_Lclk,reset)
begin
if (reset='0') then
     state1<=0;
     S_ccs<='Z';
     S_ads_o<='Z';
     S_blast_o<='Z';  
     S_wr_o<='Z';
     S_la_o<=(others=>'Z');
     S_command<=(others=>'Z');
     S_command_en<='1';
elsif rising_edge (S_Lclk) then
     case state1 is
         when 0 =>
             if S_PCI_usero='0' then
               S_ads_o<='1';
               state1<=1;
            else
               S_ccs<='Z';
                S_ads_o<='Z';
                S_blast_o<='Z';  
                S_wr_o<='Z';
                  S_la_o<=(others=>'Z');
                 S_command<=(others=>'Z');
               S_command_en<='1';
            end if;
      when 1 =>
          S_ccs<='0';
         S_ads_o<='0';
         S_wr_o<='0';
         S_la_o<=G_C8;
         state1<=2;
     when 2 =>
        S_ccs<='Z';
        S_ads_o<='1';
        S_blast_o<='0';
        state1<=3;
     when 3 =>
        S_ccs<='Z';   
        state1<=4;
    when 4=>
       if S_ready_i='0' then
         S_command<=pci_ld;
         S_command_en<='0';
         state1<=5;
      else
         null;
       end if;
     when 5=>
       state1<=6;   
   when 6 =>
       if S_PCI_usero='1' then
          S_command_en<='1';
         state1<=0;
      else
        null;
      end if;
      S_blast_o<='Z';  
      S_wr_o<='Z';
      S_ads_o<='Z';
    when others =>
      state1<=0;

   end case;
else
  null;
end if;
end process p_reg2;

这个进程的时钟是我用40M分频产生的(不是用DCM,就是写了个简单的分频代码,即如果上升沿A<=not A),
它即作为本进程的时钟,又作为外部PCI LOCAL总线的时钟。
其它的进程采用的是40M时钟
状态机编码类型是在ise的综合选项中选的。


上述问题的解决方法:

问题解决了!十分感谢夏老师!
就像夏老师说的一样,我将状态机中外部的信号和它的时钟进行了一下同步
p_reg2_1: process(S_Lclk)
begin
        if rising_edge(S_Lclk) then
                S_PCI_usero<=PCI_usero;
                S_ready_i<=ready;
        else
                null;
        end if;
问题就解决了!


解答1:夏宇闻

两种可能:1)状态机的输入信号与本地时钟不同步,出现了冒险竞争现象,造成状态机死锁。
                   2)状态机综合后没有生成一旦进入非有效状态便立即复位,然后进入某个有效状态的电路。
解决办法:1)把外部引入的异步输入信号,做同步处理,作为本状态机的输入。
                   2)用综合指令或者约束,强行规定综合后必须生成一旦进入非有效状态便立即复位随即进入有效状态的电路。

我所说的输入信号是指除了从当前状态反馈信号以外的信号,即从状态机外部输入的信号。
是否会产生一旦进入非有效状态立即进行强制复位的电路,并不会因为你在状态机中加入when others=> state1 综合后就一定生成这样的电路。若想生成这样的电路,必须在综合时要通过综合指令(约束)命令综合器强制生成,才会生成的。


不同的综合工具所用的综合指令(或者属性 attributes)的写法是不同的。
例如QuartusII 中可在定义状态变量的寄存器之前或之后用
(* syn_encoding = "safe, one-hot " *)reg[9:0] state ;  Verilog 2001支持的 或者
  reg [9:0] state /* syn_encoding = "safe, one-hot " */ ;  Verilog 1995也支持
看似注释语句的综合指令,强行命令综合器生成复位逻辑。这时,default分支项的定义才能真的起作用。我写的具体细节不一定对,您可以用Synthesis attributes做关键字在帮助搜寻中查有关细节。综合指令常用的有5-6条,一般情况下用默认的就可以了,只有非常情况下才需要使用。


解答2:

状态机跑飞,不是天灾,是人祸;  用状态机进行代码描述电路的时候需要注意几点:

 

1.  状态机编码要用ONE-HOT 或格雷编码, 避免冒险和竞争;

2.  状态机要用FSM, 有限状态机, 不用状态需要复位;

3.  要采用三段式描述风格, 不要采用一段式描述.




原创粉丝点击