BMP280之IIC读部分的 verilog代码

读可以为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

仿真波形:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Verilog代码示例,用于实现I2C通信协议: ```verilog module I2C ( input wire clk, input wire reset, input wire sda_in, input wire scl_in, output wire sda_out ); // 状态定义 reg [2:0] state; parameter IDLE = 3'b000; parameter START = 3'b001; parameter ADDRESS = 3'b010; parameter DATA = 3'b011; parameter STOP = 3'b100; // 数据寄存器 reg [7:0] data_reg; // 计数器 reg [3:0] count; // 状态机 always @(posedge clk, posedge reset) begin if (reset) begin state <= IDLE; count <= 0; end else begin case (state) IDLE: if (sda_in == 1 && scl_in == 1) state <= START; START: if (scl_in == 0) state <= ADDRESS; ADDRESS: if (count < 8) state <= DATA; else state <= STOP; DATA: if (count < 8) state <= DATA; else state <= STOP; STOP: state <= IDLE; endcase end end // 数据寄存器写入 always @(posedge clk, posedge reset) begin if (reset) data_reg <= 0; else begin case (state) ADDRESS, DATA: if (count < 8) data_reg <= {data_reg[6:0], sda_in}; endcase end end // 输出控制 assign sda_out = (state == ADDRESS || state == DATA) ? data_reg[7] : 1'b1; endmodule ``` 这是一个简单的I2C通信协议的Verilog代码示例。它实现了一个有限状态机来处理I2C通信的不同阶段,包括开始、地址传输、数据传输和停止。代码中使用的输入信号包括时钟信号(clk)、复位信号(reset)、数据信号(sda_in)和时钟信号(scl_in),输出信号为数据信号(sda_out)。 请注意,此代码仅为示例,实际应用中可能需要根据具体要求进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值