IIC命令级传输的VERILOG实现

文章详细描述了如何通过VERILOG语言实现IIC协议的多字节(命令级)传输,包括状态机设计、端口定义、状态转移以及使用任务函数来配置数据传输。作者展示了如何在I2C_control.v文件中管理写入和读取操作,以及同步应答信号的处理。
摘要由CSDN通过智能技术生成

iic可以有字节级命令传输实现和命令级实现,字节级实现就是如何通过VERILOG编写驱动,实现单个字节iic一些的传输。

单字节iic的传输可以看下面文章

IIC驱动的VERILOG实现-CSDN博客

现在讲的是多字节(命令级)传输实现

所谓命令级传输实现,是指在进行iic协议通信时,往往不是只进行单个字节进行传输,字节传输的上层就是命令集,就是给字节传输模块分配每次传输的字节。既i2c_control.v文件

模块端口如下

module i2c_control
#(
	parameter SYS_CLOCK = 50_000_000,//系统时钟
	parameter SCL_CLOCK = 400_000,//iic通信速率
	parameter SLAVE_ADDR = 7'h00//iic器件的地址
	)
	(
	clk,
	rst_n,
	
	wrreg_req,
	rdreg_req,
	w_len,
	r_len,
	wrdata,
	rddata,
	// device_id,
	RW_Done,
	
	ack,
	
	i2c_sclk,
	i2c_sdat
);

端口主要包括一些参数的以及端口的定义

主要端口包括

    clk,    //时钟

    rst_n,   复位

    wrreg_req,   写数据请求

    rdreg_req,  读数据请求

    w_len,    写数据的长度

    r_len,   读数据的长度

    wrdata,  //要写入的数据,当前代码最多支持8字节

    rddata,//读出的数据

    RW_Done,  //读写操作完成信号

    ack,    //应答信号

    i2c_sclk,  //iic器件的scl

    i2c_sdat  //iic器件的sda

同样使用状态机完成设计

状态定义如下

	localparam
		IDLE 		 = 7'b0000001,  //空闲状态
		WR_REG 		 = 7'b0000010,  //写寄存器状态
		WAIT_WR_DONE = 7'b0000100,  //等待写数据完成
		WR_REG_DONE  = 7'b0001000,   //写数据完成
		RD_REG 		 = 7'b0010000,   //读寄存器数据
		WAIT_RD_DONE = 7'b0100000,    //等待数据读完
		RD_REG_DONE  = 7'b1000000;   //读数据完成

状态转移如下

			IDLE:
				begin
					cnt <= 0;
					ack <= 0;
					RW_Done <= 1'b0;					
					if(wrreg_req)//空闲状态下,有写请求信号,去写寄存器状态
					begin
						state <= WR_REG;
						wrdata_r <= wrdata;
					end
					else if(rdreg_req)//空闲状态下,有读请求信号,去读寄存器状态
					begin
						state <= RD_REG;
						rddata <= 0;
					end
					else
						state <= IDLE;
				end

空闲状态下等待读写请求输入

写寄存器状态

			WR_REG:
				begin
					state <= WAIT_WR_DONE;//配置本次传输的字节
					if(cnt==0)
						write_byte(WR | STA, (SLAVE_ADDR<<1|1'b0));
					else if(cnt==w_len)
						write_byte(WR | STO, wrdata_r[63:56]);
					else 
						write_byte(WR, wrdata_r[63:56]);
				end

在写寄存器状态,利用一个周期分配本次数据传输的字节,同时设置一个计数器,传输完每个字节,计数器加一,然后根据计数值的值,分配为数据,并且生成对应的操作指令。

等待写完状态

			WAIT_WR_DONE:
				begin
					Go <= 1'b0; 
					if(Trans_Done)begin
						ack <= ack | ack_o;
						if(cnt>0)
							wrdata_r <= wrdata_r << 8;

						if(cnt==w_len)
							state <= WR_REG_DONE;  //写数据到达最大值,进入写数据完成状态
						else
							begin cnt <= cnt+1; state <= WR_REG; end//未到最大值,继续写数据	
					end
				end

在字节传输结束信号来临后,将数据写入寄存器wrdata_r左移8位,这样在写数据时,就可以只写最高的8位

写数据完成

			WR_REG_DONE:
				begin
					RW_Done <= 1'b1;
					state <= IDLE;
				end

这个状态比较简单,就是命令结束信号,告知上层模快进行下一步操作

读数据状态,代码最大支持6字节数据读取

			RD_REG:
				begin
					state <= WAIT_RD_DONE;
					case(cnt)
						0:write_byte(WR | STA, (SLAVE_ADDR<<1|1'b1));
						1,2,3,4,5:read_byte(RD | ACK);
						6:read_byte(RD | NACK | STO);
						default:;
					endcase
				end

在读数据时,我们首先会传送起始位和器件地址,并且用1'b1表示本次时读操作,计数器剩下的都在从从机读出数据

等待数据读完状态

			WAIT_RD_DONE:
				begin
					Go <= 1'b0; 
					if(Trans_Done)begin
						if(cnt <= 5)
							ack <= ack | ack_o;
						if(cnt==0)
							cnt <= 4'd7-r_len;
						else
							cnt <= cnt + 1'b1;

						if(cnt==6)
							state <= RD_REG_DONE;//读到预定的值,进入读完状态
						else
							state <= RD_REG;  //否则继续读数据
						if(cnt>0)
							rddata <= {rddata[39:0],Rx_DATA};//每次读数据将数据缓存,cnt=0时传输地址,没有读出数据
					end
				end

                        if(cnt==0)

                            cnt <= 4'd7-r_len;

                        else

                            cnt <= cnt + 1'b1;

在cnt=0时,将cnt设定一个合适的值,以便再读到6字节数据时,可以配合读数据状态中cnt=6时不应答,停止位生成,

比如读3个数据,当cnt=0是,cnt会被置成4,这样等待读到6时,正好经历了4,5,6.在cnt=6生成不应答和停止位的同时实际上只读了3字节数据

数据读完状态

			RD_REG_DONE:
				begin
					RW_Done <= 1'b1;
					state <= IDLE;
				end

比较简单,就是生成了读写状态完成信号

该模块利用了任务的写法,这是verilog的标准语法,格式如下

	task task_name;
		logic...
	endtask

模块中具体用到的语句是

	task read_byte;
		input [5:0]Ctrl_Cmd;
		begin
			Cmd <= Ctrl_Cmd;
			Go <= 1'b1; 
		end
	endtask
	
	task write_byte;
		input [5:0]Ctrl_Cmd;
		input [7:0]Wr_Byte_Data;
		begin
			Cmd <= Ctrl_Cmd;
			Tx_DATA <= Wr_Byte_Data;
			Go <= 1'b1; 
		end
	endtask

大致的意思就是一个数据配置的任务,就是给什么变量配置什么值,其实这些内容直接写在状态机的逻辑中,也是完全可以的。

上面就是verilog实现iic底层通信的具体实现了,可以在驱动上层再封装一个模块作为具体的器件适配模块。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值