Verilog实现多地址I2C Slave

FX平台CPLD代码,通过I2C总线访问CPLD实现的控制寄存器,对系统进行复位等相关控制。下面是代码,实现多地址的I2C Slaver,能够类似I2C的EEPROM方式进行读写访问。
module top_fx_cpld2(
SDA, SCL,
//output
csm3_rst_n, csm2_rst_n, csm1_rst_n, csm0_rst_n,
b_10gf_rst_n, f_10gf_rst_n, b_ge_rst_n, f_ge_rst_n,
mucus_rst_n, daughter_rst_n,
csm0_led_n, csm1_led_n, csm2_led_n, csm3_led_n, hdd_cf_led_n,
in_out_irq_n, csm_run_irq_n,
//input
csm0_n, csm1_n, csm2_n, csm3_n,
csm0_run_n, csm1_run_n, csm2_run_n, csm3_run_n,
b_10gf_n, f_10gf_n, b_ge_n, f_ge_n,
ps_key_n, daughter_run_n, daughter_n,
ich_sata_led_n, cf_led_n,
clk_50M, reset_n

);

inout SDA;
input SCL;
input clk_50M, reset_n;

output csm3_rst_n, csm2_rst_n, csm1_rst_n, csm0_rst_n;
output b_10gf_rst_n, f_10gf_rst_n, b_ge_rst_n, f_ge_rst_n;
output mucus_rst_n, daughter_rst_n;
output csm0_led_n, csm1_led_n, csm2_led_n, csm3_led_n;
output hdd_cf_led_n;
output in_out_irq_n, csm_run_irq_n;

input csm0_n, csm1_n, csm2_n, csm3_n;
input csm0_run_n, csm1_run_n, csm2_run_n, csm3_run_n;
input b_10gf_n, f_10gf_n, b_ge_n, f_ge_n;
input ps_key_n;
input daughter_run_n, daughter_n;

input ich_sata_led_n, cf_led_n;

wire clk = clk_50M;
wire rst_n = reset_n;

// The 7-bits address that we want for our I2C slave
parameter I2C_ADR = 7'h27;

// I2C start and stop conditions detection logic
// That's the "black magic" part of this design...
// We use two wires with a combinatorial loop to detect the start and stop conditions
// making sure these two wires don't get optimized away
wire SDA_shadow /* synthesis keep = 1 */;
wire start_or_stop /* synthesis keep = 1 */;
assign SDA_shadow = (~SCL | start_or_stop)? SDA : SDA_shadow;
assign start_or_stop = ~SCL? 1'b0 : (SDA ^ SDA_shadow);
reg incycle;

always @(negedge SCL or posedge start_or_stop)
if(start_or_stop)
incycle <= 1'b0;
else if(~SDA)
incycle <= 1'b1;


// Now we are ready to count the I2C bits coming in
reg [3:0] bitcnt; // counts the I2C bits from 7 downto 0, plus an ACK bit
wire bit_DATA = ~bitcnt[3]; // the DATA bits are the first 8 bits sent
wire bit_ACK = bitcnt[3]; // the ACK bit is the 9th bit sent
reg data_phase;

always @(negedge SCL or negedge incycle)
if(~incycle)
begin
bitcnt <= 4'h7; // the bit 7 is received first
data_phase <= 0;
end
else
begin
if(bit_ACK)
begin
bitcnt <= 4'h7;
data_phase <= 1;
end
else
begin
bitcnt <= bitcnt - 4'h1;
end
end

// and detect if the I2C address matches our own
wire adr_phase = ~data_phase;
reg adr_match, op_read, got_ACK;
reg SDAr;

always @(posedge SCL) SDAr<=SDA; // sample SDA on posedge since the I2C spec specifies as low as 0μs hold-time on negedge
reg [7:0] w_mem;
reg [7:0] r_mem;
wire op_write = ~op_read;

