8-logoПосле первых опытов с ПЛИС, остался осадок, что чего то не хватает. Поразмыслив стало понятно, не хватает периферии, например какого нибудь интерфейса, для передачи данных.

Собственно зачем это нужно. Как вы могли уже понять скорость у ПЛИС очень высокая, но ресурсов довольно не много, по крайней мере у EPM240. Что наводит на мысль использования ПЛИС только как быстрого исполнителя, при этом в качестве «мозгов» можно использовать микроконтроллер. Одно маленькое «но», как их подружить между собой. На мой взгляд, самый популярный интерфейс это Uart.

Verilog все еще трудно воспринимается, видимо дело привычки, поэтому здесь не будет красивых и оптимизированных кусков кода. Просто расскажу как я действовал, поэтому стоит немного рассказать про то как передаются данные. Изначально передатчик и приемник «договариваются» о скорости, на которой будет производиться обмен. Настройка скорости и пр. делается индивидуально, для каждого устройства. Если микроконтроллер, то это записывается в программе. Если Com порт на пк, то выставляется в настройках программы использующей его.

Когда данные не передаются, передатчик притягивает линию к логической единице. Допустим мы решили передать символ ‘0’ в кодировке ASCII он идет под номером 0x30 или 0b110000. Первым пойдет стартбит, независимо от остальных данных, он всегда будет нулем. Этот логический ноль на ножке передатчика будет в течение времени t=1/s где s-скорость передачи бит в секунду. Далее последует нулевой бит наших данных, в данном случае 0(0b110000), который будет на ножке еще 1/s секунд.

Соответственно дальше пойдут следующие данные. До тех пор пока все восемь бит не уйдут. По окончании передачи на ножке установится стопбит, который всегда равен единице. После этого мы готовы принимать следующий символ
uart_fpga

Все выше сказанное справедливо, если в настройках указано тип передачи 8-N-1, т.е. 8 бит данных, нет контроля четности, один стоп бит. Если настройки другие, то и суть программы будет меняться. Немного стоит сказать про скорость передачи. Существует общепринятый ряд скоростей, по умолчанию скорость равна 9600 бит/с. Изначально идея была выжать побольше, поэтому было решено использовать 57600 бит/с. Вообще с той точки зрения, что кварц у нас быстрый, то чем выше будет выбрана скорость, тем меньше будет использовано ресурсов.

Как же это реализовать. Так как нам требуются четкие временные промежутки, то другого варианта как использовать кварцевый генератор у нас нет. На борту моей платы генератор 100МГц. В качестве привязки будем использовать положительный фронт тактовой частоты, т.е. код находящийся внутри данного цикла будет выполняться в моменты указанные стрелочкой.

always @ (posedge clk) begin
....
....	
end

clk_uart

Кварцевый генератор на 100МГц, т.е. за 1 секунду он сделает 100 000 000 колебаний, период будет равен 0,01мкс. Один бит будет передаваться 1/57600 = 17,36мкс. Таким образом, чтобы ушел старт бит, необходимо выставить логическую единицу и внутри цикла отсчитать 17,36/0,01 = 1736 раз. Затем выставить нулевой бит данных, сделать еще 1736 тиков и т.д. пока все 10 битов не будут отправлены.

module test_uart(clk,Tx);
input clk; //ножка к которой подключен кварц
output reg Tx=1'b1; //ножка которая выдает сигнал uart
 
reg [11:0]count = 1'b0; //счетчик для пауз в 1736
reg [9:0]data = 10'b1001100000;  //данные, аски код '0'
reg [4:0]i= 1'b0; //счетчик битов
 
always @ (posedge clk) //с каждым тактом
begin
	count <= count + 1'b1; //увеличивать счетчик
 
	if(count==1736) //когда досчитали до 1736
	begin
	  Tx <= data[i]; //отправили 1 бит данных
	  count <= 0; //обнулили счетчик
	  i <= i + 1; //перешли к следующему биту данных
	   if(i>9) // если все 10 бит отправлены
	   begin
	     i <= 0;  //обнулить счетчик битов
	     Tx <=1'b1; //подтянуть ножку к лог 1
	   end
	end
 
end
endmodule

Результат предсказуем, программа постоянно отправляет нули в терминал, тем не менее это уже что то, ведь результат достигнут, комп общается с ПЛИС, пусть и так коряво.
result

Ради интереса решил привязать отправку байта к нажатию кнопки с неким подобием «антидребезга». Если кнопка нажата, то увеличивается счетчик, если счетчик перевалил за 16000000 (подобрано опытным путем), то считаем что кнопка нажата. Если кнопка отжата, то отбавляем от счетчика значения. В итоге получилась смачная каша))) которая тем не менее работает.

module test_uart(clk,Tx,button);
input clk; //вход для тактовой
output reg Tx=1'b1; //выход юарта
input button; //вход кнопки
 
