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.

[Moved] FPGA VHDL UART RX line how to handle incoming bytes?

Status
Not open for further replies.

macellan

Newbie level 6
Joined
Dec 14, 2010
Messages
13
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,498
Hello

I'm trying to design a counter system on my FPGA board using VHDL. My design needs to receive some bytes as control signals like start, stop reset and measurement period info. For this purpose I have a UART module including both TX and RX serial lines and I'm also using a usb serial converter.

For processing the commands I have used a case block. Depending on the received byte I want to perform different tasks as it is indicated as start, stop, reset and period. I' ve attached the test bench files which shows everything is fine. However, in reality when I send a command through my GUI on computer first it works but then the next received byte changes the previous. So I can' t handle each different bytes or commands successfully.

How can I handle incoming bytes? Does anyone have any suggestion related to a modification or a different structure?

Thanks in advance...

stop_watch.vhd

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
--==================================================================================
--
-- timer = 100.000.000)  ->  1/1     second
-- timer =  50.000.000)  ->  1/2     second = 500 mili second
-- timer =  25.000.000)  ->  1/4     second = 250 mili second
-- timer =  10.000.000)  ->  1/10    second = 100 mili second
-- timer =     100.000)  ->  1/1000  second =   1 mili second
-- timer =      50.000)  ->  1/2000  second = 0.5 mili second = 500 micro second
 
--===================================================================================
 
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
 
entity Stop_Watch is
    Port (  clk                     : IN  STD_LOGIC ;   -- 100 MHz
                OPERATION               : IN    STD_LOGIC ;
                RESET                       : IN  STD_LOGIC ;
                Period_Info             : IN    STD_LOGIC_VECTOR(3 DOWNTO 0) ;
                SW_Period_Over_Flag     : OUT STD_LOGIC ;
                Period                  : OUT INTEGER range 0 to 5*10E+3);
end Stop_Watch;
 
architecture Behavioral of Stop_Watch is
 
signal s_clk                  : STD_LOGIC ;
signal s_OPERATION            : STD_LOGIC ;
signal s_RESET                    : STD_LOGIC ;
signal s_SW_Period_Over_Flag : STD_LOGIC ;
signal s_Period_Info              : STD_LOGIC_VECTOR(3 DOWNTO 0) ;
signal i_Period               : INTEGER range 0 to 5*10E+3 := 0;
 
begin
    
    s_clk           <= clk ;
    s_OPERATION     <= OPERATION ;
    s_RESET             <= RESET ;
    s_Period_Info   <=  Period_Info ;
    
    i_Period <= 1       when s_period_info = "0001" else    
                    5       when s_period_info = "0010" else    
                    10      when s_period_info = "0011" else    
                    30      when s_period_info = "0100" else    
                    60      when s_period_info = "0101" else    
                    300 when s_period_info = "0110" else    
                    600 when s_period_info = "0111" else    
                    1800    when s_period_info = "1000" else    
                    3600    when s_period_info = "1001" else    
                    1 ;
                     
                     
    process(s_clk, s_OPERATION, s_RESET, i_Period )
    variable v_timer                : integer range 0 to 5*100E+6 := 0;
    variable v_timer_seconds    : integer range 0 to 5*10E+3 := 0;
    begin
        if ( rising_edge( s_clk ) ) then
            if (s_OPERATION = '1') then
                if ( s_RESET = '1' ) then
                    v_timer := 0 ;
                else
                
                    if ( v_timer =  5 ) then
                        v_timer := 0;
                        if ( v_timer_seconds = i_Period) then
                            v_timer_seconds := 0 ;
                            s_SW_Period_Over_Flag <= '1';
                        else
                            v_timer_seconds := v_timer_seconds + 1 ;
                            s_SW_Period_Over_Flag <= '0';
                        end if;                     
                    else                        
                        s_SW_Period_Over_Flag <= '0';
                        v_timer := v_timer + 1 ;
                    end if ;
                    
                end if ;
            else
                v_timer := 0 ;
            end if ;            
        end if ;
    end process ;
 
    SW_Period_Over_Flag <= s_SW_Period_Over_Flag ;
    Period <= i_Period ;
    
end Behavioral;



device_controller.vhd

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
 
