I don't know if this belongs here or stackoverflow. I assume here as although verilog looks like software it's actually describing hardware connections?
I have a Spartan-3AN evaluation board and I'm trying to implement a simple rs232 port interface on it which I can't get to work. I'm an experienced software developer but new to verilog and digital design. I want to move up from flashing a single LED to the next step.
I've tried to implement it like this - 1) Generate a clock pulse "serclock" at the baud rate, so at the start of each bit. 2) Implement a state machine that once it's told to start steps through the states at the correct speed. 3) Implement a lookup to output the correct data bit depending on the state that 2) is in.
If there is a better way I'd appreciate any help. However I would expect this to work but I get nothing at all. Can anyone spot anything stupid that I've done? I'd appreciate any advice.
// Serial port demo program
//
// Assumptions: 50Mhz clock rate
module SerDemo(input clk, output ser);
// Start signal tells it to start sending bits
reg start;
//The bits of data to send
reg [7:0] data;
/////////////////////////////////////////////////////////////////////////////
// Serial port clock generator
// Generate a 9600 baud clock signal for the serial port by dividing the
// 50Mhz clock by 5208
reg [14:0] clockdiv;
// Count from 0..5207 then reset back to zero
always @(posedge clk)
begin
if (clockdiv == 5207)
clockdiv <= 0;
else
clockdiv <= clockdiv + 1;
end
// The serclock is a short pulse each time we are reset
wire serclock = (clockdiv == 0);
/////////////////////////////////////////////////////////////////////////////
// Serial port state machine
// Only start the state machine when "start" is set. Only advance to the
// next state when serclock is set.
reg [3:0] state;
always @(posedge clk)
begin
case (state)
4'b0000: if (start) state <= 4'b0001;
4'b0001: if (serclock) state <= 4'b0010; // Start bit
4'b0010: if (serclock) state <= 4'b0011; // Bit 0
4'b0011: if (serclock) state <= 4'b0100; // Bit 1
4'b0100: if (serclock) state <= 4'b0101; // Bit 2
4'b0101: if (serclock) state <= 4'b0110; // Bit 3
4'b0110: if (serclock) state <= 4'b0111; // Bit 4
4'b0111: if (serclock) state <= 4'b1000; // Bit 5
4'b1000: if (serclock) state <= 4'b1001; // Bit 6
4'b1001: if (serclock) state <= 4'b1010; // Bit 7
4'b1010: if (serclock) state <= 4'b0000; // Stop bit
default: state <= 4'b0000; // Undefined, skip to stop
endcase
end
///////////////////////////////////////////////////////////////////////////////
// Serial port data
// Ensure that the serial port has the correct data on it in each state
reg outbit;
always @(posedge clk)
begin
case (state)
4'b0000: outbit <= 1; // idle
4'b0001: outbit <= 0; // Start bit
4'b0010: outbit <= data[0]; // Bit 0
4'b0011: outbit <= data[1]; // Bit 1
4'b0100: outbit <= data[2]; // Bit 2
4'b0101: outbit <= data[3]; // Bit 3
4'b0110: outbit <= data[4]; // Bit 4
4'b0111: outbit <= data[5]; // Bit 5
4'b1000: outbit <= data[6]; // Bit 6
4'b1001: outbit <= data[7]; // Bit 7
4'b1010: outbit <= 0; // Stop bit
default: outbit <= 1; // Bad state output idle
endcase
end
// Output register to pin
assign ser = outbit;
///////////////////////////////////////////////////////////////////////////////
// Test by outputting a letter 'd'
always @(posedge clk)
begin
data = 100;
start = 1;
end
endmodule
2 Answers 2
I don't speak Verilog, but I noticed that your stopbit is zero, which should be 1. Are you reading the port on a scope, or are you reading on a UART? In the latter case you may not have a character received if it doesn't see the stopbit.
You did not reset the system to a known state.
That said, I assume that you are doing this to learn Verilog? Otherwise, there are many freely available cores that you can find on the Internet that does this. :)
As an example:
// Count from 0..5207 then reset back to zero
always @(posedge clk)
begin
if (rst) begin
clockdiv <= 0;
end else begin
if (clockdiv == 5207)
clockdiv <= 0;
else
clockdiv <= clockdiv + 1;
end
end
-
\$\begingroup\$ Yes absolutly this is to learn verilog. Seemed like a nice manageable little project to learn some basics. \$\endgroup\$John Burton– John Burton2011年05月01日 15:04:51 +00:00Commented May 1, 2011 at 15:04
-
1\$\begingroup\$ I'll add a reset. I figured that the clock would wrap around soon enough anyway though so this would just cause the first bit to be delayed a few ms. Not what I'd do for real projects but a reasonable shortcut while learning. Am I wrong? \$\endgroup\$John Burton– John Burton2011年05月01日 15:05:54 +00:00Commented May 1, 2011 at 15:05
-
2\$\begingroup\$ You cannot assume that the registers start at 0. Therefore, it is imperative that all registers be reset to a known state at startup. In your case, state and clockdiv are both undefined at startup. So, incrementing an undefined value is still undefined, etc... \$\endgroup\$sybreon– sybreon2011年05月01日 16:38:18 +00:00Commented May 1, 2011 at 16:38
-
1\$\begingroup\$ I figured that it would have some value between 0..8191 so would eventually end up at zero and start working. Point taken though, I will be sure to handle reset properly in future. \$\endgroup\$John Burton– John Burton2011年05月01日 17:03:47 +00:00Commented May 1, 2011 at 17:03
-
2\$\begingroup\$ On an FPGA, a reset may not be strictly necessary. I don't know for sure about Spartan-3, but for other Xilinx architectures, the initial state of the registers is defined in the configuration. For maximum portability (to different architectures, or an ASIC), HDL descriptions should typically still have a reset, but a reset is not required. \$\endgroup\$Andy– Andy2011年05月01日 18:52:38 +00:00Commented May 1, 2011 at 18:52
outbit
you could use a shift register rather than a mux to reduce resource usage. \$\endgroup\$