always @(negedge SCL or negedge incycle)
if(~incycle)
begin
got_ACK <= 0;
adr_match <= 1;
op_read <= 0;
end
else
begin
if(adr_phase & bitcnt==7 & SDAr!=I2C_ADR[6]) adr_match<=0;
if(adr_phase & bitcnt==6 & SDAr!=I2C_ADR[5]) adr_match<=0;
if(adr_phase & bitcnt==5 & SDAr!=I2C_ADR[4]) adr_match<=0;
if(adr_phase & bitcnt==4 & SDAr!=I2C_ADR[3]) adr_match<=0;
if(adr_phase & bitcnt==3 & SDAr!=I2C_ADR[2]) adr_match<=0;
if(adr_phase & bitcnt==2 & SDAr!=I2C_ADR[1]) adr_match<=0;
if(adr_phase & bitcnt==1 & SDAr!=I2C_ADR[0]) adr_match<=0;
if(adr_phase & bitcnt==0) op_read <= SDAr;
if(bit_ACK) got_ACK <= ~SDAr; // we monitor the ACK to be able to free the bus when the master doesn't ACK during a read operation

if(adr_match & bit_DATA & data_phase & op_write) w_mem[bitcnt] <= SDAr; // memory write
end

reg [2:0] byte_addr; // byte address for registers
reg cur_addr_phase; // current address phrase
reg addring_phase; // register addressing phrase
always @(negedge SCL or negedge incycle)
if(~incycle)
begin
cur_addr_phase <= 0;
byte_addr <= byte_addr;
addring_phase <= 0;
end
else
if(bit_ACK & adr_match)
if(op_write) //i2c write
begin
if(!data_phase) cur_addr_phase <= 1'b1; //first byte is the current address
else cur_addr_phase <= 0;

if(!data_phase) byte_addr <= byte_addr;
else if(cur_addr_phase) byte_addr <= w_mem[2:0];
else byte_addr <= byte_addr + 1'b1;

if(!data_phase) addring_phase <= 0;
else if(cur_addr_phase) addring_phase <= 1'b1;
else addring_phase <= addring_phase;
end
else //i2c read
begin
cur_addr_phase <= 0;

if(!data_phase) byte_addr <= byte_addr;
else byte_addr <= byte_addr + 1'b1;

addring_phase <= 1'b1;
end


// registers definition in file "FX5 5PRO CPLD2 register description_V1.0.doc"
//interrupt register, offset 2
reg irq_en, csm_run_irq_mask, csm_irq_mask, lan_irq_mask; //irq register
//csm state registers, offset 3, 4
reg csm0_run_event_n, csm1_run_event_n, csm2_run_event_n, csm3_run_event_n;
reg st_csm0_run_n, st_csm1_run_n, st_csm2_run_n, st_csm3_run_n;
reg csm0_event_n, csm1_event_n, csm2_event_n, csm3_event_n;
reg st_csm0_n, st_csm1_n, st_csm2_n, st_csm3_n;
//lan card state register, offset 5
reg b_10gf_event_n, f_10gf_event_n, b_ge_event_n, f_ge_event_n;
reg st_b_10gf_n, st_f_10gf_n, st_b_ge_n, st_f_ge_n;
//system reset control register, offset 6
reg csm3_rst_n, csm2_rst_n, csm1_rst_n, csm0_rst_n, b_10gf_rst_n, f_10gf_rst_n, b_ge_rst_n, f_ge_rst_n;
//Daughter Card and Mucus Register, offset 7
reg mucus_rst_n, daughter_rst_n;
//i2c write
always@(negedge SCL or negedge rst_n)
if(!rst_n)
begin
st_csm0_run_n <= 1'b1;
st_csm1_run_n <= 1'b1;
st_csm2_run_n <= 1'b1;
st_csm3_run_n <= 1'b1;
st_csm0_n <= 1'b1;
st_csm1_n <= 1'b1;
st_csm2_n <= 1'b1;
st_csm3_n <= 1'b1;
st_b_10gf_n <= 1'b1;
st_f_10gf_n <= 1'b1;
st_b_ge_n <= 1'b1;
st_f_ge_n <= 1'b1;

