weiqi7777

FPGA之IIC

0
阅读(6463)

FPGA之IIC

这几天实现FPGA对AT24C02进行读写。采用的是IIC总线,所以要写IIC控制代码。写代码花了一下午,可是调试花了三天。真是相当蛋疼,用了各种方式进行调试。

AT24C02采用的是IIC总线,256KB字节的存储容量。分为32夜,每页有8字节。

首先是写的时序:

clip_image002

如上所示:

第一个是字节写,即每次写一个字节。顺序是首先写器件地址,然后是数据地址,最后是数据。因为IIC可以外挂很多器件,所以需要一个器件地址要表明是对哪一个外设进行操作。

第二个是多字节写,即每次写多个字节。每写一个字节,数据地址会自己加1。比如对数据地址0写数据DATA(n),那么写DATA(n+1)的时候,数据地址会自己加1,即对地址0写数据DATA(N+1)。但是这里要相当注意,这个数据n的个数是有限制的。由每页规定的字节数据个数规定的。AT24C02每页有8字节,所以最高只能写8字节的数据。超过8字节的数据,会覆盖当前页之前的数据。这里要相当注意。

至于这里的回应信号ACK,这里也要注意都是低有效,而且这个ACK信号是AT24C02器件给的。

器件地址,数据手册也有说明:

clip_image004

前4位的值都是1010,后面3位是由你外接的A2,A1,A0电平决定的。后面的R/W是读写位。0表示写,1表示读。

clip_image005

上图是AT24C02的封装图,有三个管脚A2,A1,A0,这里就是器件地址中的A2,A1,A0。这三个可以接不同的电平。所以在一个IIC总线上,最多可以外挂8个AT24C02器件。

然后是读的时序:

clip_image007

读的部分要比写要麻烦很多。下面逐次介绍一下:

第一个图:

读当前数据地址的值。这个当前数据地址是由上次操作的地址决定的。比如,在之前的一次操作,对0x00地址写数据,那么目前的当前数据地址就是0x00。

第二个图:

随机读数据。读取指定的数据地址的值。

第三个图:

读多个数据。读取制定的数据首地址的多个数据的值。这里只要有首地址,每读完一个数据,数据地址会自己加1,这样就可以读取下一个数据。

这里要注意第一个和后面两个在时序上有点不一样。

对于第一个:首先是发器件地址,但是读写位为1。

对于后面两个:也是发器件地址,但是读写位要为0。然后发数据地址。在然后要重新发送起始信号,然后在发器件地址,但是这时候读写位要为1,表示读数据。后面就是读取的数据。如果读的数据不是最后一个,ACK信号为低,如果是最后一个,ACK信号要为高。

这里要注意的地方:

1、随机读数据和连续读数据,第一个发的器件地址的读写位要为0,然后是发数据地址,然后要重新发送起始信号,这个相当重要,不发重新起始信号,是读不到数据的。然后在重新发送器件地址,然后读写位要为1.然后就读数据了。

2、这里的响应信号ACK,要注意这个ACK信号时主机给的,不是AT24C02给的。没有读最后一个数据,主机发ACK低,从机接收到低,表示读数据继续。读最后一个数据,主机发ACK高,从机接收到高,表示数据读取结束。

以上就是读数据要注意的地方,我就是在读数据这里卡了很久,第一个是没有注意,器件地址要发两次,第二个是没有注意要重新发送起始信号,第三个就是ACK信号给错,以为这ACK信号时从机给的。造成数据一直读取不成功。

具体的IIC协议的内容,大家可自行百度查询。

如果注意到了以上的问题,那么写程序控制IIC器件就比较容易了。根据数据手册的时序,注意各个信号之间的时间要求,如保持时间,建立时间要求,然后写程序即可。

采用状态机设计:

首先是定义各个状态:

clip_image009

这里说明一下各个状态作用以及状态中的代码:

这里先说明几个变量的作用:

delay_time_next,delay_time:用来记录每个状态中的计数,该计数是用来使每个状态保持一个固定的时间。

bit_counter_next,bit_counter:用来记录发送8-bit数据的哪一位数据。

counter_number_next, counter_number: 用来记录发送的第几个数据或者是接收的第几个数据。因为考虑到传输多个数据的情况。

i2c_sda_reg: 是FPGA的SDA输出。

