FPGA Board Based FPGA for Beginners FPGA Tutor Pocket Boards PRA006/PRA010

Reading and Writing EEPROM, the Basic Principles of Asynchronous IIC Bus, the IIC Communication Protocol, IIC transmitting Experiment – FPGA Beginner Study Board PRA006, PRA010 Experiment 11

Experiment 11 IIC transmitting Experiment

11.1 Experiment Objective

  1. Learning the basic principles of asynchronous IIC bus, and the IIC communication protocol
  2. Master the method of reading and writing EEPROM
  3. Joint debugging using logic analyzer

11.2 Experiment Implement

  1. Correctly write a number to any address in the EEPROM (this experiment writes to the register of 8’h03 address) through the FPGA (here changes the written 8-bit data value by (SW7~SW0)). After writing in successfully, read the data as well. The read data is displayed directly on the segment display.
  2. Program the FPGA and press the LEFT push button to execute the data write into EEPROM operation. Press the RIGHT push button to read the data that was just written.
  3. Determine whether it is correct or not by reading the displayed number on the segment display. If the segment display has the same value as written value, the experiment is successful.
  4. Analyze the correctness of the internal data with SignalTap II and verify it with the illustration of the segment display.

11.3 Experiment

11.3.1 Introduction to EEPROM and IIC Protocol

  1. Introduction of EEPROM

EEPROM (Electrically Erasable Programmable Read Only Memory) refers to a charged erasable programmable read only register. It is a memory chip that does not lose data after turning off power.

On the experiment board, there is an IIC interface EEPROM chip 24LC02 with a capacity of 256 bytes. Users can store some hardware configuration data or user information due to the characteristics that the data is not lost after power-off.

  1. The overall timing protocol of IIC is as follows
  2. Bus idle state: SDA, SCL are high
  3. Start of IIC protocol: SCL stays high, SDA jumps from high level to low level, generating a start signal
  4. IIC read and write data stage: including serial input and output of data and response signal issued by data receiver
  5. IIC transmission end bit: SCL is in high level, SDA jumps from low level to high level, and generates an end flag. See Figure 11.1.
  6. SDA must remain unchanged when SCL is high. It changes only when SCL is low

Figure 11.1 Timing protocol of IIC

11.3.2 Hardware Introduction

Each IIC device has a device address. When some device addresses are shipped from the factory, they are fixed by the manufacturer (the specific data can be found in the manufacturer’s data sheet). Some of their higher bits are determined, and the lower bits can be configured by the user according to the requirement. The higher four-bit address of the EEPROM chip 24LC02 used by the develop board has been fixed to 1010 by the component manufacturer. The lower three bits are linked in the develop board as shown below, so the device address is 1010000. See Figure 11.2.

Figure 11.2 EEPROM schematics of IIC device

EEPROM reads and writes data from the FPGA through the I2C_SCL clock line and the I2C_SDA data line.

11.3.3 Introduction to the Program

This experiment has two main modules, IIC reading and writing module and LED display module; The first module is mainly introduced here.

The first step: establishment of the main program framework

module iic_com(

input clk,

input rst,

input [7:0] data,

input sw1,sw2,

inout scl,

inout sda,

output reg iic_done,

output [7:0] dis_data

);

The input 8-bit data is needed to be written into the EEPROM, provided by an 8-bit DIP switch.

The second step : Create clock I2C_CLK

reg [2:0] cnt;

reg [8:0] cnt_delay;

reg scl_r;

reg scl_link ;

always @ (posedge clk or posedge rst)

begin

if (rst)

cnt_delay <= 9’d0;

else if (cnt_delay == 9’d499)

cnt_delay <= 9’d0;

else

cnt_delay <= cnt_delay + 1’b1;

end

always @ (posedge clk or posedge rst)

begin

if (rst)

cnt <= 3’d5;

else begin

case (cnt_delay)

9’d124: cnt <= 3’d1; //cnt=1:scl

9’d249: cnt <= 3’d2; //cnt=2:scl

9’d374: cnt <= 3’d3; //cnt=3:scl

9’d499: cnt <= 3’d0; //cnt=0:scl

default: cnt<=3’d5;

endcase

end

end

`define SCL_POS (cnt==3’d0) //cnt=0:scl

`define SCL_HIG (cnt==3’d1) //cnt=1:scl

`define SCL_NEG (cnt==3’d2) //cnt=2:scl

`define SCL_LOW (cnt==3’d3) //cnt=3:scl

always @ (posedge clk or posedge rst)

begin

if (rst)

scl_r <= 1’b0;

else if (cnt == 3’d0)

scl_r <= 1’b1;

else if (cnt == 3’d2)

scl_r <= 1’b0;

end

assign scl = scl_link ? scl_r: 1’bz ;

First, use the system 50 MHz clock to get a 100 kHz clock with a period of 10us by frequency division as the transmission clock of the IIC protocol. Then, the rising edge, the high state, the falling edge and the low state of the clock are defined by the counter, prepared for the subsequent data reading and writing and the beginning of the IIC protocol. The last line of code means to define a data valid signal. Only when the signal is high, that is, when the data is valid, the IIC clock is valid again, otherwise it is in high impedance. This is also set according to the IIC transport protocol.

The third step: specific implementation of I2C transmission

`define DEVICE_READ 8’b1010_0001

`define DEVICE_WRITE 8’b1010_0000

`define BYTE_ADDR 8’b0000_0011

parameter IDLE = 4’d0;

parameter START1 = 4’d1;

parameter ADD1 = 4’d2;

parameter ACK1 = 4’d3;

parameter ADD2 = 4’d4;

parameter ACK2 = 4’d5;

parameter START2 = 4’d6;

parameter ADD3 = 4’d7;

parameter ACK3 = 4’d8;

parameter DATA = 4’d9;

parameter ACK4 = 4’d10;

parameter STOP1 = 4’d11;

parameter STOP2 = 4’d12;

reg [7:0] db_r;

reg [7:0] read_data;

reg [3:0] cstate;

reg sda_r;

reg sda_link;

reg [3:0] num;

always @ (posedge clk or posedge rst)

begin

if (rst) begin

cstate <= IDLE;

sda_r <= 1’b1;

scl_link <= 1’b1;

sda_link <= 1’b1;

num <= 4’d0;

read_data <= 8’b0000_0000;

cnt_5ms <= 20’h00000;

iic_done <= 1’b0;

end

else case (cstate)

IDLE :

begin

sda_link <= 1’b1;

scl_link <= 1’b1;

iic_done <= 1’b0 ;

if (sw1_r || sw2_r) begin

db_r <= `DEVICE_WRITE;

cstate <= START1;

end

else cstate <= IDLE;

end

START1 :

begin

if (`SCL_HIG) begin

sda_link <= 1’b1;

sda_r <= 1’b0;

num <= 4’d0;

cstate <= ADD1;

end

else cstate <= START1;

end

ADD1 :

begin

if (`SCL_LOW) begin

if (num == 4’d8) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK1;

end

else begin

cstate <= ADD1;

num <= num + 1’b1;

case (num)

4’d0 : sda_r <= db_r[7];

4’d1 : sda_r <= db_r[6];

4’d2 : sda_r <= db_r[5];

4’d3 : sda_r <= db_r[4];

4’d4 : sda_r <= db_r[3];

4’d5 : sda_r <= db_r[2];

4’d6 : sda_r <= db_r[1];

4’d7 : sda_r <= db_r[0];

default : ;

endcase

end

end

else cstate <= ADD1;

end

ACK1 :

begin

if (`SCL_NEG) begin

cstate <= ADD2;

db_r <= `BYTE_ADDR;

end

else cstate <= ACK1;

end

ADD2 :

begin

if (`SCL_LOW) begin

if (num == 4’d8) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK2;

end

else begin

sda_link <= 1’b1;

num <= num+1’b1;

case (num)

4’d0 : sda_r <= db_r[7];

4’d1 : sda_r <= db_r[6];

4’d2 : sda_r <= db_r[5];

4’d3 : sda_r <= db_r[4];

4’d4 : sda_r <= db_r[3];

4’d5 : sda_r <= db_r[2];

4’d6 : sda_r <= db_r[1];

4’d7 : sda_r <= db_r[0];

default : ;

endcase

cstate <= ADD2;

end

end

else cstate <= ADD2;

end

ACK2 :

begin

if (`SCL_NEG) begin

if (sw1_r) begin

cstate <= DATA;

db_r <= data_tep;

end

else if (sw2_r) begin

db_r <= `DEVICE_READ;

cstate <= START2;

end

end

else cstate <= ACK2;

end

START2 :

begin

if (`SCL_LOW) begin