csm0_event_n <= 1'b1;
csm1_event_n <= 1'b1;
csm2_event_n <= 1'b1;
csm3_event_n <= 1'b1;
csm0_run_event_n <= 1'b1;
csm1_run_event_n <= 1'b1;
csm2_run_event_n <= 1'b1;
csm3_run_event_n <= 1'b1;
b_10gf_event_n <= 1'b1;
f_10gf_event_n <= 1'b1;
b_ge_event_n <= 1'b1;
f_ge_event_n <= 1'b1;

csm3_rst_n <= 1'b1;
csm2_rst_n <= 1'b1;
csm1_rst_n <= 1'b1;
csm0_rst_n <= 1'b1;
b_10gf_rst_n <= 1'b1;
f_10gf_rst_n <= 1'b1;
b_ge_rst_n <= 1'b1;
f_ge_rst_n <= 1'b1;
mucus_rst_n <= 1'b1;
daughter_rst_n <= 1'b1;

//Interrupt Register, offset 0x2
irq_en <= 1'b0;
csm_run_irq_mask <= 1'b1;
csm_irq_mask <= 1'b1;
lan_irq_mask <= 1'b1;
end
else
begin
if(bit_ACK & addring_phase & op_write)
case(byte_addr)
3'h2: //Interrupt Register
begin
irq_en <= w_mem[7];
csm_run_irq_mask <= w_mem[6];
csm_irq_mask <= w_mem[5];
lan_irq_mask <= w_mem[4];
end
3'h3: //CSM Status Register1
begin
csm1_run_event_n <= w_mem[7];
csm1_event_n <= w_mem[6];
csm0_run_event_n <= w_mem[3];
csm0_event_n <= w_mem[2];
end
3'h4: //CSM Status Register2
begin
csm3_run_event_n <= w_mem[7];
csm3_event_n <= w_mem[6];
csm2_run_event_n <= w_mem[3];
csm2_event_n <= w_mem[2];
end
3'h5: //Lan module Card Status and Event Register
begin
b_10gf_event_n <= w_mem[7];
f_10gf_event_n <= w_mem[6];
b_ge_event_n <= w_mem[5];
f_ge_event_n <= w_mem[4];
end
3'h6: //System Reset Control Register
begin
csm3_rst_n <= w_mem[7];
csm2_rst_n <= w_mem[6];
csm1_rst_n <= w_mem[5];
csm0_rst_n <= w_mem[4];
b_10gf_rst_n <= w_mem[3];
f_10gf_rst_n <= w_mem[2];
b_ge_rst_n <= w_mem[1];
f_ge_rst_n <= w_mem[0];
end
3'h7: //Recover Key, FPGA Daughter Card and Mucus Register
begin
mucus_rst_n <= w_mem[4];
daughter_rst_n <= w_mem[0];
end
endcase
else
begin
st_csm0_run_n <= csm0_run_n;
st_csm1_run_n <= csm1_run_n;
st_csm2_run_n <= csm2_run_n;
st_csm3_run_n <= csm3_run_n;
st_csm0_n <= csm0_n;
st_csm1_n <= csm1_n;
st_csm2_n <= csm2_n;
st_csm3_n <= csm3_n;

st_b_10gf_n <= b_10gf_n;
st_f_10gf_n <= f_10gf_n;
st_b_ge_n <= b_ge_n;
st_f_ge_n <= f_ge_n;

if(st_csm0_n ^ csm0_n) csm0_event_n <= 1'b0;
 if(st_csm1_n ^ csm1_n) csm1_event_n <= 1'b0;
 if(st_csm2_n ^ csm2_n) csm2_event_n <= 1'b0;
 if(st_csm3_n ^ csm3_n) csm3_event_n <= 1'b0;
 if(st_csm0_run_n ^ csm0_run_n) csm0_run_event_n <= 1'b0;
 if(st_csm1_run_n ^ csm1_run_n) csm1_run_event_n <= 1'b0;
 if(st_csm2_run_n ^ csm2_run_n) csm2_run_event_n <= 1'b0;
 if(st_csm3_run_n ^ csm3_run_n) csm3_run_event_n <= 1'b0;

 if(st_b_10gf_n ^ b_10gf_n) b_10gf_event_n <= 1'b0;
 if(st_f_10gf_n ^ f_10gf_n) f_10gf_event_n <= 1'b0;
 if(st_b_ge_n ^ b_ge_n) b_ge_event_n <= 1'b0;
 if(st_f_ge_n ^ f_ge_n) f_ge_event_n <= 1'b0;
 end
 end

