Модуль UART на ПЛИС
21.06.2021, 15:58. Показов 853. Ответов 1
Здравствуйте, уважаемые форумчане.
Пробую написать UART на VHDL, с которым раньше не работал.
Ради учебных целей, решил не брать готовые реализации, а написать самостоятельно.
По итогу передатчик работает, а вот приемник в симуляторе тоже работает, а на деле нет.
У меня три файла: основной, модуль приемника и модуль передатчика. Скорость, требуемая для обмена - 1 Мбод.
В основном своём модуле я по нажатию кнопки отправляю в первый UART байт данных. С выхода передатчика сигнал поступает на вход приемника. Затем принятый байт я отправляю по другому передатчику UART и смотрю осциллографом что получаю. В итоге ничего не бьется.
Посмотрите пожалуйста на код.
Это основной модуль
Code | 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
| library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity s_6kv is
port(
clk_i : in std_logic; -- тактирование
rst_i : in std_logic; -- ресет
rx_i : in std_logic; -- вход приемника uart
tx1_start_i : in std_logic; -- кнопка запуска передатчика uart
tx_o : out std_logic; -- выход передатчика uart
tx2_o : out std_logic; -- выход передатчика uart
link_led_o : out std_logic -- светодиод LINK
);
end s_6kv;
architecture s_6kv_arch of s_6kv is
------ декларация компонента uart_tx ---------
component uart_tx
generic(
FREQ : positive := 16000000; -- frequency. Default 16 MHz
BAUD : positive := 1000000 -- data transfert speed 1Mbit
);
port(
clk_i : in std_logic;
rst_i : in std_logic;
tx_start_i : in std_logic;
data_i : in unsigned(7 downto 0);
busy_o : out std_logic;
tx_o : out std_logic
);
end component;
------ декларация компонента uart_rx ---------
component uart_rx
port(
clk_i : in std_logic;
rst_i : in std_logic;
rx_i : in std_logic;
busy_o : out std_logic; -- флаг занятости приемника
receive_cmpl_o : out std_logic;
rx_o : out unsigned(7 downto 0)
);
end component;
--------- константы ---------
--------- сигналы ---------
signal tx1_start : std_logic; -- включение передатчика uart
signal tx_busy : std_logic; -- флаг занятости передатчика uart
signal rx_busy : std_logic; -- флаг занятости приемника uart
signal tx : std_logic; -- выход передатчика
signal tp : std_logic;
signal link_led_on : std_logic; -- сигнал включения светодиода LINK
signal tx_buf : unsigned(7 downto 0);-- буфер передатчика
signal rx_buf : unsigned(7 downto 0);-- буфер передатчика
signal receive_cmpl : std_logic; -- флаг завершения приема
signal tx2_start : std_logic; -- включение передатчика uart
signal tx2_busy : std_logic; -- флаг занятости передатчика uart
signal tx2_buf : unsigned(7 downto 0);-- буфер передатчика
signal tx2 : std_logic; -- выход передатчика
begin
--------- создание компонента uart_tx_comp -----------
uart_tx_comp : uart_tx
port map(
clk_i => clk_i,
rst_i => rst_i,
tx_start_i => tx1_start,
data_i => tx_buf,
busy_o => tx_busy,
tx_o => tx
);
--------- создание компонента uart_tx2_comp -----------
uart_tx2_comp : uart_tx
port map(
clk_i => clk_i,
rst_i => rst_i,
tx_start_i => tx2_start,
data_i => tx2_buf,
busy_o => tx2_busy,
tx_o => tx2
);
--------- создание компонента uart_rx_comp -----------
uart_rx_comp : uart_rx
port map(
clk_i => clk_i,
rst_i => rst_i,
rx_i => rx_i,
busy_o => rx_busy,
receive_cmpl_o => receive_cmpl,
rx_o => rx_buf
);
process(rst_i, clk_i, tx1_start_i)
begin
if rst_i = '0' then
tx1_start <= '0';
elsif rising_edge (clk_i)then
if tx1_start_i = '0' then
tx_buf <= "01000001";
tx1_start <= '1';
end if;
end if;
end process;
process(clk_i, rst_i, receive_cmpl)
begin
if rst_i = '0' then
tx2_start <= '0';
elsif rising_edge (clk_i) then
if receive_cmpl = '1' then
tx2_buf <= rx_buf;
tx2_start <= '1';
else
tx2_start <= '0';
end if;
end if;
end process;
----- выходы ------
tx_o <= tx;
tx2_o <= tx2;
end s_6kv_arch; |
|
Это приемник
Code | 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
| library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
use ieee.numeric_std.all;
entity uart_rx is
port(
clk_i : in std_logic;
rst_i : in std_logic;
rx_i : in std_logic;
busy_o : out std_logic; -- флаг занятости приемника
receive_cmpl_o : out std_logic; -- флаг завершения приема байта
rx_o : out unsigned(7 downto 0)
);
end uart_rx;
architecture uart_rx_arch of uart_rx is
type t_uart_rx_sm is (
s_idle,
s_start,
s_data,
s_stop,
s_out
);
signal rx_state : t_uart_rx_sm;
signal rx_nextState : t_uart_rx_sm;
---- сигналы счетчика передискретизации -----
signal clk16_start : std_logic; -- запуск счетчика
signal clk16_cnt : unsigned(4 downto 0); -- сам счетчик
signal clk16_stop : std_logic; -- сигнал окончания счета
signal clk16_half : std_logic; -- счет до половины ширины бита
---- сигналы счетчика принятых битов -----
signal bit_cnt_start : std_logic;
signal bit_cnt : unsigned (3 downto 0);
signal bit_cnt_stop : std_logic;
signal uart_buf : unsigned(7 downto 0); -- принятый байт
signal rx_temp : std_logic;
signal MULT : integer := 16;
signal err_frame : std_logic;
signal receive_cmpl : std_logic; -- флаг завершения приема
signal led_on : std_logic;
signal busy : std_logic;
constant START_BIT : std_logic := '0';
constant STOP_BIT : std_logic := '1';
begin
process(rst_i, clk_i, MULT, clk16_start, bit_cnt_start)
begin
if rst_i = '0' then
clk16_cnt <= (others => '0');
bit_cnt <= (others => '0');
elsif rising_edge (clk_i) then
if clk16_cnt = 7 then
clk16_half <= '1';
else
clk16_half <= '0';
end if;
if clk16_cnt = (MULT - 1) then
clk16_cnt <= (others => '0');
clk16_stop <= '1';
elsif clk16_start = '1' then
clk16_cnt <= clk16_cnt + 1;
clk16_stop <= '0';
bit_cnt_stop <= '0';
end if;
if bit_cnt = 8 then
if clk16_cnt = (MULT - 1) then
bit_cnt <= (others => '0');
bit_cnt_stop <= '1';
end if;
elsif bit_cnt_start = '1' then
bit_cnt <= bit_cnt + 1;
bit_cnt_stop <= '0';
end if;
end if;
end process;
-------------------------------------
---------- конечный автомат ---------
-------------------------------------
---------- регистр -----------
process (rst_i, clk_i)
begin
if rst_i = '0' then
rx_state <= s_idle;
elsif rising_edge(clk_i) then
rx_state <= rx_nextState;
end if;
end process;
------------------------------
process (rx_state, rx_i)
begin
case rx_state is
when s_idle =>
clk16_start <= '0';
receive_cmpl <= '0';
busy <= '0';
when s_start =>
clk16_start <= '1';
receive_cmpl <= '0';
busy <= '1';
when s_data =>
clk16_start <= '1';
receive_cmpl <= '0';
busy <= '1';
when s_stop =>
clk16_start <= '1';
receive_cmpl <= '0';
busy <= '1';
when s_out =>
clk16_start <= '0';
receive_cmpl <= '1';
busy <= '1';
end case;
end process;
------------ логика перехода в следующее состояние------------
process (rx_state, rx_i, clk16_stop, bit_cnt_stop, clk16_half, rx_temp)
begin
case rx_state is
when s_idle =>
err_frame <= '0';
uart_buf <= (others => '0');
if rx_i = '0' then
rx_nextState <= s_start;
else
rx_nextState <= s_idle;
end if;
when s_start =>
if clk16_stop = '1' then
if rx_temp = START_BIT then
err_frame <= '0';
rx_nextState <= s_data;
else
err_frame <= '1';
rx_nextState <= s_idle;
end if;
else
rx_nextState <= s_start;
end if;
when s_data =>
if clk16_half = '1' then
bit_cnt_start <= '1';
uart_buf <= rx_temp & uart_buf(7 downto 1);
else
uart_buf <= uart_buf;
bit_cnt_start <= '0';
end if;
if bit_cnt_stop = '1' then
rx_nextState <= s_stop;
else
rx_nextState <= s_data;
end if;
when s_stop =>
if clk16_stop = '1' then
if rx_temp = STOP_BIT then
err_frame <= '0';
rx_nextState <= s_out;
else
err_frame <= '1';
rx_nextState <= s_idle;
end if;
else
rx_nextState <= s_stop;
end if;
when s_out =>
--rx_o <= uart_buf;
rx_nextState <= s_idle;
end case;
end process;
process(clk16_half)
begin
if clk16_half = '1' then
rx_temp <= rx_i;
else
rx_temp <= rx_temp;
end if;
end process;
------- выходы --------
receive_cmpl_o <= receive_cmpl;
rx_o <= uart_buf;
end uart_rx_arch; |
|
Это передатчик
Code | 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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
| library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity uart_tx is
generic(
FREQ : positive := 16000000; -- frequency. Default 16 MHz
BAUD : positive := 1000000 -- data transfert speed
);
port(
clk_i : in std_logic;
rst_i : in std_logic;
tx_start_i : in std_logic;
data_i : in unsigned(7 downto 0);
busy_o : out std_logic;
tx_o : out std_logic
);
end uart_tx;
architecture uart_tx_arch of uart_tx is
------ декларация компонента uart_tx_fsm ---------
component uart_tx_fsm
port(
clk_i : in std_logic;
rst_i : in std_logic;
tx_en_i : in std_logic;
cnt_stop_i : in std_logic;
bit_cnt_stop_i : in std_logic;
tx_ready_o : out std_logic;
cnt_en_o : out std_logic;
bit_cnt_en_o : out std_logic;
ld_en_o : out std_logic
);
end component;
--------- константы ---------
constant START_BIT : std_logic := '0';
constant STOP_BIT : std_logic := '1';
constant cnt_len : natural := FREQ/BAUD; -- 16000000 / 1000000 = 16
constant bit_cnt_len : natural := 10;
----- сигналы управления и состояния автомата -------
signal tx_en : std_logic; -- включение передатчика
signal tx_ready : std_logic; -- флаг состояния передатчика
signal ld_en : std_logic; -- загрузка данных в регистр сдвига
----- входные и выходные сигналы -------
signal tx : std_logic; -- выходной сигнал
signal tx_reg : unsigned (9 downto 0); -- регистр данных для отправки
------ сигналы для счётчиков ----------
signal cnt : unsigned (8 downto 0);
signal cnt_en : std_logic;
signal bit_cnt : unsigned (3 downto 0);
signal bit_cnt_en : std_logic;
signal cnt_stop : std_logic;
signal bit_cnt_stop : std_logic;
begin
--------- создание компонента uart_tx_fsm_comp -----------
uart_tx_fsm_comp : uart_tx_fsm
port map(
clk_i => clk_i,
rst_i => rst_i,
tx_en_i => tx_en,
ld_en_o => ld_en,
cnt_stop_i => cnt_stop,
bit_cnt_stop_i => bit_cnt_stop,
tx_ready_o => busy_o,
cnt_en_o => cnt_en,
bit_cnt_en_o => bit_cnt_en
);
-----------------------------------------------------------
process(rst_i, clk_i, tx_start_i)
begin
if rst_i = '0' then
tx_en <= '0';
elsif rising_edge (clk_i) then
if tx_start_i = '1' then
tx_en <= '1';
else
tx_en <= '0';
end if;
end if;
end process;
process (rst_i, clk_i)
begin
if rst_i = '0' then
tx <= STOP_BIT;
elsif rising_edge (clk_i) then
tx <= tx_reg(0);
end if;
end process;
process (rst_i, clk_i, ld_en, cnt_stop)
begin
if rst_i = '0' then
tx_reg <= (others => '1');
elsif rising_edge (clk_i) then
if ld_en = '1' then
tx_reg <= STOP_BIT & data_i & START_BIT;
elsif cnt_stop = '1' then
tx_reg <= STOP_BIT & tx_reg (9 downto 1);
end if;
end if;
end process;
-- счётчики
process (rst_i, clk_i)
begin
if rst_i = '0' then
cnt <= (others => '0');
bit_cnt <= (others => '0');
elsif rising_edge(clk_i) then
if cnt = cnt_len then
cnt <= (others => '0'); -- обнуление счётчика
cnt_stop <= '1'; -- выставление флага окончания счёта
elsif cnt_en = '1' then
cnt <= cnt + 1;
cnt_stop <= '0';
end if;
if bit_cnt_en = '1' then
if bit_cnt = 10 then
bit_cnt <= (others => '0'); -- обнуление счётчика
bit_cnt_stop <= '1'; -- выставление флага окончания счёта
else
bit_cnt <= bit_cnt + 1;
bit_cnt_stop <= '0';
end if;
end if;
end if;
end process;
------ выходы --------
tx_o <= tx;
end uart_tx_arch;
----------------------------------------------------------------
--------------------- конечный автомат -------------------------
----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity uart_tx_fsm is
port(
clk_i : in std_logic;
rst_i : in std_logic;
tx_en_i : in std_logic;
ld_en_o : out std_logic;
cnt_stop_i : in std_logic;
bit_cnt_stop_i : in std_logic;
tx_ready_o : out std_logic;
cnt_en_o : out std_logic;
bit_cnt_en_o : out std_logic
);
end uart_tx_fsm;
architecture uart_tx_fsm_arch of uart_tx_fsm is
type t_UART_TX_SM is (
s_Idle,
s_LoadData,
s_ShiftData,
s_Cnt
);
signal UART_TX_State : t_UART_TX_SM;
signal UART_TX_NextState : t_UART_TX_SM;
begin
---------- регистр -----------
process (rst_i, clk_i)
begin
if rst_i = '0' then
UART_TX_State <= s_Idle;
elsif rising_edge(clk_i) then
UART_TX_State <= UART_TX_NextState;
end if;
end process;
-------------------------------
------------- логика перехода в следующее состояние------------
process (UART_TX_State, tx_en_i, cnt_stop_i, bit_cnt_stop_i)
begin
case UART_TX_State is
when s_Idle =>
if tx_en_i = '1' then
UART_TX_NextState <= s_LoadData;
else
UART_TX_NextState <= s_Idle;
end if;
when s_LoadData =>
UART_TX_NextState <= s_ShiftData;
when s_ShiftData =>
UART_TX_NextState <= s_Cnt;
when s_Cnt =>
if bit_cnt_stop_i = '1' then
UART_TX_NextState <= s_Idle;
elsif cnt_stop_i = '1' then
UART_TX_NextState <= s_ShiftData;
else
UART_TX_NextState <= s_Cnt;
end if;
end case;
end process;
----------------------------------------------------------------
------------ автомат Мура-----------
process (UART_TX_State)
begin
case UART_TX_State is
when s_Idle =>
tx_ready_o <= '1';
cnt_en_o <= '0';
bit_cnt_en_o <= '0';
ld_en_o <= '0';
when s_LoadData =>
tx_ready_o <= '0';
cnt_en_o <= '0';
bit_cnt_en_o <= '0';
ld_en_o <= '1';
when s_ShiftData =>
tx_ready_o <= '0';
bit_cnt_en_o <= '1';
ld_en_o <= '0';
when s_Cnt =>
tx_ready_o <= '0';
cnt_en_o <= '1';
bit_cnt_en_o <= '0';
ld_en_o <= '0';
end case;
end process;
-------------------------------------
end uart_tx_fsm_arch; |
|
0
|