6
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ 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) \$\endgroup\$ – John Burton May 1 '11 at 13:38
  • \$\begingroup\$ I just found similar code on fpga4fun.com/SerialInterface.html which works when I try it. I would still like to know what's wrong with mine though \$\endgroup\$ – John Burton May 1 '11 at 13:55
  • 4
    \$\begingroup\$ 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. \$\endgroup\$ – stevenvh May 1 '11 at 14:05
  • 1
    \$\begingroup\$ 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? \$\endgroup\$ – John Burton May 1 '11 at 15:17
  • \$\begingroup\$ 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. \$\endgroup\$ – The Photon Jul 20 '12 at 16:11
13
\$\begingroup\$

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.

\$\endgroup\$
  • 1
    \$\begingroup\$ Accepted this answer because it was my actual problem. But thanks for all the input too from others, +1 for them :) \$\endgroup\$ – John Burton May 2 '11 at 15:32
6
\$\begingroup\$

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
\$\endgroup\$
  • \$\begingroup\$ Yes absolutly this is to learn verilog. Seemed like a nice manageable little project to learn some basics. \$\endgroup\$ – John Burton May 1 '11 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 May 1 '11 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 May 1 '11 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 May 1 '11 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 May 1 '11 at 18:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.