sda_link <= 1’b1;

sda_r <= 1’b1;

cstate <= START2;

end

else if (`SCL_HIG) begin

sda_r <= 1’b0;

cstate <= ADD3;

end

else cstate <= START2;

end

ADD3 :

begin

if (`SCL_LOW) begin

if (num == 4’d8) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK3;

end

else begin

num <= num + 1’b1;

case (num)

4’d0 : sda_r <= db_r[7];

4’d1 : sda_r <= db_r[6];

4’d2 : sda_r <= db_r[5];

4’d3 : sda_r <= db_r[4];

4’d4 : sda_r <= db_r[3];

4’d5 : sda_r <= db_r[2];

4’d6 : sda_r <= db_r[1];

4’d7 : sda_r <= db_r[0];

default: ;

endcase

end

end

else cstate <= ADD3;

end

ACK3 :

begin

if (`SCL_NEG) begin

cstate <= DATA;

sda_link <= 1’b0;

end

else cstate <= ACK3;

end

DATA :

begin

if (sw2_r) begin

if (num <= 4’d7) begin

cstate <= DATA;

if(`SCL_HIG) begin

num <= num + 1’b1;

case (num)

4’d0 : read_data[7] <= sda;

4’d1 : read_data[6] <= sda;

4’d2 : read_data[5] <= sda;

4’d3 : read_data[4] <= sda;

4’d4 : read_data[3] <= sda;

4’d5 : read_data[2] <= sda;

4’d6 : read_data[1] <= sda;

4’d7 : read_data[0] <= sda;

default: ;

endcase

end

end

