Implementação de Lógica Sequencial para Comunicação Serial em Verilog

Este projeto detalha o desenvolvimento de um sistema de comunicação serial síncrono copmosto por três módulos principais: um gerador de estímulos (M0), um transmissor paralelo-serial (M1) e um decodificador de dados recebidos (M2). O fluxo de dados consiste no envio de informações de 4 bits convertidas em um fluxo serial (SDA) sincronizado por um sinal de clock (SCL).

Análise de Temporização e Protocolo

O protocolo de comunicação baseia-se na relação entre o sinal de dados (SDA) e o sinal de clock (SCL). As condições funadmentais são: - Início de Trasnmissão: Ocorre quando o SDA transita de alto para baixo enquanto o SCL permanece em nível lógico alto.

  • Fim de Transmissão: Ocorre quando o SDA transita de baixo para alto enquanto o SCL está em nível lógico alto.
  • Estabilidade de Dados: As alterações no estado do SDA devem ocorrer apenas quando o SCL estiver em nível baixo. Quando o SCL está em nível alto, o dado no barramento SDA deve permanecer estável para leitura.

Módulo M1: Conversor Paralelo-Serial

Este módulo atua como o mestre da transmissão, gerenciando uma máquina de estados finitos (FSM) para converter o dado paralelo de entrada em um sinal serial. ```

module transmissor_serial ( input wire clk_sistema, input wire reset_n, input wire [3:0] dados_entrada, output reg solicitacao_ready, output reg scl_out, output reg sda_out );

reg [7:0] estado_atual;
reg [3:0] buffer_interno;
reg sda_buffer;
reg link_ativo;

localparam IDLE   = 8'h01,
           START  = 8'h02,
           BIT_3  = 8'h04,
           BIT_2  = 8'h08,
           BIT_1  = 8'h10,
           BIT_0  = 8'h20,
           STOP   = 8'h40,
           WAIT   = 8'h80;

// Geração do sinal SCL (metade da frequência do clock de sistema)
always @(posedge clk_sistema or negedge reset_n) begin
    if (!reset_n)
        scl_out <= 1'b1;
    else
        scl_out <= ~scl_out;
end

// Captura de dados paralelos
always @(posedge solicitacao_ready) begin
    buffer_interno <= dados_entrada;
end

// Máquina de Estados Principal
always @(negedge clk_sistema or negedge reset_n) begin
    if (!reset_n) begin
        link_ativo <= 1'b0;
        estado_atual <= IDLE;
        sda_buffer <= 1'b1;
        solicitacao_ready <= 1'b0;
    end else begin
        case (estado_atual)
            IDLE: begin
                if (solicitacao_ready) begin
                    link_ativo <= 1'b1;
                    estado_atual <= START;
                end else begin
                    link_ativo <= 1'b0;
                    solicitacao_ready <= 1'b1;
                    estado_atual <= IDLE;
                end
            end

            START: begin
                if (scl_out) begin
                    sda_buffer <= 1'b0;
                    estado_atual <= BIT_3;
                end
            end

            BIT_3: if (!scl_out) begin
                sda_buffer <= buffer_interno[3];
                solicitacao_ready <= 1'b0;
                estado_atual <= BIT_2;
            end

            BIT_2: if (!scl_out) begin
                sda_buffer <= buffer_interno[2];
                estado_atual <= BIT_1;
            end

            BIT_1: if (!scl_out) begin
                sda_buffer <= buffer_interno[1];
                estado_atual <= BIT_0;
            end

            BIT_0: if (!scl_out) begin
                sda_buffer <= buffer_interno[0];
                estado_atual <= STOP;
            end

            STOP: if (scl_out) begin
                sda_buffer <= 1'b1;
                estado_atual <= WAIT;
            end

            WAIT: begin
                link_ativo <= 1'b0;
                estado_atual <= IDLE;
            end

            default: estado_atual <= IDLE;
        endcase
    end
end

// Controle de alta impedância do barramento SDA
always @(*) begin
    if (link_ativo)
        sda_out = sda_buffer;
    else
        sda_out = 1'bz;
end

endmodule


### Módulo M2: Receptor e Decodificador

O módulo receptor monitora as transições no SDA para identificar o início da mensagem e reconstrói o dado de 4 bits, mapeando-o para uma saída de 16 bits (one-hot encoding). ```

module decodificador_receptor (
    input wire scl_in,
    input wire sda_in,
    output reg [15:0] saida_mapeada
);

    reg [5:0] estado_rx;
    reg [3:0] registrador_deslocamento, dado_final;
    reg flag_inicio, flag_fim;

    localparam S_IDLE = 6'b000001,
               S_B3   = 6'b000010,
               S_B2   = 6'b000100,
               S_B1   = 6'b001000,
               S_B0   = 6'b010000,
               S_DONE = 6'b100000;

    // Detecção de condição de início (Start Condition)
    always @(negedge sda_in) begin
        if (scl_in)
            flag_inicio <= 1'b1;
        else if (flag_fim)
            flag_inicio <= 1'b0;
    end

    // Detecção de condição de parada (Stop Condition)
    always @(posedge sda_in) begin
        if (scl_in) begin
            flag_fim <= 1'b1;
            dado_final <= registrador_deslocamento;
        end else begin
            flag_fim <= 1'b0;
        end
    end

    // Mapeamento One-Hot
    always @(dado_final) begin
        saida_mapeada = 16'b0;
        saida_mapeada[dado_final] = 1'b1;
    end

    // Amostragem de dados no clock SCL
    always @(posedge scl_in) begin
        if (flag_inicio) begin
            case (estado_rx)
                S_IDLE: begin
                    registrador_deslocamento[3] <= sda_in;
                    estado_rx <= S_B3;
                end
                S_B3: begin
                    registrador_deslocamento[2] <= sda_in;
                    estado_rx <= S_B2;
                end
                S_B2: begin
                    registrador_deslocamento[1] <= sda_in;
                    estado_rx <= S_B1;
                end
                S_B1: begin
                    registrador_deslocamento[0] <= sda_in;
                    estado_rx <= S_B0;
                end
                S_B0: estado_rx <= S_IDLE;
                default: estado_rx <= S_IDLE;
            endcase
        end else begin
            estado_rx <= S_IDLE;
        end
    end

endmodule

Módulo M0: Gerador de Estímulos (Testbench)

Este módulo gera os sinais de clock e reset, além de incrementar os dados de teste sempre que o transmissor solicita novos valores. ```

`timescale 1ns/1ns

module test_stimulus ( output reg rst_n, output reg clk_main, output reg [3:0] val_data, input wire req_ack );

initial begin
    rst_n = 1'b1;
    #15 rst_n = 1'b0;
    #110 rst_n = 1'b1;
end

initial begin
    clk_main = 1'b0;
    val_data = 4'h0;
    #50000 $finish;
end

always #50 clk_main = ~clk_main;

always @(posedge req_ack) begin
    #60 val_data <= val_data + 1'b1;
end

endmodule


### Integração do Sistema (Top Level)

A integração conecta os três módulos para simulação e verificação funcional do fluxo de dados serial. ```

`timescale 1ns/1ns

module sistema_top;
    wire [3:0] bus_dados;
    wire clk_sig, scl_line, sda_line, rst_line, ack_sig;
    wire [15:0] resultado_final;

    test_stimulus m0 (
        .rst_n(rst_line),
        .clk_main(clk_sig),
        .val_data(bus_dados),
        .req_ack(ack_sig)
    );

    transmissor_serial m1 (
        .clk_sistema(clk_sig),
        .reset_n(rst_line),
        .dados_entrada(bus_dados),
        .solicitacao_ready(ack_sig),
        .scl_out(scl_line),
        .sda_out(sda_line)
    );

    decodificador_receptor m2 (
        .scl_in(scl_line),
        .sda_in(sda_line),
        .saida_mapeada(resultado_final)
    );

endmodule

Tags: Verilog FPGA SerialCommunication DigitalDesign StateMachines

Publicado em 7-3 20:55