UPD: По просьбе пользователя andrey добавлены статьи по каждому из частей — приемнику и передатчику.


Данная статья посвящена вопросу создания универсального асинхронного приемопередатчика (УАПП) — в дальнейшем, ввиду распространенности его английского названия мы будем называть его UART. Статья содержит основные понятия о принципах работы UART, приводится исходный код и результаты работы непосредственно «прошитой» ПЛИС.

UART — является полнодуплексным последовательным приемопередатчиком. Полнодуплексный означает что прием и передача могут происходить одовременно и независимо друг от друга. Последовательный — означает что все данные передаются по одному каналу побайтово.

Структура передачи данных представлена на рисунке 1.

2015-06-19 13-59-40 Скриншот экрана

Рисунок 1 — Метод передачи данных

 

В тот момент, когда отсутствует передача данных — в канале сигнал находится на уровне логической «1». Стартовым битом служит нулевой бит, который оповещает о начале пакета. Следует обратить внимание, что данные передаются от младшего бита к старшему. После того, как один байт (байт состоит из 8 бит) передан выставляется уровень логической «1», что означает конец передаваемого пакета (байта).

Как видно, структура довольно проста.

Приступим к непосредственному описанию блока UART для ПЛИС. Для этого будет использовать язык Verilog. Но перед этим нужно примерно понять структуру приемопередатчика.

На входе у нас идут последовательные данные, с которыми наш приемопередатчик работает. Для того, чтобы по итогу создания блока проверить правильность его работы последовательный поток данных нужно сохранить в 8-битный регистр, тем самым, сравнив данные в регистре с переданными данными мы оценим правильность работы.

После приема и обработки осуществим передачу данных. Структура приемопередатчика приведена на рисунке 2.

2015-06-19 13-51-24 Скриншот экрана

Рисунок 2- Схема приемапередатчика UART

На схема блок CLK_smth — передает тактовые сигналы от генератора тактовых импульсов к блокам receive и transmit по витой паре. Данный блок генерируется CoreGen’ом (об этом позже).  RX и TX — соответственно входной и выходной порты. Блок receive принимает последовательные биты, преобразует в байт данных и по готовности байта выставляется флаг rdy и передает данные data[7:0]. Блок transmit принимает данные data[7:0]  по флагу rdy и обратно преобразует их в последовательный вид для выдачи на выход (TX_out).

Данный блок, как видно из схемы, состоит из трех подблоков — CLK_smth, receive и transmit.

Для того,чтобы они функционировали вместе и для их объединения создается специальный файл (top.v), который объединяет нужные порты.

Содержимое top.v (объединения блоков) 

//---------------top.v
`timescale 1ns / 100ps
module UART_top(
				input clk_p,	 // LVDS clocks... отсюда сигнал 200 МГц попадает на PLL
				input clk_n,	 // LVDS clocks... отсюда сигнал 200 МГц попадает на PLL
				input RX_in, 	 // UART вход
				output TX_out	 // UART выход
				);
	wire rdy;
	wire [7:0] data;
	wire TX_out;
	wire clk_out;
clk_wiz_v3_6 CLK_smth(
					// Clock in ports
					.CLK_IN1_P(clk_p),
					.CLK_IN1_N(clk_n),
					// Clock out ports
					.CLK_OUT1(clk_out)
					);
// Core UART приемника
UART_receiver receive(
					.RX(RX_in),
					.CLK(clk_out),
					.Rdy(rdy),
					.DATA(data)
);
// Core UART передатчика
UART_transmitter transmit (
				.DATA(data),
				.CLK(clk_out),
				.Rdy(rdy),
				.TX(TX_out)
);
endmodule

Содержимое receiver.v (приемника UART)

//----------receiver.v
module UART_receiver (
					input RX,
					input CLK,
					output reg Rdy = 0,
					output reg [7:0] DATA
					);

 reg starter =1'd0;
 reg [7:0] count = 8'd0;
 reg [2:0] want_to_know;
 reg true_RX;
 reg [7:0] shifter;
 reg [7:0] start = 8'd0;
 reg smth =1'd0;
 
 always @( posedge CLK )
 begin
	if (RX==0)
	begin
		starter<=1'd1;
	end
	
	if (starter)
	begin
		count<=count+1;
		if (count==57||count==114||count==171) // Три выборки от результата деления частоты CLK на скорость UART в бодах (CLK/Vuart) (в начале, середине и конце)
		begin // В данном случае CLK - 20 МГц, Vuart = 115200 бод ( значения также необходимо заменить в файле transmitter.v )
			want_to_know[2:1]<=want_to_know[1:0];
			want_to_know[0]<=RX;
		end
		
		if (count==172)
		begin
			if (want_to_know[2]&&want_to_know[0]||want_to_know[1])
			begin
				true_RX<=1;
			end
			else
			begin
				true_RX<=0;
			end
		end
		
		if (count==173) // результат от деления частоты CLK на скорость UART в бодах (CLK/Vuart)
		begin
			count<=0;
			start<=start+1; if (start>0&&start<9)
			begin
				shifter[7:1]<=shifter[6:0];
				shifter[0]<=true_RX;
			end
			else
				if (start==9)
				begin
					DATA<=shifter;
					starter<=0;
					smth<=1'd1;
					start<=0;
				end
		end
	end

	if (smth)
	begin
		Rdy<=1;
		smth<=0;
		shifter<=8'd0;
	end
	else
	begin
		Rdy<=0;
	end 
 end
 endmodule

Содержимое transmitter.v (передатчика UART)

module UART_transmitter(
						input [7:0] DATA,
						input CLK,
						input Rdy,
						output reg TX =1
						);
	reg start_trans=1'd0;
	reg [7:0] count = 8'd0;
	reg [7:0] tr_count = 8'd0;
	reg [7:0] shifter;
always @ (posedge CLK)
begin
	if (Rdy)
	begin
		start_trans<=1'd1;
		shifter<=DATA;
	end
	if (start_trans)
	begin
		tr_count<=tr_count+1;
		
		if (count==0)
		begin
			if (tr_count<173) // результат от деления частоты CLK на скорость UART в бодах (CLK/Vuart)
			begin
				TX<=0;
			end
		else
		begin
			count<=1;
			tr_count<=0;
		end
	end
	else
	begin
		if (tr_count<173) // результат от деления частоты CLK на скорость UART в бодах (CLK/Vuart)
		begin
			TX<=shifter[7];
		end
		
		else
		begin
			shifter[7:1]<=shifter[6:0];
			tr_count<=0;
			count<=count+1;
		end
	end
	
	if (count==9) // если нужен бит четности, то добавлять if (count==10) begin .... end
	begin
		TX<=1;
		start_trans<=1'd0;
		count<=0;
		shifter<=8'd0;
	end
	end
end
endmodule


Как уже говорилось CLK_smth — сгенерирована CoreGen’ом и ее код здесь приводить не имеет смысла.
Для тестирования воспользовались Putty, соединили ПК и прошитый ПЛИС через UART.

2015-04-30 18-04-49 Скриншот экрана (2)

Рисунок 3 — Параметры соединения ПК с ПЛИС по UART (номер виртуального COM порта и скорость UART)

2015-04-30 18-04-33 Скриншот экрана (2)

Рисунок 4 — Результаты приема и передачи данных с ПЛИС