Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

UART Transmitter by FPGA

Status
Not open for further replies.

huytergan

Member level 3
Joined
Jun 18, 2018
Messages
57
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
372
I want to send 8 bit data from FPGA to PC, 9600 baudrate, 8 bit data, 1 start&stop bit, no parity. I did coded my Basys3 Fpga and connected to PC. By using Tera Term, wanted to see how it works out. But probably something big I'm missing out. I just wrote a transmitter code and somewhere I saw that some button&top modules. Do I need them to see a 8-bit data's ASCII equivalent on my PC?

My code is below,
Code:
library ieee;
use ieee.std_logic_1164.all;


entity rs232_omo is
generic(clk_max:integer:=10400); --for baudrate
                                      

port(

clk : in std_logic;
rst : in std_logic;
start : in std_logic;
input : in std_logic_vector(7 downto 0);
done : out std_logic;
output : out std_logic;
showstates: out std_logic_vector(3 downto 0)

);
end entity;

architecture dataflow of rs232_omo is

type states is (idle_state,start_state,send_state,stop_state);
signal present_state,next_state : states;
signal data,data_next : std_logic;


begin


process(clk,rst)
variable count : integer range 0 to clk_max;
variable index : integer range 0 to 10;
begin
        
    if rst='1' then
        present_state<=idle_state;
        count:=0;
        data<='1';
        
        
    elsif rising_edge(clk) then
        
        present_state<=next_state;
        count:=count+1;
        index:=index+1;
        data<=data_next;

    end if;

end process;

process(present_state,data,clk,rst,start)
variable count : integer range 0 to clk_max;
variable index : integer range 0 to 10;
begin

done<='0';
data_next<='1';

    case present_state is
    
        when idle_state =>
            showstates<="1000";
            data_next<='1';
            
            if start='1' and rst='0' then
                count:=count+1;
                if count=clk_max then
                    next_state<=start_state;
                    count:=0;
                end if;    
            end if;
            
        when start_state =>
            showstates<="0100";
            data_next<='0';
           
            count:=count+1;
            if count=clk_max then
                next_state<=send_state;
                count:=0;
            end if;
        
        when send_state =>
            showstates<="0010";
            count:=count+1;
            data_next<=input(index);
            
            if count=clk_max then
                if index=7 then
                    index:=0;
                    next_state<=stop_state;
                else
                    index:=index+1;
                end if;
            count:=0;
            end if;

        when stop_state =>
            showstates<="0001";
            count:=count+1;
            if count=clk_max then
            next_state<=idle_state;
            done<='1';
            count:=0;
            end if;
            
end case;

end process;
output<=data;

end architecture;

Testbench simulation(input is "00001111")

rs232.jpg


For any help, I appreciate in advance
 
Last edited:

Hi,

Honestly, I don't understand your code....maybe because I'm not that experienced. But usually when I see cide, then I understand at least a little.

But here I don't recognize
* what's your system clock frequency
* where the baud rate generator is, that generates an ENABLE every 1/9600 s
* and where the state machine is: idle, start, 8 bits data, stop...then return to start or idle

Klaus
 

Hi,

Honestly, I don't understand your code....maybe because I'm not that experienced. But usually when I see cide, then I understand at least a little.

But here I don't recognize
* what's your system clock frequency
* where the baud rate generator is, that generates an ENABLE every 1/9600 s
* and where the state machine is: idle, start, 8 bits data, stop...then return to start or idle

Klaus

Hi,
System clock frequency is 100 MHz(10 ns)
For baud rate generator, 1/9600 = clk_max x 10 ns equation tells me the clk_max will be 10400 which’s defined in entity’s generic. For each state/bit, ‘count’ is counting up to ‘clk_max’, then change state/bit.

States are defined in declaration part of Architecture. And their operation is shown inside of second process.(idle_state, start_state, send_state, stop_state)
 

Hi,

It will not cause your UART communication to fail, but it won't hurt to do the math more precisely:
100,000,000 / 9,600 = 10,416.6666. Thus 10,417 is the rounded integer value. The counter should run 0.... 10,416.

I understand a bit more now of your code. It's hard to read. I really recommend to do the baudrate generation in an extra process.

In your first process you handle the reset state, I assume correctly.
But then there is an "else if" where COUNT is incremented unconditionally and INDEX is incremented unconditionally.
But the same is handled in your second process, too. This may cause problems.

****
Some other issues.
I recommend to buffer your INPUT. It sould be latched when you start transmission, to prevent transmitting a corrupted byte when INPUT is modified externally.

When RESET is asserted you stop transmission immediately. I may want this or not ... but when you do this, it will cause problems at the receiver, because the byte is not transmitted completely .... and - when you start to transmit a new byte too soon it will be corrupted at the receiver, too.
If you really want to stop immediately: you should at least wait for 10 bit times outputting "1" before you start to transmit a new byte.

Klaus
 

index/count are variables local to each process. index/count in the first process are never used but are assigned. The are different from index/count declared in the second process.

The need to hold start for 10k cycles is odd. It basically forces two stop bits. But that only affects bandwidth and not functionality.

You would need to get inputs to this module, define the clock constraint, and define the IO placement for all of the external IO. If this module is intended to be the top level module you would also need to define where the inputs come from and where the output goes. It makes more sense to have a top level module that has your rs232 as a module. In that case you wouldn't need to connect done/showstates to external IO.

If you have specific problems you should post them.

--edit: also, for the two-process style of code you should place next_state <= present_state (and next_data <= data) before the case statement. this is a simple trick to avoid latches.

More important, the count/index inside the second process only work in simulation. The expression x = x + 1 inside a combinatorial process doesn't make sense. in works in simulation because the sensitivity list prevents x from incrementing multiple times, but the synthesis tool ignores this.
 
Last edited:

index/count are variables local to each process. index/count in the first process are never used but are assigned. The are different from index/count declared in the second process.
Unfortunately index/count are incremented in a combination process without clock edge sensitivity condition. This "works" in a simulation as a side effect of the sensitivity list but not in real hardware because a counter without clock isn't synthesizable. You need to restructure your two process FSM.

As for the original question "do I need a top module". The present code (if made synthesizable) can send a constant single character endlessly, but not output meaningful UART data. Your PC won't be able to receive the endlessly repeated character correctly without a preceeding pause.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top