1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-14 06:42:54 +08:00

Added UART receiver and transmitter modules

This commit is contained in:
Konstantin Pavlov (pt) 2016-03-30 21:33:41 +03:00
parent 9e19abc733
commit ee9d1b9e66
5 changed files with 303 additions and 10 deletions

View File

@ -15,12 +15,12 @@
wire [7:0] actions;
ActionBurst AB1 (
.clk(clk200pll),
.nrst(1'b1),
.step_wdth(32'b1),
.start(E_ClockDivider[24]),
.clk(),
.nrst(),
.step_wdth(),
.start(),
.busy(),
.out(actions[7:0])
.out()
);
defparam AB1.WIDTH = 8;

View File

@ -3,22 +3,26 @@
####(licensed under CC BY-SA 4_0)
**/Advanced Synthesis Cookbook/** useful code from Altera`s cookbook
**/Advanced Synthesis Cookbook/** - useful code from Altera`s cookbook
**/KCPSM6_Release9_30Sept14/** - Xilinx`s Picoblaze soft processor
**/pacoblaze-2.2/** - version of Picoblaze adapted for Altera devices
**Main_tb.v** - basic testbench template
**ActionBurst.v - multichannel one-shot triggering module
**ActionBurst.v** - multichannel one-shot triggering module
**ClkDivider.v** - wide reference clock divider
**DeBounce.v** - two-cycle debounce for input buttons
**DynDelay.v** - dynamic delay made on general-purpose trigger elements
**EdgeDetect.v** - edge detector, gives one-tick pulses on every signal edge
**Encoder.v** encoder input module
**Encoder.v** - encoder input module
**PulseGen.v** - generates pulses with given width and delay
**ResetSet.v** - SR trigger variant w/o metastable state, set dominates here
**SetReset.v** - SR trigger variant w/o metastable state, reset dominates here
**SimplePulseGen.v** - generates one-cycle pulse with given delay
**StaticDelay.v** static delay made on Xilinx`s SRL16E primitives
**Synch.v** - input syncnronizer (and also "static delay module"), standard way to get rid of metastability issues
**StaticDelay.v** - static delay made on Xilinx`s SRL16E primitives
**Synch.v** - input synchronizer (and also "static delay module"), standard way to get rid of metastability issues
**UartRx.v** - straightforward yet simple UART receiver implementation for FPGA written in Verilog
**UartTx.v** - straightforward yet simple UART transmitter implementation for FPGA written in Verilog
Also added some simple testbenches for selected modules

104
UartRx.v Normal file
View File

@ -0,0 +1,104 @@
//--------------------------------------------------------------------------------
// UartRx.v
// Konstantin Pavlov, pavlovconst@gmail.com
//--------------------------------------------------------------------------------
// INFO --------------------------------------------------------------------------------
// Straightforward yet simple UART receiver implementation for FPGA written in Verilog
// Expects at least one stop bit
/* --- INSTANTIATION TEMPLATE BEGIN ---
UartRx UR1 (
.clk(),
.nrst(),
.rx_data(),
.rx_busy(),
.rx_done(),
.rxd()
);
defparam UR1.CLK_HZ = 200_000_000;
defparam UR1.BAUD = 9600; // max. BAUD is CLK_HZ / 2
--- INSTANTIATION TEMPLATE END ---*/
module UartRx(clk, nrst, rx_data, rx_busy, rx_done, rxd);
parameter CLK_HZ = 200_000_000;
parameter BAUD = 9600;
parameter BAUD_DIVISOR_2 = CLK_HZ / BAUD / 2;
input wire clk;
input wire nrst;
output reg [7:0] rx_data = 0;
output reg rx_busy = 0;
output reg rx_done = 0; // read strobe
input wire rxd;
reg rxd_prev = 0;
always @ (posedge clk) begin
if (~nrst) begin
rxd_prev <= 0;
end else begin
rxd_prev <= rxd;
end
end
wire start_bit_strobe = ~rxd & rxd_prev;
reg [15:0] rx_sample_cntr = (BAUD_DIVISOR_2 - 1);
wire rx_do_sample = (rx_sample_cntr[15:0] == 0);
reg [3:0] rx_data_cntr = 4'b1000;
always @ (posedge clk) begin
if (~nrst) begin
rx_data[7:0] <= 0;
rx_busy <= 0;
rx_done <= 0;
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 - 1);
rx_data_cntr[3:0] <= 4'b1000;
end else begin
if (~rx_busy) begin
if (start_bit_strobe) begin
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 3 - 1); // wait for 1,5-bit period till next sample
rx_data[7:0] <= 0;
rx_busy <= 1;
rx_done <= 0;
rx_data_cntr[3:0] <= 4'b1000;
end // start_bit_strobe
end else begin
if (rx_sample_cntr[15:0] == 0) begin
rx_sample_cntr[15:0] <= (BAUD_DIVISOR_2 * 2 - 1); // wait for 1-bit-period till next sample
end else begin
rx_sample_cntr[15:0] <= rx_sample_cntr[15:0] - 1; // counting and sampling only when 'busy'
end
if (rx_do_sample) begin
if (rx_data_cntr[3:0] == 0) begin // do stop bit check
if (rxd) begin
rx_done <= 1;
end else begin
rx_busy <= 0;
end // rxd
end else begin // do sample and shift data
rx_data[7:0] <= {rxd, rx_data[7:1]};
rx_data_cntr[3:0] <= rx_data_cntr[3:0] - 1;
end // rx_data_cntr[3:0]
end // rx_do_sample
if (rx_done) begin
rx_busy <= 0;
rx_done <= 0;
end // rx_done
end // ~rx_busy
end // ~nrst
end
endmodule

