verilogシリアルポートが複数のデータを受信して処理する実現方法

18365 ワード

シリアルポートを用いて複数のデータを受信して処理する問題について、現在ネット上に存在するverilogシリアルポート通信に関する資料は、シリアルポートを用いて単一文字の受信と送信を実現することを説明するものである.一方、シリアルポートを使用して通信する場合、データ端子はシリアルポートを通じて多くのデータを受信し、すべてのデータが受信されたり、何らかの条件に達したりした後、自分の後続の仕事を開始する必要があります.だからここで私は自分のいくつかの具体的な実現過程とverilogソースコードを分かち合って、みんなに役に立つことを望んでいます.(ここではシリアルポートを利用してデータを受信して処理する部分だけを話して、その部分を送信してから共有します)まずインターネット上の多くのシリアルポートで受信したコードを貼って、以下のようにします.
module my_uart_rx(
                clk,rst_n,
                rs232_rx,rx_data,rx_int,
                clk_bps,bps_start
            );

input clk;      // 50MHz   
input rst_n;    //       
input rs232_rx; // RS232      
input clk_bps;  // clk_bps                    
output bps_start;       //      ,           
output[7:0] rx_data;    //       ,            
output rx_int;  //        ,             

//----------------------------------------------------------------
reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;    //       ,   
wire neg_rs232_rx;  //           

always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) begin
            rs232_rx0 <= 1'b0;
            rs232_rx1 <= 1'b0;
            rs232_rx2 <= 1'b0;
            rs232_rx3 <= 1'b0;
        end
    else begin
            rs232_rx0 <= rs232_rx;
            rs232_rx1 <= rs232_rx0;
            rs232_rx2 <= rs232_rx1;
            rs232_rx3 <= rs232_rx2;
        end
end
    //            <20ns-40ns   (           ),
    //          (                ,           ) 
    //(                   40ns )
assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;    //       neg_rs232_rx        

//----------------------------------------------------------------
reg bps_start_r;
reg[3:0] num;   //    
reg rx_int;     //        ,             

