A Comprehensive Guide to Implementing I2C Master Core in FPGA (Part 6): Data Shifting for Read/Write Operations

▼ Follow for more valuable content

In FPGA development, the design and implementation of the I2C Master controller is a critical aspect. Especially when handling multi-byte data read and write operations, the design of byte shifting directly affects the stability and efficiency of communication. This article will delve into the design concepts and specific implementations of byte shifting for reading and writing in the I2C Master core, detailing how to achieve precise control of multi-byte data transmission through Verilog code, from interface parameter definitions to timing state control. Whether you are a beginner or an experienced engineer, these practical experiences will provide strong references for your project development.

01 Design Concepts for Read & Write Byte Shifting

Interface and Parameters for Multi-byte Read/Write

In the previous article: A Guide to Implementing I2C Master Core in FPGA (Part 2): Module Interface Design, weconfigured the multi-byte data read and write functionality through the maximum length parameters for read and write. The interface, parameters, and their Verilog code are as follows:

Interface Direction Type Bit Description
write_byte_len input wire 8 Write transmission: number of bytes N.
write_data input wire N*8 Write transmission: data.
read_byte_len input wire 8 Read transmission: number of bytes M.
read_data output reg M*8 Read transmission: the data read.
Parameter Type Description
WMEN_LEN integer Maximum length of data written during a single communication. Unit: bytes
RMEN_LEN integer Maximum length of data read during a single communication. Unit: bytes
module iic_master_control #(  parameter integer WMEN_LEN = 8, // write data length. (bytes)  parameter integer RMEN_LEN = 8, // read data length. (bytes)  ...)(  ...  input   wire    [WMEN_LEN*8-1:0]    write_data      ,   // write data.  input   wire    [7:0]               write_byte_len  ,   // write data byte len.
  output  reg     [RMEN_LEN*8-1:0]    read_data       ,   // read data.  input   wire    [7:0]               read_byte_len   ,   // read data byte len.  ... );

Design Concepts for Write Byte Shifting

In the I2C communication protocol, the following conventions apply to the control byte:

  • The high 7 bits ([7:1]) are used as the slave address

  • The 0th bit ([0]) is for transmission control (1 – read, 0 – write)

In our I2C master controller, the first byte of the write_data interface is used as the control byte, which is utilized after the start bit (START) for write operations and the repeated start bit (RE_START) for read operations. The pseudocode is as follows:

After START: sda_data_reg <= write_data[7:0];
After RE_START: sda_data_reg <= {write_data[7:1], 1'b1};
Explanation: 1. The RE_START is initiated during data reading; 2. The control byte after RE_START has bit0=1 indicating read, and bits 7~1 indicating the slave address.

When designing the byte shifting for write operations, in addition to the above situations, we also need to consider the following:

  • Bit shifting of a single byte

  • Switching assignment of the byte to be written

Situation Description
Bit shifting of a single byte The I2C bus protocol data transmission mode is MSB. That is, the high bit is in front, and the low bit is in the back.
Switching assignment of the byte to be written After the current byte (8 bits) transmission is completed, the byte to be written completes the switching assignment while waiting for the write acknowledgment (ACK).

Design Concepts for Read Byte Shifting

When designing the byte shifting for read operations, consider the following:

  • Bit shifting of a single byte

  • Shifting of buffer data during reading

Situation Description
Bit shifting of a single byte The I2C bus protocol data transmission mode is MSB. That is, the high bit is in front, and the low bit is in the back.
Switching assignment of the byte to be written After the current byte (8 bits) transmission is completed, the byte to be written completes the switching assignment while waiting for the write acknowledgment (ACK).

02 Implementation of Read & Write Byte Shifting Design

The timing logic control clock for the I2C master controller is SCL_CLK. The data on the SDA line is switched on the falling edge of SCL, and is valid on the high level. For write byte shifting, the timing logic is executed on the falling edge of SCL_CLK; for read byte shifting, the timing logic is executed on the rising edge of SCL_CLK.

Design for Write Byte Shifting

For write byte shifting, the resources we need are as follows:

Signal Type Bit Description
sda_data_reg reg 8 Register for write byte shifting data

Combining the content from the previous section, we design the assignment for each timing state of the byte shifting data register as follows:

State Assignment
START

write_data[7:0]

RE_START

{write_data[7:1], 1’b1}

W_ACK

write_data[(write_byte_cnt*8) +: 8]

WRITE

{sda_data_reg[6:0], 1’b1}

The Verilog code for the timing logic of write byte shifting is as follows:

reg [7:0] sda_data_reg;
// write bytes shift control: sda_data_reg signal timing control.
always @(negedge scl_clk or negedge rst_n) begin    if(rst_n == 1'b0) begin        sda_data_reg    <= 8'hFF;    end    else begin        case (current_state)            START: begin                sda_data_reg    <= write_data[7:0];            end            RE_START: begin                 sda_data_reg    <= {write_data[7:1], 1'b1};            end	    W_ACK: begin		if(write_byte_cnt < write_byte_len)          sda_data_reg    <= write_data[(write_byte_cnt*8) +: 8];            end            WRITE: begin                sda_data_reg    <= {sda_data_reg[6:0], 1'b1};            end            default: begin                sda_data_reg    <= sda_data_reg;            end        endcase    endend

Design for Read Byte Shifting

For read byte shifting, the resources we need are as follows:

Signal Type Bit Description
sda_read_reg reg 8 Register for read byte shifting data

Combining the content from the previous section, we design the assignment for each timing state of the read byte shifting data register as follows:

State Assignment
READ

{sda_read_reg[6:0], sda_i}

R_ACK

8’h00

The Verilog code for the timing logic of read byte shifting is as follows:

reg [7:0] sda_read_reg;
// read bytes shift control: sda_read_reg signal timing control.
always @(posedge scl_clk or negedge rst_n) begin    if(rst_n == 1'b0) begin        sda_read_reg    <= 8'h00;    end    else begin        case (current_state)            READ:               sda_read_reg     <= {sda_read_reg[6:0], sda_i};             R_ACK:                sda_read_reg    <= 8'h00;            default:                 sda_read_reg    <= sda_read_reg;        endcase    endend
// read_data: timing control.
always @(posedge scl_clk or negedge rst_n) begin    if(rst_n == 1'b0)        read_data   <= {RMEN_LEN*8{1'b0}};    else if(current_state == R_ACK)        read_data[((read_byte_cnt-1'b1)*8) +: 8]   <= sda_read_reg;    else         read_data   <= read_data;end

03 Conclusion

Through this detailed analysis of the design of read and write byte shifting for the I2C Master controller, we can see that a stable and reliable I2C communication core requires careful design of data shifting and switching at each timing state. The clever handling of control bytes in write operations and the precise collection of data bits in read operations reflect the extreme pursuit of detail in hardware design. This state machine-based shifting control method not only ensures strict adherence to the I2C protocol but also lays a solid foundation for efficient transmission of multi-byte data. We hope these design concepts and code implementations can inspire your FPGA project development, and in the next issue, we will continue to explore other key technical points in I2C communication.

Thank you for reading!

Click “Like” to let more friends see this valuable content 🌟

Leave a Comment