i2c_sda: FPGA的SDA输入。 因为SDA是双向的,所以需要将输入和输出分开。向SDA写数据,就向i2c_sda_reg写数据即可。而要读取SDA数据,就只要读取i2c_sda的值即可。

first_byte_to_send:起始信号后发送的第一个字节数据,即器件地址加RW。


第一个idle_state:空闲状态,即没有数据传输时的状态。


idle_state: begin delay_time_next = 'd0; bit_counter_next = 'd0; //send bit counter counter_number_next = 'd0; //send data counter read_data_reg = 'd0; write_idle = 1'b1; i2c_sda_reg = 1'b1; //if no data transfer ,i2c data is 1 if(start) state_next = ready_state; end


在这个状态下,SCL和SDA都为高电平。

第二个ready_state:准备状态,这里其实就是产生开始信号。即SCL保持高,SDA拉低。产生一个开始信号,开始进行IIC通信。


ready_state: begin i2c_sda_reg = 1'b0; //ic2 data pull down.mean begin to transfer data if(delay_time >= 99) //delay 2us, meeting i2c data setup and hole timing begin delay_time_next = 'd0; state_next = send_device_address_state; end else delay_time_next = delay_time + 1'b1; end


第三个状态send_device_address_state:发送器件地址状态,在这个状态中,FPGA将器件地址和RW组成的8-bits数据发送给AT24C02。


//send first byte. including device address and r/w enable send_device_address_state: begin if(delay_time == 16) //delay 320ns ,let i2c data meet setup and hold time i2c_sda_reg = first_byte_to_send[7-bit_counter]; if(delay_time >= 199) //delay 4us , 1-bits data transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_device_ack_state; delay_time_next = 'd0; i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end


第四个状态wait_device_ack_state:等待响应ACK信号。在发完器件地址8-bits数据后,FPGA要等待从AT24C02发来的响应信号。该响应信号为低,表示通信正常,否则通信不正常。回到idle状态。


//wait ack signal. in this condition ,i2c_sda is input. when i2c_sda is low ,mean receive ack signal success wait_device_ack_state: begin if(delay_time >= 199) //delay 4us begin if(!i2c_sda) //receive ack signal begin state_next = send_rom_address_state; delay_time_next = 'd0; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end


第五个状态,发送数据地址状态:即发送需要操作的地址。


//send the address will be write or read send_rom_address_state: begin if(delay_time == 16) //delay 320ns ,let data meet setup and hold time i2c_sda_reg = rom_address[7-bit_counter]; if(delay_time >= 199) //delay 4us , 1-bit dats transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_address_ack_state; delay_time_next = 'd0; i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end


第六个状态,等待数据地址写入回应ACK信号状态:在发完数据地址8-bits数据后,FPGA要等待从AT24C02发来的响应信号。该响应信号为低,表示通信正常,否则通信不正常。回到idle状态。这里要注意了,如果是写数据的话,要跳转到写数据的状态,而如果是读数据的话,要调到重新产生起始信号状态。因为前面说过,读操作的时候,在写完数据地址后,需要重新产生起始信号。


wait_address_ack_state: begin i2c_sda_reg = 1'b1; if(delay_time >= 199) //delay 2us begin if(!i2c_sda) //receive ack signal begin //according to the write_or_read decide enter write state or read state //0 mean write state 1 mean read state if(!write_or_read) state_next = send_write_data_state; else state_next = regenerate_start_state; delay_time_next = 'd0; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end


第七个状态:写数据状态。发送8-bit数据。


send_write_data_state: begin if(delay_time == 16) //delay 320ns ,let data meet hold time i2c_sda_reg = rom_write_data[7-bit_counter]; if(delay_time >= 199) //delay 4us ,1-bits transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_write_data_ack_state; delay_time_next = 'd0; counter_number_next = counter_number + 1'b1; // send 1 8-bits data i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end


第八个状态:等待写数据响应ACK信号:在发完数据8-bits数据后,FPGA要等待从AT24C02发来的响应信号。该响应信号为低,表示通信正常,否则通信不正常。回到idle状态。


wait_write_data_ack_state: begin i2c_sda_reg = 1'b0; if(delay_time >= 199) //delay 4us begin if(!i2c_sda) //receive ack signal begin //when write operation number == data_number ,means this write operation is finish //otherwise continue write operation if( counter_number == write_data_number) state_next = stop_state; else state_next = send_write_data_state; delay_time_next = 'd0; write_finish = 1'b1; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end


以上就是写的状态机设计。

