使用Xilinx UART-LITE IP实现串口--逻辑代码实现

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2019/01/10 21:13:43
// Design Name: 
// Module Name: uart_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_top(
    input CLK100MHZ,
      input ck_rst,
    output tx,
    input rx,
    output led
    );
    
    localparam COUNT_5MS = 28'h2_FA_F0_7F;//100M  500ms
 //闪灯指示   
    reg [27:0]r_count = 28'h0;
    reg r_led = 1'b0;
    always @ (posedge CLK100MHZ)
    begin
        if(r_count >= COUNT_5MS) begin
            r_count <= 28'h0;
            r_led <= ~r_led;
        end
        else begin
            r_count <= r_count +1'b1;
            r_led <= r_led;
        end
    end
    assign led = r_led;
    
    
  wire w_uart_rstn;
  (*MARK_DEBUG = "TRUE"*)wire w_uart_int;
    (*MARK_DEBUG = "TRUE"*)reg [3:0]s_axi_awaddr;
    (*MARK_DEBUG = "TRUE"*)reg s_axi_awvalid;
    (*MARK_DEBUG = "TRUE"*)wire s_axi_awready;
    (*MARK_DEBUG = "TRUE"*)reg [31:0]s_axi_wdata;
    (*MARK_DEBUG = "TRUE"*)reg [3:0]s_axi_wstrb;
    (*MARK_DEBUG = "TRUE"*)reg s_axi_wvalid = 1'b0;
    (*MARK_DEBUG = "TRUE"*)wire s_axi_wready;
    (*MARK_DEBUG = "TRUE"*)wire [1:0]s_axi_bresp;
    (*MARK_DEBUG = "TRUE"*)wire s_axi_bvalid;
    (*MARK_DEBUG = "TRUE"*)reg s_axi_bready = 1'b0;
    (*MARK_DEBUG = "TRUE"*)reg [3:0]s_axi_araddr = 4'h0;
    (*MARK_DEBUG = "TRUE"*)reg s_axi_arvalid = 1'b0;
    (*MARK_DEBUG = "TRUE"*)wire s_axi_arready;//Read ready. This signal indicates that the master can accept the read data and response information.
    (*MARK_DEBUG = "TRUE"*)wire [31:0]s_axi_rdata;
    (*MARK_DEBUG = "TRUE"*)wire [1:0]s_axi_rresp;
    wire s_axi_rvalid;
    (*MARK_DEBUG = "TRUE"*)reg s_axi_rready = 1'b0;
    axi_uartlite_0 uart_lite
     (
        .s_axi_aclk(CLK100MHZ),
        .s_axi_aresetn(ck_rst),
        
        .interrupt(w_uart_int),
        .s_axi_awaddr(s_axi_awaddr),// : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
        .s_axi_awvalid(s_axi_awvalid),// : IN STD_LOGIC;
        .s_axi_awready(s_axi_awready),// : OUT STD_LOGIC;
        .s_axi_wdata(s_axi_wdata),// : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
        .s_axi_wstrb(s_axi_wstrb),// : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
        .s_axi_wvalid(s_axi_wvalid),// : IN STD_LOGIC;
        .s_axi_wready(s_axi_wready),// : OUT STD_LOGIC;
        .s_axi_bresp(s_axi_bresp),// : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
        .s_axi_bvalid(s_axi_bvalid),// : OUT STD_LOGIC;
        .s_axi_bready(s_axi_bready),// : IN STD_LOGIC;
        .s_axi_araddr(s_axi_araddr),// : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
        .s_axi_arvalid(s_axi_arvalid),//: IN STD_LOGIC;
        .s_axi_arready(s_axi_arready),//: OUT STD_LOGIC;
        .s_axi_rdata(s_axi_rdata),// : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
        .s_axi_rresp(s_axi_rresp),// : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
        .s_axi_rvalid(s_axi_rvalid),// : OUT STD_LOGIC;
        .s_axi_rready(s_axi_rready),// : IN STD_LOGIC;
        
        .rx(rx),// : IN STD_LOGIC;
        .tx(tx)// : OUT STD_LOGIC
      );
    //debug  
    wire begin_init;
    reg [31:0]r_receive_data;
    vio_0 debug(
        .clk(CLK100MHZ),
        .probe_in0(r_receive_data),
        .probe_out0(begin_init)
    );