81
UartTx.v Normal file
View File

@ -0,0 +1,81 @@
//--------------------------------------------------------------------------------
// UartTx.v
// Konstantin Pavlov, pavlovconst@gmail.com
//--------------------------------------------------------------------------------
// INFO --------------------------------------------------------------------------------
// Straightforward yet simple UART transmitter implementation for FPGA written in Verilog
// One stop bit setting is hardcoded
/* --- INSTANTIATION TEMPLATE BEGIN ---
UartTx UT1 (
.clk(),
.nrst(),
.tx_data(),
.tx_start(),
.tx_busy(),
.txd()
);
defparam UT1.CLK_HZ = 200_000_000;
defparam UT1.BAUD = 9600; // max. BAUD is CLK_HZ / 2
--- INSTANTIATION TEMPLATE END ---*/
module UartTx(clk, nrst, tx_data, tx_start, tx_busy, txd);
parameter CLK_HZ = 200_000_000;
parameter BAUD = 9600;
parameter BAUD_DIVISOR = CLK_HZ / BAUD;
input wire clk;
input wire nrst;
input wire [7:0] tx_data;
input wire tx_start; // write strobe
output reg tx_busy = 0;
output reg txd = 1;
reg [15:0] tx_sample_cntr = (BAUD_DIVISOR-1);
reg [9:0] tx_shifter = 0;
always @ (posedge clk) begin
if ((~nrst) || (tx_sample_cntr[15:0] == 0)) begin
tx_sample_cntr[15:0] <= (BAUD_DIVISOR-1);
end else begin
tx_sample_cntr[15:0] <= tx_sample_cntr[15:0] - 1'b1;
end
end
wire tx_do_sample = (tx_sample_cntr[15:0] == 0);
always @ (posedge clk) begin
if (~nrst) begin
tx_busy <= 0;
tx_shifter[9:0] <= 0;
txd <= 1;
end else begin
if (~tx_busy) begin
if (tx_start) begin // asynchronous data load and 'busy' set
tx_shifter[9:0] <= {1'b1,tx_data[7:0],1'b0};
tx_busy <= 1;
end
end else begin
if (tx_do_sample) begin // next bit
{tx_shifter[9:0],txd} <= {tx_shifter[9:0],txd} >> 1; // txd MUST change only on tx_do_sample although data may be loaded earlier
end // tx_do_sample
if (~|tx_shifter[9:0]) begin // asynchronous 'busy' reset
tx_busy <= 0; // txd still holds data, but shifter is ready
end
end // ~tx_busy
end // ~nrst
end
endmodule

104
UartTx_UartRx_tb.v Normal file
View File

@ -0,0 +1,104 @@
//--------------------------------------------------------------------------------
// SimWrapper.v
// Konstantin Pavlov, pavlovconst@gmail.com
//--------------------------------------------------------------------------------
// INFO --------------------------------------------------------------------------------
//
//
`timescale 1ns / 1ps
module SimWrapper();
reg clk200;
initial begin
#0 clk200 = 1;
forever
#2.5 clk200 = ~clk200;
end
reg rst;
initial begin
#10.2 rst = 1;
#5 rst = 0;
//#10000;
forever begin
#9985 rst = ~rst;
#5 rst = ~rst;
end
end
wire nrst = ~rst;
reg rst_once;
initial begin // initializing non-X data before PLL starts
#10.2 rst_once = 1;
#5 rst_once = 0;
end
initial begin
#510.2 rst_once = 1; // PLL starts at 500ns, clock appears, so doing the reset for modules
#5 rst_once = 0;
end
wire nrst_once = ~rst_once;
wire [31:0] DerivedClocks;
ClkDivider CD1 (
.clk(clk200),
.nrst(nrst_once),
.out(DerivedClocks[31:0]));
defparam CD1.WIDTH = 32;
wire [31:0] E_DerivedClocks;
EdgeDetect ED1 (
.clk(clk200),
.nrst(nrst_once),
.in(DerivedClocks[31:0]),
.rising(E_DerivedClocks[31:0]),
.falling(),
.both()
);
defparam ED1.WIDTH = 32;
wire [15:0] RandomNumber1;
c_rand RNG1 (
.clk(clk200),
.rst(rst_once),
.reseed(1'b0),
.seed_val(DerivedClocks[31:0]),
.out(RandomNumber1[15:0]));
reg start;
initial begin
#100.2 start = 1;
#5 start = 0;
end
wire txd_pin;
wire txbusy_pin;
UartTx UT1 (
.clk(clk200),
.nrst(nrst),
.tx_data(RandomNumber1[7:0]),
.tx_start(1'b1), // .tx_start(~|RandomNumber1[15:10]),
.tx_busy(txbusy_pin),
.txd(txd_pin)
);
defparam UT1.CLK_HZ = 200_000_000;
defparam UT1.BAUD = 100_000_000;
UartRx UR1 (
.clk(clk200),
.nrst(nrst),
.rx_data(),
.rx_busy(),
.rx_done(),
.rxd(txd_pin)
);
defparam UR1.CLK_HZ = 200_000_000;
defparam UR1.BAUD = 100_000_000;
endmodule