RS232 UART verilog code

serialverilog

I am trying to generate a Verilog code for transmitter that sends data at 1 start bit and 1 stop bit from FPGA and receive on my PC at 1 stop bit. If anyone can provide a link or suggestion, it will be highly appreciated.

Code is as follows:

module tb_tx_serial (input clk, output TxD);

  // Inputs
  reg TxD_start=0;
  reg [7:0] TxD_data=0;
  reg [7:0] count=0;

  // Outputs
  //wire TxD;
  wire TxD_busy;

  // Instantiate the Unit Under Test (UUT)
  async_transmitter uut (
    .clk(clk), 
    .TxD_start(TxD_start), 
    .TxD_data(TxD_data), 
    .TxD(TxD), 
    .TxD_busy(TxD_busy)
  );

  always @(posedge clk) begin
    //if(count <= 6) begin
      TxD_start <= 1'b1;
      TxD_data <= count; 
    // else TxD_data <= 8'b10111011;
  end

  always @(posedge clk) begin
    count <= count + 1;
  end

endmodule

module async_transmitter (
  input clk,
  input TxD_start,
  input [7:0] TxD_data,
  output TxD,
  output TxD_busy
);

  // Assert TxD_start for (at least) one clock cycle to start transmission of TxD_data
  // TxD_data is latched so that it doesn't have to stay valid while it is being sent

  parameter ClkFrequency = 50000000;  // 50MHz
  parameter Baud = 9600;

  //generate
  //  if(ClkFrequency<Baud*8 && (ClkFrequency % Baud!=0)) ASSERTION_ERROR PARAMETER_OUT_OF_RANGE("Frequency incompatible with requested Baud rate");
  //endgenerate

  ////////////////////////////////
`ifdef SIMULATION
  wire BitTick = 1'b1;  // output one bit per clock cycle
`else
  wire BitTick;

  BaudTickGen #(ClkFrequency, Baud) tickgen (
    .clk(clk), 
    .enable(TxD_busy), 
    .tick(BitTick)
  );
`endif

  reg [3:0] TxD_state = 0;
  wire TxD_ready = (TxD_state==0);

  assign TxD_busy = ~TxD_ready;

  reg [7:0] TxD_shift = 0;

  always @(posedge clk) begin
    if (TxD_ready & TxD_start)
      TxD_shift <= TxD_data;
    else if (TxD_state[3] & BitTick)
      TxD_shift <= (TxD_shift >> 1);

    case(TxD_state)
    4'b0000: if (TxD_start) TxD_state <= 4'b0100;
    4'b0100: if (BitTick) TxD_state <= 4'b1000;  // start bit
    4'b1000: if (BitTick) TxD_state <= 4'b1001;  // bit 0
    4'b1001: if (BitTick) TxD_state <= 4'b1010;  // bit 1
    4'b1010: if (BitTick) TxD_state <= 4'b1011;  // bit 2
    4'b1011: if (BitTick) TxD_state <= 4'b1100;  // bit 3
    4'b1100: if (BitTick) TxD_state <= 4'b1101;  // bit 4
    4'b1101: if (BitTick) TxD_state <= 4'b1110;  // bit 5
    4'b1110: if (BitTick) TxD_state <= 4'b1111;  // bit 6
    4'b1111: if (BitTick) TxD_state <= 4'b0010;  // bit 7
    4'b0010: if (BitTick) TxD_state <= 4'b0011;  // stop1
    4'b0011: if (BitTick) TxD_state <= 4'b0000;  // stop2
    default: if (BitTick) TxD_state <= 4'b0000;
    endcase
  end

  assign TxD = (TxD_state<4) | (TxD_state[3] & TxD_shift[0]);  // put together the start, data and stop bits

endmodule

////////////////////////////////////////////////////////
// dummy module used to be able to raise an assertion in Verilog
//module ASSERTION_ERROR();
//endmodule

`timescale 1ns / 1ps

////////////////////////////////////////////////////////
module BaudTickGen
(
  input clk, enable,
  output tick  // generate a tick at the specified baud rate * oversampling
);
  parameter ClkFrequency = 50000000;
  parameter Baud = 9600;
  parameter Oversampling = 1;

  function integer log2(input integer v); 
    begin 
      log2=0; 
      while (v>>log2) log2 = log2 + 1; 
    end 
  endfunction

  localparam AccWidth = log2(ClkFrequency/Baud)+8;  // +/- 2% max timing error over a byte

  reg [AccWidth:0] Acc = 0;
  localparam ShiftLimiter = log2(Baud*Oversampling >> (31-AccWidth));  // this makes sure Inc calculation doesn't overflow
  localparam Inc = ((Baud*Oversampling << (AccWidth-ShiftLimiter))+(ClkFrequency>>(ShiftLimiter+1)))/(ClkFrequency>>ShiftLimiter);

  always @(posedge clk) begin
    if (enable) 
      Acc <= Acc[AccWidth-1:0] + Inc[AccWidth:0]; 
    else Acc <= Inc[AccWidth:0];
  end

  assign tick = Acc[AccWidth];

