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 + 1'b1;
 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 <= 1'b0;
 44         led <= 1'b0;
 45         abcd <= 4'b1110;
 46         end
 47         else begin
 48             case (state)
 49                 2'b00 : begin
 50                     if(nedge)begin
 51                         state <= 2'b01;
 52                         en_cnt <= 1'b1;
 53             abcd <= 4'b01;
 54                     end
 55                     else begin
 56                         state <= 2'b00;
 57             abcd <= 4'b10;
 58             end
 59                 end 
 60                 2'b01 : begin
 61                     if(cnt >= 999999)begin
 62                         en_cnt <= 1'b0;
 63                         state <= 2'b10;
 64             abcd <= 4'b11;
 65                     end
 66                     else if(pedge)begin
 67                         en_cnt <= 1'b0;
 68                         state <= 2'b00;
 69             abcd <= 4'b100;
 70                     end
 71             else begin
 72             state <= state;
 73             end
 74                 end
 75                 2'b10 : begin
 76                     if(pedge)begin
 77                         state <= 2'b11;
 78                         en_cnt <= 1'b1;
 79             abcd <= 4'b101;
 80                     end
 81                     else begin
 82                         state <= 2'b10;
 83             abcd <= 4'b110;
 84                     end
 85                 end
 86                 2'b11 : begin
 87                     if(cnt >= 999999)begin
 88             led <= led + 1'b1;
 89             //led <= 4'b0011;
 90                         en_cnt <= 1'b0;
 91                         state <= 2'b00;
 92             abcd <= 4'b111;
 93                     end
 94                     else if(nedge)begin
 95                         en_cnt <= 1'b0;
 96                         state <= 2'b10;
 97             abcd <= 4'b1000;
 98                     end
 99             else begin
100             state <= state;
101             end
102                 end
103                 default: begin
104                 state <= 2'b00;
105             abcd <= 4'b1111;
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 <= 1'b0;
 5               key_in_sb <= 1'b0;
 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 <= 1'b0;
17               pre_keyb <= 1'b0;
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

(4)按鍵亞穩態解決方案的原理

亞穩態其實就是數據的轉變沒有符合時鍾采樣所需要的setup/hold時間,在時鍾的上升沿或下降沿到來時正好采到數據的變化狀態。此時,由於數據並沒有穩定,所以會導致采到的數據不停變化,而不是邏輯0或邏輯1.此時采到的數據會一直抖動,直至隔一段時間穩定。

兩級觸發器可防止亞穩態傳播的原理:假設第一級觸發器的輸入不滿足其建立保持時間,它在第一個脈沖沿到來后輸出的數據就為亞穩態,那么在下 一個脈沖沿到來之前,其輸出的亞穩態數據在一段恢復時間后必須穩定下來,而且穩定的數據必須滿足第二級觸發器的建立時間,如果都滿足了,在下一個脈沖沿到 來時,第二級觸發器將不會出現亞穩態,因為其輸入端的數據滿足其建立保持時間。
原文鏈接:https://blog.csdn.net/dongdongnihao_/article/details/79590213

參考鏈接:https://www.cnblogs.com/amanlikethis/p/3721968.html

參考鏈接:https://blog.csdn.net/emperor_strange/article/details/82491085


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM