FPGA UART Transmitter — Передатчик UART, реализованный на ПЛИС

В данной статье речь пойдет о передатчике UART, и она немного перекликается с предыдущей статьей [в ней Вы можете ознакомиться с теоретической частью работы UART и посмотреть код для приемопередатчика с тактовой частотой 20 Мгц и инф. скоростью 115200 кБит/с], за тем исключением, что здесь мы рассмотрим один из модулей Асинхронного Универсального Приемопередатчика (UART) — а именно передатчик.

Представленный ниже код является легко параметризуемым — его можно использовать в проектах с разными частотами и на разных информационных скоростях … следует лишь изменить один параметр.


Немного теории и о том, как использовать данный модуль передатчика …

В модуле используются следующие порты:

clk — входной однобитный порт. По данному порту подаются тактовые импульсы, по которым тактируется весь наш блок

data — входной 8-битный порт. На этом параллельном порту мы получаем данные, которые будем передавать по последовательному порту tx

data_rdy — входной однобитный порт. Лог. единица на данном порту сигнализирует о том, что данные (data) валидны и их необходимо передать по tx

tx — выходной однобитный порт. По нему мы передаем последовательный поток данных

transm_rdy — выходной однобитный порт. Данный порт сигнализирует остальным блокам о своем состоянии. Если на нем лог. 1, то блок — готов к передаче данных и ждет на вход data и data_rdy для передачи данных, если лог. 0 — то блок находится в процессе работы (занят)


Код передатчика — Verilog код

Здесь  сountOfStrobe — параметр, меняя который может регулировать информационную скорость нашего UART’а. В данном случае UART настроен на скорость 115200 кБит/с при тактовой частоте clk = 20 МГц.

сountOfStrobe = Fclk(Гц)/Vuart(бит/c) = 20*10^6 / 115200 = 173;

[php]
module uart_param_trans #(
parameter countOfStrobe = 173    // Параметр, который высчитывается из соотношения Fclk[Гц] / V[бит/c]
// соответствует тому, сколько тактов приходится на передачу одного
// бита данных при выбраной скорости UART(бит/с) и тактовой частоте CLK (Гц)
)(
input clk,                       // Тактовая частота
input [7:0] data,              // Данные, которые собираемся передать по TX
input data_rdy,                // Строб, который соответствует тому, что данные валидные и их нужно передать
output reg tx = 1,          // Выходной порт, передает данные по последовательному интерфейсу
output reg transm_rdy = 1   // Строб, который сигнализирует о том, что данные переданы и блок готов к передаче новых данных
);

reg [1:0] state = 2’b00;     // Регистр, который будет менять значение в зависимости от состояния нашего модуля
reg [7:0] cntStrobe = 0;     // Регистр — счетчик, который будет накапливаться до необходимого числа стробов (до countOfStrobe)
reg [4:0] cntBit = 0;         // Регистр — счетчик, указываюший на номер передаваемого бита из data
reg [7:0] shiftData;         // Сдвиговый регистр, в который мы записываем входные данные (data), а затем последовательно, побитово
// передаем по TX

always @(posedge clk)
begin
case(state)
2’b00 :    begin
if (data_rdy)
begin
state <= 2’b01;
shiftData <= data;
transm_rdy <= 0;
tx <= 0;
end
end
2’b01 :    begin
if (cntBit == 0)
begin
if (cntStrobe < countOfStrobe)
cntStrobe <= cntStrobe + 1;
else
begin
cntStrobe <= 0;
cntBit <= 1;
tx <= shiftData[0];
shiftData[6:0] <= shiftData[7:1];
end
end
if (cntBit > 0 && cntBit < 9)
begin
if (cntStrobe < countOfStrobe)
cntStrobe <= cntStrobe + 1;
else
begin
cntStrobe <= 0;
cntBit <= cntBit + 1;
tx <= shiftData[0];
shiftData[6:0] <= shiftData[7:1];
end
end
if (cntBit == 9)
begin
if (cntStrobe < countOfStrobe)
begin
cntStrobe <= cntStrobe + 1;
tx <= 1;
end
else
begin
cntStrobe <= 0;
cntBit <= 0;
transm_rdy <= 1;
state <= 2’b00;
end
end
end

endcase
end
endmodule
[/php]


Testbench проекта … Симуляция работы модуля в ModelSim

Для того, чтобы убедиться в том, что модуль работает — напишем тестбенч. Тестбенч — файл, который пишется для симуляции работы модуля и он симулирует работу портов, так, как это указано в техническом задании.

В нашем случае testbench подаст на наш блок — тактовый сигнал clk, данные data и строб data_rdy, при этом он будет следить за стробом transm_rdy и когда тот будет переходить в лог.1 (т.е. передатчик будет готов передавать новые данные по tx) testbench будет инкрементировать данные  (увеличивать значение на 1) и переводить data_rdy в лог. 1.

[php]
`timescale 1ns / 100 ps;
module uart_param_tb();
parameter fr = 50; // 20 MHz

reg clk = 0;
reg [7:0] data = 8’b0111_1110;
reg data_rdy = 0;
reg [1:0] state = 2’b00;

wire tx, transm_rdy;

always
begin
#(fr/2) clk = 1;
#(fr/2) clk = 0;
end

always @(posedge clk)
begin

case (state)
2’b00 :    begin
if (transm_rdy)
begin
state <= 2’b01;
data <= data + 1;
end
end
2’b01 : begin
data_rdy <= 1;
state <= 2’b10;
end
2’b10 : begin
data_rdy <= 0;
state <= 2’b00;
end
endcase
end

uart_param_trans tb(
.clk(clk),
.data(data),
.data_rdy(data_rdy),
.tx(tx),
.transm_rdy(transm_rdy)
);

endmodule
[/php]


Результаты моделирования в ModelSim

Ниже представлены рисунки симуляции при скорости UART 115200 и 230400 Кбит/c. Причем для изменения скорости, как говорилось выше, был поменян только один параметр.

87

Работа модуля на скорости 230400 Кбит/с

173

Работа модуля на скорости 115200 Кбит/с

Из рисунков видно, что передатчик работает правильно.


Файлы для скачивания

Вы можете скачать файлы ( uart_trans ). В архиве прикреплен файл script.do, в котором указаны все параметры для запуска симуляции в ModelSim. Для его запуска необходимо разархивировать архив, в ModelSim с помощью команды

[php]

cd вашаДиректорияГдеЛежатФайлы (Например C:/Users/Me/Decktop/thisPrj/)

do script.do

[/php]

Если есть вопросы, замечания, предложения — пиши в комментариях

FPGA UART Transmitter — Передатчик UART, реализованный на ПЛИС: 1 комментарий

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