//global event indicator
wire csm_run_event_n = csm3_run_event_n & csm2_run_event_n & csm1_run_event_n & csm0_run_event_n;
wire csm_event_n = csm3_event_n & csm2_event_n & csm1_event_n & csm0_event_n;
wire lan_event_n = b_10gf_event_n & f_10gf_event_n & b_ge_event_n & f_ge_event_n;
//I2C read registers
always@*
case(byte_addr)
3'h0: //CPLD Device ID
r_mem <= 8'h02; //Device ID, 0x02 => O2 Security
3'h1: //CPLD Code Version and Device ID Register
r_mem <= 8'h0b; //code ver: r_mem[7:3] 1.0; CPLD type: r_mem[2:0] 011 =>XC95144
3'h2: //Interrupt and Password Recover Key Status Register
begin
r_mem[7] <= irq_en; //interrupt mode enable
r_mem[6] <= csm_run_irq_mask; //CSM Run interrupt mask
r_mem[5] <= csm_irq_mask; //CSM fixing/removing interrupt mask
r_mem[4] <= lan_irq_mask; //LAN Card fixing/removing interrupt mask

r_mem[2] <= csm_run_event_n; //CSM card run event indicate
r_mem[1] <= csm_event_n; //CSM card fix/unfix event indicate
r_mem[0] <= lan_event_n; //Lan card fix/unfix event indicate
end
3'h3: //CSM Status Register1
r_mem <= {csm1_run_event_n, csm1_event_n, csm1_run_n, csm1_n,
csm0_run_event_n, csm0_event_n, csm0_run_n, csm0_n};
3'h4: //CSM Status Register2
r_mem <= {csm3_run_event_n, csm3_event_n, csm3_run_n, csm3_n,
csm2_run_event_n, csm2_event_n, csm2_run_n, csm2_n};
3'h5: //Lan module Card Status and Event Register
r_mem <= {b_10gf_event_n, f_10gf_event_n, b_ge_event_n, f_ge_event_n,
b_10gf_n, f_10gf_n, b_ge_n, f_ge_n};
3'h6: //System Reset Control Register
r_mem <= {csm3_rst_n, csm2_rst_n, csm1_rst_n, csm0_rst_n,
b_10gf_rst_n, f_10gf_rst_n, b_ge_rst_n, f_ge_rst_n};
3'h7: //Recover Key, FPGA Daughter Card and Mucus Register
begin
r_mem[7] <= ps_key_n; //Password key press indication
r_mem[4] <= mucus_rst_n; //Mucus reset
r_mem[2] <= daughter_run_n; //daughter card run OK status. 0=>OK; 1=>not started
r_mem[1] <= daughter_n; //daughter card fix/unfix status. 0=>fixed; 1=>unfixed
r_mem[0] <= daughter_rst_n; //daughter card reset
end
endcase

assign csm0_led_n = csm0_n;
assign csm1_led_n = csm1_n;
assign csm2_led_n = csm2_n;
assign csm3_led_n = csm3_n;
assign hdd_cf_led_n = ich_sata_led_n & cf_led_n;
assign in_out_irq_n = irq_en ? (csm_event_n & lan_event_n) : 1'b1;
assign csm_run_irq_n = irq_en ? csm_run_event_n : 1'b1;


// and drive the SDA line when necessary.
wire mem_bit_low = ~r_mem[bitcnt[2:0]];
wire SDA_assert_low = adr_match & bit_DATA & data_phase & op_read & mem_bit_low & got_ACK;
wire SDA_assert_ACK = adr_match & bit_ACK & (adr_phase | op_write);
wire SDA_low = SDA_assert_low | SDA_assert_ACK;
assign SDA = SDA_low ? 1'b0 : 1'bz;

