1. 程式人生 > >並行資料流轉化為一種特殊序列資料流模組的設計

並行資料流轉化為一種特殊序列資料流模組的設計

       設計兩個可綜合的電路模組:第一個模組(M1)接受四位並行資料,並將其轉化為簡化I2C傳輸格式。sclk為輸入主鍾,data[3:0]為輸入的四位資料,ack為請求傳送資料訊號(請求後才有資料傳送到data[3:0]),資料流用scl和sda兩條線傳輸。第二個模組(M2)接收以簡化I2C協議通過scl和sda傳輸來的資料,並轉化為相應16條訊號線上的高電平,若資料為1,則第一條線路為高電平,資料為n,則第N條線路為高電平。模組如下圖所示。

        本文引用自https://blog.csdn.net/llxxyy507/article/details/81046981


       簡化的I2C通訊協議如下:scl為時鐘訊號,當scl為高電平的時候,sda從高電平變為低電平,表示序列資料流開始傳輸;當scl為高電平,sda從低電平變為高電平的時候,表示序列資料流結束。sda訊號只能在scl為低電平的時候變化,在scl為高電平期間應該維持穩定。


       上圖中,sda訊號在scl為高時從高變低,為資料流的開始。在scl為低電平時傳輸第一位資料(MSB),並在整個scl為高的期間都維持訊號的穩定,接著傳遞剩下的資料。sda訊號在scl為高時從低變高,表示資料流的結束。

       模組M1的verilog程式碼(ptosda.v)如下:

module ptosda(sclk,rst,data,ack,scl,sda);
input sclk,rst,data;
wire [3:0]data;

output scl,sda,ack;
reg scl,ack,link_sda,sdabuf;
reg [3:0]databuf;
reg [7:0]state;

out16hi m2(.scl(scl), .sda(sda), .outhigh() );    //呼叫M2模組

assign  sda = link_sda ? sdabuf : 1'b0;        //link_sda控制sdabuf輸出到序列總線上

parameter  ready  =  8'b0000_0000,
           start  =  8'b0000_0001,
           bit1   =  8'b0000_0010,
           bit2   =  8'b0000_0100,
           bit3   =  8'b0000_1000,
           bit4   =  8'b0001_0000,
           bit5   =  8'b0010_0000,
           stop   =  8'b0100_0000,
           IDLE   =  8'b1000_0000;

always @(posedge sclk or negedge rst)         //主鍾sclk產生序列輸出時鐘clk
       begin
              if (!rst)
                scl <= 1;
              else
                scl <= ~scl;
       end

always @(posedge ack)
       databuf <= data;

always @(negedge sclk or negedge rst)
       if (!rst)
           begin
                 link_sda <= 0;
                 state <= ready;
                 sdabuf <= 1;
                 ack <= 0;
           end
        else  
           begin
              case(state)
              ready : if(ack) 
                        begin 
                           link_sda <= 1;
                           state <= start;
                        end
                      else
                        begin
                           link_sda <= 0;
                           state <= ready;
                           ack <= 1;
                        end
               
               start : if(scl && ack)
                         begin 
                            sdabuf <= 0;
                            state <= bit1;
                         end
                       else
                         state <= start;

                bit1  : if(!scl)
                          begin
                             sdabuf <= databuf[3];
                             state <= bit2;
                             ack <= 0;
                          end
                         else
                          state <= bit1;
                            
                bit2  : if(!scl)
                          begin
                             sdabuf <= databuf[2];
                             state <= bit3;
                          end
                         else
                          state <= bit2;
                            
                bit3  : if(!scl)
                          begin
                             sdabuf <= databuf[1];
                             state <= bit4;
                          end
                         else
                          state <= bit3;
                            
                bit4  : if(!scl)
                          begin
                             sdabuf <= databuf[0];
                             state <= bit5;
                          end
                         else
                          state <= bit4;
                            
                bit5  : if(!scl)
                          begin
                             sdabuf <= 0;
                             state <= stop;
                          end
                         else
                          state <= bit5;
                            
                stop  : if(scl)
                          begin
                             sdabuf <= 1;
                             state <= IDLE;
                          end
                         else
                          state <= stop;
                            
                IDLE  :  begin
                             link_sda <= 0;
                             state <= ready;
                          end
                            
               default  : begin
                             link_sda <= 0;
                             sdabuf <= 1;
                            state <= ready;
                          end
             endcase
          end
