Старт ПЛИС-ы. Самописный UART .

Приветствую тебя, мой уважаемый читатель! Продолжаем пилить ПЛИСины (FPGA). Сегодня у нас UART. Информации много о принципах работы UART и в ARM-ах мы его уже “юзали“.

Передача данных в UART осуществляется по одному биту в равные промежутки времени. Этот временной промежуток определяется заданной скоростью UART и для конкретного соединения указывается в бодах (что в данном случае соответствует битам в секунду). Существует общепринятый ряд стандартных скоростей: 300; 600; 1200; 2400; 4800; 9600; 19200; 38400; 57600; 115200; 230400; 460800; 921600 бод. Скорость (S, бод) и длительность бита (T, секунд) связаны соотношением T = 1/S. Скорость в бодах иногда называют сленговым словом битрейт.

Помимо собственно информационного потока UART автоматически вставляет в поток синхронизирующие метки, так называемые стартовый и стоповый биты. При при приёме эти лишние биты удаляются из потока информационного назначения. Обычно стартовый и стоповый биты обрамляют один байт информации (8 бит), однако встречаются реализации UART, которые позволяют передавать по 5,6,7, 8 или 9 бит. Обрамленные стартом и стоповым битами, последовательность битов являются минимальной посылкой. Некоторые реализации UART позволяют вставлять два стоповых бита при передаче для уменьшения вероятности рассинхронизации приёмника и передатчика при плотном трафике. Приёмник игнорирует второй стоповый бит, воспринимая его как короткую паузу на линии.

Принято соглашение, что пассивным (в отсутствие потока данных) состоянием входа и выхода UART является логическая 1. Стартовый бит всегда логический 0, поэтому приёмник UART ждёт перепада из 1 в 0 и отсчитывает от него временной промежуток в половину длительности бита (середина передачи стартового бита). Если в этот момент на входе всё ещё 0, то запускается процесс приёма минимальной посылки. Для этого приёмник отсчитывает 9 битовых длительностей подряд (для 8-бит данных) и в каждый момент фиксирует состояние входа. Первые 8 значений являются принятыми данными, последнее значение проверочное (стоп-бит). Значение стоп-бита всегда 1, если реально принятое значение иное, UART фиксирует ошибку.

Для формирования временных интервалов передающий и приёмный UART имеют источник точного времени (тактирования). Точность этого источника должна быть такой, чтобы сумма погрешностей (приёмника и передатчика) установки временного интервала от начала стартового импульса до середины стопового импульса не превышала половины (а лучше хотя бы четверти) битового интервала. Для 8-бит посылки 0,5/9,5 = 5 % (в реальности не более 3 %). Поскольку эта сумма ошибок приёмника и передатчика плюс возможные искажения сигнала в линии, то рекомендуемый допуск на точность тактирования UART не более 1,5 %.

Поскольку синхронизирующие биты занимают часть битового потока, то результирующая пропускная способность UART не равна скорости соединения. Например, для 8-битных посылок формата 8-N-1 синхронизирующие биты занимают 20 % потока, что для физической скорости 115 200 бод даёт битовую скорость данных 92160 бит/с или 11 520 байт/с.

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

entity UARTv1 is 
	port (clk : in  std_logic := '0';
			Tx  : out std_logic := '1');
end UARTv1;

architecture UARTv1_architecture of UARTv1 is

function DividerUART(HSE : in integer; BitsPerSecond : in integer) return integer is 
begin
	return HSE/BitsPerSecond;
end DIViderUART;

constant ConstantCounter      	  : integer := 1;
constant ConstantFrequency_HSE 	  : integer := 50000000;
constant ConstantBitsPerSecondUART : integer := 9600;
constant ConstantDividerUART	     : integer := 
DividerUART(ConstantFrequency_HSE, ConstantBitsPerSecondUART);
signal   CounterDivederUART		  : integer	:= 0 ;

begin
	process (clk)	 
	begin
		if(clk = '1' and clk'event) 
			then 
			CounterDivederUART <= CounterDivederUART + ConstantCounter;
			
			--СТАРТОВЫЙ БИТ
			if  	
			((CounterDivederUART >= (ConstantDividerUART * 1)) and (CounterDivederUART < (ConstantDividerUART * 2)))
			then Tx <= '0';
			
			--0 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 2)) and (CounterDivederUART < (ConstantDividerUART * 3)))
			then Tx <= '1';  
			
			--1 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 3)) and (CounterDivederUART < (ConstantDividerUART * 4)))
			then Tx <= '0';  
		
			--2 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 4)) and (CounterDivederUART < (ConstantDividerUART * 5)))
			then Tx <= '0';  
			
			--3 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 5)) and (CounterDivederUART < (ConstantDividerUART * 6)))
			then Tx <= '0';  
			
			--4 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 6)) and (CounterDivederUART < (ConstantDividerUART * 7)))
			then Tx <= '0';  
	
			--5 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 7)) and (CounterDivederUART < (ConstantDividerUART * 8)))
			then Tx <= '0';

			--6 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 8)) and (CounterDivederUART < (ConstantDividerUART * 9)))
			then Tx <= '1'; 
			
			--7 БИТ ДАННЫХ
			elsif 
			((CounterDivederUART >= (ConstantDividerUART * 9)) and (CounterDivederUART < (ConstantDividerUART * 10)))
			then Tx <= '0'; 
			
			--СТОПОВЫЙ БИТ
			elsif   
			(CounterDivederUART < (ConstantDividerUART * 1))
			then Tx <= '1'; 
			
			else	  
			CounterDivederUART <= 0; 
			Tx <= '1'; 
			end if;
			
		end if;
	end process;
end UARTv1_architecture;

UARTv1 – исходник проекта.

Спасибо за Ваше внимание.