读可以为1-3个读突发:
module bmp280_rd(
input wire sclk,//system clock 100MHz
input wire rst,//system reset,active high
input wire start,//starting signal for sending datas
input wire[7:0] regaddr,//register address
input wire[2:0] burst_len,
output reg [23:0] rece_data,
output reg read_ok,
output reg read_fail,
output reg rd_scl,//400kHz clock for slave device
output wire rd_sdo,//define slave device address bit[0]=111011_bit[0]
inout wire rd_sda //iic data port for input and output
);
parameter SCLKCNT_MAX=250-1;//100_000_000/400_000=250 for 400kHz scl
parameter IDLE =5'b00001;
parameter START=5'b00010;
parameter SEND =5'b00100;
parameter RECE =5'b01000;
parameter STOP =5'b10000;
reg [4:0] state;
reg [7:0] sclk_cnt;
reg [6:0] slave_addr;
reg sda_r;
reg oe;
reg [3:0] bit_cnt;
reg [3:0] byte_cnt;
reg [23:0] data_temp;
reg wr_rd_flag;
reg [2:0] bl;
always @(posedge sclk) begin
if (rst==1'b1) begin
bl<='d0;
end
else if (start==1'b1) begin
bl<=burst_len;
end
end
always @(posedge sclk) begin
if (rst==1'b1) begin
data_temp<='d0;
end
else if (start==1'b1) begin
data_temp<={slave_addr,1'b0,regaddr,slave_addr,1'b1};
end
else if(state==SEND && byte_cnt<'d2 && bit_cnt!='d8&& sclk_cnt=='d0)begin
data_temp<=data_temp<<1;
end
else if(state==RECE && byte_cnt=='d0 && bit_cnt!='d8 && sclk_cnt=='d0)begin
data_temp<=data_temp<<1;
end
end
always @(posedge sclk) begin
if (rst==1'b1) begin
oe<=1'b1;
end
else if (state==SEND) begin
if(byte_cnt<'d2 && bit_cnt=='d7 && sclk_cnt==SCLKCNT_MAX)begin
oe<=1'b0;
end
else if(bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)begin
oe<=1'b1;
end
end
else if(state==RECE)begin
if(byte_cnt=='d0)begin
if(bit_cnt=='d7 && sclk_cnt==SCLKCNT_MAX)begin
oe<=1'b0;
end
end
else begin
if(bit_cnt=='d7 && sclk_cnt==SCLKCNT_MAX)begin
oe<=1'b1;
end
else if(bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)begin
oe<=1'b0;
end
end
end
else begin
oe<=1'b1;
end
end
assign rd_sda = (oe==1'b1)?sda_r:1'bz;
assign rd_sdo = 1'b0;//slave device address 1110_110
always @(posedge sclk) begin
if (rst==1'b1) begin
slave_addr<='d0;
end
else if (rd_sdo==1'b1) begin
slave_addr<=7'b1110_111;
end
else begin
slave_addr<=7'b1110_110;
end
end
//sclk_cnt
always @(posedge sclk) begin
if (rst==1'b1) begin
sclk_cnt<='d0;
end
else if ((state==IDLE) || (sclk_cnt==SCLKCNT_MAX)) begin
sclk_cnt<='d0;
end
else begin
sclk_cnt<=sclk_cnt+1'b1;
end
end
//bit_cnt
always @(posedge sclk) begin
if (rst==1'b1) begin
bit_cnt<='d0;
end
else if(state==START || read_fail==1'b1 || read_ok==1'b1) begin
bit_cnt<='d0;
end
else if (state==SEND && sclk_cnt==SCLKCNT_MAX) begin
if(bit_cnt=='d8)begin
bit_cnt<='d0;
end
else begin
bit_cnt<=bit_cnt+1'b1;
end
end
else if(state==RECE && sclk_cnt==SCLKCNT_MAX)begin
if(bit_cnt=='d8)begin
bit_cnt<='d0;
end
else begin
bit_cnt<=bit_cnt+1'b1;
end
end
end
//byte_cnt
always @(posedge sclk) begin
if (rst==1'b1) begin
byte_cnt<='d0;
end
else if (state==SEND) begin
if(byte_cnt=='d1 && bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)
byte_cnt<='d0;
else if(byte_cnt!='d1 && bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)begin
byte_cnt<=byte_cnt+1'b1;
end
end
else if(state==RECE) begin
if(byte_cnt==bl && bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)
byte_cnt<='d0;
else if(byte_cnt!=bl && bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)begin
byte_cnt<=byte_cnt+1'b1;
end
end
else begin
byte_cnt<='d0;
end
end
//wr_rd_flag
always @(posedge sclk) begin
if (rst==1'b1) begin
wr_rd_flag<=1'b0;
end
else begin
case(state)
IDLE:begin
wr_rd_flag<=1'b0;
end
SEND:begin
if(byte_cnt=='d1 && bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)begin
wr_rd_flag<=1'b1;
end
end
endcase
end
end
//state
always @(posedge sclk) begin
if (rst==1'b1) begin
state<=IDLE;
end
else begin
case(state)
IDLE:begin
if(start==1'b1)begin
state<=START;
end
end
START:begin
if(wr_rd_flag==1'b0 && sclk_cnt==SCLKCNT_MAX)begin
state<=SEND;
end
else if(wr_rd_flag==1'b1 && sclk_cnt==SCLKCNT_MAX)begin
state<=RECE;
end
end
SEND:begin
if(bit_cnt=='d8 && sclk_cnt==((SCLKCNT_MAX>>1)+(SCLKCNT_MAX>>2)) && rd_sda==1'b1)begin
state<=IDLE;
end
else if(byte_cnt=='d1 && bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)begin
state<=START;
end
end
RECE:begin
if(byte_cnt=='d0 && bit_cnt=='d8 && sclk_cnt==((SCLKCNT_MAX>>1)+(SCLKCNT_MAX>>2)) && rd_sda==1'b1)begin
state<=IDLE;
end
else if(byte_cnt==bl && bit_cnt=='d8 && sclk_cnt==SCLKCNT_MAX)begin
state<=STOP;
end
end
STOP:begin
if(sclk_cnt==SCLKCNT_MAX)begin
state<=IDLE;
end
end
default:state<=IDLE;
endcase
end
end
//sda_r
always @(posedge sclk) begin
if (rst==1'b1) begin
sda_r<=1'b1;
end
else begin
case(state)
START:begin
if(sclk_cnt>(SCLKCNT_MAX>>1))begin
sda_r<=1'b0;
end
else begin
sda_r<=1'b1;
end
end
SEND:begin
if(bit_cnt!='d8 && sclk_cnt=='d0)begin
sda_r<=data_temp[23];
end
end
RECE:begin
if(byte_cnt=='d0 && bit_cnt!='d8 && sclk_cnt=='d0)begin
sda_r<=data_temp[23];
end
else if(byte_cnt<bl && bit_cnt=='d8 && sclk_cnt=='d0) begin
sda_r<=1'b0;
end
else if(byte_cnt==bl && bit_cnt=='d8 && sclk_cnt=='d0)begin
sda_r<=1'b1;
end
end
STOP:begin
if(sclk_cnt>((SCLKCNT_MAX>>1)+(SCLKCNT_MAX>>2)))begin
sda_r<=1'b1;
end
else begin
sda_r<=1'b0;
end
end
default:sda_r<=1'b1;
endcase
end
end
//rd_scl
always @(posedge sclk) begin
if (rst==1'b1) begin
rd_scl<=1'b1;
end
else begin
case(state)
START:begin
if(sclk_cnt==SCLKCNT_MAX)begin
rd_scl<=1'b0;
end
else begin
rd_scl<=1'b1;
end
end
SEND:begin
if(sclk_cnt==SCLKCNT_MAX)begin
rd_scl<=1'b0;
end
else if(sclk_cnt==(SCLKCNT_MAX>>1))begin
rd_scl<=1'b1;
end
end
RECE:begin
if(sclk_cnt==SCLKCNT_MAX)begin
rd_scl<=1'b0;
end
else if(sclk_cnt==(SCLKCNT_MAX>>1))begin
rd_scl<=1'b1;
end
end
STOP:begin
if(sclk_cnt=='d0)begin
rd_scl<=1'b0;
end
else if(sclk_cnt==(SCLKCNT_MAX>>1))begin
rd_scl<=1'b1;
end
end
default:rd_scl<=1'b1;
endcase
end
end
//read_fail
always @(posedge sclk) begin
if (rst==1'b1) begin
read_fail<=1'b0;
end
else if (state==SEND && bit_cnt=='d8 && sclk_cnt==((SCLKCNT_MAX>>1)+(SCLKCNT_MAX>>2)) && rd_sda==1'b1) begin
read_fail<=1'b1;
end
else if (state==RECE && byte_cnt=='d0 && bit_cnt=='d8 && sclk_cnt==((SCLKCNT_MAX>>1)+(SCLKCNT_MAX>>2)) && rd_sda==1'b1) begin
read_fail<=1'b1;
end
else begin
read_fail<=1'b0;
end
end
//read_ok
always @(posedge sclk) begin
if (rst==1'b1) begin
read_ok<=1'b0;
end
else if (state==STOP && sclk_cnt==SCLKCNT_MAX) begin
read_ok<=1'b1;
end
else begin
read_ok<=1'b0;
end
end
//rece_data
always @(posedge sclk) begin
if (rst==1'b1) begin
rece_data<='d0;
end
else if (start==1'b1) begin
rece_data<='d0;
end
else if(state==RECE && byte_cnt!='d0 && bit_cnt!='d8 &&(sclk_cnt==((SCLKCNT_MAX>>1)+(SCLKCNT_MAX>>2))))begin
rece_data<={rece_data[22:0],rd_sda};
end
end
endmodule
仿真代码:
`timescale 1ns/1ns
module tb_bmp280_rd (); /* this is automatically generated */
parameter IDLE =5'b00001;
parameter START=5'b00010;
parameter SEND =5'b00100;
parameter RECE =5'b01000;
parameter STOP =5'b10000;
// clock
reg clk;
reg rst;
reg start;
reg [7:0] regaddr;
reg [2:0] burst_len;
wire [23:0] rece_data;
wire read_ok;
wire read_fail;
wire rd_scl;
wire rd_sdo;
wand rd_sda;
reg rd_sda_r;
initial begin
clk = 0;
forever #(5) clk = ~clk;
end
// synchronous reset
initial begin
start=0;
regaddr=0;
burst_len=0;
rst = 1;
repeat(100)@(posedge clk)
rst = 0;
repeat(100)@(posedge clk);
rece_dat(8'hf7,3);
rece_dat(8'hf7,2);
rece_dat(8'hf7,1);
$stop;
end
bmp280_rd inst_bmp280_rd (
.sclk (clk),
.rst (rst),
.start (start),
.regaddr (regaddr),
.burst_len (burst_len),
.rece_data (rece_data),
.read_ok (read_ok),
.read_fail (read_fail),
.rd_scl (rd_scl),
.rd_sdo (rd_sdo),
.rd_sda (rd_sda)
);
task rece_dat;
input [7:0] regaddr_r;
input [2:0] burst_len_r;
begin
start=0;
regaddr=regaddr_r;
burst_len=burst_len_r;
@(negedge clk) start=1;
@(negedge clk) start=0;
@(posedge read_ok or posedge read_fail);
#1000;
end
endtask
always @(posedge clk) begin
if (rst==1'b1) begin
rd_sda_r<=1'b1;
end
else if (inst_bmp280_rd.state==SEND && inst_bmp280_rd.bit_cnt==8) begin
rd_sda_r<=1'b0;
end
// else if (inst_bmp280_rd.state==SEND && inst_bmp280_rd.byte_cnt==1 && inst_bmp280_rd.bit_cnt==8) begin
// rd_sda_r<=1'b1;
// end
else if(inst_bmp280_rd.state==RECE && inst_bmp280_rd.byte_cnt==0 && inst_bmp280_rd.bit_cnt==8)begin
rd_sda_r<=1'b0;
end
else begin
rd_sda_r<=1'b1;
end
end
assign rd_sda = rd_sda_r;
endmodule
仿真波形: