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:
parent
9e19abc733
commit
ee9d1b9e66
@ -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;
|
||||
|
||||
|
14
README.md
14
README.md
@ -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
104
UartRx.v
Normal 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
81
UartTx.v
Normal 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
104
UartTx_UartRx_tb.v
Normal 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
|
Loading…
x
Reference in New Issue
Block a user