之后是读的状态机设计。

第九个状态,重新产生起始信号状态。即重新产生起始信号,SCL保持高电平,SDA先保持高然后在拉低。


regenerate_start_state: begin if(delay_time <= 40) i2c_sda_reg = 1'b1; else i2c_sda_reg = 1'b0; //ic2 data pull down.mean begin to transfer data if(delay_time >= 99) //delay 2us, meeting i2c data setup and hole timing begin delay_time_next = 'd0; state_next = rewrite_device_address_state; end else delay_time_next = delay_time + 1'b1; end


第十个状态:发送数据地址和读。此时的first_byte_to_send的最低位为1,表示为读数据。


rewrite_device_address_state: begin if(delay_time == 16) //delay 320ns ,let i2c data meet setup and hold time i2c_sda_reg = first_byte_to_send[7-bit_counter]; if(delay_time >= 199) //delay 4us , 1-bits data transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_rewrite_ack_state; delay_time_next = 'd0; i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end


第十个状态:等待重新写器件地址回应信号。在发完8-bits数据后,FPGA要等待从AT24C02发来的响应信号。该响应信号为低,表示通信正常,否则通信不正常。回到idle状态。


wait_rewrite_ack_state: begin i2c_sda_reg = 1'b0; if(delay_time >= 199) //delay 4us begin if(!i2c_sda) //receive ack signal begin state_next = read_data_state; delay_time_next = 'd0; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end


下面才是读数据的状态。

第十一个状态:读数据状态。在SCL高电平读取SDA数据,将数据移位至read_data_reg中保存。这里要注意,有个counter_number_next判断。这个counter_number_next用来表示已经读取的数据个数,因为支持连读,所以当已经读取的个数和设定的个数一致时,就要停止读取。而停止读取和继续读取的响应信号是不一样的。


read_data_state: begin if(delay_time == 160) //delay3.2us ,let data meet setup and hold time read_data_reg = {read_data[6:0],i2c_sda}; if(delay_time >= 199) //delay 4us begin if(bit_counter_next >= 7) //read_8-bits data begin bit_counter_next = 'd0; delay_time_next = 'd0; counter_number_next = counter_number + 1'b1; //if the read data is the last data,goto the no ack state //if the read data is not the last data,goto the ack state if(counter_number_next == read_data_number ) state_next = get_read_data_no_ack_state; else state_next = get_read_data_ack_state; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end


第十二个状态:发送读取信号响应ACK信号。读取8-bit数据后,如果读取继续,FPGA要向AT24C02发送ACK低电平信号,表示要继续读取数据。


get_read_data_ack_state: begin i2c_sda_reg = 1'b0; if(delay_time >= 199) //delay 4us begin // if(!i2c_sda) //receive ack signal // begin //// when write operation number == data_number ,means this control is finish //// otherwise continue write operation state_next = read_data_state; delay_time_next = 'd0; read_finish = 1'b1; // end // else //if no receice ack signal , means communication is wrong , back to idle state // begin // delay_time_next = 'd0; // state_next = idle_state; // end end else delay_time_next = delay_time + 1'b1; end


第十三个状态:发送读取非响应ACK信号。读到最后一个8-bit数据后,要结束读取,FPGA要向AT24C02发送ACK高电平信号,表示读取结束。


get_read_data_no_ack_state: begin i2c_sda_reg = 1'b1; if(delay_time >= 199) //delay 4us begin // if(!i2c_sda) //receive ack signal // begin //when write operation number == data_number ,means this control is finish //otherwise continue write operation state_next = stop_state; delay_time_next = 'd0; read_finish = 1'b1; // end // else //if no receice ack signal , means communication is wrong , back to idle state // begin // delay_time_next = 'd0; // state_next = idle_state; // end end else delay_time_next = delay_time + 1'b1; end


最后一个状态;发送停止信号状态。SCL保持高电平,SDA数据先保持低,然后在拉高。产生一个结束信号。


stop_state: begin if(delay_time >= 150) i2c_sda_reg = 1'b1; else i2c_sda_reg = 1'b0; if(delay_time >= 199) state_next = idle_state; else delay_time_next = delay_time + 1'b1; end


这样,就完成了IIC的状态机设计。这里有几个地方要注意:

1、 读取数据,要重新产生起始信号,如果不重新产生起始信号,读取不到数据。

2、 读取数据的时候,ACK信号是由FPGA给的。这要特别注意,不然的话,状态就直接跳转到idle状态了。既不能读取数据。