entity Device_Controller is
 
    Port(   clk             : IN   STD_LOGIC  ;
            CTRL_BYTE   : IN   STD_LOGIC_VECTOR(7 DOWNTO 0)  ;
            
            RESET       : OUT  STD_LOGIC  ;
            PERIOD      : OUT  STD_LOGIC_VECTOR(3 DOWNTO 0)  ;
            OPERATION   : OUT  STD_LOGIC );
                
end Device_Controller;
 
architecture Behavioral of Device_Controller is
    
    signal s_clk            : STD_LOGIC ;
    signal s_RESET          : STD_LOGIC := '0';
    signal s_CTRL_BYTE  : STD_LOGIC_VECTOR(7 DOWNTO 0) ;
    signal s_PERIOD     : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0001";
    SIGNAL s_OPERATION  : STD_LOGIC := '0';
    
begin
 
    s_clk       <= clk ;
    RESET       <= s_RESET ;
    s_CTRL_BYTE <= CTRL_BYTE ;
    
    process(s_clk, s_CTRL_BYTE)
    begin
    
        if ( rising_edge(s_clk) ) then
            
            case s_CTRL_BYTE is
                
                when "01000001" =>      -- A start BYTE
                    s_OPERATION <= '1' ;
                    
                when "01000010" =>      -- B stop BYTE
                    s_OPERATION <= '0' ;    
                    
                ------ PERIOD --------------------------------------------- 
                when "01000011" =>      -- C 1 sec BYTE
                    s_PERIOD <= "0001" ;
                    
                when "01000100" =>      -- D 5sec  BYTE
                    s_PERIOD <= "0010" ;
                    
                when "01000101" =>      -- E 10sec  BYTE
                    s_PERIOD <= "0011" ;
                    
                when "01000110" =>      -- F 30sec  BYTE
                    s_PERIOD <= "0100" ;
                    
                when "01000111" =>      -- G 1min  BYTE
                    s_PERIOD <= "0101" ;
                    
                when "01001000" =>      -- H 5min  BYTE
                    s_PERIOD <= "0110" ;
                    
                when "01001001" =>      -- I 10min  BYTE
                    s_PERIOD <= "0111" ;
                    
                when "01001010" =>      -- J 30min  BYTE
                    s_PERIOD <= "1000" ;    
                    
                when "01001011" =>      -- K 1 hour BYTE
                    s_PERIOD <= "1001" ;        
                    
                ----------------------------------------------------------  
                when "01001100" =>      -- L "set RESET" BYTE
                    s_RESET <= '1' ;        
                    
                when "01001101" =>      -- M "reset RESET" BYTE
                    s_RESET <= '0' ;        
                    
                when others =>
                    s_OPERATION <= '0' ;            
                
            end case ;
            
        end if ;
        
    end process;
 
    OPERATION   <= s_OPERATION ; 
    PERIOD      <= s_PERIOD ;
 
end Behavioral;



tb_period_selection.vhd

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
 
ENTITY TB_Period_Selection IS
END TB_Period_Selection;
 
