7

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
Kevin Vermeer
  • 20,067
  • 8
  • 57
  • 102
John Burton
  • 2,106
  • 4
  • 23
  • 34
  • Oh, I didn't say what the problem is. The problem is that I get nothing at all on the serial port output. I would expect a stream of letters 'd's (ascii code 100) – John Burton May 01 '11 at 13:38
  • I just found similar code on http://www.fpga4fun.com/SerialInterface.html which works when I try it. I would still like to know what's wrong with mine though – John Burton May 01 '11 at 13:55
  • 4
    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. – stevenvh May 01 '11 at 14:05
  • 1
    Oh no a typo. That's all it was. I looked at that code 100 times and didn't notice. Thank you, it works perfectly now. Can you put this as an answer then I can accept it? – John Burton May 01 '11 at 15:17
  • Not related to your question, but synthesizable Verilog depends a lot on following convention rather than just the strict rules of the language. Your code is almost certainly functional, but could use some review by experienced designers. First suggestion I'd make is that where you generate outbit you could use a shift register rather than a mux to reduce resource usage. – The Photon Jul 20 '12 at 16:11
  • Second is, where you generate state, if you move the test for serclock outside the case statement, you will generate a proper gated clock, and also keep your start detection sync'ed with serclock. As is, you may generate a runt start bit. – The Photon Jul 20 '12 at 16:12
  • If you post another question asking for general code review, you might get a few other useful suggestions. – The Photon Jul 20 '12 at 16:13
  • Thanks for the suggestions. Good idea. I'm not using this code any more but I do have some other verilog that works but might not be ideal that I might post for review in the next week or two. I figure it would also be a good question for people wanting to learn what is good practice as well as helping me. – John Burton Jul 20 '12 at 16:25
  • Also, I just realized I should have said enabled clocks, not gated clocks. Gated clocks are generally bad practice in FPGA's, but proper use of the clock-enable input of the flip-flops will save resources and improve timing. – The Photon Jul 20 '12 at 16:35
  • Also, not sure why this question popped to the front page, I didn't realize it was more than a year old when I commented. – The Photon Jul 20 '12 at 16:37
  • I was a little suprised to get a notification of comments, but it's still valid to add advice to an old question as the point of this site is to build up searchable questions as much as to answer people directly. – John Burton Jul 20 '12 at 16:40

2 Answers2

14

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.

stevenvh
  • 145,832
  • 21
  • 457
  • 668
7

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
sybreon
  • 1,601
  • 1
  • 13
  • 13
  • Yes absolutly this is to learn verilog. Seemed like a nice manageable little project to learn some basics. – John Burton May 01 '11 at 15:04
  • 1
    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? – John Burton May 01 '11 at 15:05
  • 2
    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... – sybreon May 01 '11 at 16:38
  • 1
    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. – John Burton May 01 '11 at 17:03
  • 2
    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. – Andy May 01 '11 at 18:52
  • While it's okay to allow specific signals to be undefined if they cannot take illegal values, it's generally good form to provide some mechanism to reset all flops to a known state. You'll be glad you did once it comes time to debug things. That said, the state variable of a finite state machine is most definitely not one of those signals that can be left undefined - ever. You must start from a known state. – ajs410 May 02 '11 at 16:04