I can't figure out why is it that when I set the clock frequency from 50MHz to 100MHz, by changing the clk period to 5 in the testbench, my output transmit and receive data stays at 0. Can anyone enlighten me on this? I need my clock frequency to be 100MHz. Your help will be much appreciated.
Testbench
`timescale 1ns / 1ps
module uart_tx_test();
parameter periodCLK_2 = 5;
parameter perioddump = 10;
parameter delay = 1;
parameter delay_in = 2;
reg CLK_TB = 0 ;
reg RSTN ;
reg [7:0] data = 0;
reg clk = 0;
reg enable = 0;
wire tx_busy;
wire rdy;
wire [7:0] rxdata;
wire loopback;
reg rdy_clr = 0;
uart test_uart(.din(data),
.wr_en(enable),
.clk_50m(clk),
.tx(loopback),
.tx_busy(tx_busy),
.rx(loopback),
.rdy(rdy),
.rdy_clr(rdy_clr),
.dout(rxdata));
initial begin
// $dumpfile("uart.vcd");
$dumpvars(0, uart_tx_test);
enable <= 1'b1;
#2 enable <= 1'b0;
end
always begin
#5 clk = ~clk; //I set period to 5; period was 1 previously.
end
always #(posedge rdy) begin
#2 rdy_clr <= 1;
#2 rdy_clr <= 0;
if (rxdata != data) begin
$display("FAIL: rx data %x does not match tx %x", rxdata, data);
$finish;
end else begin
if (rxdata == 8'hff) begin
$display("SUCCESS: all bytes verified");
$finish;
end
data <= data + 1'b1;
enable <= 1'b1;
#2 enable <= 1'b0;
end
end
endmodule
Design Sources
module uart(
input wire [7:0] din,
input wire wr_en,
input wire clk_50m,
output wire tx,
output wire tx_busy,
input wire rx,
input wire rdy_clr,
output wire rdy,
output wire [7:0] dout
);
wire rxclk_en, txclk_en;
baud_rate_gen uart_baud(
.clk_50m(clk_50m),
.rxclk_en(rxclk_en),
.txclk_en(txclk_en)
);
transmitter uart_tx(
.tx(tx),
.din(din),
.clk_50m(clk_50m),
.clken(txclk_en),
.wr_en(wr_en),
.tx_busy(tx_busy)
);
receiver uart_rx(
.rx(rx),
.data(dout),
.clk_50m(clk_50m),
.clken(rxclk_en),
.rdy(rdy),
.rdy_clr(rdy_clr)
);
endmodule
/*
* Hacky baud rate generator to divide a 50MHz clock into a 9600 baud
* rx/tx pair where the rx clcken oversamples by 16x.
*/
module baud_rate_gen(input wire clk_50m,
output wire rxclk_en,
output wire txclk_en);
parameter RX_ACC_MAX = 100000000 / (9600 * 16);
parameter TX_ACC_MAX = 100000000 / 9600;
parameter RX_ACC_WIDTH = $clog2(RX_ACC_MAX);
parameter TX_ACC_WIDTH = $clog2(TX_ACC_MAX);
reg [RX_ACC_WIDTH - 1:0] rx_acc = 0;
reg [TX_ACC_WIDTH - 1:0] tx_acc = 0;
assign rxclk_en = (rx_acc == 5'd0);
assign txclk_en = (tx_acc == 9'd0);
always #(posedge clk_50m) begin
if (rx_acc == RX_ACC_MAX[RX_ACC_WIDTH - 1:0])
rx_acc <= 0;
else
rx_acc <= rx_acc + 5'b1;
end
always #(posedge clk_50m) begin
if (tx_acc == TX_ACC_MAX[TX_ACC_WIDTH - 1:0])
tx_acc <= 0;
else
tx_acc <= tx_acc + 9'b1;
end
endmodule
module transmitter(
input wire [7:0] din,
input wire wr_en,
input wire clk_50m,
input wire clken,
output reg tx,
output wire tx_busy
);
initial begin
tx = 1'b1;
end
parameter STATE_IDLE = 2'b00;
parameter STATE_START = 2'b01;
parameter STATE_DATA = 2'b10;
parameter STATE_STOP = 2'b11;
reg [7:0] data = 8'h00;
reg [2:0] bitpos = 3'h0;
reg [1:0] state = STATE_IDLE;
always #(posedge clk_50m) begin
case (state)
STATE_IDLE: begin
if (wr_en) begin
state <= STATE_START;
data <= din;
bitpos <= 3'h0;
end
end
STATE_START: begin
if (clken) begin
tx <= 1'b0;
state <= STATE_DATA;
end
end
STATE_DATA: begin
if (clken) begin
if (bitpos == 3'h7)
state <= STATE_STOP;
else
bitpos <= bitpos + 3'h1;
tx <= data[bitpos];
end
end
STATE_STOP: begin
if (clken) begin
tx <= 1'b1;
state <= STATE_IDLE;
end
end
default: begin
tx <= 1'b1;
state <= STATE_IDLE;
end
endcase
end
assign tx_busy = (state != STATE_IDLE);
endmodule
module receiver(
input wire rx,
input wire rdy_clr,
input wire clk_50m,
input wire clken,
output reg rdy,
output reg [7:0] data
);
initial begin
rdy = 0;
data = 8'b0;
end
parameter RX_STATE_START = 2'b00;
parameter RX_STATE_DATA = 2'b01;
parameter RX_STATE_STOP = 2'b10;
reg [1:0] state = RX_STATE_START;
reg [3:0] sample = 0;
reg [3:0] bitpos = 0;
reg [7:0] scratch = 8'b0;
always #(posedge clk_50m) begin
if (rdy_clr)
rdy <= 0;
if (clken) begin
case (state)
RX_STATE_START: begin
/*
* Start counting from the first low sample, once we've
* sampled a full bit, start collecting data bits.
*/
if (!rx || sample != 0)
sample <= sample + 4'b1;
if (sample == 15) begin
state <= RX_STATE_DATA;
bitpos <= 0;
sample <= 0;
scratch <= 0;
end
end
RX_STATE_DATA: begin
sample <= sample + 4'b1;
if (sample == 4'h8) begin
scratch[bitpos[2:0]] <= rx;
bitpos <= bitpos + 4'b1;
end
if (bitpos == 8 && sample == 15)
state <= RX_STATE_STOP;
end
RX_STATE_STOP: begin
/*
* The baud clock may not be running at exactly the
* same rate as the transmitter. If we thing that
* we're at least half way into the stop bit, allow
* transition into handling the next start bit.
*/
if (sample == 15 || (sample >= 8 && !rx)) begin
state <= RX_STATE_START;
data <= scratch;
rdy <= 1'b1;
sample <= 0;
end else begin
sample <= sample + 4'b1;
end
end
default: begin
state <= RX_STATE_START;
end
endcase
end
end
endmodule
You need to scale all your other delays accordingly. Change all your #2 to #10, then you will see the SUCCESS: all bytes verified message.
With your original clock delay of #1, your other input signal pulses (enable and rdy_clr) were wide enough for your uart design module to sample properly. For example, on the 1st posedge of clk, your design properly sampled the enable input as 1, which started the TX state machine.
You increased the clock period by a factor of 5 when you changed the delay from #1 to #5. However, your enable pulse stayed the same width as before, which means that the design sampled enable as 0, not 1. So your TX state machine stayed in the IDLE state. By changing the enable delay from #2 to #10, you are able to properly sample enable as 1.
You can easily prove this to yourself by dumping a VCD file, and viewing the waveforms inside the design.
You could replace the numeric delays with a parameter to make it easier to change to different frequencies.
Note: You stated the clk delay was originally #1. This gives the clk signal a period of 2ns, which is 500MHz, not 50MHz.
Related
I have written the code for SPI Master and I want the output SPI frequency to be 1MHz.
But, when I run the behaviroal simulation, I don't get a 1MHz spi_sclk. Any suggestions what is wrong with my code? Thanks!
module spi_master(
input wire clk,
input wire reset,
input wire [15:0] datain,
output wire spi_cs_l,
output wire spi_sclk,
output wire spi_data,
output wire [4:0] counter
);
reg [15:0] MOSI;
reg [4:0] count;
reg cs_l;
reg sclk = 1'b0;
reg [2:0] state;
reg [4:0] clk_counter = 0;
// SPI Output Clock frequency = 1MHz
always #(posedge clk) begin
if (clk_counter == 24) begin
clk_counter <= 0;
sclk <= ~sclk;
end
else begin
clk_counter <= clk_counter + 1'd1;
end
end
always #(posedge clk or posedge reset) begin
if(reset) begin
MOSI <= 16'b0;
count <= 5'd16;
cs_l <= 1'b1;
end
else begin
case (state)
0:begin
cs_l <= 1'b1;
state <= 1;
end
1:begin
cs_l <= 1'b0;
MOSI <= datain[count-1];
count <= count-1;
state <= 2;
end
2:begin
if(count > 0) begin
state <= 1;
end
else begin
count <= 16;
state <= 0;
end
end
default:state<=0;
endcase
end
end
assign spi_cs_l = cs_l;
assign spi_sclk = sclk;
assign spi_data = MOSI;
assign counter = count;
endmodule
Testbench
module spi_master_tb;
// Inputs
reg clk;
reg reset;
reg [15:0] datain;
// Outputs
wire spi_cs_l;
wire spi_sclk;
wire spi_data;
wire [4:0] counter;
spi_master dut(
.clk(clk),
.reset(reset),
.counter(counter),
.datain(datain),
.spi_cs_l(spi_cs_l),
.spi_sclk(spi_sclk),
.spi_data(spi_data)
);
initial begin
clk = 0;
reset = 1;
datain = 0;
end
always #5 clk=~clk;
initial begin
#10 reset = 1'b0;
#10 datain = 16'hA569;
#335 datain = 16'h2563;
#335 datain = 16'h9B63;
#335 datain = 16'h6A61;
end
endmodule
Waveform
It helps if you create Minimal reproducible example. Also your waveform don't include an important signal clk_counter.
Try this in your testbench, if it doesn't work you at least have the minimum reproducible example.
I changed the initialization of clk_counter and in the increment I simply added 1 instead of 1'b1, if you wanted to be strict you could add a 5-bit wide 1 (5'b1).
module spi_master(
input wire clk,
input wire reset,
output wire spi_sclk,
);
reg [4:0] clk_counter;
// SPI Output Clock frequency = 1MHz
always #(posedge clk) begin
if(reset) begin
sclk <= 1'b0;
clk_counter <= 1;
end
else begin
if (clk_counter == 24) begin
clk_counter <= 0;
sclk <= ~sclk;
end
else begin
clk_counter <= clk_counter + 1;
end
end
end
assign spi_sclk = sclk;
endmodule
I'm trying to write an I2C Slave and test it in isolation.
I have a simulation that should be pulling SDA low when write_ack is high (Also highlighted by the red dots). However, you can see that SDA remains the same.
Part of me thinks it's to do with the way I'm testing with the force methods and the delays.
Any help appreciated.
I have found the keyword release which seems to help.
Code below & EDA Playground is here: https://edaplayground.com/x/6snM
/**
I2C Slave to Read/Write 8 bits of data only
*/
`timescale 1ns / 1ps
module Slave(
inout wire SDA,
input wire SCL);
reg [4:0] IDLE = 4'b0000;
reg [4:0] START = 4'b0001;
reg [4:0] READ_ADDRESS = 4'b0010;
reg [4:0] READ_WRITE = 4'b0011;
reg [4:0] DATA = 4'b0100;
reg [4:0] DATA_ACK = 4'b0101;
reg [4:0] STOP = 4'b0110;
reg [4:0] ADDRESS_ACK = 4'b0111;
reg [4:0] state = 4'b0010;
reg [6:0] slaveAddress = 7'b0001000;
reg [7:0] addr;
reg [6:0] addressCounter = 7'b0000000;
reg [7:0] data;
reg [6:0] dataCounter = 7'b0000000;
reg readWrite = 1'b0;
reg start = 0;
reg write_ack = 0;
assign SDA = (write_ack == 1) ? 0 : 'b1z;
always #(negedge SDA) begin
if ((start == 0) && (SCL == 1))
begin
start <= 1;
addressCounter <= 0;
dataCounter <= 0;
end
end
always #(posedge SDA) begin
if (state == DATA_ACK && SCL == 1)
begin
start <= 0;
state <= READ_ADDRESS;
end
end
always #(posedge SCL)
begin
if (start == 1)
begin
case (state)
READ_ADDRESS:
begin
addr[addressCounter] <= SDA;
addressCounter <= addressCounter + 1;
if (addressCounter == 6)
begin
state <= READ_WRITE;
end
end
READ_WRITE:
begin
readWrite <= SDA;
state <= ADDRESS_ACK;
end
ADDRESS_ACK:
begin
write_ack <= 1;
state <= DATA;
end
DATA:
begin
write_ack <= 0;
data[dataCounter] <= SDA;
dataCounter <= dataCounter + 1;
if (dataCounter == 8)
begin
state <= DATA_ACK;
write_ack <= 1;
end
end
DATA_ACK:
begin
write_ack <= 0;
state <= STOP;
end
STOP:
begin
start <= 0;
state <= READ_ADDRESS;
end
endcase
end
end
endmodule
Test Code
/**
Testing I2C Slace for reading/writing 8 bits of data only
*/
`timescale 1ns / 1ps
module Slave_TB ();
reg clk;
wire SDA;
wire SCL;
pullup(SDA);
pullup(SCL);
reg [6:0] addressToSend = 7'b0001000;
reg readWite = 1'b1;
reg [7:0] dataToSend = 8'b01100111;
integer ii=0;
initial begin
clk = 0;
force SCL = clk;
forever begin
clk = #1 ~clk;
force SCL = clk;
end
end
Slave #() UUT
(.SDA(SDA),
.SCL(SCL));
initial
begin
$display("Starting Testbench...");
clk = 0;
force SCL = clk;
#11
// Set SDA Low to start
force SDA = 0;
// Write address
for(ii=0; ii<7; ii=ii+1)
begin
$display("Address SDA %h to %h", SDA, addressToSend[ii]);
#2 force SDA = addressToSend[ii];
end
// Are we wanting to read or write to/from the device?
$display("Read/Write %h SDA: %h", readWite, SDA);
#2 force SDA = readWite;
$display("SDA: %h", SDA);
#2; // Wait for ACK bit
for(ii=0; ii<8; ii=ii+1)
begin
$display("Data SDA %h to %h", SDA, dataToSend[ii]);
#2 force SDA = dataToSend[ii];
end
#2; // Wait for ACK bit
// Force SDA high again, we are done
#2 force SDA = 1;
#100;
$finish();
end
initial
begin
// Required to dump signals to EPWave
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule
Instead of using force, a more conventional approach is to add a tristate buffer to the testbench, just like you have in the design.
For SDA, create a buffer control signal (drive_sda) and a testbench data signal (sda_tb). Use a task to drive a byte and wait for the ACK.
Since SCL is not an inout, there is no need for a pullup, and it can be directly driven by clk.
module Slave_TB;
reg clk;
wire SDA;
wire SCL = clk;
pullup(SDA);
reg [6:0] addressToSend = 7'b000_1000; //8
reg readWite = 1'b1; //write
reg [7:0] dataToSend = 8'b0110_0111; //103 = 0x67
reg sda_tb;
reg drive_sda;
assign SDA = (drive_sda) ? sda_tb : 1'bz;
integer ii=0;
initial begin
clk = 0;
forever begin
clk = #1 ~clk;
end
end
Slave UUT
(.SDA(SDA),
.SCL(SCL));
initial begin
$display("Starting Testbench...");
drive_sda = 0;
sda_tb = 1;
#11;
// Set SDA Low to start
drive_sda = 1;
sda_tb = 0;
write({addressToSend, readWite});
write(dataToSend);
// Force SDA high again, we are done
#2;
drive_sda = 1;
sda_tb = 1;
#50;
$finish;
end
task write (reg [7:0] data);
integer ii;
for (ii=7; ii>=0; ii=ii-1) begin
$display("Data SDA %h to %h", SDA, data[ii]);
#2;
drive_sda = 1;
sda_tb = data[ii];
end
#2 drive_sda = 0;
endtask
initial begin
// Required to dump signals to EPWave
$dumpfile("dump.vcd");
$dumpvars(0);
end
endmodule
Sorry if anything in here seems obvious but I am starting out in this new FPGA thing and I really enjoy it so far but this is driving me crazy.
Here is the Verilog code for a block that should in principle do the following to an 8 bit register:
00000001
00000010
00000100
.....
01000000
10000000
01000000
00100000
module bit_bouncer(clock, enable, bouncer_out);
//INPUTS PORTS
input clock;
input enable;
//OUTPUTS PORTS
output bouncer_out;
//INPUT DATA TYPE
wire clock;
wire enable;
//OUTPUT DATA TYPE
reg [7:0] bouncer_out = 8'b00000001;
//Register to store data
reg direction = 0;
//CODE STARTS HERE
always # (posedge clock) begin
if(enable) begin
bouncer_out = direction ? (bouncer_out >> 1) : (bouncer_out << 1);
direction <= (bouncer_out == 8'b00000001 || bouncer_out == 8'b10000000) ? ~direction : direction;
end
end
endmodule
This works perfectly in simulation but fails on the FPGA (DE10-Nano board, if interested).
I should also point out that this gets driven by a clock passed trough a PLL on the FPGA that is then
passed trough a divideByN block.
Here is the code for the divideByN block:
module clk_divn #(
parameter WIDTH = 20,
parameter N = 1000000)
(clk,reset, clk_out);
input clk;
input reset;
output clk_out;
reg [WIDTH-1:0] pos_count = {WIDTH{1'b0}};
reg [WIDTH-1:0] neg_count = {WIDTH{1'b0}};
wire [WIDTH-1:0] r_nxt = {WIDTH{1'b0}};
always #(posedge clk)
if (reset)
pos_count <=0;
else if (pos_count ==N-1) pos_count <= 0;
else pos_count<= pos_count +1;
always #(negedge clk)
if (reset)
neg_count <=0;
else if (neg_count ==N-1) neg_count <= 0;
else neg_count<= neg_count +1;
assign clk_out = ((pos_count > (N>>1)) | (neg_count > (N>>1)));
endmodule
The divideByN has also been tested in simulation and works fine.
I actually made a simulation in which the divideByN is connected to the "bouncer_block" if I can
call it like that and it also works.
Everything simulates but nothing works in real life....but isn't it always like that :P
I hope someone can help me figure this out because I really want to learn more about FPGA and use
them in future projects.
If you read all this you are awesome and I wish you an amazing day :)
Your bit bouncer is not operating synchronously to the system clock and neither does it have a reset condition, which is a recipe for trouble.
A better approach is to use a clock strobe and test for it on edges of the main system clock. Also, all inputs from tactile buttons should be synchronised to the system clock and debounced. Something like this:
Schematic
RTL
BitBouncer
module BitBouncer
(
input wire clock,
input wire reset,
input wire enable,
input wire clock_strobe,
output reg[7:0] bouncer_out
);
// Register to store data
reg direction = 0;
// CODE STARTS HERE
always #(posedge clock)
begin
if (reset)
begin
bouncer_out = 1;
direction = 0;
end
else if (enable && clock_strobe)
begin
bouncer_out = direction ? (bouncer_out >> 1) : (bouncer_out << 1);
direction <= (bouncer_out == 8'b00000001 || bouncer_out == 8'b10000000) ? ~direction : direction;
end
end
endmodule
ClockStrobe
module ClockStrobe
#(
parameter MAX_COUNT = 50000000
)
(
input wire clock,
input wire reset,
output reg clock_strobe
);
reg [$clog2(MAX_COUNT) - 1: 0] counter;
always #(posedge clock)
begin
if (reset)
begin
counter <= 0;
end
else
begin
counter <= counter + 1;
if (counter == MAX_COUNT)
begin
clock_strobe <= 1;
counter <= 0;
end
else
begin
clock_strobe <= 0;
end
end
end
endmodule
Sync
module Sync
(
input wire clock,
input wire in,
output reg out
);
reg [2:0] sync_buffer;
initial
begin
out = 0;
sync_buffer = 3'd0;
end
always #*
begin
out <= sync_buffer[2];
end
always #(posedge clock)
begin
sync_buffer[0] <= in;
sync_buffer[2:1] <= sync_buffer[1:0];
end
endmodule
Debounce
module Debounce
#(
parameter MAX_COUNT = 2500000
)
(
input wire clock,
input wire in,
output reg out
);
reg previous_in;
reg [$clog2(MAX_COUNT) - 1:0] counter;
initial begin
previous_in = 0;
counter = 0;
out = 0;
end
always #(posedge clock)
begin
counter <= counter + 1;
if (counter == MAX_COUNT)
begin
out <= previous_in;
counter <= 0;
end
else if (in != previous_in)
begin
counter <= 0;
end
previous_in <= in;
end
endmodule
I have tried to add a reset with no success but I have made my own divideByN and kept the reset Charles suggested and now it's working flawlessly. I think the code for the divideByN I took online might be unable to synthesize properly. Here is my new code for the divideByN:
module my_div_n #(parameter N = 1_000_000, parameter WIDTH = 20) (clock_in,
clock_out);
input wire clock_in;
output reg clock_out;
reg[WIDTH-2:0] counter; //WIDTH-2 because the last bit is taken care of by the fact that we flip the output (it acts as the last bit)
always # (posedge clock_in) begin
counter <= counter + 19'b1;
if(counter == N>>1) begin
counter <= 0;
clock_out <= !clock_out;
end
end
endmodule
And the code for my bit_bouncer:
module bit_bouncer(clock, enable, reset, bouncer_out);
//INPUTS PORTS
input clock;
input enable;
input reset;
//OUTPUTS PORTS
output [7:0] bouncer_out;
//INPUT DATA TYPE
wire clock;
wire enable;
wire reset;
//OUTPUT DATA TYPE
reg [7:0] bouncer_out;
//Register to store data
reg direction;
//CODE STARTS HERE
always # (posedge clock) begin
if(reset) begin
bouncer_out <= 8'b00000001;
direction <= 0;
end
else if(enable) begin
bouncer_out = direction ? (bouncer_out >> 1) : (bouncer_out << 1);
direction <= (bouncer_out == 8'b00000001 || bouncer_out == 8'b10000000) ? ~direction : direction;
end
end
endmodule
Here how everything is wired:
I would still like to know the purpose of the clock strobe because you make it seem as if I should probably know this if I want to understand my circuit better and all about synchronicity.
I've got a simple project which requires me to write a code for RS232 receiver and sender, then put them together and, finally, test if it works properly. I've prepared code for both sender and receiver (and also connecting block - top). My problem is that I don't know how to connect them, so they could work with each other properly.
The main issue is that I can't "transfer" data from data_o to data_i because of the fact that one is reg and second - wire. I wouldn't like to use inout for these purposes. I can't figure out any possible modifications to make it work.
Another issue is putting some flags that could kind of follow idea like this: if receiving -> not sending, if sending -> not receiving.
Here's my code:
top.v
`timescale 1ns / 1ps
module top (
clk_i,
rst_i,
RXD_i,
data_i,
TXD_o,
data_o
);
input clk_i;
input rst_i;
input RXD_i;
output TXD_o;
//the problem is here, can't data_i <= data_o because output is reg
input [7:0] data_i;
output [7:0] data_o;
receiver r1(clk_i, RXD_i, data_o);
sender s1(clk_i, data_i, TXD_o);
endmodule
receiver.v
`timescale 1ns / 1ps
module receiver (
clk_i,
RXD_i,
data_o
);
//inputs and outputs
input clk_i;
input RXD_i;
output reg [7:0] data_o;
//counter values
parameter received_bit_period = 5208;
parameter half_received_bit_period = 2604;
//state definitions
parameter ready = 2'b00;
parameter start_bit = 2'b01;
parameter data_bits = 2'b10;
parameter stop_bit = 2'b11;
//operational regs
reg [12:0] counter = 0; //9765.625Hz
reg [7:0] received_data = 8'b00000000;
reg [3:0] data_bit_count = 0;
reg [1:0] state = ready;
//latching part
reg internal_RXD;
always #(posedge clk_i) //latch RXD_i value to internal_RXD
begin
internal_RXD = RXD_i;
end
always #(clk_i) //receiving process
begin
case (state)
ready :
begin
if (internal_RXD == 0)
begin
state <= start_bit;
counter <= counter + 1;
end
else
begin
state <= ready;
counter <= 0;
data_bit_count <= 0;
end
end
start_bit :
begin
if (counter == half_received_bit_period)
begin
if (internal_RXD == 0)
begin
state <= data_bits;
counter <= 0;
end
end
else
begin
state <= start_bit;
counter <= counter + 1;
end
end
data_bits :
begin
if (counter == received_bit_period)
begin
received_data[data_bit_count] <= internal_RXD;
data_bit_count <= data_bit_count + 1;
counter <= 0;
if (data_bit_count == 8)
state <= stop_bit;
end
else
counter <= counter + 1;
end
stop_bit:
begin
counter <= counter + 1;
if (counter == received_bit_period)
begin
state <= ready;
data_o <= received_data;
end
end
endcase
end
endmodule
sender.v
`timescale 1ns / 1ps
module sender (
clk_i,
data_i,
TXD_o
);
//inputs and outputs
input clk_i;
input [7:0] data_i;
output reg TXD_o;
//counter values
parameter received_bit_period = 5208;
parameter half_received_bit_period = 2604;
//state definitions
parameter ready = 1'b0;
parameter data_bits = 1'b1;
//operational regs
reg [12:0] counter = 0; //9765.625Hz
reg [9:0] framed_data = 0;
reg [3:0] data_bit_count = 0;
reg state = ready;
always #(posedge clk_i) //sending process
begin
case (state)
ready :
begin // flag needed?
state <= data_bits;
TXD_o <= 1;
framed_data[0] <= 1'b0;
framed_data[8:1] <= data_i;
framed_data[9] <= 1'b1;
counter <= 0;
end
data_bits :
begin
counter <= counter + 1;
if (data_bit_count == 10)
begin // flag needed?
state <= ready;
data_bit_count <= 0;
TXD_o <= 1;
end
else
begin
if (counter == received_bit_period)
begin
data_bit_count <= data_bit_count + 1;
end
TXD_o <= framed_data[data_bit_count];
end
end
endcase
end
endmodule
You don't!
In all CPU's and FPGA nowadays the read and write data path are separate buses. You will find that also with all CPU cores. Have a look at AXI or AHB bus protocols from ARM.
What is more worrying is the way you have implemented your functions. You would at least need some 'data valid' signal for the transmitter to know when there is valid data to transmit and for the receive when valid data has arrived.
Even that is not enough because for the TX the connecting logic would need to know when the data has been send and the next byte can go out.
You need to make a (preferably standard) CPU interface which talks to your UART. (For beginner I would not use AXI.)
As to your flags: they would come from within the CPU interface.
Last: a UART should be capable of transmitting and receiving at the same time.
EDIT: removed some redundancies, moved all assignments to non-blocking, inserted a reset mapped as one of the input buttons of my FPGA... but when I implement the code, it starts transmitting the same wrong character and gets stuck in a single state of my machine.
Post Synthesis and Post-Implementation simulations are identical,$time-wise
module UART (reset_button, sysclk_p, sysclk_n,TxD, Tx_busy, Tx_state_scope_external);
input reset_button, sysclk_p, sysclk_n;
output wire TxD, Tx_busy;
output wire [1:0]Tx_state_scope_external;
//internal communications signals
wire clk_internal;
//buffer unit control signals
wire [7:0]TxD_data_internal;
wire Tx_start_internal;
wire Tx_busy_internal;
wire reset_flag;
reset_buf RESET_BUFF (.reset_internal (reset_flag), .reset (reset_button));
differential_CK CK_GENERATION (.sysclk_p (sysclk_p), .sysclk_n(sysclk_n), .clk(clk_internal));
output_Dbuffer OB1 (.reset (reset_flag), .RTS_n (Tx_busy_internal), .clk(clk_internal), .TX_trigger (Tx_start_internal), .TX_data(TxD_data_internal));
async_transmitter TX1 (.reset (reset_flag), .clk (clk_internal), .TxD_data(TxD_data_internal), .Tx_start (Tx_start_internal), .TxD(TxD), .Tx_busy_flag(Tx_busy_internal), .Tx_state_scope(Tx_state_scope_external));
obuf_TX O_TX1( .Tx_busy(Tx_busy), .Tx_busy_flag(Tx_busy_internal));
endmodule
module reset_buf (
output reset_internal,
input reset
);
// IBUF: Single-ended Input Buffer
// 7 Series
// Xilinx HDL Libraries Guide, version 14.7
IBUF #(
.IBUF_LOW_PWR("TRUE"), // Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
.IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUF_inst (
.O(reset_internal), // Buffer output
.I(reset) // Buffer input (connect directly to top-level port)
);
// End of IBUF_inst instantiation
endmodule
module differential_CK(
input sysclk_p,
input sysclk_n,
output clk
);
// IBUFGDS: Differential Global Clock Input Buffer
// 7 Series
// Xilinx HDL Libraries Guide, version 14.7
IBUFGDS #(
.DIFF_TERM("FALSE"), // Differential Termination
.IBUF_LOW_PWR("TRUE"), // Low power="TRUE", Highest performance="FALSE"
.IOSTANDARD("DEFAULT") // Specify the input I/O standard
) IBUFGDS_inst (
.O(clk), // Clock buffer output
.I(sysclk_p), // Diff_p clock buffer input (connect directly to top-level port)
.IB(sysclk_n) // Diff_n clock buffer input (connect directly to top-level port)
);
// End of IBUFGDS_inst instantiation
endmodule
module output_Dbuffer (
input reset,
input RTS_n, //TX_BUSY flag of the transmitter is my ready to send flag
input clk, //ck needed for the FSM
output wire TX_trigger, //TX_START flag of the transmitter now comes from THIS unit instead of Receiver
output wire [7:0]TX_data //byte for transmission
);
//internal variables
reg [7:0] mem [0:9]; //memory init, 10 * 8 bit locations
integer m, n, i, j, k ; //M = row [a.k.a. bytes], N = column [a.k.a. single bits]
reg TX_trigger_int;
reg [7:0] TX_data_int, TX_complete;
//reg sum256_ok;
reg [7:0]checksum_buff ;
//buffer FSM required variables
localparam //state enumeration declaration
BUF_IDLE = 3'b000,
BUF_START = 3'b001,
BUF_BYTES = 3'b010,
BUF_BUSY = 3'b011,
BUF_TX_CHECKSUM = 3'b100;
reg [2:0] buf_state; //2 bits for 4 states
//static assignments of OUTPUTS : Transmission Flag and Transmission Data (content)
assign TX_trigger = TX_trigger_int;
assign TX_data = TX_data_int;
//Block for transmitting [here I manage the TX_Data and TX_Trigger functionality]
always #(posedge clk)
begin
if (reset)
begin
buf_state <= BUF_IDLE;
TX_trigger_int <= 0;
TX_data_int <= 8'b00000000;
end
else case (buf_state)
BUF_IDLE:
begin
TX_trigger_int <= 0;
TX_data_int <= 8'b00000000;
m <=0;
n <=0;
i <=0;
j <=0;
mem[9] <= 8'b01010001; //81
mem[8] <= 8'b01000000; //64
mem[7] <= 8'b00110001; //49
mem[6] <= 8'b00100100; //36
mem[5] <= 8'b00011001; //25
mem[4] <= 8'b00010000; //16
mem[3] <= 8'b00001001; //9
mem[2] <= 8'b00000100; //4
mem[1] <= 8'b00000001; //1
mem[0] <= 8'b00000010;//2
checksum_buff <= 8'd31;
//check if the TX is not busy
if (RTS_n == 0) buf_state <= BUF_START;
end
BUF_START:
begin
TX_trigger_int <= 0;
if ((i == 0) || ( (j - i) > 1 )) buf_state <= BUF_BYTES;
else begin
$display ("BUFFER BUSY #time:", $time);
buf_state <= BUF_BUSY;
end
end
BUF_BYTES:
begin
//check if the TX is busy
if (RTS_n==0)
begin
// TX_trigger_int = 1; 21.09 MOVED THE TRIGGER INSIDE THE ELSE N LINE 498
if (j > 9)
begin
TX_trigger_int <= 0;
buf_state <= BUF_TX_CHECKSUM;
end
else begin
TX_data_int <= mem[j];
TX_trigger_int <= 1;
j <= j+1;
//TX_trigger_int =0;
buf_state <= BUF_START;
end
end
else buf_state <= BUF_BYTES;
end
BUF_BUSY:
begin
if (RTS_n == 0)
begin
$display ("BUFFER AVAILABLE AGAIN #time:", $time);
buf_state <= BUF_START;
end
end
BUF_TX_CHECKSUM:
begin
if (RTS_n==0) begin
TX_data_int <= checksum_buff;
// sum256_ok = 0;
TX_trigger_int <= 1;
buf_state <= BUF_IDLE;
end
end
//default: buf_state <= BUF_IDLE;
endcase
end
endmodule
module async_transmitter(
input clk,
input reset,
//differential clock pair
input [7:0] TxD_data,
input Tx_start, // it is ==TX_TRIGGER
output wire TxD, //bit being sent to the USB
output reg Tx_busy_flag,
output wire [1:0]Tx_state_scope
);
localparam //state enumeration declaration
TX_IDLE = 2'b00,
TX_START_BIT = 2'b01,
TX_BITS = 2'b10,
TX_STOP_BIT = 2'b11;
parameter ClkFrequencyTx = 200000000; // 200MHz
parameter BaudTx = 9600;
reg [1:0] Tx_state; //2 bits for 4 states
integer bit_counter; //bit counter variable
reg [7:0]TxD_data_int, TxD_int;
integer i; //vector index for output data
wire TXSTART_Trigger;
StartDetectionUnitTX SDU_TX (.clk(clk), .state (Tx_state), .signal_in (Tx_start), . trigger (TXSTART_Trigger));
wire BitTick;
BaudTickGen #(ClkFrequencyTx, BaudTx) as (.clk(clk), .trigger (TXSTART_Trigger), .tick(BitTick));
//BitTick is 16times the frequency generated during the RX portion
assign TxD = TxD_int;
always #(posedge clk) begin
if (reset)
begin
Tx_state <= TX_IDLE;
TxD_int <= 1;
Tx_busy_flag <=0;
end
else case (Tx_state)
TX_IDLE:
begin //reinitialization and check on the trigger condition
bit_counter <= 0;
TxD_data_int <= 8'b00000000;
i <= 0;
TxD_int <= 1; //idle state
Tx_busy_flag <= 0;
if (TXSTART_Trigger) begin
Tx_state <= TX_START_BIT;
TxD_data_int <= TxD_data;
Tx_busy_flag <= 1;
bit_counter <= 8;
end
end
TX_START_BIT:
begin
if (BitTick)
begin
TxD_int <= 0 ; //start bit is a ZERO logical value
Tx_state <= TX_BITS;
end
end
TX_BITS:
begin
if (BitTick)
begin
bit_counter <= bit_counter -1;
TxD_int <= TxD_data_int[i];
// $display ("ho trasmesso dalla UART un bit di valore %b al tempo: ", TxD, $time);
i <= i+1;
if (bit_counter < 1) Tx_state <= TX_STOP_BIT;
end
end
TX_STOP_BIT:
begin
if (BitTick) begin
TxD_int <= 1; //STOP BIT is a logical '1'
Tx_busy_flag <= 0;
Tx_state <= TX_IDLE;
end
end
// default: Tx_state <= TX_IDLE;
endcase
end
assign Tx_state_scope = Tx_state;
endmodule
module obuf_TX (
output Tx_busy,
input Tx_busy_flag
);
// OBUF: Single-ended Output Buffer
// 7 Series
// Xilinx HDL Libraries Guide, version 14.7
OBUF #(
.DRIVE(12), // Specify the output drive strength
.IOSTANDARD("DEFAULT"), // Specify the output I/O standard
.SLEW("SLOW") // Specify the output slew rate
) OBUF_inst (
.O(Tx_busy), // Buffer output (connect directly to top-level port)
.I(Tx_busy_flag) // Buffer input
);
// End of OBUF_inst instantiation
endmodule
module StartDetectionUnitTX ( //detects a rising edge of the start bit == TRANSMISSION START, during the IDLE state = 0000
input clk, [1:0]state,
input signal_in,
output trigger
);
reg signal_d;
always #(posedge clk)
begin
signal_d <= signal_in;
end
assign trigger = signal_in & (!signal_d) & (!state);
endmodule
module BaudTickGen (
input clk, trigger,
output tick //generates a tick at a specified baud rate *oversampling
);
parameter ClkFrequency = 200000000; //sysclk at 200Mhz
parameter Baud = 9600;
parameter Oversampling = 1;
//20832 almost= ClkFrequency / Baud, to make it an integer number
integer counter = (20833/Oversampling)-1; //-1 so counter can get to 0
reg out;
always #(posedge clk)
begin
if (trigger)
begin
counter <= (20833/Oversampling)-1; //-1 so counter can get to 0
out <= 1;
end
if (counter == 0)
begin
counter <= (20833/Oversampling)-1; //-1 so counter can get to 0
out <= 1;
end
else begin
counter <= counter-1;
out <= 0;
end
end
assign tick = out;
endmodule
My FPGA is a Virtex-7 VC707 and I'm using Vivado for my design flow.
Here I am attaching an image of my looping error.
error image
What have you done? Have you just simulated the code? Are you saying that it fails on the board, but the post-implementation sim is Ok?
A difference between pre- and post-implementation sim could point to a race condition. Get rid of all your blocking assignments, replace with NBAs (why did you use blocking assignments?)
Don't go to Chipscope - it's just a red flag that you don't know what you're doing
The code is a mess - simplify it. The Xilinx-specific stuff is irrelevant - get rid of it if you want anyone to look at it, fix comments (2-bit state?!), fix your statement about getting stuck in '10', etc
Have you run this through Vivado? Seriously? You have multiple drivers on various signals. Get rid of the initial block, use a reset. Initialise the RAM in a way which is understood by the tools. Even if Vivado is capable of initialising stuff using a separate initial block, don't do it
Get rid of statements like 'else Tx_state = TX_IDLE' in the TX_IDLE branch - they're redundant, and just add verbosity
Write something which fails stand-alone, and post it again.