ARCHITECTURE behavior OF TB_Period_Selection IS 
   
    -- Clock period definitions
   constant clk_period : time := 10 ns;   
    
    --Inputs
   signal clk               : std_logic := '0';
   signal s_CTRL_BYTE   : std_logic_vector(7 downto 0) ; --:= (others => '0');
    
    
    COMPONENT Device_Controller
    PORT(   clk             : IN   std_logic ;
            CTRL_BYTE   : IN   std_logic_vector(7 downto 0);
            
            RESET       : OUT  std_logic ;
            PERIOD      : OUT  std_logic_vector(3 downto 0);
            OPERATION   : OUT  std_logic );
    END COMPONENT;
    
    --Outputs and Inputs2
   signal s_RESET       : std_logic;
   signal s_PERIOD_info : std_logic_vector(3 downto 0);
   signal s_OPERATION   : std_logic;
    
    COMPONENT Stop_Watch
    Port(   clk                     : IN  STD_LOGIC ;   -- 100 MHz
            OPERATION               : IN    STD_LOGIC ;
            RESET                       : IN  STD_LOGIC ;
            Period_Info             : IN    STD_LOGIC_VECTOR(3 DOWNTO 0) ;
            
            SW_Period_Over_Flag     : OUT STD_LOGIC ;
            Period                  : OUT INTEGER range 0 to 5*10E+3);
    END COMPONENT;
    
    --Outputs2
   signal s_SW_Period_Over_Flag     : std_logic;
   signal s_Period      : integer range 0 to 5*10E+3 ;
 
 
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: Device_Controller PORT MAP (
          clk           => clk ,
          CTRL_BYTE     => s_CTRL_BYTE ,
             
          RESET         => s_RESET ,
          PERIOD        => s_PERIOD_info ,
          OPERATION     => s_OPERATION  );  
             
    -- Instantiate the Unit Under Test (UUT)
   uut2: Stop_Watch PORT MAP (
          clk                       => clk ,
          OPERATION                 => s_OPERATION,
          RESET                     => s_RESET,
          Period_Info           => s_PERIOD_info,
             
          SW_Period_Over_Flag => s_SW_Period_Over_Flag,
          Period                    => s_Period);
 
   -- Clock process definitions
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;
        clk <= '1';
        wait for clk_period/2;
   end process;
 
 
  -- Stimulus process
   stim_proc: process
   begin        
 
      wait for clk_period*2;
        
        ------------------------------------------
        
        s_CTRL_BYTE <= "01000101";  --  10 SEC      
      wait for clk_period*5;
        
        ------------------------------------------
        
        s_CTRL_BYTE <= "01000001";  -- START
      wait for clk_period*10;
        
        ------------------------------------------
        
        s_CTRL_BYTE <= "01000011";  -- 1 SEC    
      wait for clk_period*5;
        
        s_CTRL_BYTE <= "01001100";  -- set RESET        
      wait for clk_period*2;
        
        s_CTRL_BYTE <= "01001101";  -- reset RESET      
      wait for clk_period*2;
        
 
--      
--      s_CTRL_BYTE <= "01000111";  -- 1 MIN        
--      wait for clk_period*2;
--      
--      s_CTRL_BYTE <= "01001011";  -- 1 HOUR       
--      wait for clk_period*2;
--      
--      ------------------------------------------
--      
        s_CTRL_BYTE <= "01000010";  -- STOP     
      wait for clk_period*5;
        
        ------------------------------------------
        
--      s_CTRL_BYTE <= "01001100";  -- set RESET        
--      wait for clk_period*2;
--      
--      s_CTRL_BYTE <= "01001101";  -- reset RESET      
--      wait for clk_period*2;
        
      wait;
   end process;
 
END;

 

Attachments

  • TB_Period_Selection.txt
    3 KB · Views: 39
  • Device_Controller.txt
    2 KB · Views: 50
  • Stop_Watch.txt
    2.6 KB · Views: 43
Last edited by a moderator:

Re: FPGA VHDL UART RX line how to handle incoming bytes?

Hi,

What's tlhe exact problem now?
You tell a lot about your application, but forgot to focus on the real problem.

Additionally.
You posted in the PC programming section, but your headline talks about PLD programming.

Klaus
 

Hi KlausST,

Sorry I missed the section part and thank you for moving to the correct place!

Actually I don't know how I can define the problem different than below but maybe an example...

when I send a command through my GUI on computer first it works but then the next received byte changes the previous. So I can' t handle each different bytes or commands successfully.
How can I handle incoming bytes? Does anyone have any suggestion related to a modification or a different structure?

For instance:
A received byte ascii "E" means counting period of 10 secs. At first this is processed correct. Then when I transmit ascii "A" to FPGA (meaning start counting) it starts but the previous "E" is not valid anymore. Instead it counts for a different time period. So I couldn' t construct a successful two way communication link.

Is it not good to use a case block then how it should be? or anyother suggestion will be very welcome...
 

Then when I transmit ascii "A" to FPGA (meaning start counting) it starts but the previous "E" is not valid anymore.
Yes, but why is this so? Before you didn't manage to store internal states of your system in a reasonable way. Presently the only state variable you have is holding the present command, but none is remembering the period setting or start/stop state. Reconsider your design.
 

A reset buried inside an enable is not the standard template for a resetable flip-flop.

Code VHDL - [expand]
1
2
3
4
5
if ( rising_edge( s_clk ) ) then
            if (s_OPERATION = '1') then
                if ( s_RESET = '1' ) then
                    v_timer := 0 ;
                else



