added FIFO to UART RX
Stefan Schuermans

Stefan Schuermans commited on 2012-02-20 13:36:12
Showing 4 changed files, with 89 additions and 18 deletions.

... ...
@@ -7,6 +7,7 @@
7 7
 //#define CFG_DELAY
8 8
 //#define CFG_LCD
9 9
 #define CFG_UART
10
+#define CFG_UART_CHK
10 11
 
11 12
 const int myconst = 0x12345678;
12 13
 
... ...
@@ -75,6 +76,16 @@ int main()
75 76
   uart_tx('I');
76 77
   uart_tx('\r');
77 78
   uart_tx('\n');
79
+#ifdef CFG_UART_CHK
80
+  if (uart_rx() != 'M') while(1);
81
+  if (uart_rx() != 'I') while(1);
82
+  if (uart_rx() != 'P') while(1);
83
+  if (uart_rx() != 'S') while(1);
84
+  if (uart_rx() != ' ') while(1);
85
+  if (uart_rx() != 'I') while(1);
86
+  if (uart_rx() != '\r') while(1);
87
+  if (uart_rx() != '\n') while(1);
88
+#endif
78 89
 #endif
79 90
 
80 91
   while (1) {
... ...
@@ -36,7 +36,19 @@ void uart_cfg_stop(unsigned char stop)
36 36
  */
37 37
 void uart_tx(unsigned short chr)
38 38
 {
39
-  while (!*(uart_ptr + 4));
40
-  *(unsigned short *)(uart_ptr + 8) = chr;
39
+  while (!*(uart_ptr + 4)); /* wait for ready */
40
+  *(unsigned short *)(uart_ptr + 8) = chr; /* write data */
41
+}
42
+
43
+/**
44
+ * @brief receive a character
45
+ * @return character received
46
+ */
47
+unsigned short uart_rx(void)
48
+{
49
+  while (!*(uart_ptr + 5)); /* wait for data */
50
+  unsigned short chr = *(unsigned short *)(uart_ptr + 12); /* read data */
51
+  *(unsigned short *)(uart_ptr + 12) = 0; /* remove data from FIFO */
52
+  return chr;
41 53
 }
42 54
 
... ...
@@ -25,6 +25,11 @@ void uart_cfg_stop(unsigned char stop);
25 25
  */
26 26
 void uart_tx(unsigned short chr);
27 27
 
28
+/**
29
+ * @brief receive a character
30
+ * @return character received
31
+ */
32
+unsigned short uart_rx(void);
28 33
 
29 34
 #endif /* #ifndef UART_H */
30 35
 
... ...
@@ -26,6 +26,13 @@ ARCHITECTURE a_io_uart OF e_io_uart IS
26 26
     SIGNAL n_cfg_stop:  std_logic_vector( 1 DOWNTO 0);
27 27
     SIGNAL r_cfg_stop:  std_logic_vector( 1 DOWNTO 0) := "01";
28 28
 
29
+    SIGNAL s_rx_wr_rdy:  std_logic;
30
+    SIGNAL s_rx_wr_data: std_logic_vector(15 DOWNTO 0);
31
+    SIGNAL s_rx_wr_en:   std_logic;
32
+    SIGNAL s_rx_rd_rdy:  std_logic;
33
+    SIGNAL s_rx_rd_data: std_logic_vector(15 DOWNTO 0);
34
+    SIGNAL s_rx_rd_en:   std_logic;
35
+
29 36
     SIGNAL n_rx_scale:   natural RANGE 2**16 - 1 DOWNTO 0;
30 37
     SIGNAL r_rx_scale:   natural RANGE 2**16 - 1 DOWNTO 0 := 1;
31 38
     SIGNAL n_rx_bits:    natural RANGE 15        DOWNTO 0;
... ...
@@ -124,20 +131,42 @@ BEGIN
124 131
         END IF;
125 132
     END PROCESS p_cfg_sync;
126 133
 
134
+    s_rx_rd_en <= '1' WHEN i_addr = "11" AND i_wr_en(1 DOWNTO 0) = "11"
135
+                  ELSE '0';
136
+
137
+    rx_fifo: e_block_fifo
138
+        GENERIC MAP (
139
+            addr_width => 4,
140
+            data_width => 16
141
+        )
142
+        PORT MAP (
143
+            rst       => rst,
144
+            clk       => clk,
145
+            o_wr_rdy  => s_rx_wr_rdy,
146
+            i_wr_data => s_rx_wr_data,
147
+            i_wr_en   => s_rx_wr_en,
148
+            o_rd_rdy  => s_rx_rd_rdy,
149
+            o_rd_data => s_rx_rd_data,
150
+            i_rd_en   => s_rx_rd_en
151
+        );
152
+
127 153
     p_rx_next: PROCESS(r_cfg_scale, r_cfg_bits, r_cfg_stop,
128 154
                        r_rx_scale, r_rx_bits, r_rx_stop,
129 155
                        r_rx_state, r_rx_cnt, r_rx_sample, r_rx_bit,
130 156
                        r_rx_samples, r_rx_data,
131
-                       pin_i_rx)
157
+                       pin_i_rx, s_rx_wr_rdy)
132 158
         VARIABLE v_next_cnt:    boolean;
133 159
         VARIABLE v_next_sample: boolean;
134 160
         VARIABLE v_next_bit:    boolean;
