解析ALTER 公司的UART代码

eeleader   2010-12-3 12:48 楼主

 

------------以下串口发送部分

module uart_tx (clk,rst,tx_data,tx_data_valid,tx_data_ack,txd);

-----------敏感变量包括时钟/复位,发送数据,发送数据有效,发送数据响应,发送数据线
 
output txd;   ----------数据发送线
input clk, rst; ---------系统时钟,复位
input [7:0] tx_data;  ------数据发送
input tx_data_valid;  -----数据发送使能
output tx_data_ack;  ------数据发送响应

parameter BAUD_DIVISOR = 868; -----波特分频比

reg [15:0] sample_cntr; ----发送抽样计数器
reg [10:0] tx_shift;  ------发送数据移位积存器“起始位+8个数据位+停止位”
reg sample_now;   ------发送时钟
reg tx_data_ack;   ------发送数据响应积存器

assign txd = tx_shift[0]; -----开始发送数据

always @(posedge clk) begin   -----检测时钟上升沿
 if (rst) begin      ------高复位
  sample_cntr <= 0;           ------寄存器清0 
  sample_now <= 1'b0;     ------ 清0
 end
 else if (sample_cntr == (BAUD_DIVISOR-1)) begin
  sample_cntr <= 0;
  sample_now <= 1'b1;
    end
 else begin
  sample_now <= 1'b0;
  sample_cntr <= sample_cntr + 1'b1;
 end
end

reg ready;
always @(posedge clk) begin    -----检测上升沿
 if (rst) begin
  tx_shift <= {11'b00000000001};   ----发送移位初试化
  ready <= 1'b1;                             ----发送准备
 end
 else begin  
  if (!ready & sample_now) begin   ----发送时钟上升沿且发送未完成
   tx_shift <= {1'b0,tx_shift[10:1]};
   tx_data_ack <= 1'b0;
   ready <= ~|tx_shift[10:1];----- ready 置高, 确保tx_shift 初始化
  end  
  else if (ready & tx_data_valid) begin
   tx_shift[10:1] <= {1'b1,tx_data,1'b0};
   tx_data_ack <= 1'b1;  -----开始发送数据
   ready <= 1'b0;  -----发送数据标志
  end
  else begin
   tx_data_ack <= 1'b0;
   ready <= ~|tx_shift[10:1]; ---发送数据,ready 置高!!!!!!!!!!!!
  end
 end  
end

endmodule

////////////////////////////////////////////////////////////////////

module uart_rx (clk,rst,rx_data,rx_data_fresh,rxd);   -----敏感信号时钟,复位,接收数据,接收数据更新,接收数据线
 
input clk, rst, rxd;
output [7:0] rx_data;  ----接收数据
output rx_data_fresh; -----接收数据更新

parameter BAUD_DIVISOR = 868;  ----波特率分频比

reg [15:0] sample_cntr;  ----分频计数器
reg [7:0] rx_shift;  ----接收移位寄存器
reg sample_now; -----接收分频时钟信号
reg [7:0] rx_data;  -----接收数据
reg rx_data_fresh; -----接收数据更新

reg last_rxd;  -----接收缓冲

always @(posedge clk) begin
 last_rxd <= rxd;
end
wire slew = rxd ^ last_rxd;

always @(posedge clk) begin
 if (rst) begin
  sample_cntr <= 0;
  sample_now <= 1'b0;
 end
 else if (sample_cntr == (BAUD_DIVISOR-1) || slew) begin
  sample_cntr <= 0;
 end
 else if (sample_cntr == (BAUD_DIVISOR/2)) begin
  sample_now <= 1'b1;
  sample_cntr <= sample_cntr + 1'b1;
 end
 else begin
  sample_now <= 1'b0;   -----接收时钟占空比1
  sample_cntr <= sample_cntr + 1'b1;
 end
end

reg [1:0] state;
reg [3:0] held_bits;
parameter WAITING = 2'b00, READING = 2'b01, STOP = 2'b10, RECOVER = 2'b11;

always @(posedge clk) begin
 if (rst) begin
  state <= WAITING;
  held_bits <= 0;
  rx_shift <= 0;
  rx_data_fresh <= 1'b0;
  rx_data <= 0;
 end
 else begin
  rx_data_fresh <= 1'b0;
  case (state)
   WAITING : begin
    // wait for a start bit (0)
    if (!slew & sample_now && !last_rxd) begin  -----下降沿,接收时钟,起始位
     state <= READING;
     held_bits <= 0;
    end
   end
   READING : begin
    // gather data bits
    if (sample_now) begin
     rx_shift <= {last_rxd,rx_shift[7:1]};
     held_bits <= held_bits + 1'b1;
     if (held_bits == 4'h7) state <= STOP;
    end
   end
   STOP : begin
    // verify stop bit (1)
    if (sample_now) begin
     if (last_rxd) begin
      rx_data <= rx_shift;
      rx_data_fresh <= 1'b1;
      state <= WAITING;
     end
     else begin
      // there was a framing error -
      // discard the byte and work on resync
      state <= RECOVER;
     end
    end     
   end
   RECOVER : begin
    // wait for an idle (1) then resume
    if (sample_now) begin
     if (last_rxd) state <= WAITING;
    end    
   end
  endcase
 end
end

endmodule

////////////////////////////////////////////////////////////////////

module uart (clk,rst,
   tx_data,tx_data_valid,tx_data_ack,txd,
   rx_data,rx_data_fresh,rxd);

parameter CLK_HZ = 50_000_000;
parameter BAUD = 115200;
parameter BAUD_DIVISOR = CLK_HZ / BAUD;

initial begin
 if (BAUD_DIVISOR > 16'hffff) begin
  // This rate is too slow for the TX and RX sample
  // counter resolution
  $display ("Error - Increase the size of the sample counters");
  $stop();
 end
end

output txd;
input clk, rst, rxd;
input [7:0] tx_data;
input tx_data_valid;
output tx_data_ack;
output [7:0] rx_data;
output rx_data_fresh;

uart_tx utx (
 .clk(clk),.rst(rst),
 .tx_data(tx_data),
 .tx_data_valid(tx_data_valid),
 .tx_data_ack(tx_data_ack),
 .txd(txd));

defparam utx .BAUD_DIVISOR = BAUD_DIVISOR;

uart_rx urx (
 .clk(clk),.rst(rst),
 .rx_data(rx_data),
 .rx_data_fresh(rx_data_fresh),
 .rxd(rxd));

defparam urx .BAUD_DIVISOR = BAUD_DIVISOR;

endmodule

一个为理想不懈前进的人,一个永不言败人! http://shop57496282.taobao.com/ 欢迎光临网上店铺!

回复评论 (1)

不错,但是不知道可靠性整么样。串口数据接收最大的问题就是可靠性问题。因为串口帧协议简单,不能保证数据可靠传递。经常出现各种各样的错误!让人防不胜防!

点赞  2010-12-29 10:41
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复