Given you are defining v_timer as 0 to 500,000,000 and only using it to count from 0 to 5 makes me wonder if you understand how VHDL translates into logic circuits. There seems to be a major disjoint between what you want your circuit to do and what the code you are writing does and unfortunately I can't tell what it is you actually need you circuit to do as the TB seems to test something that is completely different than your as written code, e.g. waiting for 50 ns to test a 10 second setting seems rather strange or maybe its the 100ns after you send "start"?
 

Given you are defining v_timer as 0 to 500,000,000 and only using it to count from 0 to 5 ...

Maybe I should ask if we are agree about something. If we want to design a i.e 1 minute timer using 100MHz clock, we need to count 60 times until 100M-1. Here for testbench instead of 100M-1 I count until 5 and then make v_timer_seconds +1. This is just for observing the signals in a reasonable time window. Real design counts 100M-1 and when I insert i.e 60 for i_Period it performs the measurements successfully.

So far as I understand the problem is driving different signals in case statement. All example codes for case statement are like


Code VHDL - [expand]
1
2
3
4
5
6
7
case "control_signal" is                
                when "case1" =>
                    signal_1 <= "0001";   
                 
                when "case2" =>
                     signal_1 <= "0010";  
                ...



but I wish to drive signal_1 for first case, signal_2 for seconds case etc. and keep the previous signals stay at the same configuration until I do some modification.

So when I work with case_2, why and how signal 1 changes ?
 
Last edited by a moderator:

The simulation doesn't show how CTRL_BYTE is received -- it is just generated in the simulation. If CTRL_BYTE is shifted 1 bit at a time from the uart, then you would need to have some enable signal to avoid interpreting intermediate results as commands.

The case statement isn't special. Signals have the same behavior -- the last reached assignment in the process is the one that is used. If no assignment is made in the process then the value is retained. In the case of a clocked process, that would be a register. In the case of a non-clocked process, that would result in a latch. I didn't see anything wrong with the case statement, other than a possible lack of a clock enable.

I'm also not sure why you take input ports and assign them to signals. You also include too many signals in the sensitivity list for the clocked processes.
 

Hi vGoodtimes

I made some trials but didn't succeeded yet. Here is the final version of UART RX. In case of applying a half received byte, I've located another FSM to transfer the complete byte after the receiving sequence completes. But what a pity It doesn't make any sense.

why you take input ports and assign them to signals. You also include too many signals

I actually don't have a specific reason for this. This is just because of the first examples that I used when started my designs on FPGA. I also think if it is good or not but so far I didn't have a problem.

looking forward to your comments.

Thanks ...


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
 
entity RX_Serial_Link is
    generic( Baud_Match_Number : integer := 868 );
    port (  clk         : in  std_logic ;
            RX_Serial   : in  std_logic ;
--          Link_Info   : out std_logic ;
            RX_Byte     : out std_logic_vector(7 downto 0) );
end RX_Serial_Link;
 
architecture Behavioral of RX_Serial_Link is
 
    signal s_clk : STD_LOGIC ;
 
    type  STATE is (ST_IDLE, ST_START_BIT, ST_DATA_BITS, ST_STOP_BITS, ST_CLEANUP);
    signal NEXT_STATE : STATE := ST_IDLE;
 
    signal s_RX_Serial_temp : std_logic ;
    signal s_RX_Serial      : std_logic ;
 
    signal Bit_Keep_Count   : integer range 0 to Baud_Match_Number := 0;
    signal Bit_Index        : integer range 0 to 7 := 0;        -- 8 Bits Total
    signal s_RX_Byte        : std_logic_vector(7 downto 0) := (others => '0');
    signal s_state_info     : std_logic := '0';
   
    type  STATE_BT is (ST_READ, ST_BYTE_HOLD); -- STATE_BT: State Byte Transfer
    signal NEXT_STATE_BT : STATE_BT := ST_READ;
    