endmodule

        模組M2(out16hi.v)verilog程式碼如下:

module out16hi(scl,sda,outhigh);
input scl,sda;
output [15:0]outhigh;

reg [4:0]mstate;
reg [3:0]pdata,pdatabuf;
reg [15:0]outhigh;
reg StartFlag,EndFlag;              //序列資料開始和結束標誌

always @(negedge sda)
     begin
       if (scl)
           StartFlag <= 1;
       else if (EndFlag)
           StartFlag <= 0;
     end

always @(posedge sda)
       if (scl)
          begin
            EndFlag <= 1;
				pdatabuf <= pdata;
          end
       else
            EndFlag <= 0;
       
parameter sbit0 = 5'b0_0001,
          sbit1 = 5'b0_0010,
          sbit2 = 5'b0_0100,
          sbit3 = 5'b0_1000,
          sbit4 = 5'b1_0000;

always @(pdatabuf)                              //接受到的資料轉化為相應的輸出位的高電平
       begin
         case(pdatabuf)
             4'b0001: outhigh = 16'b0000_0000_0000_0001; 
             4'b0010: outhigh = 16'b0000_0000_0000_0010; 
             4'b0011: outhigh = 16'b0000_0000_0000_0100; 
             4'b0100: outhigh = 16'b0000_0000_0000_1000; 
             4'b0101: outhigh = 16'b0000_0000_0001_0000; 
             4'b0110: outhigh = 16'b0000_0000_0010_0000; 
             4'b0111: outhigh = 16'b0000_0000_0100_0000; 
             4'b1000: outhigh = 16'b0000_0000_1000_0000; 
             4'b1001: outhigh = 16'b0000_0001_0000_0000; 
             4'b1010: outhigh = 16'b0000_0010_0000_0000; 
             4'b1011: outhigh = 16'b0000_0100_0000_0000; 
             4'b1100: outhigh = 16'b0000_1000_0000_0000; 
             4'b1101: outhigh = 16'b0001_0000_0000_0000; 
             4'b1110: outhigh = 16'b0010_0000_0000_0000; 
             4'b1111: outhigh = 16'b0100_0000_0000_0000; 
             4'b0000: outhigh = 16'b1000_0000_0000_0000; 
          endcase
         end

always @(posedge scl)
       if (StartFlag)
          case(mstate)
              sbit0 : begin
                        mstate <= sbit1;
                        pdata[3] <= sda;
                      end

              sbit1 : begin
                        mstate <= sbit2;
                        pdata[2] <= sda;
                      end

              sbit2 : begin
                        mstate <= sbit3;
                        pdata[1] <= sda;
                      end

              sbit3 : begin
                        mstate <= sbit4;
                        pdata[0] <= sda;
                      end

              sbit4 : begin
                        mstate <= sbit0;
                      end
 
              default : mstate <= sbit0;

           endcase
      else   mstate <= sbit0;
endmodule

testbench檔案(sigdata_test.v)內容如下:

`timescale 1ns/1ns
`define halfperiod 50

module sigdata_test(rst,sclk,data,ack_for_data,sda,scl,outhigh);
output rst;
output [3:0]data;
output sclk;
input ack_for_data;
reg rst,sclk;
reg [3:0]data;

output sda,scl,outhigh;
wire sda;
wire scl;
wire [15:0]outhigh;

ptosda m1(.sclk(sclk), .rst(rst), .data(data), .ack(ack_for_data), .scl(scl), .sda(sda) );
out16hi m2(scl,sda,outhigh);

initial
      begin
          rst = 1;
        #10 rst = 0;
        #(`halfperiod*2+3) rst = 1;
      end

initial
      begin
          sclk = 0;
          data = 0;
          #(`halfperiod*1000) $stop;
      end

always #(`halfperiod) sclk = ~sclk;

always @(posedge ack_for_data)
       begin
          #(`halfperiod/2 + 3) data = data + 1;
       end

endmodule

        模擬的結果如下:


        加入中間變數檢視結果得到如下,可以看出data[3:0]資料準確的傳入到了pdatabuf[3:0],並通過outhigh準確輸出了對應訊號線的高電平。