请问有fpga配置adv7611的i2c例程吗,最好是附带注释。
如果刚开始学习,请仿照这个链接:https://zhuanlan.zhihu.com/p/543472995
基于FPGA的I2C协议——以EEPROM为例
可以借鉴下
https://blog.csdn.net/weixin_52761825/article/details/125058946
引用chatGPT作答,以下是一个使用FPGA配置ADV7611的I2C例程。这个例程基于Verilog HDL,使用一个I2C总线控制器(如AXI IIC)与ADV7611进行通信。注释已经添加在代码中以帮助您更好地理解代码的功能和工作原理。
/********************************************
* ADV7611 I2C Configuration Example
* Author: ChatGPT
* Date: 2023-04-27
********************************************/
/*********** I2C Registers ************/
// ADV7611 I2C地址
`define ADV7611_I2C_ADDR 8'b100_1010
// ADV7611芯片ID寄存器
`define ADV7611_CHIP_ID_REG 8'h00
// ADV7611芯片ID值
`define ADV7611_CHIP_ID_VAL 8'h20
// ADV7611输入映射寄存器
`define ADV7611_INPUT_MAP_REG 8'h04
// ADV7611输入映射值
`define ADV7611_INPUT_MAP_VAL 8'h00
// ADV7611输入控制寄存器
`define ADV7611_INPUT_CTRL_REG 8'h05
// ADV7611输入控制值
`define ADV7611_INPUT_CTRL_VAL 8'h1f
// ADV7611CEC配置寄存器
`define ADV7611_CEC_CONFIG_REG 8'h15
// ADV7611CEC配置值
`define ADV7611_CEC_CONFIG_VAL 8'h9c
// ADV7611输入信号检测寄存器
`define ADV7611_INPUT_DETECT_REG 8'h42
// ADV7611输入信号检测值
`define ADV7611_INPUT_DETECT_VAL 8'ha3
/*********** I2C Controller ************/
// AXI IIC控制器地址
`define AXI_IIC_ADDR 32'h40000000
// IIC控制器数据寄存器地址
`define IIC_DATA_ADDR 8'h00
// IIC控制器状态寄存器地址
`define IIC_STATUS_ADDR 8'h04
// IIC控制器控制寄存器地址
`define IIC_CONTROL_ADDR 8'h08
// IIC控制器读命令
`define IIC_READ_CMD 8'h01
// IIC控制器写命令
`define IIC_WRITE_CMD 8'h00
/*********** I2C Functions ************/
// 写一个字节到ADV7611的I2C寄存器
function automatic void adv7611_i2c_write(
input iic_addr, // I2C地址
input reg_addr, // 寄存器地址
input data // 数据
);
reg [7:0] tx_data;
// 将寄存器地址和数据组合成一个字节
tx_data = {reg_addr, data};
// 向IIC控制器写入数据
i2c_write(iic_addr, tx_data);
endfunction
// 从ADV7611的I2C寄存器读取一个字节
function automatic byte adv7611_i2c_read(
input iic_addr, // I2C地址
input reg_addr // 寄存器地址
) returns (byte);
reg [7:0] tx_data;
reg [7:0] rx_data;
// 将寄存器地址转换为单字节
tx_data = {reg_addr};
// 向IIC控制器写入寄存器地址
i2c_write(iic_addr, tx_data);
// 从IIC控制器读取一个字节的数据
rx_data = i2c_read(iic_addr, 1);
// 返回读取的数据
return rx_data;
endfunction
/*********** Main Function ************/
// ADV7611 I2C配置例程
module adv7611_i2c_config(
input wire i2c_scl, // I2C时钟线
input wire i2c_sda // I2C数据线
);
// 设置IIC控制器寄存器
reg [31:0] iic_ctrl = 0;
// 初始化I2C控制器
initial begin
iic_ctrl[IIC_CONTROL_ADDR] = 8'h80; // 使能IIC控制器
iic_ctrl[IIC_STATUS_ADDR] = 8'h7; // 复位IIC状态
end
// 写入芯片ID寄存器
adv7611_i2c_write(`ADV7611_I2C_ADDR, `ADV7611_CHIP_ID_REG, `ADV7611_CHIP_ID_VAL);
// 验证芯片ID
if (adv7611_i2c_read(`ADV7611_I2C_ADDR, `ADV7611_CHIP_ID_REG) != `ADV7611_CHIP_ID_VAL) begin
$display("Error: ADV7611 Chip ID mismatch!");
$finish;
end
// 配置输入映射寄存器
adv7611_i2c_write(`ADV7611_I2C_ADDR, `ADV7611_INPUT_MAP_REG, `ADV7611_INPUT_MAP_VAL);
// 配置输入控制寄存器
adv7611_i2c_write(`ADV7611_I2C_ADDR, `ADV7611_INPUT_CTRL_REG, `ADV7611_INPUT_CTRL_VAL);
// 配置CEC配置寄存器
adv7611_i2c_write(`ADV7611_I2C_ADDR, `ADV7611_CEC_CONFIG_REG, `ADV7611_CEC_CONFIG_VAL);
// 配置输入信号检测寄存器
adv7611_i2c_write(`ADV7611_I2C_ADDR, `ADV7611_INPUT_DETECT_REG, `ADV7611_INPUT_DETECT_VAL);
$display("ADV7611 I2C Configuration Successful!");
// 等待1秒
#1000000000;
// 关闭I2C控制器
iic_ctrl[IIC_CONTROL_ADDR] = 8'h00;
endmodule
// I2C写函数
function automatic void i2c_write(
input iic_addr, // I2C地址
input byte data // 数据
);
// 在I2C总线上发送起始信号
i2c_start();
// 发送I2C地址和写命令
i2c_send_byte(iic_addr << 1 | `IIC_WRITE_CMD);
// 发送数据
i2c_send_byte(data);
// 在I2C总线上发送停止信号
i2c_stop();
endfunction
// I2C读函数
function automatic byte i2c_read(
input iic_addr, // I2C地址
input int num_bytes // 要读取的字节数
) returns (byte);
reg [7:0] rx_data;
reg [7:0] tx_data;
// 在I2C总线上发送起始信号
i2c_start();
// 发送I2C地址和读命令
i2c_send_byte(iic_addr << 1 | `IIC_READ_CMD);
// 读取数据
for (int i = 0; i < num_bytes; i++) begin
if (i == num_bytes - 1) begin
// 最后一个字节,不发送ACK
rx_data[i] = i2c_receive_byte(`IIC_NACK);
end else begin
// 发送ACK,继续读取下一个字节
rx_data[i] = i2c_receive_byte(`IIC_ACK);
end
end
// 在I2C总线上发送停止信号
i2c_stop();
// 返回读取的数据
return rx_data;
endfunction
// I2C总线控制函数
// 发送起始信号
task automatic i2c_start();
// 设置SDA为高电平
assign i2c_sda = 1'b1;
// 在SCL为高电平时设置SDA为低电平
always @(posedge i2c_scl) begin
if (i2c_sda == 1'b1) begin
i2c_sda <= 1'b0;
end
end
endtask
// 发送停止信号
task automatic i2c_stop();
// 设置SDA为低电平
assign i2c_sda = 1'b0;
// 在SCL为高电平时设置SDA为高电平
always @(posedge i2c_scl) begin
if (i2c_sda == 1'b0) begin
i2c_sda <= 1'b1;
end
end
endtask
// 发送一个字节的数据,并返回ACK信号
function automatic bit i2c_send_byte(
input byte data // 要发送的数据
) returns (bit);
// 发送数据
for (int i = 7; i >= 0; i--) begin
assign i2c_sda = data[i];
// 在SCL的上升沿时更新SDA的值
always @(posedge i2c_scl) begin
if (i2c_sda != data[i]) begin
$display("Error: SDA value changed during SCL rising edge!");
$finish;
end
end
end
// 接收ACK
assign i2c_sda = 1'b1;
always @(posedge i2c_scl) begin
if (i2c_sda == 1'b0) begin
i2c_sda <= 1'b1;
end
end
// 返回ACK信号
return !i2c_sda;
endfunction
// 接收一个字节的数据,并发送ACK或NACK信号
function automatic byte i2c_receive_byte(
input bitack // 是否发送ACK信号
) returns (byte);
reg [7:0] data;
// 接收数据
for (int i = 7; i >= 0; i--) begin
// 在SCL的上升沿时读取SDA的值
always @(posedge i2c_scl) begin
data[i] <= i2c_sda;
end
end
// 发送ACK或NACK信号
assign i2c_sda = ~ack;
// 在SCL的上升沿时更新SDA的值
always @(posedge i2c_scl) begin
if (i2c_sda != ~ack) begin
$display("Error: SDA value changed during SCL rising edge!");
$finish;
end
end
// 返回接收到的数据
return data;
endfunction
// 主函数
module tb;
reg [7:0] reg_data;
// 初始化I2C总线
initial begin
i2c_scl = 1'b1;
i2c_sda = 1'b1;
#10;
i2c_stop();
#10;
end
// 从ADV7611的寄存器读取数据
initial begin
reg_data = adv7611_i2c_read(`ADV7611_I2C_ADDR, `ADV7611_REG_ADDR);
$display("Data read from ADV7611: %h", reg_data);
end
// 向ADV7611的寄存器写入数据
initial begin
reg_data = `ADV7611_REG_DATA;
adv7611_i2c_write(`ADV7611_I2C_ADDR, `ADV7611_REG_ADDR, reg_data);
$display("Data written to ADV7611: %h", reg_data);
end
// 从I2C设备读取数据
initial begin
reg_data = i2c_read(`I2C_ADDR, `NUM_BYTES);
$display("Data read from I2C device: %h", reg_data);
end
// 向I2C设备写入数据
initial begin
reg_data = `I2C_DATA;
i2c_write(`I2C_ADDR, reg_data);
$display("Data written to I2C device: %h", reg_data);
end
endmodule
给你贴一份 米联客-Artix7-MA703-35T/100T 开发板中的 ADV7611 I2C 配置的代码
例化代码
IIC_ADV7611_Config IIC_ADV7611_Config_inst
(
.ADV_CLK (clk_100m), // input wire ADV_CLK
.ADV_RST (v_rstn), // input wire ADV_RST
.ADV_SCLK (iic_scl), // output wire ADV_SCLK
.ADV_SDAT (iic_sda) // inout wire ADV_SDAT
);
IIC_ADV7611_Config.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/03/07 17:22:20
// Design Name:
// Module Name: IIC_ADV7611_Config
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module IIC_ADV7611_Config #(
parameter ADV_CLK_FREQ = 100_000000, //100 MHz
parameter ADV_I2C_FREQ = 10_000 //10 KHz(< 400KHz)
)
(
input ADV_CLK,
input ADV_RST,//低电平复位
output ADV_SCLK,
inout ADV_SDAT
);
wire I2C_EN;
//----------------------------------------------
//i2c timing controller module
wire [9:0] i2c_config_index;
wire [23:0]i2c_config_data;
wire [9:0] i2c_config_size;
wire i2c_config_done;
wire i2c_RW_flag;
wire [7:0] i2c_rdata; //i2c register data
i2c_timing_ctrl
#(
.CLK_FREQ (ADV_CLK_FREQ), //100 MHz
.I2C_FREQ (ADV_I2C_FREQ) //100 kHz(<= 400KHz)
)
u_i2c_timing_ctrl
(
//global clock
.clk (ADV_CLK), //100MHz
.rst_n (I2C_EN), //system reset
//i2c interface
.i2c_sclk (ADV_SCLK), //i2c clock
.i2c_sdat (ADV_SDAT), //i2c data for bidirection
//i2c config data
.i2c_RW_flag(i2c_RW_flag),
.i2c_config_index (i2c_config_index), //i2c config reg index, read 2 reg and write xx reg
.i2c_config_data (i2c_config_data), //i2c config data
.i2c_config_size (i2c_config_size), //i2c config data counte
.i2c_config_done (i2c_config_done), //i2c config timing complete
.i2c_rdata (i2c_rdata) //i2c register data while read i2c slave
);
//----------------------------------------------
//I2C Configure Data of OV7725
//I2C_OV7725_RGB565_Config u_I2C_OV7725_RGB565_Config
I2C_ADV7611_Config u_I2C_ADV7611_Config
(
.clk (ADV_CLK),
.rst_n (ADV_RST),
.I2C_EN (I2C_EN),
.I2C_RW_flag (i2c_RW_flag),
.I2C_rdata (i2c_rdata),
.I2C_config_done(i2c_config_done),
.LUT_INDEX (i2c_config_index),
.LUT_DATA (i2c_config_data),
.LUT_SIZE (i2c_config_size)
);
endmodule
i2c_timing_ctrl.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/03/07 17:17:54
// Design Name:
// Module Name: i2c_timing_ctrl
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns/1ns
module i2c_timing_ctrl
#(
parameter CLK_FREQ = 100_000000, //100 MHz
parameter I2C_FREQ = 10_000 //10 KHz(< 400KHz)
)
(
//global clock
input clk, //100MHz
input rst_n, //system reset
//i2c interface
output i2c_sclk, //i2c clock
inout i2c_sdat, //i2c data for bidirection
//user interface
input i2c_RW_flag,
input [9:0] i2c_config_size, //i2c config data counte
output reg [9:0] i2c_config_index, //i2c config reg index, read 2 reg and write xx reg
input [23:0] i2c_config_data, //i2c config data
output i2c_config_done, //i2c config timing complete
output reg [7:0] i2c_rdata //i2c register data while read i2c slave
);
//----------------------------------------
//Delay xxus until i2c slave is steady
reg [19:0] delay_cnt;
localparam DELAY_TOP = CLK_FREQ/1000; //1ms Setting time after software/hardware reset
//localparam DELAY_TOP = 17'hff; //Just for test
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
delay_cnt <= 0;
else if(delay_cnt < DELAY_TOP - 1'b1)
delay_cnt <= delay_cnt + 1'b1;
else
delay_cnt <= delay_cnt;
end
wire delay_done = (delay_cnt == DELAY_TOP - 1'b1) ? 1'b1 : 1'b0; //81us delay
//----------------------------------------
//I2C Control Clock generate
reg [15:0] clk_cnt; //divide for i2c clock
/******************************************
_______ _______
SCLK ____| |________| |
________________ ______________
SDAT |________________|______________
_ _
CLK_EN | |______________| |____________
_ _
CAP_EN _______| |______________| |_____
*******************************************/
reg i2c_ctrl_clk; //i2c control clock, H: valid; L: valid
reg i2c_transfer_en; //send i2c data before, make sure that sdat is steady when i2c_sclk is valid
reg i2c_capture_en; //capture i2c data while sdat is steady from cmos
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
clk_cnt <= 0;
i2c_ctrl_clk <= 0;
i2c_transfer_en <= 0;
i2c_capture_en <= 0;
end
else if(delay_done)
begin
if(clk_cnt < (CLK_FREQ/I2C_FREQ) - 1'b1)
clk_cnt <= clk_cnt + 1'd1;
else
clk_cnt <= 0;
//i2c control clock, H: valid; L: valid
i2c_ctrl_clk <= ((clk_cnt >= (CLK_FREQ/I2C_FREQ)/4 + 1'b1) &&
(clk_cnt < (3*CLK_FREQ/I2C_FREQ)/4 + 1'b1)) ? 1'b1 : 1'b0;
//send i2c data before, make sure that sdat is steady when i2c_sclk is valid
i2c_transfer_en <= (clk_cnt == 16'd0) ? 1'b1 : 1'b0;
//capture i2c data while sdat is steady from cmos
i2c_capture_en <= (clk_cnt == (2*CLK_FREQ/I2C_FREQ)/4 - 1'b1) ? 1'b1 : 1'b0;
end
else
begin
clk_cnt <= 0;
i2c_ctrl_clk <= 0;
i2c_transfer_en <= 0;
i2c_capture_en <= 0;
end
end
//-----------------------------------------
//I2C Timing state Parameter
localparam I2C_IDLE = 5'd0;
//Write I2C: {ID_Address, REG_Address, W_REG_Data}
localparam I2C_WR_START = 5'd1;
localparam I2C_WR_IDADDR = 5'd2;
localparam I2C_WR_ACK1 = 5'd3;
localparam I2C_WR_REGADDR = 5'd4;
localparam I2C_WR_ACK2 = 5'd5;
localparam I2C_WR_REGDATA = 5'd6;
localparam I2C_WR_ACK3 = 5'd7;
localparam I2C_WR_STOP = 5'd8;
//I2C Read: {ID_Address + REG_Address} + {ID_Address + R_REG_Data}
localparam I2C_RD_START1 = 5'd9;
localparam I2C_RD_IDADDR1 = 5'd10;
localparam I2C_RD_ACK1 = 5'd11;
localparam I2C_RD_REGADDR = 5'd12;
localparam I2C_RD_ACK2 = 5'd13;
localparam I2C_RD_STOP1 = 5'd14;
localparam I2C_RD_IDLE = 5'd15;
localparam I2C_RD_START2 = 5'd16;
localparam I2C_RD_IDADDR2 = 5'd17;
localparam I2C_RD_ACK3 = 5'd18;
localparam I2C_RD_REGDATA = 5'd19;
localparam I2C_RD_NACK = 5'd20;
localparam I2C_RD_STOP2 = 5'd21;
//-----------------------------------------
// FSM: always1
reg [4:0] current_state, next_state; //i2c write and read state
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
current_state <= I2C_IDLE;
else if(i2c_transfer_en)
current_state <= next_state;
end
//-----------------------------------------
wire i2c_transfer_end = (current_state == I2C_WR_STOP || current_state == I2C_RD_STOP2) ? 1'b1 : 1'b0;
reg i2c_ack; //i2c slave renpose successed
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
i2c_config_index <= 0;
else if(i2c_transfer_en)
begin
if(i2c_transfer_end & ~i2c_ack)
// if(i2c_transfer_end /*& ~i2c_ack*/) //Just for test
begin
if(i2c_config_index < i2c_config_size)
i2c_config_index <= i2c_config_index + 1'b1;
// i2c_config_index <= {i2c_config_index[7:1], ~i2c_config_index[0]}; //Just for test
else
i2c_config_index <= i2c_config_size;
end
else
i2c_config_index <= i2c_config_index;
end
else
i2c_config_index <= i2c_config_index;
end
assign i2c_config_done = (i2c_config_index == i2c_config_size) ? 1'b1 : 1'b0;
//-----------------------------------------
// FSM: always2
reg [3:0] i2c_stream_cnt; //i2c data bit stream count
always@(*)
begin
next_state = I2C_IDLE; //state initialization
case(current_state)
I2C_IDLE: //5'd0
begin
if(delay_done) //1ms Setting time after software/hardware reset
begin
if(i2c_transfer_en)
begin
//if(i2c_config_index < 8'd2)
// next_state = I2C_RD_START1; //Read I2C Slave ID
//else
if(i2c_config_index < i2c_config_size)
if(!i2c_RW_flag)
next_state = I2C_WR_START; //Write Data to I2C
else next_state = I2C_RD_START1;
else// if(i2c_config_index >= i2c_config_size)
next_state = I2C_IDLE; //Config I2C Complete
end
else
next_state = next_state;
end
else
next_state = I2C_IDLE; //Wait I2C Bus is steady
end
//Write I2C: {ID_Address, REG_Address, W_REG_Data}
I2C_WR_START: //5'd1
begin
if(i2c_transfer_en) next_state = I2C_WR_IDADDR;
else next_state = I2C_WR_START;
end
I2C_WR_IDADDR: //5'd2
if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)
next_state = I2C_WR_ACK1;
else next_state = I2C_WR_IDADDR;
I2C_WR_ACK1: //5'd3
if(i2c_transfer_en) next_state = I2C_WR_REGADDR;
else next_state = I2C_WR_ACK1;
I2C_WR_REGADDR: //5'd4
if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)
next_state = I2C_WR_ACK2;
else next_state = I2C_WR_REGADDR;
I2C_WR_ACK2: //5'd5
if(i2c_transfer_en) next_state = I2C_WR_REGDATA;
else next_state = I2C_WR_ACK2;
I2C_WR_REGDATA://5'd6
if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)
next_state = I2C_WR_ACK3;
else next_state = I2C_WR_REGDATA;
I2C_WR_ACK3: //5'd7
if(i2c_transfer_en) next_state = I2C_WR_STOP;
else next_state = I2C_WR_ACK3;
I2C_WR_STOP: //5'd8
if(i2c_transfer_en) next_state = I2C_IDLE;
else next_state = I2C_WR_STOP;
//I2C Read: {ID_Address + REG_Address} + {ID_Address + R_REG_Data}
I2C_RD_START1: //5'd9
if(i2c_transfer_en) next_state = I2C_RD_IDADDR1;
else next_state = I2C_RD_START1;
I2C_RD_IDADDR1://5'd10
if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)
next_state = I2C_RD_ACK1;
else next_state = I2C_RD_IDADDR1;
I2C_RD_ACK1: //5'd11
if(i2c_transfer_en) next_state = I2C_RD_REGADDR;
else next_state = I2C_RD_ACK1;
I2C_RD_REGADDR://5'd12
if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)
next_state = I2C_RD_ACK2;
else next_state = I2C_RD_REGADDR;
I2C_RD_ACK2: //5'd13
if(i2c_transfer_en) next_state = I2C_RD_STOP1;
else next_state = I2C_RD_ACK2;
I2C_RD_STOP1: //5'd14
if(i2c_transfer_en) next_state = I2C_RD_IDLE;
else next_state = I2C_RD_STOP1;
I2C_RD_IDLE: //5'd15
if(i2c_transfer_en) next_state = I2C_RD_START2;
else next_state = I2C_RD_IDLE;
I2C_RD_START2: //5'd16
if(i2c_transfer_en) next_state = I2C_RD_IDADDR2;
else next_state = I2C_RD_START2;
I2C_RD_IDADDR2: //5'd17
if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)
next_state = I2C_RD_ACK3;
else next_state = I2C_RD_IDADDR2;
I2C_RD_ACK3: //5'd18
if(i2c_transfer_en) next_state = I2C_RD_REGDATA;
else next_state = I2C_RD_ACK3;
I2C_RD_REGDATA: //5'd19
if(i2c_transfer_en == 1'b1 && i2c_stream_cnt == 4'd8)
next_state = I2C_RD_NACK;
else next_state = I2C_RD_REGDATA;
I2C_RD_NACK: //5'd20
if(i2c_transfer_en) next_state = I2C_RD_STOP2;
else next_state = I2C_RD_NACK;
I2C_RD_STOP2: //5'd21
if(i2c_transfer_en) next_state = I2C_IDLE;
else next_state = I2C_RD_STOP2;
default:; //default vaule
endcase
end
//-----------------------------------------
// FSM: always3
//reg i2c_write_flag, i2c_read_flag;
reg i2c_sdat_out; //i2c data output
//reg [3:0] i2c_stream_cnt; //i2c data bit stream count
reg [7:0] i2c_wdata; //i2c data prepared to transfer
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
i2c_sdat_out <= 1'b1;
i2c_stream_cnt <= 0;
i2c_wdata <= 0;
end
else if(i2c_transfer_en)
begin
case(next_state)
I2C_IDLE: //5'd0
begin
i2c_sdat_out <= 1'b1; //idle state
i2c_stream_cnt <= 0;
i2c_wdata <= 0;
end
//Write I2C: {ID_Address, REG_Address, W_REG_Data}
I2C_WR_START: //5'd1
begin
i2c_sdat_out <= 1'b0;
i2c_stream_cnt <= 0;
i2c_wdata <= i2c_config_data[23:16]; //ID_Address
end
I2C_WR_IDADDR: //5'd2
begin
i2c_stream_cnt <= i2c_stream_cnt + 1'b1;
i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];
end
I2C_WR_ACK1: //5'd3
begin
i2c_stream_cnt <= 0;
i2c_wdata <= i2c_config_data[15:8]; //REG_Address
end
I2C_WR_REGADDR: //5'd4
begin
i2c_stream_cnt <= i2c_stream_cnt + 1'b1;
i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];
end
I2C_WR_ACK2: //5'd5
begin
i2c_stream_cnt <= 0;
i2c_wdata <= i2c_config_data[7:0]; //W_REG_Data
end
I2C_WR_REGDATA: //5'd6
begin
i2c_stream_cnt <= i2c_stream_cnt + 1'b1;
i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];
end
I2C_WR_ACK3: //5'd7
i2c_stream_cnt <= 0;
I2C_WR_STOP: //5'd8
i2c_sdat_out <= 1'b0;
//I2C Read: {ID_Address + REG_Address} + {ID_Address + R_REG_Data}
I2C_RD_START1: //5'd10
begin
i2c_sdat_out <= 1'b0;
i2c_stream_cnt <= 0;
i2c_wdata <= i2c_config_data[23:16];
end
I2C_RD_IDADDR1: //5'd11
begin
i2c_stream_cnt <= i2c_stream_cnt + 1'b1;
i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];
end
I2C_RD_ACK1: //5'd11
begin
i2c_stream_cnt <= 0;
i2c_wdata <= i2c_config_data[15:8];
end
I2C_RD_REGADDR: //5'd12
begin
i2c_stream_cnt <= i2c_stream_cnt + 1'b1;
i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];
end
I2C_RD_ACK2: //5'd13
i2c_stream_cnt <= 0;
I2C_RD_STOP1: //5'd14
i2c_sdat_out <= 1'b0;
I2C_RD_IDLE: //5'd15
i2c_sdat_out <= 1'b1; //idle state
//-------------------------
I2C_RD_START2: //5'd16
begin
i2c_sdat_out <= 1'b0;
i2c_stream_cnt <= 0;
i2c_wdata <= {i2c_config_data[23:17],1'b1};
end
I2C_RD_IDADDR2: //5'd17
begin
i2c_stream_cnt <= i2c_stream_cnt + 1'b1;
if(i2c_stream_cnt < 5'd7)
i2c_sdat_out <= i2c_wdata[3'd7 - i2c_stream_cnt];
else
i2c_sdat_out <= 1'b1; //Read flag for I2C Timing
end
I2C_RD_ACK3: //5'd18
i2c_stream_cnt <= 0;
I2C_RD_REGDATA: //5'd19
i2c_stream_cnt <= i2c_stream_cnt + 1'b1;
I2C_RD_NACK: //5'd20
i2c_sdat_out <= 1'b1; //NACK
I2C_RD_STOP2: //5'd21
i2c_sdat_out <= 1'b0;
endcase
end
else
begin
i2c_stream_cnt <= i2c_stream_cnt;
i2c_sdat_out <= i2c_sdat_out;
end
end
//---------------------------------------------
//respone from slave for i2c data transfer
reg i2c_ack1, i2c_ack2, i2c_ack3;
//reg i2c_ack;
//reg [7:0] i2c_rdata;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
{i2c_ack1, i2c_ack2, i2c_ack3} <= 3'b111;
i2c_ack <= 1'b1;
i2c_rdata <= 0;
end
else if(i2c_capture_en)
begin
case(next_state)
I2C_IDLE:
begin
{i2c_ack1, i2c_ack2, i2c_ack3} <= 3'b111;
i2c_ack <= 1'b1;
end
//Write I2C: {ID_Address, REG_Address, W_REG_Data}
I2C_WR_ACK1: i2c_ack1 <= i2c_sdat;
I2C_WR_ACK2: i2c_ack2 <= i2c_sdat;
I2C_WR_ACK3: i2c_ack3 <= i2c_sdat;
I2C_WR_STOP: i2c_ack <= (i2c_ack1 | i2c_ack2 | i2c_ack3);
//I2C Read: {ID_Address + REG_Address} + {ID_Address + R_REG_Data}
I2C_RD_ACK1: i2c_ack1 <= i2c_sdat;
I2C_RD_ACK2: i2c_ack2 <= i2c_sdat;
I2C_RD_ACK3: i2c_ack3 <= i2c_sdat;
I2C_RD_STOP2: i2c_ack <= (i2c_ack1 | i2c_ack2 | i2c_ack3);
I2C_RD_REGDATA: i2c_rdata <= {i2c_rdata[6:0], i2c_sdat};
endcase
end
else
begin
{i2c_ack1, i2c_ack2, i2c_ack3} <= {i2c_ack1, i2c_ack2, i2c_ack3};
i2c_ack <= i2c_ack;
end
end
//---------------------------------------------------
wire bir_en =( current_state == I2C_WR_ACK1 || current_state == I2C_WR_ACK2 || current_state == I2C_WR_ACK3 ||
current_state == I2C_RD_ACK1 || current_state == I2C_RD_ACK2 || current_state == I2C_RD_ACK3 ||
current_state == I2C_RD_REGDATA) ? 1'b1 : 1'b0;
assign i2c_sclk = (current_state >= I2C_WR_IDADDR && current_state <= I2C_WR_ACK3 ||
current_state >= I2C_RD_IDADDR1 && current_state <= I2C_RD_ACK2 ||
current_state >= I2C_RD_IDADDR2 && current_state <= I2C_RD_NACK) ?
i2c_ctrl_clk : 1'b1;
assign i2c_sdat = (~bir_en) ? i2c_sdat_out : 1'bz;
endmodule