因为SDA数据是双向IO口,所以这里要判断SDA什么时候为输入,什么时候为输出。

reg i2c_sda_reg;

assign enable_read = (state == wait_device_ack_state ||state == wait_address_ack_state ||

state == read_data_state ||

//state == wait_read_data_ack_state ||

state == wait_write_data_ack_state ||

state == wait_rewrite_ack_state)?1'b1:1'b0;

assign i2c_sda = enable_read ? 1'bz : i2c_sda_reg_reg;

这里,定义了一个i2c_sda_reg,用来保存SDA的输出值。Enable_read为输入输出判断信号。为1,表示输入,为0,表示输出。那在什么为1,什么时候为0.只需判断现在的状态即可。即在需要从机ACK信号和读取数据是为1.

下面就是SCL。


always@(*) begin //in idle_state , stop_state and ready_state, I2C clk is 1 if(state == idle_state || state == ready_state || state == regenerate_start_state) i2c_scl = 1'b1; // //in ready_state,to meet timing require . I2C clk is 0, wait to transfer data // else if(state == ready_state) // i2c_scl = 1'b0; else begin //I2C clk period is 4us. so counter value is 200 . set duty is 50% if(delay_time < 100) i2c_scl = 1'b0; else i2c_scl = 1'b1; end end


这里如果不是产生起始信号,空闲状态和重新产生起始信号状态是,前半个状态为0,后半个状态为高。这里要注意,为什么不把停止信号状态放到第一个if中,那是为了防止误产生判断起始信号。

假设在前一个状态,SDA为高,到了停止状态,SCL为高,此时SDA变低,那就误产生了一个起始信号。

而first_byte_to_send,这里代码为:


reg [7:0] first_byte_to_send; always@(*) begin //first write device address,the last bit is 0,mean write if( state == send_device_address_state ) first_byte_to_send = {4'b1010,device_address,1'b0}; //when read data ,should rewrite device address, and the last bit is 1,mean read else first_byte_to_send = {4'b1010,device_address,1'b1}; end
        


这里就是确定最低位为低还是高,从而表示还是写还是读。

按照这样一个状态机弄下来,就完成了IIC协议的AT24C02的驱动。然后添加串口模块,将串口发送的数据写入到AT24C02中,然后在将该数据读取回来,看看是否一样。

clip_image011

预先向0x0地址连续写入16个数据。也就是向0x0到0xf 16个地址写入数据。读17个数据,发现前16个数据是一样的,但是最后一个数据是FF。因为这个地址还没有写入数据,所以数据就是0xff。

以下附上的的程序端口部分:


