Verilog数字系统设计
例15.2
M0模块:接收M1产生的新数据使能信号,产生测试数据,如系统时钟、复位信号和需要传输的4位并行数据
M1模块:将4位并行数据转换成串行数据,并且按照协议将串行数据输送到M2模块
M2模块:将串行数据复原为4位并行数据,并且根据并行数据的值,输出相应的高电平,即若数据为1,则第一条线路为0;
通信协议:scl为不断输出的时钟信号。在scl为高电平的前提下,sda由高变低,串行数据流准备传输;在scl为高电平的前提下,sda由低变高,串行数据流传输结束。sda所传输的数据必须在scl为低电平时变化。
信号表示:data为待传输4位并行数据,sclk为系统时钟,ack(en)为产生新数据使能信号,scl为根据sclk分频得到的时钟,sda为串行数据,outhigh高电平结果。
心得
- M0模块实际上就是一个tb,运用了模块化的思想,输入为en,输出为sclk、rst_n、data;当新数据使能信号到来时,产生新数据。
- M1模块使用三段式状态机,分为IDLE、START、BIT1、BIT2、BIT3、BIT4、READY、STOP 8个状态。为了满足“在scl为高电平的前提下.......sda所传输的数据必须在scl为低电平时变化”这一协议要求,状态机是在sclk下降沿触发。
3、en信号拉高,新数据产生,此时状态机切换到START状态,此状态下将sda由高拉低,表示可以传输数据了;传完4bit之后,状态切换到READY,将sda变化为0,为由低拉高sda作准备;STOP状态时,将sda拉高,表示数据传输结束。
4、在BIT1状态时,将flag_start信号拉高,告诉M2模块:我要传输第一个bit了,你可以接收第一个bit了;在READY状态,将flag_start信号拉低,告诉M2模块:4bit数据已经传输完了,你可以停止接收了。
5、M2模块使用计数器(简单),不使用状态机。在scl上升沿且falg_start为1时,开始计数,表示此时传输bit了;在scl下降沿且falg_start为1时,将sda存入缓冲器;在flag_start下降沿且计数器为4时,将缓冲器里的4bit数据赋值给DATA。
M0模块:
//**************************************************************************************************
//****************************************模块功能***************************************************
//****************************************本模块产生测试信号,不能综合成电路***************************
//**************************************************************************************************
`timescale 1ns/1ns
module sigdata (
input ask_data,
output reg rst_n,
output reg[3:0] data,
output reg sclk
);
parameter halfperiod = 50;
initial begin
rst_n = 0;
#100 rst_n = 1;
end
initial begin
sclk = 0;
data = 0;
#(halfperiod*1000) $stop;
end
always begin #(halfperiod) sclk = ~sclk; end
always @(posedge ask_data) begin
#(halfperiod*2+3) data = data + 1;
end
endmodule
M1模块
//**************************************************************************************************
//****************************************模块功能***************************************************
//*********把4位并行数据转换为符合协议的串行数据流,数据流用scl、sda两条线传输,sclk为输入的时钟信号*******
//**************************************************************************************************
module ptosda (
input sclk,
input rst_n,
output reg en, //the signal that allows new data to export
input [3:0]data, //data which needs to be exported
output reg scl, //clk that generated by sclk
output reg flag_start, //the signal which tells out16hi.v that it can recieve the bits
//output flag_end, //the signal which tells out16hi.v that it can refuse recieving the bits
output sda //Serial data that fits agreements, take out: inout!
);
reg buffer_sda;
reg [3:0]buffer_data;
reg link_sda;
reg [7:0]cstate;
reg [7:0]nstate;
parameter [7:0]
IDLE = 8'b0000_0001,
READY = 8'b0000_0010,
START = 8'b0000_0100,
BIT1 = 8'b0000_1000,
BIT2 = 8'b0001_0000,
BIT3 = 8'b0010_0000,
BIT4 = 8'b0100_0000,
STOP = 8'b1000_0000;
//the generation of scl
always @(posedge sclk, negedge rst_n) begin
if(~rst_n) begin
scl <= 0;
end
else begin
scl <= ~scl;
end
end
//deposit new data in buffer
always @(negedge sclk ) begin
if(en) begin
buffer_data <= data;
end
else begin
buffer_data <= buffer_data;
end
end
assign sda = link_sda? buffer_sda : 0;
//1st state transition
always @(negedge sclk, negedge rst_n) begin
if(~rst_n) begin
cstate <= IDLE;
end
else begin
cstate <= nstate;
end
end
//2nd condition judgement
always @* begin
nstate = 8'bx;
case(cstate)
IDLE: begin
if(en==1) nstate = START;
else nstate = IDLE;
end
START: begin
if(scl==0) nstate = BIT1;
else nstate = START;
end
BIT1: begin
if(scl==0) begin nstate = BIT2; flag_start = 1; end
else nstate = BIT1;
end
BIT2: begin
if(scl==0) nstate = BIT3;
else nstate = BIT2;
end
BIT3: begin
if(scl==0) nstate = BIT4;
else nstate = BIT3;
end
BIT4: begin
if(scl==0) nstate = READY;
else nstate = BIT4;
end
READY: begin
if(scl==1) begin nstate = STOP; flag_start = 0; end
else nstate = READY;
end
STOP: begin
if(scl==1) nstate = IDLE;
else nstate = STOP;
end
default: nstate <= IDLE;
endcase
end
//3rd output
always @(negedge sclk, negedge ~rst_n) begin
if(~rst_n) begin
cstate <= IDLE;
link_sda <= 0;
buffer_sda <= 1;
en <= 0;
flag_start <= 0;
//flag_end <= 0;
end
else begin
case(nstate)
IDLE: begin
link_sda <= 1;
en <= 1;
buffer_sda <= 1;
end
START: if(scl) begin
buffer_sda <= 0;
end
else begin
buffer_sda <= buffer_sda;
end
BIT1: if(!scl) begin
buffer_sda <= buffer_data[3];
en <= 0;
end
BIT2: if(!scl) begin
buffer_sda <= buffer_data[2];
end
BIT3: if(!scl) begin
buffer_sda <= buffer_data[1];
end
BIT4: if(!scl) begin
buffer_sda <= buffer_data[0];
end
READY: if(!scl) begin
buffer_sda <= 0; //结束传输预准备
end
STOP: if(scl) begin
buffer_sda <= 1;
end
endcase
end
end
endmodule
M2模块:
//*************************************************************************************
//************************************模块功能******************************************
//******************按照协议接收串行数据,进行处理,并按要求输出相应的高电平*****************
//**************************************************************************************
module out16hi (
input scl,
input rst_n,
input flag_start,
input sda,
output reg[15:0]high
);
reg [3:0] DATA; //initial data
reg [3:0] buffer_data;
reg [3:0] cnt;
//counter for 4 bits
always @(posedge scl, negedge rst_n) begin
if(~rst_n) begin
cnt <= 4'd0;
end
else if(flag_start) begin
if(cnt != 4'd4) begin
cnt <= cnt + 4'd1;
end
else begin
cnt <= 4'd0;
end
end
else begin
cnt <= 4'd0;
end
end
//buffer_data
always @(negedge scl, negedge rst_n) begin
if(~rst_n) begin
buffer_data <= 4'dx;
end
else if(flag_start) begin
buffer_data[4-cnt] <= sda;
end
else begin
buffer_data <= 0;
end
end
//DATA
always @(negedge flag_start) begin
if(cnt == 4) begin
DATA <= buffer_data;
end
else begin
DATA <= 0;
end
end
//highlight
always @(*) begin
if(cnt == 0) begin
case (DATA)
4'b0000: high = 16'b0000_0000_0000_0000;
4'b0001: high = 16'b0000_0000_0000_0001;
4'b0010: high = 16'b0000_0000_0000_0010;
4'b0011: high = 16'b0000_0000_0000_0100;
4'b0100: high = 16'b0000_0000_0000_1000;
4'b0101: high = 16'b0000_0000_0001_0000;
4'b0110: high = 16'b0000_0000_0010_0000;
4'b0111: high = 16'b0000_0000_0100_0000;
4'b1000: high = 16'b0000_0000_1000_0000;
4'b1001: high = 16'b0000_0001_0000_0000;
4'b1010: high = 16'b0000_0010_0000_0000;
4'b1011: high = 16'b0000_0100_0000_0000;
4'b1100: high = 16'b0000_1000_0000_0000;
4'b1101: high = 16'b0001_0000_0000_0000;
4'b1110: high = 16'b0010_0000_0000_0000;
4'b1111: high = 16'b0100_0000_0000_0000;
default: high = 16'b0000_0000_0000_0000;
endcase
end
else begin
high = high;
end
end
endmodule
top模块
`timescale 1ns/1ns
module top;
wire rst_n;
wire sclk;
wire [3:0] data;
wire scl;
wire en;
wire flag_start;
wire sda;
wire [15:0]high;
ptosda t1(
.sclk(sclk),
.rst_n(rst_n),
.en(en),
.data(data),
.flag_start(flag_start),
.scl(scl),
.sda(sda)
);
out16hi t2(
.scl(scl),
.rst_n(rst_n),
.sda(sda),
.flag_start(flag_start),
.high(high)
);
sigdata t3(
.ask_data(en),
.rst_n(rst_n),
.data(data),
.sclk(sclk)
);
endmodule