FPGA状态机跑飞问题记录

Posted cnlntr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FPGA状态机跑飞问题记录相关的知识,希望对你有一定的参考价值。

(1)状态机跑飞的原因

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

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

(2)问题记录

本次的状态机跑飞的原因是第一种,即:状态机的输入信号与本地时钟不同步,出现了冒险竞争现象,造成状态机死锁

实验:使用状态机按键防抖,实现二进制累加,二进制的表现形式为四个LED灯

最初代码:(注:变量abcd没有任何意义,仅在调试中使用)

  1 module key_detect(
  2     clk    ,
  3     rst_n  ,
  4     key    ,
  5     led    ,
  6     abcd   ,
  7     );
  8 
  9     //参数定义
 10     parameter           DATA_W =            4;
 11     //输入信号定义
 12     input               clk;
 13     input               rst_n;
 14     input               key;
 15     //输出信号定义  
 16     output[DATA_W-1:0]  led;
 17     output[3:0]                abcd;
 18     //输出信号reg定义   
 19     reg  [DATA_W-1:0]  led;
 20     reg  [3:0]         abcd;
 21     //中间信号定义  
 22     reg                 pre_key;
 23     wire                nedge;
 24     wire                pedge;
 25 
 26     reg    [20:0]       cnt;
 27     reg                 en_cnt;
 28     reg    [1:0]        state;
 29     always @(posedge clk or negedge rst_n)begin
 30         if(!rst_n)begin
 31             cnt <= 0;
 32         end
 33         else if(en_cnt)begin
 34         cnt <= cnt + 1b1;
 35         end
 36         else
 37         cnt <= 0;
 38     end
 39     
 40     //时序逻辑写法
 41     always@(posedge clk or negedge rst_n)begin
 42         if(!rst_n)begin
 43             state <= 1b0;
 44         led <= 1b0;
 45         abcd <= 4b1110;
 46         end
 47         else begin
 48             case (state)
 49                 2b00 : begin
 50                     if(nedge)begin
 51                         state <= 2b01;
 52                         en_cnt <= 1b1;
 53             abcd <= 4b01;
 54                     end
 55                     else begin
 56                         state <= 2b00;
 57             abcd <= 4b10;
 58             end
 59                 end 
 60                 2b01 : begin
 61                     if(cnt >= 999999)begin
 62                         en_cnt <= 1b0;
 63                         state <= 2b10;
 64             abcd <= 4b11;
 65                     end
 66                     else if(pedge)begin
 67                         en_cnt <= 1b0;
 68                         state <= 2b00;
 69             abcd <= 4b100;
 70                     end
 71             else begin
 72             state <= state;
 73             end
 74                 end
 75                 2b10 : begin
 76                     if(pedge)begin
 77                         state <= 2b11;
 78                         en_cnt <= 1b1;
 79             abcd <= 4b101;
 80                     end
 81                     else begin
 82                         state <= 2b10;
 83             abcd <= 4b110;
 84                     end
 85                 end
 86                 2b11 : begin
 87                     if(cnt >= 999999)begin
 88             led <= led + 1b1;
 89             //led <= 4‘b0011;
 90                         en_cnt <= 1b0;
 91                         state <= 2b00;
 92             abcd <= 4b111;
 93                     end
 94                     else if(nedge)begin
 95                         en_cnt <= 1b0;
 96                         state <= 2b10;
 97             abcd <= 4b1000;
 98                     end
 99             else begin
100             state <= state;
101             end
102                 end
103                 default: begin
104                 state <= 2b00;
105             abcd <= 4b1111;
106         end
107             endcase
108         end
109     end
110 
111     always @(posedge clk)begin
112         pre_key <= key;
113     end
114     //检测下降沿
115     assign nedge = !key && pre_key;
116     //检测上升沿
117     assign pedge = key && !pre_key;                        

出现的问题:

以上代码在仿真中没有发现问题

但是,将程序下载进FPGA电路板中,发现在随机一次按键按下去之后,LED灯保持当前这个状态在其后不管按几次按键都无法改变LED灯的状态

随后使用quartus自带的逻辑笔进行调试

技术图片

 

 在出错的时序中,状态机的状态都转为无效

 因此,推断是状态机跑飞的原因->key按键输入信号与本地时钟不同步

(3)问题的解决方案

将检测按键上跳沿与下降沿的程序进行异步信号同步化

出错代码:

技术图片
1     always @(posedge clk)begin
2         pre_key <= key;
3     end
4     //检测下降沿
5     assign nedge = !key && pre_key;
6     //检测上升沿
7     assign pedge = key && !pre_key;
edge_detect

异步信号同步化代码:

技术图片
 1 reg key_in_sa,key_in_sb;
 2      always @(posedge clk or negedge rst_n)begin
 3          if(!rst_n)begin
 4               key_in_sa <= 1b0;
 5               key_in_sb <= 1b0;
 6          end
 7          else begin
 8               key_in_sa <= key;
 9               key_in_sb <= key_in_sa;
10          end
11      end
12      
13      reg pre_keya,pre_keyb;
14     always @(posedge clk or negedge rst_n)begin
15          if(!rst_n)begin
16               pre_keya <= 1b0;
17               pre_keyb <= 1b0;
18          end
19          else begin
20               pre_keya <= key_in_sb;
21               pre_keyb <= pre_keya;
22          end
23       end
24     //检测下降沿
25     assign nedge = !pre_keya && pre_keyb;
26     //检测上升沿
27     assign pedge = pre_keya && !pre_keyb;
edge_detect

参考代码原文链接:https://www.cnblogs.com/xiaomeige/p/5500964.html

 

以上是关于FPGA状态机跑飞问题记录的主要内容,如果未能解决你的问题,请参考以下文章

FPGA/数字IC手撕代码4——FSM状态机的简单应用

FPGA 串口通信

fpga至简设计法四段式状态及原理是啥?

HAL库常见报错:程序跑飞后使用Debug定位问题点

HAL库常见报错:程序跑飞后使用Debug定位问题点

VSCode自定义代码片段13——Vue的状态大管家