endmodule


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
I2C接口RTC实时时钟pcf8563读写Verilog驱动源码Quartus工程文件,FPGA型号Cyclone4E系列中的EP4CE10F17C8,Quartus版本18.0。 module rtc( //system clock input sys_clk , // 系统时钟 input sys_rst_n , // 系统复位 //pcf8563 interface output rtc_scl , // i2c时钟线 inout rtc_sda , // i2c数据线 //user interface input key2 , // 开关按键 output [5:0] sel , // 数码管位选 output [7:0] seg_led // 数码管段选 ); //parameter define parameter SLAVE_ADDR = 7'h51 ; // 器件地址 parameter BIT_CTRL = 1'b0 ; // 字地址位控制参数(16b/8b) parameter CLK_FREQ = 26'd50_000_000; // i2c_dri模块的驱动时钟频率(CLK_FREQ) parameter I2C_FREQ = 18'd250_000 ; // I2C的SCL时钟频率 parameter POINT = 6'b010100 ; // 控制点亮数码管小数点的位置 //初始时间设置,从高到低为年到秒,各占8bit parameter TIME_INI = 48'h18_05_23_09_30_00; //wire define wire clk ; // I2C操作时钟 wire i2c_exec ; // i2c触发控制 wire [15:0] i2c_addr ; // i2c操作地址 wire [ 7:0] i2c_data_w; // i2c写入的数据 wire i2c_done ; // i2c操作结束标志 wire i2c_ack ; // I2C应答标志 0:应答 1:未应答 wire i2c_rh_wl ; // i2c读写控制 wire [ 7:0] i2c_data_r; // i2c读出的数据 wire [23:0] num ; // 数码管要显示的数据 wire key_value ; // 按键消抖后的数据 //***************************************************** //** main code //***************************************************** //例化i2c_dri,调用IIC协议 i2c_dri #( .SLAVE_ADDR (SLAVE_ADDR), // slave address从机地址,放此处方便参数传递 .CLK_FREQ (CLK_FREQ ), // i2c_dri模块的驱动时钟频率(CLK_FREQ) .I2C_FREQ (I2C_FREQ ) // I2C的SCL时钟频率 ) u_i2c_dri( //global clock .clk (sys_clk ), // i2c_dri模块的驱动时钟(CLK_F
以下是一个Verilog代码示例,用于实现I2C通信的slave模块: ```verilog module I2C_slave ( input [6:0 slv_id, input RESET, input scl_i, // I2C时钟 input sda_i, // I2C数据输入 input [7:0 I2C_RDDATA, // I2C读取数据 // 其他输入和输出端口 ); // 定义状态机的状态 typedef enum logic [2:0 { IDLE, ADDRESS, DATA, ACK, ACK_WAIT, STOP } state_type; reg state_type state; // 当前状态寄存器 reg [6:0 slave_address; // 从机地址寄存器 // 状态机 always @ (posedge scl_i) begin if (RESET) begin state <= IDLE; slave_address <= 7'b0000000; end else begin case (state) IDLE: if (sda_i == 1'b0) begin state <= ADDRESS; end ADDRESS: if (sda_i == 1'b1) begin // TODO: 检查地址匹配 state <= DATA; end DATA: // TODO: 处理数据 state <= ACK; ACK: // TODO: 发送ACK state <= ACK_WAIT; ACK_WAIT: if (sda_i == 1'b0) begin state <= DATA; end else begin state <= STOP; end STOP: // TODO: 处理停止条件 state <= IDLE; endcase end end // 其他逻辑和功能实现 // ... endmodule ``` 这是一个简单的I2C从机模块的Verilog代码示例。它使用状态机来处理I2C通信过程中的不同阶段,并根据输入信号scl_i和sda_i的状态来切换状态。 请注意,这只是一个示例代码,需要根据具体应用和硬件平台进行适当的修改和调整。具体的地址匹配、数据处理、ACK发送、停止条件处理等逻辑需要根据实际需求进行实现。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [i2c.zip_I2C slave verilog_Work It_i2c master verilog_i2c slave](https://download.csdn.net/download/weixin_42664597/86663220)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [verilog实现I2C通信的slave模块源码状态机设计可做I2C接口的仿真模型.rar](https://download.csdn.net/download/GJZGRB/15079674)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值