File: uart.vhd

package info (click to toggle)
bladerf 0.2017.12~rc1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 14,620 kB
  • sloc: ansic: 50,123; vhdl: 12,873; python: 1,062; tcl: 1,060; xml: 1,017; makefile: 657; sh: 589; csh: 18; cpp: 9
file content (220 lines) | stat: -rw-r--r-- 8,747 bytes parent folder | download | duplicates (8)
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
-- Copyright (c) 2013 Nuand LLC
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-- THE SOFTWARE.

library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;

entity uart is
  port (
    -- FPGA internal interface to the TX and RX FIFOs
    clock           :   in  std_logic ;
    reset           :   in  std_logic ;
    enable          :   in  std_logic ;

    -- RS232 interface
    rs232_rxd       :   out std_logic ;
    rs232_txd       :   in  std_logic ;

    -- UART -> FIFO interface
    txd_we          :   out std_logic ;
    txd_full        :   in  std_logic ;
    txd_data        :   out std_logic_vector(7 downto 0) ;

    -- FIFO -> UART interface
    rxd_re          :   out std_logic ;
    rxd_empty       :   in  std_logic ;
    rxd_data        :   in  std_logic_vector(7 downto 0)
  ) ;
end entity ; -- uart

architecture arch of uart is

    -- TODO: Make this a generic instead of a constant
    constant CLOCKS_PER_BIT :   natural := 10 ;

    -- Send and receive state machine definitions
    type send_fsm_t is (IDLE, SEND_START, SEND_DATA, SEND_STOP ) ;
    type receive_fsm_t is (WAIT_FOR_START, CENTER_START, SAMPLE_DATA, WAIT_FOR_STOP) ;

    -- FSM signals
    signal send_fsm     : send_fsm_t ;
    signal receive_fsm  : receive_fsm_t ;

    -- Synchronization signals for asynchronous input
    signal reg_txd      : std_logic ;
    signal sync_txd     : std_logic ;

begin

    -- Synchronize asynchronous inputs
    reg_txd <= rs232_txd when rising_edge( clock ) ;
    sync_txd <= reg_txd when rising_edge( clock ) ;

    -- Receive data from the UART and put it in the FIFO
    receive_from_uart : process(all)
        variable bits           :   std_logic_vector(7 downto 0) ;
        variable bit_count      :   natural range 0 to bits'length ;
        variable clock_count    :   natural range 0 to CLOCKS_PER_BIT ;
        variable txd_delay      :   std_logic ;
    begin
        if( reset = '1' ) then
            receive_fsm <= WAIT_FOR_START ;
            txd_we <= '0' ;
            txd_data <= (others =>'0') ;
            bits := (others =>'0') ;
            bit_count := 0 ;
            clock_count := 0 ;
            txd_delay := '0' ;
        elsif( rising_edge(clock) ) then
            if( enable = '0' ) then
                txd_we <= '0' ;
                txd_data <= (others =>'0') ;
                bits := (others =>'0') ;
                bit_count := 0 ;
                clock_count := 0 ;
                txd_delay := '0' ;
            else
                txd_we <= '0' ;
                case receive_fsm is
                    -- Wait for the start signal
                    when WAIT_FOR_START =>
                        if( sync_txd = '0' and txd_delay = '1' ) then
                            receive_fsm <= CENTER_START ;
                            clock_count := CLOCKS_PER_BIT/2-1 ;
                        end if ;
                        txd_delay := sync_txd ;

                    -- Center the start bit
                    when CENTER_START =>
                        clock_count := clock_count - 1 ;
                        if( clock_count = 0 ) then
                            receive_fsm <= SAMPLE_DATA ;
                            clock_count := CLOCKS_PER_BIT ;
                            bit_count := bits'length ;
                        end if ;

                    -- Sample the bits
                    when SAMPLE_DATA =>
                        clock_count := clock_count - 1 ;
                        if( clock_count = 0 ) then
                            bits := sync_txd & bits(bits'high downto 1) ;
                            bit_count := bit_count - 1 ;
                            clock_count := CLOCKS_PER_BIT ;
                            if( bit_count = 0 ) then
                                receive_fsm <= WAIT_FOR_STOP ;
                                txd_data <= bits ;
                                txd_we <= '1' ;
                            end if ;
                        end if ;

                    -- Wait for the stop bit
                    when WAIT_FOR_STOP =>
                        clock_count := clock_count - 1 ;
                        if( clock_count = 0 ) then
                            receive_fsm <= WAIT_FOR_START ;
                            assert sync_txd = '1' report "STOP bit not found!" severity error ;
                        end if ;

                    when others =>
                end case ;
            end if ;
        end  if ;
    end process ;

    -- Send data to the UART from the FIFO
    send_to_uart : process(all)
        variable bits           : std_logic_vector(7 downto 0) ;
        variable bit_count      : natural range 0 to bits'length ;
        variable clock_count    : natural range 0 to CLOCKS_PER_BIT ;
    begin
        if( reset = '1' ) then
            send_fsm    <= IDLE ;
            rxd_re      <= '0' ;
            rs232_rxd   <= '1' ;
            bit_count   := 0 ;
            clock_count := 0 ;
            bits        := (others =>'0') ;
        elsif( rising_edge(clock) ) then
            if( enable = '0' ) then
                send_fsm    <= IDLE ;
                rxd_re      <= '0' ;
                rs232_rxd   <= '1' ;
                bit_count   := 0 ;
                clock_count := 0 ;
                bits        := (others =>'0') ;
            else
                rxd_re <= '0' ;
                case send_fsm is
                    -- Wait until we have something to send
                    when IDLE =>
                        rs232_rxd <= '1' ;
                        if( rxd_empty = '0' ) then
                            send_fsm    <= SEND_START ;
                            rxd_re      <= '1' ;
                            bit_count   := bits'length ;
                            clock_count := CLOCKS_PER_BIT ;
                        end if ;

                    -- Send the start bit
                    when SEND_START =>
                        rs232_rxd <= '0' ;
                        -- bits        := rxd_data ;
                        clock_count := clock_count - 1 ;
                        if( clock_count = 0 ) then
                            send_fsm    <= SEND_DATA ;
                            clock_count := CLOCKS_PER_BIT ;
                        elsif( clock_count = 9 ) then
                            bits := rxd_data ;
                        end if ;
                    -- Send the data
                    when SEND_DATA =>
                        rs232_rxd   <= bits(0) ;
                        clock_count := clock_count - 1 ;
                        if( clock_count = 0 ) then
                            bits        := '0' & bits(bits'high downto 1) ;
                            bit_count   := bit_count - 1 ;
                            clock_count := CLOCKS_PER_BIT ;
                            if( bit_count = 0 ) then
                                send_fsm <= SEND_STOP ;
                            end if ;
                        end if ;

                    -- Send the stop bit
                    when SEND_STOP =>
                        rs232_rxd   <= '1' ;
                        clock_count := clock_count - 1 ;
                        if( clock_count = 0 ) then
                            send_fsm <= IDLE ;
                        end if ;

                    -- Weird
                    when others =>
                        send_fsm    <= IDLE ;
                        rs232_rxd   <= '1' ;
                        bit_count   := 0 ;
                        clock_count := 0 ;
                        bits        := (others =>'0') ;
                end case ;
            end if ;
        end if ;
    end process ;

end architecture ; -- arch