2021年5月2日 星期日

HBLbits_Verilog Basic_Fsm serial

HBLbits_Verilog Basic_Fsm serial 

In many (older) serial communications protocols, each data byte is sent along with a start bit and a stop bit, to help the receiver delimit bytes from the stream of bits. One common scheme is to use one start bit (0), 8 data bits, and 1 stop bit (1). The line is also at logic 1 when nothing is being transmitted (idle).

Design a finite state machine that will identify when bytes have been correctly received when given a stream of bits. It needs to identify the start bit, wait for all 8 data bits, then verify that the stop bit was correct. If the stop bit does not appear when expected, the FSM must wait until it finds a stop bit before attempting to receive the next byte.

Some timing diagrams



在許多(較舊的)串列通信協定中,每個資料位元組都與起始位元和停止位一起發送,以幫助接收器從位元流中分隔位元組。 一種常見的方案是使用一個起始位(0),8個資料位元和1個停止位(1)。 當沒有任何傳輸(空閒)時,線路也處於邏輯1

 設計一個有限狀態機,當給定位元流時,它將識別何時正確接收了位元組。 它需要標識起始位元,等待所有8個資料位元,然後驗證停止位是否正確。 如果在預期的情況下沒有出現停止位元,則FSM必須等待直到找到停止位,然後再嘗試接收下一個位元組。

 

狀態轉移圖

根據描述,我們設計一個狀態轉移圖:


module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 
   parameter stop = 0,b0=1,b1=2,b2=3,b3=4,b4=5, b5=6,b6=7,b7=8,stop_ok=9,stop_notok=10,start = 11;
    //parameter idle = 0,start = 1,b0=2,b1=3,b2,=4,b3,b4,b5,b6,b7,stop;


    reg [4:0]state ,next;
    
    always @(*)
        begin
            case(state)
                stop:next = (~in)? start:stop;
                start: next = b0;
                b0: next =b1;
                b1: next = b2;
                b2: next = b3;
                b3: next = b4;
                b4: next = b5;
                b5: next = b6;
                b6: next = b7;
                b7: next = in?stop_ok:stop_notok;
                //stop: next = in?stop_ok: idle;
                stop_ok: next = (~in)?start:stop;
                stop_notok: next = in?stop:stop_notok;
            endcase
        end
    
    always @(posedge clk)
        begin
            if (reset)
                state <= stop;
            else
                state <= next;
        end
    
    assign done =(state ==stop_ok);
endmodule

另一方法

要注意的是最後一步的設計,也就是STOP狀態之後的判斷如果輸入資料為1,則資料接受結束,給出接受完畢信號done;否則的話,我們不得不等到結束位元標誌1之後才能進入下一串資料的接收,且一旦進入這種情況,則拋棄這一串資料的接受,也即不會產生接受完畢信號done
 
最後不得不說的是,Uart接受協議可以有多個結束位元,甚至還可以有校驗位等,一旦確認了協議,我們就可以編寫類似的代碼來實現資料的接收。

module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 
parameter stop = 0,b0=1,b1=2,b2=3,b3=4,b4=5,b5=6,b6=7,b7=8,stop_ok=9,stop_notok=10,start = 11;
    //parameter idle = 0,start = 1,b0=2,b1=3,b2,=4,b3,b4,b5,b6,b7,stop;
    reg [4:0]state ,next;
    
    always @(*)
        begin
            case(state)
                stop:next = (~in)? start:stop;
                start: next = b0;
                b0: next =b1;
                b1: next = b2;
                b2: next = b3;
                b3: next = b4;
                b4: next = b5;
                b5: next = b6;
                b6: next = b7;
                b7: next = in?stop_ok:stop_notok;
                //stop: next = in?stop_ok: idle;
                stop_ok: next = (~in)?start:stop;
                stop_notok: next = in?stop:stop_notok;
            endcase
        end
    
    always @(posedge clk)
        begin
            if (reset)
                state <= stop;
            else
                state <= next;
        end
    
    assign done =(state ==stop_ok);
endmodule

很多串列通信協定發送過程中會在資料位元組前後增加標記來標識位元組首尾,即包含 start 位和 stop 位元,比如 UART 協議就是這樣。該題就類比了這種類型協議的接收端行為。這裡開始的標記是低電平,結束的標記是高電平,在開始和結束之間傳輸的 bit 位元為8即一個位元組,這是正確接收的條件,當滿足該條件後會在 stop 位元後面的時鐘沿給出 done 的輸出標記。如果不滿足該條件,比如起始 start 條件不滿足,則會一直等待知道接收到低電平信號才開始;又如 start 開始後,中間的位數超過了8 bit,即8 bit 後一直是低電平信號,不出現高電平的 stop 信號,則 receiver 繼續等待知道出現高電平位才結束,但這是一個錯誤接收,不會給出 done 的輸出標記。波形圖如下所示。

 設計了五個狀態,分別是 IDLE, START, DATA, STOP, ERROR。狀態機如下圖所示(畫圖畫的,湊合看吧)。這裡控制狀態轉移的有輸入信號 in 和自訂的計數器 cnt,計數器用於計數 start stop 之間的位元數是資料是否滿足1 bytecnt的條件判斷只用在 DATA 狀態中,在 DATA 狀態時,cnt 實行計數,當 cnt 8時表示真正的資料夠了,此時再比較輸入 in,如果 in 為高電平則資料接收正常,跳轉至 STOP,否則表示出現錯誤,進入 ERROR。跳出 ERROR 的條件是輸入in出現高電平。這裡需要注意 STOP 狀態可以直接跳轉至 START 狀態,即 in 為高電平後緊接著出現低電平情況,如果輸入 in 為連續的幾個高電平,則 STOP 會進入 IDLE 等待低電平到來。另外這裡的 START 狀態應該可以合併到 DATA 狀態中實現狀態機化簡,可以試試。


module top_module(
    input clk,
    input in,
    input reset,    // Synchronous reset
    output done
); 

    localparam idle = 0;
    localparam start = 1;
    localparam data = 2;
    localparam stop =3;
    localparam error = 4;
    
    reg[2:0] state, next_state;
    reg[3:0] cnt;
    reg done_r;
    
//transition
    always@(*)begin
        case(state)
            idle:next_state=in?idle:start;
            start:next_state=data;
            data:next_state=(cnt==8)?(in?stop:error):data;
            stop:next_state=in?idle:start;
            error:next_state=in?idle:error;
        endcase
    end
    
//state
    always@(posedge clk)begin
        if(reset)
            state <= idle;
        else
            state <= next_state;
    end
    
//cnt
    always@(posedge clk)begin
        if(reset)
            cnt<=0;
        else
            case(next_state)
                start:cnt<=0;
                data:cnt<=cnt+1;
                default:cnt<=cnt;
            endcase
    end
    
//done_r
    always@(posedge clk)
        case(next_state)
            stop:done_r <= 1;
            default:done_r <= 0;
        endcase
    
    assign done = done_r;
    
endmodule

沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...