//receive data to fifo
(*MARK_DEBUG = "TRUE"*)wire [9:0]  data_count;//8 bit count
(*MARK_DEBUG = "TRUE"*)wire [7:0]w_receive_data;
wire fifo_empty;
fifo_generator_0 receive_fifo
 (
    .clk(CLK100MHZ),// : IN STD_LOGIC;
    .srst(~ck_rst),// : IN STD_LOGIC;
    .din(s_axi_rdata[7:0]),// : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
    .wr_en(s_axi_rvalid & (state == 8'b00000100)),// : IN STD_LOGIC;
    .rd_en(r_Read_en),// : IN STD_LOGIC;
    .dout(w_receive_data),// : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
    .full(),// : OUT STD_LOGIC;
    .almost_full(),// : OUT STD_LOGIC;
    .empty(fifo_empty),// : OUT STD_LOGIC;
    .almost_empty(),// : OUT STD_LOGIC;
    .data_count(data_count)// : OUT STD_LOGIC_VECTOR(9 DOWNTO 0)
  );
    
      
   parameter IDLE  = 8'b00000001;
   parameter INIT  = 8'b00000010;
   parameter RECIVE  = 8'b00000100;
   parameter T_R_IDLE  = 8'b00001000;
   parameter RECEIVE  = 8'b00010000;
   parameter CHECK_STA  = 8'b00100000;
   parameter state7  = 8'b01000000;
   parameter state8  = 8'b10000000;

   (*MARK_DEBUG = "TRUE"*)reg [7:0] state = IDLE;
   (*MARK_DEBUG = "TRUE"*)reg [7:0]cnt = 8'h00;

   always @(posedge CLK100MHZ)
      if (~ck_rst) begin
         state  <= IDLE;
      end
      else
         case (state)
            IDLE : begin
               if (begin_init)
                  state <= INIT;
               else if (w_uart_int)
                  state <= RECIVE;
               else
                  state <= IDLE;
            end
            INIT : begin//向0xC写入0x1F,使能中断,清空W/R FIFO
               if (s_axi_bvalid && (s_axi_bresp == 2'b00))
                    state <= CHECK_STA;
               else
                  state <= INIT;
            end
            RECIVE : begin
               if (s_axi_rvalid) begin
                  state <= CHECK_STA;
                  r_receive_data <= s_axi_rdata;
               end   
               else begin
                  state <= RECIVE;
                  r_receive_data <= r_receive_data;
               end
            end

            CHECK_STA : begin//检查状态寄存器
               if (s_axi_rvalid & s_axi_rdata[0])//receive buf is not empt
                  state <= RECIVE;
               else
                  state <= CHECK_STA;
            end
            default:begin
                
            end
        endcase
        
        
        reg [7:0]r_state;
    always @ (posedge CLK100MHZ)
            r_state <= state;
    
    always @ (posedge CLK100MHZ) begin
        if(~ck_rst) begin
            cnt <= 8'h00;
        end
        else begin
            case(state)
                RECIVE :begin
                    if(s_axi_rvalid | (cnt>8'h4))
                        cnt <= 8'h00;
                    else
                        cnt <= cnt +1'b1;
                end
                CHECK_STA :begin
                    if((s_axi_rvalid & s_axi_rdata[0]) | (cnt>8'h4))
                        cnt <= 8'h00;
                    else
                        cnt <= cnt +1'b1;
                end        
                default:begin
                    cnt <= 8'h00;
                end
            endcase
            
        end
    end
    
        
    always @ (posedge CLK100MHZ)
    begin
        case(state)
            IDLE:begin
                s_axi_awaddr <=4'h0;
                s_axi_wdata <= 32'h00_00_00_00;
                s_axi_wstrb <= 4'h0;
                s_axi_arvalid <= 1'b0;
                if(begin_init) begin
                    s_axi_awvalid <= 1'b1;
                    s_axi_wvalid <= 1'b1;
                end
                else begin
                    s_axi_awvalid <= 1'b0;
                    s_axi_wvalid <= 1'b0;
                end
            end
            INIT:begin    
                if(s_axi_wready) begin
                    s_axi_bready <= 1'b1;
                    s_axi_awvalid <= 1'b0;
                    s_axi_wvalid <= 1'b0;    
                end        
                else begin
                    s_axi_bready <= 1'b0;
                    
                    s_axi_awaddr <=4'hc;
                  s_axi_awvalid <= s_axi_awvalid;
                  s_axi_wdata <= 32'h1f;
                  s_axi_wstrb <= 4'hf;
                  s_axi_wvalid <= s_axi_wvalid;    
                end
            end
            RECIVE:begin
                if(cnt > 8'h3) begin
                    s_axi_arvalid <= 1'b0;
                end
                else if(cnt > 8'h2) begin
                    s_axi_arvalid <= 1'b1;
                end
                else if(cnt > 8'h1) begin
                    s_axi_araddr <=4'h0;
                    s_axi_rready <= 1'b1;
                end
                else begin
                 s_axi_rready <= 1'b1;
                end
            end
            CHECK_STA:begin
                if(cnt > 8'h3) begin
                    s_axi_arvalid <= 1'b0;
                end
                else if(cnt > 8'h2) begin
                    s_axi_arvalid <= 1'b1;
                end
                else if(cnt > 8'h1) begin
                    s_axi_araddr <=4'h8;
                    s_axi_rready <= 1'b1;
                end
                else begin
                 s_axi_rready <= 1'b1;
                end
            end
            default:begin
                s_axi_awaddr <=4'h0;
                s_axi_awvalid <= 1'b0;
                s_axi_wdata <= 32'h00_00_00_00;
                s_axi_wstrb <= 4'h0;
                s_axi_wvalid <= 1'b0;
                
                s_axi_arvalid <= 1'b0;
            end
        endcase
    end
    //read FIFO,unpack
    //如果读到2F,开始计数,再读11个字节,并相加,若和的最后一个字节为00,这是一个完整包,否则丢掉重新找2F
        
     parameter IDLE_P       = 4'b0001;
   parameter FIRST_BYTE   = 4'b0010;
   parameter RECEIVE_PACK = 4'b0100;
   parameter CHECK_PACK   = 4'b1000;

   (*MARK_DEBUG = "TRUE"*)reg [3:0] state_pack = IDLE_P;
     (*MARK_DEBUG = "TRUE"*)reg [3:0] r_Byte_cnt = 4'h0;
   always @(posedge CLK100MHZ)
      if (~ck_rst) begin
         state_pack <= IDLE_P;
       end
      else
         case (state_pack)
           IDLE_P : begin
               if (r_Read_en)
                  state_pack <= FIRST_BYTE;
               else
                  state_pack <= IDLE_P;
            end
            FIRST_BYTE : begin
               if (w_receive_data == 8'h2f)//check pack header
                  state_pack <= RECEIVE_PACK;
               else
                  state_pack <= IDLE_P;;
            end
            RECEIVE_PACK : begin
               if (r_Byte_cnt == 4'hb)//
                  state_pack <= CHECK_PACK;
               else
                  state_pack <= RECEIVE_PACK;
            end
            CHECK_PACK : begin
               if (pack_check_done)//no matter success or failed
                   state_pack <= IDLE_P;
               else
                  state_pack <= CHECK_PACK;
            end
            default : begin  // Fault Recovery
               state_pack <= IDLE_P;
            end
         endcase
    
    reg r_Read_en = 1'b0;
    reg [7:0]buf_data[0:11];  
    reg pack_check_done = 1'b0; 
    (*MARK_DEBUG = "TRUE"*)reg check_success = 1'b0;  
    always @ (posedge CLK100MHZ) begin
        if(~ck_rst) begin
            r_Read_en <= 1'b0;
            r_Byte_cnt <= 4'h0;
            pack_check_done <= 1'b0;
            check_success <= 1'b0;
        end
        else begin
            case(state_pack)
                IDLE_P:begin
                    check_success <= 1'b0;
                    r_Byte_cnt <= 4'h0;
                    pack_check_done <= 1'b0;
                    if(rr_fifo_empty & (~fifo_empty)) begin
                        r_Read_en <= 1'b1;
                    end
                    else begin
                        r_Read_en <= 1'b0;
                    end
                end
                FIRST_BYTE:begin//do nothing
                            r_Read_en <= 1'b0;
                end
                RECEIVE_PACK:begin
                    if(rr_fifo_empty & (~fifo_empty))begin
                        r_Byte_cnt <= r_Byte_cnt + 1'b1;
                        r_Read_en <= 1'b1;
                    end
                    else begin
                        r_Byte_cnt <= r_Byte_cnt;
                        r_Read_en <= 1'b0;
                    end
                end
                CHECK_PACK:begin
                    pack_check_done <= 1'b1;
                    if(data_check[7:0] == 8'h00) begin
                        check_success <= 1'b1;
                    end
                    else begin
                        check_success <= 1'b0;
                    end
                end
                default:begin
                    
                end
            endcase
        end
    end
    
    reg rr_fifo_empty;
    reg rr_Read_en;
    always @ (posedge CLK100MHZ) begin
        rr_fifo_empty <= fifo_empty;
        rr_Read_en <= r_Read_en;
    end
    
    //data check and buff
    (*MARK_DEBUG = "TRUE"*)reg [31:0]data_check = 32'h0000002f;
    always @ (posedge CLK100MHZ) begin
        if(state_pack == IDLE_P) begin
            data_check <= 32'h0000002f;
        end
        else if((state_pack > FIRST_BYTE) & (rr_Read_en)) begin
            buf_data[r_Byte_cnt] <= w_receive_data;
            data_check <= data_check+w_receive_data;
        end
        else begin
            data_check <= data_check;
        end
    end
    
    (*MARK_DEBUG = "TRUE"*)reg [7:0]r_checded_data[1:10];
        always @ (posedge CLK100MHZ) begin
            if(check_success) begin
                r_checded_data[1] <=  buf_data[1];
                r_checded_data[2] <=  buf_data[2];
                r_checded_data[3] <=  buf_data[3];
                r_checded_data[4] <=  buf_data[4];
                r_checded_data[5] <=  buf_data[5];
                r_checded_data[6] <=  buf_data[6];
                r_checded_data[7] <=  buf_data[7];
                r_checded_data[8] <=  buf_data[8];
                r_checded_data[9] <=  buf_data[9];
                r_checded_data[10] <=  buf_data[10];
            end
            else begin
                r_checded_data[1] <=  r_checded_data[1];  
                r_checded_data[2] <=  r_checded_data[2];  
                r_checded_data[3] <=  r_checded_data[3];  
                r_checded_data[4] <=  r_checded_data[4];  
                r_checded_data[5] <=  r_checded_data[5];  
                r_checded_data[6] <=  r_checded_data[6];  
                r_checded_data[7] <=  r_checded_data[7];  
                r_checded_data[8] <=  r_checded_data[8];  
                r_checded_data[9] <=  r_checded_data[9];  
                r_checded_data[10] <=  r_checded_data[10];
            end
        end
endmodule

参考手册“axi_lite_ipif_ds765”及“AXI UART Lite v2.0  pg142”

AXI-LITE接口,完全按照手册上的时序才能实现!!

有陀螺数据包解包校验代码,包格式说明如下图,包校验通过才更新缓存寄存器,保证缓存寄存器内存储的数据是最新的正确数据包。

需注意,IP使用主时钟100MHz产生波特率,100M时钟并不能产生较准确的波特率,波特率较高时出现异常,后改用14.7456M晶振,5倍频后作为UART IP的输入时钟,通信正常。

原文地址:https://www.cnblogs.com/dlutccj/p/10261358.html