else if((`SCL_LOW) && (num == 4’d8)) begin

num <= 4’d0;

cstate <= ACK4;

end

else cstate <= DATA;

end

else if (sw1_r) begin

sda_link <= 1’b1;

if (num <= 4’d7) begin

cstate <= DATA;

if (`SCL_LOW) begin

sda_link <= 1’b1;

num <= num + 1’b1;

case (num)

4’d0 : sda_r <= db_r[7];

4’d1 : sda_r <= db_r[6];

4’d2 : sda_r <= db_r[5];

4’d3 : sda_r <= db_r[4];

4’d4 : sda_r <= db_r[3];

4’d5 : sda_r <= db_r[2];

4’d6 : sda_r <= db_r[1];

4’d7 : sda_r <= db_r[0];

default: ;

endcase

end

end

else if ((`SCL_LOW) && (num==4’d8)) begin

num <= 4’d0;

sda_r <= 1’b1;

sda_link <= 1’b0;

cstate <= ACK4;

end

else cstate <= DATA;

end

end

ACK4 :

begin

if (`SCL_NEG)

cstate <= STOP1;

else

cstate <= ACK4;

end

STOP1 :

begin

if (`SCL_LOW) begin

sda_link <= 1’b1;

sda_r <= 1’b0;

cstate <= STOP1;

end

else if (`SCL_HIG) begin

sda_r <= 1’b1;

cstate <= STOP2;

end

else cstate <= STOP1;

end

STOP2 :

begin

if (`SCL_NEG) begin

sda_link <= 1’b0;

scl_link <= 1’b0;

end

else if (cnt_5ms==20’h3fffc) begin

cnt_5ms <= 20’h00000;

iic_done <= 1;

cstate <= IDLE;

end

else begin

cstate <= STOP2;

cnt_5ms <= cnt_5ms + 1’b1;

end

end

default: cstate <= IDLE;

endcase

end

The entire process is implemented using a state machine. When reset, it is idle state, while data line sda_r is pulled high, clock and data are both valid, i.e. scl_link, sda_link are high; counter num is cleared and read_data is 0. 5ms delay counter is cleared, IIC transmission end signal Iic_done is low thus invalid.

  1. IDLE state: When receiving the read enable or write enable signal sw1_r || sw2_r, assign the write control word to the intermediate variable db_r <= `DEVICE_WRITE, and jump to the start state START1;
  2. START1 state: pull the data line low when the clock signal is high, generating the start signal of IIC transmission, and jump to the device address state ADD1;
  3. Device address status ADD1: After the write control word (device address plus one ‘0’ bit) is transmitted according to MSB (high order priority), the sda_link is pulled low causing data bus in a high impedance state, and jump to the first response state ACK1, waiting for the response signal from the slave (EEPROM).
  4. The first response status ACK1: If the data line is pulled low, it proves that the slave receives the data normally, otherwise the data is not written into EEPROM, and then the rewriting or stopping is decided by the user. There is no temporary judgment and processing here, jump directly to the write register address state ADD2, and assign the address BYTE_ADDR written to the intermediate variable (this experiment writes the data into the third register, i.e. BYTE_ADDR = 0000_0011 )
  5. Register address status ADD2: Same as (3), it transfers register address to slave and jump to second response status ACK2
  6. The second response state ACK2: At this time, it is urgent to judge. If it is the write state sw1, it jumps to the data transfer state DATA, and at the same time assigns the written data to the intermediate variable. If it is the read state sw2, it jumps to the second start state START2 and assign the read control word to the intermediate variable.
  7. The second start state START2: it produces a start signal identical to (2) and jumps to the read register address state ADD3
  8. Read register address status ADD3: it jumps to the third response status ACK3S after the transfer of the register address that needs to be read out
  9. The third response state ACK3: it jumps directly to the data transfer state DATA. In the read state, the data to be read is directly read out immediately following the register address.
  10. ACK4 Data transfer status DATA: it needs to be judged here. If it is the read status, the data will be directly output. If it is the write status, the data to be written will be transferred to the data line SDA. Both states need to jump to the fourth response state. ACK4
  11. The fourth response status ACK4: it direct jumps to stop transmission STOP1
  12. Stop transmission STOP1: it pulls up data line when the clock line is high, generating a stop signal, and jumps to the transfer completion status STOP2
  13. Transfer completion status STOP2: it releases all clock lines and data lines, and after a 5ms delay, returns to the IDLE state to wait for the next transfer instruction. This is because EEPROM stipulates that the interval between two consecutives read and write operations must not be less than 5ms.

11.4 Experiment Verification

The first step: pin assignements

See Table 11.1 for the pin assignment.

Table 11.1 IIC protocol transmission experiment pin mapping

Signal Name Network Label FPGA Pin Port Description
clk C10_50MCLK 91 System clock 50 MHz
rst KEY3 11 Reset, low by default
sm_db[0] SEG_PA 132 Segment selection signal
sm_db [1] SEG_PB 137
sm_db [2] SEG_PC 133
sm_db [3] SEG_PD 125
sm_db [4] SEG_PE 126
sm_db [5] SEG_PF 138
sm_db [6] SEG_PG 135
sm_db [7] SEG_DP 125
sm_cs1_n SEG_3V3_D1 142 Segment 1
sm_cs2_n SEG_3V3_D0 136 Segment 0
data[0] SW0 80 Switch 0
data[1] SW1 83 Switch 1
data[2] SW2 86 Switch 2
data[3] SW3 87 Switch 3
data[4] SW4 74 Switch 4
data[5] SW5 75 Switch 5
data[6] SW6 76 Switch 6
data[7] SW7 77 Switch 7
sw1 KEY0 3 Write EEPROM button
sw2 KEY1 7 Read EEPROM button
scl I2C_SCL R20 EEPROM clock line
sda I2C_SDA R21 EEPROM data line

The second step: board verification

After the pin assignment is completed, the compilation is performed, and the board is verified after passing.

After the board is programmed, press the LEFT key to write the 8-bit value represented by SW7~SW0 to EEPROM. Then press the RIGHT key to read the value from the write position. Observe the consistency between the value displayed on the segment display on the experiment board and the value written in the 8’h03 register of the EEPROM address (SW7~SW0) (this experiment writes 8’h34). The read value is displayed on the segment display. The experimental phenomenon is shown in Figure 11.3.

Figure 11.3 EEPROM experiment phenomenon

Related posts