endmodule

Test bench:

`timescale 1ns / 1ps
module test_srltst;

    // Inputs
    reg clk;

    // Outputs
    wire TxD;

    // Instantiate the Unit Under Test (UUT)
    tb_tx_serial uut (
        .clk(clk), 
        .TxD(TxD)
    );

    initial
    begin
        clk = 0;
        forever #10 clk = ~clk;
    end

endmodule

Dont know it would help or not, but I have provided this in my UCF file for UART

#NET "TxD" LOC = "M14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = SLOW ;

Best Answer

I have a Working code for UART Transmitter in VHDL from my latest project. I'm not familiar with verilog. If you are comfortable in VHDL, go through the following code.It's a simple FSM model and easily understandable.

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;

    entity Tx_UART_Macro is
        Port ( rst,en,clk, parity, odd_even : in  STD_LOGIC;
                tx_din                           : in  STD_LOGIC_VECTOR (8 downto 1);
                rd,tx_dout,frame_ok          : out  STD_LOGIC);
        attribute fsm_encoding: string;
        attribute fsm_encoding of Tx_UART_Macro: entity is "gray";

    end Tx_UART_Macro;

    architecture Behavioral of Tx_UART_Macro is
    type state is(idle,rd_data,start,increment,transmit,stop,frame_gap,parity_st);
    signal current_state, next_state : state;
    signal count            : integer range 0 to 15;
    signal frame_count  : integer range 0 to 7;
    signal tx_din_sig   : STD_LOGIC_VECTOR(8 downto 1);
    signal par_cnt      : STD_LOGIC_VECTOR(1 downto 0);
    signal tx_reg       : STD_LOGIC_VECTOR(4 downto 0); 

    begin
    process(rst,clk)
    begin 
            if(rst='1')then
            count   <= 0;
            tx_dout <= '1';
            current_state <= idle;
            rd <='0';
            frame_count <=0;
            tx_din_sig <= (others=>'0');
            par_cnt <= "00";
            frame_ok        <= '0';

            elsif ( rising_edge(clk)) then
                current_state <= next_state;
                case next_state is
                when idle =>
                    count <= 0; 
                    tx_dout <= '1';
                    rd <='0';
                    frame_count <=0;
                    par_cnt <= "00";
                    frame_ok        <= '0';

                when rd_data =>
                    rd <= '1';
                    tx_din_sig <= tx_din;

                when start =>
                    tx_dout <='0';

                    when increment =>
                    count <= count+1;

                    when transmit =>
                    tx_dout <= tx_din_sig(count);

                    when parity_st=>
                        tx_dout  <= tx_din_sig(1)  xor tx_din_sig(2)  xor tx_din_sig(3)  xor tx_din_sig(4)  xor
                                        tx_din_sig(5)  xor tx_din_sig(6)  xor tx_din_sig(7)  xor tx_din_sig(8)  xor odd_even;
                        par_cnt <= par_cnt + '1';

                    when stop =>
                    tx_dout <= '1';

                    when frame_gap =>
                    frame_count <=  frame_count +   1;
                    frame_ok        <= '1';

                    when others =>
                        count   <= 0;
                        tx_dout <= '1';
                        rd <='0';
                        frame_count <=0;
                        tx_din_sig <= (others=>'0');
                        frame_ok        <= '0';


                    end case;
                    end if;
        end process;
        process(current_state,en,count,frame_count, par_cnt,parity)
        begin
            next_state <= current_state;
            case current_state is
            when idle =>
            if(en ='1') then
                next_state <= rd_data;
            else
                next_state <= idle;
                end if;  
            when rd_data =>

            next_state <= start;        

            when    start =>
                next_state <= increment;
            when increment =>
            if(count < 9) then 
                next_state <= transmit;
            else
                if(parity = '1') then
                    next_state <= parity_st;
                else
                    next_state <= stop;
                end if; 
            end if; 
            when transmit =>
                next_state <= increment;
            when parity_st=>
                if(par_cnt = "10") then
                    next_state <= stop;
                else
                    next_state <= parity_st;
                end if; 
            when stop =>
                next_state <= frame_gap;
            when frame_gap =>
                next_state <= idle;
            when others =>
                next_state <= idle;
        end case;
        end process;
    end Behavioral;