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

On 05.11.2016 by nikellanjilo

В данной статье речь пойдет о передатчике 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;

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 

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

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

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

`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 

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

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

87

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

173

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

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


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

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


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

do script.do

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

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