Интерфейс RS232 или UART прием и передача на VHDL

Интерфейс RS232 или UART прием и передача на VHDLТема UART или интерфейса RS232 на  VHDL уже подымалась на нашем ресурсе. Данный пост это развитие темы UART VHDL в более продвинутой манере кодирования на VHDL. Приведенный далее код приемника и передатчика RS232 работает, можно сказать, безупречно в широком диапазоне скоростей вплоть до 115200 бод/сек. Код найден на просторах глобальной сети, немного доработан, просимулирован в Modelsim, протестирован и используется в реально действующих проектах. В конце поста имеется ссылка для загрузки полного проекта UART для Quartus11.0.

Проект содержит полный рабочий код RS232 приемника, передатчика и верхнеуровневого модуля для проверки их работоспособности на симуляторе Modelsim 6.6d. На картинке ниже представлена диаграмма работы RS232 на передачу и на прием на скоростях 115200 и 57600 бод/сек соответственно. На вход передатчика (din) поступают побайтно данные 0х55, 0хAA, 0x01 которые затем последовательно выводятся на выход (tx). На вход приемника (rx) поступают последовательные данные 0х55, 0хAA, 0x02 которые последовательно появляются на выходе (dout).

RS232

UART

Все то же самое можно просмотреть непосредственно из проекта Uart_Quartus110. Для этого достаточно его открыть в среде Quartus11.0 и затем выполнить простейшую операцию по запуску временного симулирования в ModelSim6.6d. Все подробно описано в посте о временной симуляции в Quartus+ModelSim. Если коротко то из главного меню Quartus необходимо выполнить команду EDA Gate Level Simulation...

Временная симуляция в ModelSim

Все необходимые установки для данного вида симуляции уже выполнены, файл тестбенча Uart.vht подготовлен. Далее можно поварьировать скоростями в тестбенче, не забывая при этом поменять соответствующие установочные скорости UART приемника и передатчика в верхнеуровневом файле Uart.vhd в картах соединений компонентов исходя из того что исходная частота бод в верхнеуровневом модуле выставлена 115200 бод/сек. Например, для того, чтобы изменить частоту бод для RS232 приемника в сторону уменьшения можно в generic map записать BAUDRATE => BAUDRATE/3. В этом случае UART приемник будет работать на частоте 115200/3 - 38400 бод/сек.

Частота бод

Соответственно в файле тестбенча, который представлен ниже по тексту изменить участок кода связанный с частотой бод.

	
LIBRARY ieee;                                               
USE ieee.std_logic_1164.all;                                

ENTITY Uart_vhd_tst IS
END Uart_vhd_tst;
ARCHITECTURE Uart_arch OF Uart_vhd_tst IS
-- constants   
constant clk_period : time := 20.00 ns; 
-- 115200 Гц
constant bod_period : time := 8680 ns; 
constant rx_data0 : STD_LOGIC_VECTOR(7 DOWNTO 0):= X"55";  
constant rx_data1 : STD_LOGIC_VECTOR(7 DOWNTO 0):= X"AA";  
constant rx_data2 : STD_LOGIC_VECTOR(7 DOWNTO 0):= X"02";  
                                              
-- signals                                                   
SIGNAL clk : STD_LOGIC;
SIGNAL reset : STD_LOGIC;
SIGNAL din : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL tx_en : STD_LOGIC;
SIGNAL tx : STD_LOGIC;
SIGNAL tx_done_tick : STD_LOGIC;
SIGNAL rx : STD_LOGIC;
SIGNAL rx_done_tick : STD_LOGIC;
SIGNAL dout : STD_LOGIC_VECTOR(7 DOWNTO 0);

subtype tresh_test is std_logic_vector(7 downto 0);
type memory_tresh_test  is array(7 downto 0) of tresh_test;
signal s_tresh_test : memory_tresh_test;

COMPONENT Uart
	PORT (
	clk : IN STD_LOGIC;
	dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
	din : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
	reset : IN STD_LOGIC;
	rx : IN STD_LOGIC;
	tx : OUT STD_LOGIC;
	rx_done_tick : OUT STD_LOGIC;
	tx_done_tick : OUT STD_LOGIC;
	tx_en : IN STD_LOGIC
	);
END COMPONENT;
BEGIN
	i1 : Uart
	PORT MAP (
	clk => clk,
	dout => dout,
	din => din,
	reset => reset,
	rx => rx,
	tx => tx,
	rx_done_tick => rx_done_tick,
	tx_done_tick => tx_done_tick,
	tx_en => tx_en
	);


-- системный сброс
init : PROCESS                                               
BEGIN                                                        
reset <= '0', '1' after 2*clk_period;
WAIT;                                                       
END PROCESS init;                                           

-- тактовая
always : PROCESS                                              
BEGIN 
clk <= '0';
wait for clk_period/2; 
clk <= '1';
wait for clk_period/2; 
END PROCESS always; 

-- процесс на входе com
comrx : process 
begin

	rx <= '1';

	tx_en <= '0';
	wait for 5us;
	-- данные на передатчик
	tx_en <= '1';
	din <= X"55";
	wait for bod_period*9;
	din <= X"AA";
	wait for bod_period*9;
	din <= X"01";
	wait for bod_period*9;
	tx_en <= '0';

	wait for bod_period*9;
	wait for 10us;

	-- данные на вход приемника
	for j in 0 to 2 loop
		if j = 0 then 
			s_tresh_test(j) <= rx_data0;
		elsif j = 1 then 
			s_tresh_test(j) <= rx_data1;
		elsif j = 2 then 
			s_tresh_test(j) <= rx_data2;
		end if;
		-- старт бит
		rx <= '0';
		wait for bod_period*2;
		-- передача байта 
		for i in 0 to 7 loop
		rx <= s_tresh_test(j)(i); wait for bod_period*2;
		end loop;
		-- стоп бит
		rx <= '1'; 
		wait for bod_period*2;
	end loop;

	wait;

end process comrx;
                                         
END Uart_arch;

Тоесть в участке кода ниже текста "-- данные на вход приемника" вместо bod_period*2 необходимо записать bod_period*3. Примерно так-же можно варьировать скоростью и для RS232 передатчика. При этом может также понадобиться увеличить время симуляции в файле Uart_ms.do до 2...3ms. Ну, как-то так. Дерзайте.

Ps. Полезный ресурс где представлен альтернативный вариант RS232 на Verilog.

Top.Mail.Ru