135 161
         VARIABLE v_next_state:  boolean;
162
+        VARIABLE v_complete:    boolean;
136 163
         VARIABLE v_bits:        natural RANGE 15 DOWNTO 0;
137 164
         VARIABLE v_samples:     std_logic_vector( 2 DOWNTO 0);
138 165
         VARIABLE v_bit_val:     std_logic;
139
-        VARIABLE v_err:         boolean;
166
+        VARIABLE v_data:        std_logic_vector(15 DOWNTO 0);
140 167
     BEGIN
168
+        s_rx_wr_data <= (OTHERS => '0');
169
+        s_rx_wr_en   <= '0';
141 170
         n_rx_scale   <= r_rx_scale;
142 171
         n_rx_bits    <= r_rx_bits;
143 172
         n_rx_stop    <= r_rx_stop;
... ...
@@ -146,15 +175,15 @@ BEGIN
146 175
         n_rx_sample  <= r_rx_sample;
147 176
         n_rx_bit     <= r_rx_bit;
148 177
         n_rx_samples <= r_rx_samples;
149
-        n_rx_data    <= r_rx_data;
150 178
         v_next_cnt    := false;
151 179
         v_next_sample := false;
152 180
         v_next_bit    := false;
153 181
         v_next_state  := false;
182
+        v_complete    := false;
154 183
         v_bits        := 0;
155 184
         v_samples     := "000";
156 185
         v_bit_val     := '0';
157
-        v_err         := false;
186
+        v_data        := r_rx_data;
158 187
         IF r_rx_state = inactive THEN
159 188
             IF pin_i_rx = '0' THEN
160 189
                 n_rx_scale   <= to_integer(unsigned(r_cfg_scale));
... ...
@@ -164,8 +193,8 @@ BEGIN
164 193
                 n_rx_cnt     <= 0;
165 194
                 n_rx_sample  <= 3; -- sample in middle of received bits
166 195
                 n_rx_bit     <= 0;
167
-                n_rx_samples <= "00";
168
-                n_rx_data    <= X"0000";
196
+                -- n_rx_samples: no initialization needed
197
+                -- n_rx_data/v_data: keep error bit (bit 15), no initialization needed for other bits
169 198
             END IF;
170 199
         ELSE
171 200
             v_next_cnt := true;
... ...
@@ -190,18 +219,19 @@ BEGIN
190 219
                    WHEN "011" | "101" | "110" | "111" => v_bit_val := '1';
191 220
                    WHEN OTHERS => NULL;
192 221
                 END CASE;
193
-                IF r_rx_state = data THEN
194
-                    n_rx_data(r_rx_bit) <= v_bit_val;
195
-                END IF;
196 222
                 CASE r_rx_state IS
197
-                    WHEN start => v_err := v_bit_val /= '0';
198
-                    WHEN data  => v_err := false;
199
-                    WHEN stop  => v_err := v_bit_val /= '1';
223
+                    WHEN start =>
224
+                        IF v_bit_val /= '0' THEN
225
+                            v_data(15) := '1'; -- set error bit
226
+                        END IF;
227
+                    WHEN data  =>
228
+                        v_data(r_rx_bit) := v_bit_val;
229
+                    WHEN stop  =>
230
+                        IF v_bit_val /= '1' THEN
231
+                            v_data(15) := '1'; -- set error bit
232
+                        END IF;
200 233
                     WHEN OTHERS => NULL;
201 234
                 END CASE;
202
-                IF v_err THEN
203
-                    n_rx_data(15) <= '1';
204
-                END IF;
205 235
             END IF;
206 236
             IF r_rx_sample /= 6 THEN
207 237
                 n_rx_sample <= r_rx_sample + 1;
... ...
@@ -228,10 +258,20 @@ BEGIN
228 258
             CASE r_rx_state IS
229 259
                 WHEN start => n_rx_state <= data;
230 260
                 WHEN data  => n_rx_state <= stop;
231
-                WHEN stop  => n_rx_state <= inactive;
261
+                WHEN stop  => n_rx_state <= inactive; v_complete := true;
232 262
                 WHEN OTHERS => NULL;
233 263
             END CASE;
234 264
         END IF;
265
+        IF v_complete THEN
266
+            IF s_rx_wr_rdy = '1' THEN
267
+                s_rx_wr_data <= v_data;
268
+                s_rx_wr_en   <= '1';
269
+                v_data(15)   := '0'; -- clear error bit
270
+            ELSE
271
+                v_data(15)   := '1'; -- set error bit (RX FIFO overflow)
272
+            END IF;
273
+        END IF;
274
+        n_rx_data <= v_data;
235 275
     END PROCESS p_rx_next;
236 276
 
237 277
     p_rx_sync: PROCESS(rst, clk)
... ...
@@ -404,6 +444,9 @@ BEGIN
404 444
                     o_rd_data(25 DOWNTO 24) <= r_cfg_stop;
405 445
                 WHEN "01" =>
406 446
                     o_rd_data(0) <= s_tx_wr_rdy;
447
+                    o_rd_data(8) <= s_rx_rd_rdy;
448
+                WHEN "11" =>
449
+                    o_rd_data(15 DOWNTO 0) <= s_rx_rd_data;
407 450
                 WHEN OTHERS =>
408 451
                     NULL;
409 452
             END CASE;
410 453