Verilog實現多地址I2C Slave

來源:互聯網
上載者:User
FX平台CPLD代碼,通過I2C匯流排訪問CPLD實現的控制寄存器,對系統進行複位等相關控制。下面是代碼,實現多地址的I2C Slaver,能夠類似I2C的EEPROM方式進行讀寫訪問。
module top_fx_cpld2(SDA, SCL,//outputcsm3_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,//inputcsm0_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 slaveparameter 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 awaywire 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 inreg [3:0] bitcnt; // counts the I2C bits from 7 downto 0, plus an ACK bitwire bit_DATA = ~bitcnt[3]; // the DATA bits are the first 8 bits sentwire bit_ACK = bitcnt[3]; // the ACK bit is the 9th bit sentreg data_phase;always @(negedge SCL or negedge incycle)if(~incycle)beginbitcnt <= 4'h7; // the bit 7 is received firstdata_phase <= 0;endelsebeginif(bit_ACK)beginbitcnt <= 4'h7;data_phase <= 1;endelsebeginbitcnt <= bitcnt - 4'h1;endend// and detect if the I2C address matches our ownwire 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 negedgereg [7:0] w_mem;reg [7:0] r_mem;wire op_write = ~op_read;always @(negedge SCL or negedge incycle)if(~incycle)begingot_ACK <= 0;adr_match <= 1;op_read <= 0;endelsebeginif(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 operationif(adr_match & bit_DATA & data_phase & op_write) w_mem[bitcnt] <= SDAr; // memory writeendreg [2:0] byte_addr; // byte address for registersreg cur_addr_phase; // current address phrasereg addring_phase; // register addressing phrasealways @(negedge SCL or negedge incycle)if(~incycle)begincur_addr_phase <= 0;byte_addr <= byte_addr;addring_phase <= 0;endelseif(bit_ACK & adr_match)if(op_write) //i2c writebeginif(!data_phase) cur_addr_phase <= 1'b1; //first byte is the current addresselse 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;endelse //i2c readbegincur_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 2reg irq_en, csm_run_irq_mask, csm_irq_mask, lan_irq_mask; //irq register//csm state registers, offset 3, 4reg 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 5reg 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 6reg 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 7reg mucus_rst_n, daughter_rst_n;//i2c writealways@(negedge SCL or negedge rst_n)if(!rst_n)beginst_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 0x2irq_en <= 1'b0;csm_run_irq_mask <= 1'b1;csm_irq_mask <= 1'b1;lan_irq_mask <= 1'b1;endelsebeginif(bit_ACK & addring_phase & op_write)case(byte_addr)3'h2: //Interrupt Registerbeginirq_en <= w_mem[7];csm_run_irq_mask <= w_mem[6];csm_irq_mask <= w_mem[5];lan_irq_mask <= w_mem[4];end3'h3: //CSM Status Register1begincsm1_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];end3'h4: //CSM Status Register2begincsm3_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];end3'h5: //Lan module Card Status and Event Registerbeginb_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];end3'h6: //System Reset Control Registerbegincsm3_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];end3'h7: //Recover Key, FPGA Daughter Card and Mucus Registerbeginmucus_rst_n <= w_mem[4];daughter_rst_n <= w_mem[0];endendcaseelsebeginst_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 indicatorwire 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 registersalways@*case(byte_addr)3'h0: //CPLD Device IDr_mem <= 8'h02; //Device ID, 0x02 => O2 Security3'h1: //CPLD Code Version and Device ID Registerr_mem <= 8'h0b; //code ver: r_mem[7:3] 1.0; CPLD type: r_mem[2:0] 011 =>XC951443'h2: //Interrupt and Password Recover Key Status Registerbeginr_mem[7] <= irq_en; //interrupt mode enabler_mem[6] <= csm_run_irq_mask; //CSM Run interrupt maskr_mem[5] <= csm_irq_mask; //CSM fixing/removing interrupt maskr_mem[4] <= lan_irq_mask; //LAN Card fixing/removing interrupt maskr_mem[2] <= csm_run_event_n; //CSM card run event indicater_mem[1] <= csm_event_n; //CSM card fix/unfix event indicater_mem[0] <= lan_event_n; //Lan card fix/unfix event indicateend3'h3: //CSM Status Register1r_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 Register2r_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 Registerr_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 Registerr_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 Registerbeginr_mem[7] <= ps_key_n; //Password key press indicationr_mem[4] <= mucus_rst_n; //Mucus resetr_mem[2] <= daughter_run_n; //daughter card run OK status. 0=>OK; 1=>not startedr_mem[1] <= daughter_n; //daughter card fix/unfix status. 0=>fixed; 1=>unfixedr_mem[0] <= daughter_rst_n; //daughter card resetendendcaseassign 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


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.