module AT24C02_module( input clk, input rst_n, input start, input [2:0] device_address, //the device AT24C02 address input [7:0] rom_address, //the rom address input [7:0] rom_write_data, //write 8-bits data to the AT24C02 input write_or_read, //write mode or read mode 0 write 1 read input [7:0] write_data_number, // write data number input [7:0] read_data_number, //read data number output reg[7:0] row_read_data, //read 8-bits data from AT24C02 in rom_address output reg read_finish, //read data finish,mean external can read data output reg write_finish, //write one byte data finsih. output reg write_idle, //write data state, 1 mean external can write new data inout i2c_sda, //I2C data , bidirectional port output reg i2c_scl, //I2C clk 250K output enable_read );


可以看出端口还是比较复杂的,加一些额外信号时为了外部控制方便。

有注释的话,就很容易看出各个端口的作用。

这里最后一个enable_read,这个是为了使用chioscope查看信号而添加的端口。

我在外部有一段代码

assign look_i2c_sda = enable_read==1? i2c_sda:1'b0;

用来查看SDA作为输入时候的值,直接assign look_i2c_sda = i2c_sda。生成bit流会报错,所以这里采用这样的一个方式。


只要注意我说的那些问题,就一定是可以驱动IIC器件的了。。。。


最后贴上整个源代码以及testbench代码:

源代码:


`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 21:05:22 11/12/2014 // Design Name: // Module Name: AT24C02_module // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module AT24C02_module( input clk, input rst_n, input start, input [2:0] device_address, //the device AT24C02 address input [7:0] rom_address, //the rom address input [7:0] rom_write_data, //write 8-bits data to the AT24C02 input write_or_read, //write mode or read mode 0 write 1 read input [7:0] write_data_number, // write data number input [7:0] read_data_number, //read data number output reg[7:0] row_read_data, //read 8-bits data from AT24C02 in rom_address output reg read_finish, //read data finish,mean external can read data output reg write_finish, //write one byte data finsih. output reg write_idle, //write data state, 1 mean external can write new data inout i2c_sda, //I2C data , bidirectional port output reg i2c_scl, //I2C clk 250K output enable_read ); localparam idle_state = 'd0; localparam ready_state = 'd1; localparam send_device_address_state = 'd2; localparam wait_device_ack_state = 'd3; localparam send_rom_address_state = 'd4; localparam wait_address_ack_state = 'd5; localparam send_write_data_state = 'd6; localparam wait_write_data_ack_state = 'd7; localparam regenerate_start_state = 'd8; //regenerate start ,begin to read localparam rewrite_device_address_state = 'd9; localparam wait_rewrite_ack_state = 'd10; localparam read_data_state = 'd11; localparam get_read_data_ack_state = 'd12; localparam get_read_data_no_ack_state = 'd13; localparam stop_state = 'd14; reg [3:0] state; //current state reg [3:0] state_next; //next state always@(posedge clk or negedge rst_n) begin if(!rst_n) state <= idle_state; else state <= state_next; end //record delay time, because every state has different time. reg [7:0] delay_time; reg [7:0] delay_time_next; always@(posedge clk or negedge rst_n) begin if(!rst_n) delay_time <= 'd0; else delay_time <= delay_time_next; end //record transfer which bit, serial transfer,so need a variable value reg [2:0] bit_counter; //current transfer bit reg [2:0] bit_counter_next; //next transfer bit always@(posedge clk or negedge rst_n) begin if(!rst_n) bit_counter <= 'd0; else bit_counter <= bit_counter_next; end reg [7:0] first_byte_to_send; always@(*) begin //first write device address,the last bit is 0,mean write if( state == send_device_address_state ) first_byte_to_send = {4'b1010,device_address,1'b0}; //when read data ,should rewrite device address, and the last bit is 1,mean read else first_byte_to_send = {4'b1010,device_address,1'b1}; end //when enable_read is 1, i2c_sda is input, otherwise is output //wire enable_read; reg i2c_sda_reg; assign enable_read = (state == wait_device_ack_state ||state == wait_address_ack_state || state == read_data_state || //state == wait_read_data_ack_state || state == wait_write_data_ack_state || state == wait_rewrite_ack_state)?1'b1:1'b0; assign i2c_sda = enable_read ? 1'bz : i2c_sda_reg_reg; reg i2c_sda_reg_reg; always@(posedge clk or negedge rst_n) begin if(!rst_n) i2c_sda_reg_reg = 1'b1; else i2c_sda_reg_reg = i2c_sda_reg; end //write data number or read data number //because write and read can be continuous,so need a counter_number to record the already write or read address number //when counter_number == data_number,that means control finish reg [7:0] counter_number; reg [7:0] counter_number_next; always@(posedge clk or negedge rst_n) begin if(!rst_n) counter_number = 8'd0; else counter_number = counter_number_next; end reg [7:0] read_data; reg [7:0] read_data_reg; always@(posedge clk or negedge rst_n) begin if(!rst_n) read_data <= 8'd0; else read_data <= read_data_reg; end always@(*) begin state_next = state; delay_time_next = delay_time; bit_counter_next = bit_counter; counter_number_next = counter_number; read_data_reg = read_data; i2c_sda_reg = i2c_sda_reg_reg; read_finish = 1'b0; write_finish = 1'b0; write_idle = 1'b0; case(state) idle_state: begin delay_time_next = 'd0; bit_counter_next = 'd0; //send bit counter counter_number_next = 'd0; //send data counter read_data_reg = 'd0; write_idle = 1'b1; i2c_sda_reg = 1'b1; //if no data transfer ,i2c data is 1 if(start) state_next = ready_state; end ready_state: begin i2c_sda_reg = 1'b0; //ic2 data pull down.mean begin to transfer data if(delay_time >= 99) //delay 2us, meeting i2c data setup and hole timing begin delay_time_next = 'd0; state_next = send_device_address_state; end else delay_time_next = delay_time + 1'b1; end //send first byte. including device address and r/w enable send_device_address_state: begin if(delay_time == 16) //delay 320ns ,let i2c data meet setup and hold time i2c_sda_reg = first_byte_to_send[7-bit_counter]; if(delay_time >= 199) //delay 4us , 1-bits data transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_device_ack_state; delay_time_next = 'd0; i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end //wait ack signal. in this condition ,i2c_sda is input. when i2c_sda is low ,mean receive ack signal success wait_device_ack_state: begin if(delay_time >= 199) //delay 4us begin if(!i2c_sda) //receive ack signal begin state_next = send_rom_address_state; delay_time_next = 'd0; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end //send the address will be write or read send_rom_address_state: begin if(delay_time == 16) //delay 320ns ,let data meet setup and hold time i2c_sda_reg = rom_address[7-bit_counter]; if(delay_time >= 199) //delay 4us , 1-bit dats transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_address_ack_state; delay_time_next = 'd0; i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end wait_address_ack_state: begin i2c_sda_reg = 1'b1; if(delay_time >= 199) //delay 2us begin if(!i2c_sda) //receive ack signal begin //according to the write_or_read decide enter write state or read state //0 mean write state 1 mean read state if(!write_or_read) state_next = send_write_data_state; else state_next = regenerate_start_state; delay_time_next = 'd0; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end send_write_data_state: begin if(delay_time == 16) //delay 320ns ,let data meet hold time i2c_sda_reg = rom_write_data[7-bit_counter]; if(delay_time >= 199) //delay 4us ,1-bits transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_write_data_ack_state; delay_time_next = 'd0; counter_number_next = counter_number + 1'b1; // send 1 8-bits data i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end wait_write_data_ack_state: begin i2c_sda_reg = 1'b0; if(delay_time >= 199) //delay 4us begin if(!i2c_sda) //receive ack signal begin //when write operation number == data_number ,means this write operation is finish //otherwise continue write operation if( counter_number == write_data_number) state_next = stop_state; else state_next = send_write_data_state; delay_time_next = 'd0; write_finish = 1'b1; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end regenerate_start_state: begin if(delay_time <= 40) i2c_sda_reg = 1'b1; else i2c_sda_reg = 1'b0; //ic2 data pull down.mean begin to transfer data if(delay_time >= 99) //delay 2us, meeting i2c data setup and hole timing begin delay_time_next = 'd0; state_next = rewrite_device_address_state; end else delay_time_next = delay_time + 1'b1; end rewrite_device_address_state: begin if(delay_time == 16) //delay 320ns ,let i2c data meet setup and hold time i2c_sda_reg = first_byte_to_send[7-bit_counter]; if(delay_time >= 199) //delay 4us , 1-bits data transfer finish begin if(bit_counter_next >= 7) //send_8-bits data finish begin bit_counter_next = 'd0; state_next = wait_rewrite_ack_state; delay_time_next = 'd0; i2c_sda_reg = 1'b0; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end wait_rewrite_ack_state: begin i2c_sda_reg = 1'b0; if(delay_time >= 199) //delay 4us begin if(!i2c_sda) //receive ack signal begin state_next = read_data_state; delay_time_next = 'd0; end else //if no receice ack signal , means communication is wrong , back to idle state begin delay_time_next = 'd0; state_next = idle_state; end end else delay_time_next = delay_time + 1'b1; end read_data_state: begin if(delay_time == 160) //delay3.2us ,let data meet setup and hold time read_data_reg = {read_data[6:0],i2c_sda}; if(delay_time >= 199) //delay 4us begin if(bit_counter_next >= 7) //read_8-bits data begin bit_counter_next = 'd0; delay_time_next = 'd0; counter_number_next = counter_number + 1'b1; //if the read data is the last data,goto the no ack state //if the read data is not the last data,goto the ack state if(counter_number_next == read_data_number ) state_next = get_read_data_no_ack_state; else state_next = get_read_data_ack_state; end else begin bit_counter_next = bit_counter + 1'b1; delay_time_next = 'd0; end end else delay_time_next = delay_time + 1'b1; end get_read_data_ack_state: begin i2c_sda_reg = 1'b0; if(delay_time >= 199) //delay 4us begin // if(!i2c_sda) //receive ack signal // begin //// when write operation number == data_number ,means this control is finish //// otherwise continue write operation state_next = read_data_state; delay_time_next = 'd0; read_finish = 1'b1; // end // else //if no receice ack signal , means communication is wrong , back to idle state // begin // delay_time_next = 'd0; // state_next = idle_state; // end end else delay_time_next = delay_time + 1'b1; end get_read_data_no_ack_state: begin i2c_sda_reg = 1'b1; if(delay_time >= 199) //delay 4us begin // if(!i2c_sda) //receive ack signal // begin //when write operation number == data_number ,means this control is finish //otherwise continue write operation state_next = stop_state; delay_time_next = 'd0; read_finish = 1'b1; // end // else //if no receice ack signal , means communication is wrong , back to idle state // begin // delay_time_next = 'd0; // state_next = idle_state; // end end else delay_time_next = delay_time + 1'b1; end stop_state: begin if(delay_time >= 150) i2c_sda_reg = 1'b1; else i2c_sda_reg = 1'b0; if(delay_time >= 199) state_next = idle_state; else delay_time_next = delay_time + 1'b1; end default: state_next = idle_state; endcase end /***********************I2C clk*****************************************/ always@(*) begin //in idle_state , stop_state and ready_state, I2C clk is 1 if(state == idle_state || state == ready_state || state == regenerate_start_state) i2c_scl = 1'b1; // //in ready_state,to meet timing require . I2C clk is 0, wait to transfer data // else if(state == ready_state) // i2c_scl = 1'b0; else begin //I2C clk period is 4us. so counter value is 200 . set duty is 50% if(delay_time < 100) i2c_scl = 1'b0; else i2c_scl = 1'b1; end end /***********************I2C clk*****************************************/ always@(posedge clk or negedge rst_n) begin if(!rst_n) row_read_data <= 8'd0; else if(read_finish) row_read_data <= read_data; end endmodule
testbench:



module AT24C02_module_tb; // Inputs reg clk; reg rst_n; reg start; reg [2:0] device_address; reg [7:0] rom_address; reg [7:0] rom_write_data; reg write_or_read; reg [7:0] data_number; // Outputs wire [7:0] row_read_data; wire read_finish; wire write_idle; wire i2c_scl; // Bidirs wire i2c_sda; // Instantiate the Unit Under Test (UUT) AT24C02_module uut ( .clk(clk), .rst_n(rst_n), .start(start), .device_address(device_address), .rom_address(rom_address), .rom_write_data(rom_write_data), .write_or_read(write_or_read), .data_number(data_number), .row_read_data(row_read_data), .read_finish(read_finish), .write_idle(write_idle), .i2c_sda(i2c_sda), .i2c_scl(i2c_scl) ); initial begin clk = 0; forever #10 clk = ~clk; end reg i2c_sda_reg; //SDA input data assign i2c_sda = (uut.enable_read == 1)? i2c_sda_reg : 1'bz; reg [7:0]data_reg; initial begin // Initialize Inputs rst_n = 0; start = 0; device_address = 0; rom_address = 0; rom_write_data = 0; write_or_read = 0; //write data_number = 0; data_reg = 0; // Wait 100 ns for global reset to finish #100 rst_n = 1; //write data // repeat(2) begin // data_number = 1; // write_or_read = 0; //write // write_address_byte(8'h55); // rom_write_data = {$random()}%256; // write_data_byte(rom_write_data); // #50; // end // $stop; repeat(3) begin data_number = 1; write_or_read = 1; //read data_reg = {$random()}%256; write_address_byte(8'h55); @(negedge i2c_scl); @(negedge i2c_scl); read_byte(data_reg); #200; $stop; end $stop; // Add stimulus here end task write_address_byte(input [7:0] byte_address); begin #20 device_address = 3'b000; rom_address = byte_address; @(posedge clk) start = 1; @(posedge clk) start = 0; wait(uut.state == 'd3) i2c_sda_reg = 0; //generate device address ack signal wait(uut.state == 'd5) i2c_sda_reg = 0; //generate rom address ack signal end endtask task write_data_byte(input [7 :0] byte_data); begin rom_write_data = byte_data; wait(uut.state == 'd7) i2c_sda_reg = 0; //generate ack signal wait(uut.state == 'd0); end endtask task read_byte(input [7:0] byte_data); reg [3:0] i; begin wait(uut.state == 'd10) i2c_sda_reg = 0; @(negedge i2c_scl); @(negedge i2c_scl); for(i=0; i<8; i=i+1) begin i2c_sda_reg = byte_data[7-i]; @(negedge i2c_scl); end wait(uut.state == 'd12) i2c_sda_reg = 0; wait(uut.state == 'd0); end endtask endmodule
testbench中用到了task。task在testbench中非常的好用。


Baidu
map