Управление светодиодами по UART

Написав на языке Verilog и успешно отладив модули UART-приёмника и UART-передатчика, я решил попробовать поуправлять чем-нибудь полезным, например, светодиодом, с помощью текста, вводимого с клавиатуры в эмуляторе терминала.

Управление светодиодами по UART

Для этого я добавил в схему, построенную для статьи FPGA. UART-ресивер, модуль TextToLED (скачать), который сравнивает очередной принятый байт данных, не равен ли тот ASCII-коду символов '1', '2' или '3', и если тот оказывается равен одному из этих управляющих символов, то модуль меняет состояние соответствующего бита своего выходного сигнала ledOUT[2..0].

Во вторую версию модуля я также добавил обработку символа '0', выключающего все три светодиода:

module TextToLED (

input wire clkIN,

input wire nResetIN,

input wire [7:0] dataIN,

input wire newDataIN,

output reg [2:0] ledOUT

);

`define READY 0

`define BUSY 1

reg state;


always @ (posedge clkIN)

if (~nResetIN) begin

ledOUT <= 3'b000;

state <= `READY;

end

else case (state)

`READY:

if (newDataIN)

case (dataIN)

8'h30: // ASCII character '0'

begin

ledOUT <= 3'b000;

state <= `BUSY;

end

8'h31: // ASCII character '1'

begin

ledOUT[0] <= ~ledOUT[0];

state <= `BUSY;

end

8'h32: // ASCII character '2'

begin

ledOUT[1] <= ~ledOUT[1];

state <= `BUSY;

end

8'h33: // ASCII character '3'

begin

ledOUT[2] <= ~ledOUT[2];

state <= `BUSY;

end

endcase

`BUSY:

if (~newDataIN)

state <= `READY;

endcase


endmodule

Блок-схема устройства управления светодиодами по UART:

Блок-схема FPGA-устройства управления светодиодами, передавая данные по UART

Проблема синхронизации

Как показала практика, данная схема может зависать, если тактировать модули слишком высокой частотой осциллятора. Я тестировал её на чипе Cyclone III EP3C25E144C8N, и при этом наблюдались случайного типа зависания. Частота тактирования модулей была 48 МГц (реальный битрейт 57623 бод).

Тогда я попробовал добавить в схему ещё один модуль clkdiv, который использовал как основной сигнал CLK. На частоте 1 МГц (реальный битрейт 58823 бод) данные передавать не получилось совсем. Зато на частоте тактирования 12 МГц (реальный битрейт 57692 бод) всё заработало, и схема перестала зависать.

Как показали дальнейшие исследования, на частоте 5.760 МГц (реальный битрейт 57600), тоже происходят зависания. При этом, волшебная частота 12 МГц странным образом совпадает с внутренней частотой тактирования микросхемы FT232RL, выступающей в роли виртуального COM-порта. И как выяснилось далее, зависаний не происходит, даже если тактировать модуль UartTX8N1 с частотой 5.760 МГц, а остальные модули с частотой 12 МГц. То есть это не модуль трансмиттера подвисал, хотя я был уверен, что подвисает именно он.

Решение проблемы подсказали знающие товарищи. Суть её состоит в том, что последовательный сигнал, при передаче из одного временного домена в другой временной домен, становится асинхронным, и его нужно синхронизировать под другую тактовую частоту. Более подробно можно прочитать в статье Иосифа Каршенбойма Краткий курс HDL. Часть 11. Асинхронные частоты, пересечение клоковых доменов и синхронизация.

Я применил простейшее решение - пропустить сигнал через два последовательных D-триггера, добавив в схему модуль UartRxSync (скачать).

module UartRxSync (

input wire clkIN, input wire rxIN,

output wire rxOUT

);

reg [1:0] sync;


assign rxOUT = sync[1];


always @ (posedge clkIN)

sync <= { sync[0], rxIN };


endmodule

Схема проекта (скачать BDF):

FPGA. Схема проекта управления светодиодами по UART

Модуль pll1 (скачать) сгенерирован с помощью Megafunction Wizard (I/O -> ALT_PLL). Работа схемы проверена на частотах тактирования 12 МГц и 5.760 МГц. При этом на частоте 5.760 МГц терминальная программа даже не успевала отображать принимаемые данные, выдавая данные порциями. То есть чем точнее реальный битрейт, тем выше реальная скорость передачи.

Автор: Андрей Шаройко <vanyamboe@gmail.com>