always @ (posedge clk or negedge rst_n)
    if(!rst_n) begin
            bps_start_r <= 1'bz;
            rx_int <= 1'b0;
        end
    else if(neg_rs232_rx) begin     //        rs232_rx        
            bps_start_r <= 1'b1;    //          
            rx_int <= 1'b1;         //          
        end
    else if(num==4'd11) begin       //          ///      num        11.   12!!
            bps_start_r <= 1'b0;    //      ,         
            rx_int <= 1'b0;         //          
        end

assign bps_start = bps_start_r;

//----------------------------------------------------------------
reg[7:0] rx_data_r;     //         ,           
//----------------------------------------------------------------

reg[7:0] rx_temp_data;  //         

always @ (posedge clk or negedge rst_n)
    if(!rst_n) begin
            rx_temp_data <= 8'd0;
            num <= 4'd0;
            rx_data_r <= 8'd0;
        end
    else if(rx_int) begin   //      
        if(clk_bps) begin   //       ,          ,8bit  ,1 2         
                num <= num+1'b1;
                case (num)
                        4'd1: rx_temp_data[0] <= rs232_rx;  //   0bit
                        4'd2: rx_temp_data[1] <= rs232_rx;  //   1bit
                        4'd3: rx_temp_data[2] <= rs232_rx;  //   2bit
                        4'd4: rx_temp_data[3] <= rs232_rx;  //   3bit
                        4'd5: rx_temp_data[4] <= rs232_rx;  //   4bit
                        4'd6: rx_temp_data[5] <= rs232_rx;  //   5bit
                        4'd7: rx_temp_data[6] <= rs232_rx;  //   6bit
                        4'd8: rx_temp_data[7] <= rs232_rx;  //   7bit
                        default: ;
                    endcase
            end
        else if(num == 4'd11) begin     //            1+8+1(2)=11bit     ///      num        11.   12!!
                num <= 4'd0;            //   STOP    ,num  
                rx_data_r <= rx_temp_data;  //           rx_data 
            end
        end

assign rx_data = rx_data_r; 

endmodule

ここでは概ねシリアルポートが1回のデータを受信する処理過程であり、データを受信した後に送信フラグビットを生成し、データの送信を開始するが、ここでいうデータキャッシュ処理には2つの解決方法があり、1つ目は16進数転送であるため、転送ごとに有効なデータは8ビットであるため、1つのレジスタreg[23:0]rx_を定義するcnt;長さ8の整数倍、シフト方式でデータを格納し、上記コードではNUMカウントが11になると1回データ転送が完了するのでnum=11のところに
                rx_cnt[7:0] <= rx_data_r;
                rx_cnt[23:8] <= rx_cnt[15:0] ;
                cnt <= cnt+1;//        
                if(cnt==NUMBER)//       NUMBER   ,      
                begin
                cnt<=cnt;
                end
assign rx_data_out = (cnt==NUMBER)?rx_cnt:rx_data_out;  
                  //      NUMBER   ,       ,
                  //              。

そして元の出力ポートassign rx_data = rx_data_r;削除して、新しい出力受信の完全なコードを書きます.
//`timescale 1ns / 1ps

module my_uart_rx(
                clk,
                rst_n,
                rs232_rx,
                rx_data,
                rx_int,
                start,
                clk_bps,
                bps_start,
                rom_en,
                rx_data_out

            );

input clk;      // 50MHz   
input rst_n;    //       
input rs232_rx; // RS232      
input clk_bps;  // clk_bps                    
output bps_start;       //      ,           
output[7:0] rx_data;    //       ,            
output rx_int;  //        ,             
output reg start;
output wire [23:0] rx_data_out;
//----------------------------------------------------------------
reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;    //       ,   
wire neg_rs232_rx;  //           
reg [23:0] rx_cnt;
always @ (posedge clk or negedge rst_n) begin
    if(!rst_n) begin
            rs232_rx0 <= 1'b0;
            rs232_rx1 <= 1'b0;
            rs232_rx2 <= 1'b0;
            rs232_rx3 <= 1'b0;
        end
    else begin
            rs232_rx0 <= rs232_rx;
            rs232_rx1 <= rs232_rx0;
            rs232_rx2 <= rs232_rx1;
            rs232_rx3 <= rs232_rx2;
        end
end
    //            <20ns-40ns   (           ),
    //          (                ,           ) 
    //(                   40ns )
assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;    //       neg_rs232_rx        

//----------------------------------------------------------------
reg bps_start_r;
reg[3:0] num;   //    
reg rx_int;     //        ,             

always @ (posedge clk or negedge rst_n)
    if(!rst_n) begin
            bps_start_r <= 1'bz;
            rx_int <= 1'b0;
        end
    else if(neg_rs232_rx) begin     //        rs232_rx        
            bps_start_r <= 1'b1;    //          
            rx_int <= 1'b1;         //          
        end
    else if(num==4'd9) begin        //          ///      num        11.   12!!
            bps_start_r <= 1'b0;    //      ,         
            rx_int <= 1'b0;         //          
        end

assign bps_start = bps_start_r;

//----------------------------------------------------------------
reg[7:0] rx_data_r;     //         ,           
//----------------------------------------------------------------

reg[7:0] rx_temp_data;  //         
reg [5:0]cnt;

//assign led = (cnt==10)?1:0;
always @ (posedge clk or negedge rst_n)
    if(!rst_n) begin
            rx_temp_data <= 8'd0;
            num <= 4'd0;
            cnt<= 0;
            start<=0;
            rx_cnt<=24'b0;
            //rx_data_out <= 384'd0;
            rx_data_r <= 8'd0;
        end
    else if(rx_int) begin   //      
        if(clk_bps) begin   //       ,          ,8bit  ,1 2         
                num <= num+1'b1;
                case (num)
                        4'd1: rx_temp_data[0] <= rs232_rx;  //   0bit
                        4'd2: rx_temp_data[1] <= rs232_rx;  //   1bit
                        4'd3: rx_temp_data[2] <= rs232_rx;  //   2bit
                        4'd4: rx_temp_data[3] <= rs232_rx;  //   3bit
                        4'd5: rx_temp_data[4] <= rs232_rx;  //   4bit
                        4'd6: rx_temp_data[5] <= rs232_rx;  //   5bit
                        4'd7: rx_temp_data[6] <= rs232_rx;  //   6bit
                        4'd8: rx_temp_data[7] <= rs232_rx;  //   7bit
                        default: ;
                    endcase
            end
        else if(num == 4'd9) begin      //            1+8+1(2)=11bit     ///      num        11.   12!!
                num <= 4'd0;            //   STOP    ,num  
                rx_data_r <= rx_temp_data;  //           rx_data 
                cnt <= cnt+1;
                rx_cnt[7:0] <= rx_data_r;
                rx_cnt[23:8] <= rx_cnt[15:0] ;
                if(cnt==NUMBER)//       NUMBER   ,      
                begin
                cnt<=cnt;
                start<=1;//        
                end
            end
        end
assign rx_data_out = (cnt==6'd48)?rx_cnt:rx_data_out;   
endmodule

ボーレートプロファイルはネット上のコードが多いので、ここでは貼らない.