reg [1:0]TxEnable = 1'b0; //разрешаем отправку
reg [1:0]btnFlag = 1'b0; //флаг состояния кнопки
reg [11:0]count = 1'b0;
reg [9:0]data = 10'b1001100000;  
reg [4:0]i= 1'b0;
reg [23:0]delay = 0; //счетчик "нажатости" кнопки
 
always @ (button) //смотрим в каком положении кнопка
begin //и выставляем флаг
if(button == 1)
btnFlag <= 1'b0; //если не нажата
else
begin
btnFlag <= 1'b1; //если нажата
end
end
 
always @ (posedge clk) 
begin
 
if(btnFlag == 1'b1) //если нажата
begin
delay <= delay + 1'b1; //увеличиваем счетчик
end
if((btnFlag == 1'b0) &&(delay > 0)) //если не нажата
begin
delay <= delay - 1'b1; //уменьшаем счетчик
end
 
if(delay== 16000000) //если счетчик досчитал до устойчивого нажатия
begin
TxEnable <= 1'b1; //разрешаем передачу
end
 
if(TxEnable == 1'b1) //если разрешено, то отправляем
begin
	count <= count + 1'b1;
 
	if(count==1736)
	begin
	  Tx <= data[i];
	  count <= 0;
	  i <= i + 1;
	   if(i>9)
	   begin
	     i <= 0;
	     Tx <=1'b1;
             TxEnable <= 1'b0; //запрещаем повторную отправку
	   end
	end
end
end
endmodule

Результат — нажали кнопку, один символ ушел
tera_uart

Про прием расскажу отдельно, чтобы не было мешанины. В принципе тут тоже самое: смотрим состояние входа ножки Rx. Как только ноль — значит пошел стартбит, отсчитали полбита 1736/2=868, разрешили считывать данные. Отсчитали еще 1736 находимся где то в середине нулевого бита, прочитали значение. Отсчитали еще 1736 находимся посередине 1 бита прочитали и т.д. По окончанию сравниваем полученный байт с нужным.

Тестовая программа, принимающая байт, если байт равен ‘0’ в кодировке ASCII, то зажигаем светодиод. Если нет, то тушим.

module test_uart(clk,Rx,led);
input clk;
input Rx; //ножка приема
output reg led = 0; //светодиод
 
reg [1:0]RxEnable = 1'b0; //прием разрешен
reg [11:0]count = 1'b0; 
reg [9:0]data = 10'b1001100000; //сюда складываем принятые биты  
reg [4:0]i= 1'b0;
reg [7:0]ASCII = 8'b00110000; //символ нуля в Ascii с ним сравниваем принятые биты
 
always @ (posedge clk) 
begin
 
if((Rx==0)&&(i==0)) //если на входе ноль, значит пошел стартбит - разрешаем прием
begin
RxEnable <= 1'b1;
end
 
if(RxEnable == 1'b1) //если прием разрешен
begin
	count <= count + 1'b1; //считаем
 
	if((count==868)&&(i==0)) //когда достигли середины стартбита
	begin
	i <= 1; //переключаемся на нулевой бит
	count <= 0;
	end
 
	if((i > 0)&&(count == 1736)) //если анализируем нулевой бит и счетчик отсчитал
	begin
	  data[i] <= Rx; //записываем принятый бит
	  count <= 0; //обнуляем счетчик
	  i <= i + 1; //переходим к следующему биту
	   if(i>9) //когда все биты приняты
	   begin
	     i <= 0;
	     RxEnable <= 1'b0; //запрещаем прием
	   end
	end
end
	if(RxEnable == 1'b0) //когда прием запрещен
		begin
		if(data[8:1]==ASCII[7:0]) //смотрим нужно ли зажигать светодиод
		led = 1'b1;
	end
	else
		begin
		led = 1'b0;
	end
end
endmodule

Пусть немного кривовато, но работает, суть в том что теперь можно соединять ПЛИС, с ПК, с мк. В общем то сложности есть, но пока они решаемы. По сути я показал лишь свою реализацию, на самом деле все блоки подобные юарту уже давно реализованы в модулях и доступны в сети. Достаточно взять готовый и использовать в своем проекте. Думаю постепенно можно и с плисинами освоиться, но естественно не сразу 🙂

3 комментария: ПЛИС. Передача данных по UART

  • А как насчёт реализации UART в виде независимого блока, как в Avr, где принятый байт помещается в буфер приёма и ставится флаг и генерируется прерывание программы?

  • да можно реализовать полностью state machine, задача достойная, как следующий шаг. если это вопрос будет ли такая статья, то если и будет то не в ближайшее время.

  • Вполне хороший пример.
    Если хотите «крутое-навороченное», почитайте книгу Понг Чу.

    Там их две — одна для верилога, вторая — vhdl

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика