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