В данной статье речь пойдет о передатчике 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. Причем для изменения скорости, как говорилось выше, был поменян только один параметр.
Работа модуля на скорости 230400 Кбит/с
Работа модуля на скорости 115200 Кбит/с
Из рисунков видно, что передатчик работает правильно.
Файлы для скачивания
Вы можете скачать файлы ( uart_trans ). В архиве прикреплен файл script.do, в котором указаны все параметры для запуска симуляции в ModelSim. Для его запуска необходимо разархивировать архив, в ModelSim с помощью команды
[php]
cd вашаДиректорияГдеЛежатФайлы (Например C:/Users/Me/Decktop/thisPrj/)
do script.do
[/php]
Если есть вопросы, замечания, предложения — пиши в комментариях
FPGA UART Transmitter — Передатчик UART, реализованный на ПЛИС: 1 комментарий