begin
 
    s_clk <= clk ;
 
  -- Purpose: Double-register the incoming data.
  -- This allows it to be used in the UART RX Clock Domain.
  -- (It removes problems caused by metastabiliy)
    p_SAMPLE : process (s_clk)
    begin
        if rising_edge(s_clk) then
            s_RX_Serial_temp    <= RX_Serial;
            s_RX_Serial         <= s_RX_Serial_temp;
        end if;
    end process p_SAMPLE;   
 
    -- Purpose: Control RX state machine
    p_UART_RX : process (s_clk)
    begin
        if rising_edge(s_clk) then          
            case NEXT_STATE is              
                when ST_IDLE =>                 
                    s_state_info <= '0' ;                   
                    Bit_Keep_Count <=  0 ;
                    Bit_Index   <=  0 ;                 
                    if s_RX_Serial = '0' then       -- Start bit detected
                        NEXT_STATE <= ST_START_BIT;
                    else
                        NEXT_STATE <= ST_IDLE;
                    end if; 
                    
                -- Check middle of start bit to make sure it's still low
                when ST_START_BIT =>                    
                    s_state_info <= '1' ;                   
                    if Bit_Keep_Count = (Baud_Match_Number-1)/2 then                        
                        if s_RX_Serial = '0' then
                            Bit_Keep_Count  <= 0;  -- reset counter since we found the middle
                            NEXT_STATE      <= ST_DATA_BITS;
                        else
                            NEXT_STATE  <= ST_IDLE;
                        end if;
                    else
                        Bit_Keep_Count  <= Bit_Keep_Count + 1;
                        NEXT_STATE      <= ST_START_BIT;
                    end if; 
                    
                -- Wait Baud_Match_Number-1 clock cycles to sample serial data
                when ST_DATA_BITS =>                    
                    s_state_info <= '1' ;                   
                    if Bit_Keep_Count < Baud_Match_Number-1 then
                        Bit_Keep_Count <= Bit_Keep_Count + 1;
                        NEXT_STATE      <= ST_DATA_BITS;
                    else
                        Bit_Keep_Count              <= 0;
                        s_RX_Byte(Bit_Index)    <= s_RX_Serial; --Bitlerin yazildigi yer                        
                        -- Check if we have sent out all bits
                        if Bit_Index < 7 then
                            Bit_Index   <= Bit_Index + 1;
                            NEXT_STATE  <= ST_DATA_BITS;
                        else
                            Bit_Index   <= 0;
                            NEXT_STATE  <= ST_STOP_BITS;
                        end if;
                    end if;
                    
                -- Receive Stop bit.  Stop bit = 1
                when ST_STOP_BITS =>                    
                    s_state_info <= '1' ;                   
                    -- Wait Baud_Match_Number-1 clock cycles for Stop bit to finish
                    if Bit_Keep_Count < Baud_Match_Number-1 then
                        Bit_Keep_Count  <= Bit_Keep_Count + 1;
                        NEXT_STATE      <= ST_STOP_BITS;
                    else
                        Bit_Keep_Count <= 0 ;
                        NEXT_STATE      <= ST_CLEANUP;
                    end if;
                    
                -- Stay here 1 clock
                when ST_CLEANUP =>
                    s_state_info    <= '1';
                    NEXT_STATE      <= ST_IDLE;                 
                when others =>
                    NEXT_STATE <= ST_IDLE ;                 
            end case;
        end if;
    end process p_UART_RX;
    
    -------- LATEST ADDITION --------------------------------------------
    process (s_clk, s_state_info)
    begin
        if (rising_edge(s_clk)) then            
            case NEXT_STATE_BT is       
                when ST_BYTE_HOLD =>                    
                    RX_Byte <= s_RX_Byte ;                  
                    if ( s_state_info='0' ) then
                        NEXT_STATE_BT <= ST_BYTE_HOLD;
                    else
                        NEXT_STATE_BT <= ST_READ;
                    end if;             
                when ST_READ =>                 
                    if ( s_state_info='1' ) then
                        NEXT_STATE_BT <=    ST_READ ;
                    else
                        NEXT_STATE_BT <=    ST_BYTE_HOLD ;
                    end if;             
                when others =>
                    NEXT_STATE_BT <= ST_BYTE_HOLD ;                 
            end case;
        end if; 
    end process ;
                
end Behavioral;

 
Last edited by a moderator:

I didn't look over this too much. I suspect you are interpreting intermediate values as valid commands. Your sim doesn't show this as you expect the interface to change all bits at the same time. Try a sim where you get the data 1 bit at a time.
--edit: keep in mind that you have a default statement that acts on invalid invalid inputs.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top