Download project zip from Opencores.org
Download logism circuit here(open the link and save it) >>>>>>>>>>>>>I2C.circ
module counter (clk,asyn_rst,enable,load,data_in,out); input clk,asyn_rst,enable,load; input [7:0] data_in; output [7:0] out; reg [7:0]data; always@(posedge clk or posedge asyn_rst) begin if(asyn_rst) data<=8'h0; //clear all bits upon asynchronous reset. else if(load) data<=data_in; //load the counter with incoming data if load signal is high else if(enable) data<=data + 1'b1; //Increment the counter if enable bit is high else data<=data; //else hold the data;else part is mention to avoid latch formation end assign out=data; endmodule
module shift(clk,asyn_rst,load,shift_en,serial_in,data_in,serial_out,data_out); input clk,asyn_rst,load,shift_en,serial_in; input [7:0]data_in; output serial_out; output [7:0]data_out; reg [7:0]data; always@(posedge clk or posedge asyn_rst or posedge load) begin if(asyn_rst) data<=8'h0; //clear the data register upon asynchronous reset. else if(load) data<=data_in; //Load the internal register upon insertion of load bit. else if(shift_en) data<={data[6:0],serial_in}; //Upon shift_en high every time a new serial data is coming to LSB bit and data will be shifted //to one bit. else data<=data; //Prevent formation of latches end assign data_out = data; //Output the data in a data_register assign serial_out = data[7]; //MSB is transmitted first in I2C protocol. endmodule //change loading into asynchronous mode
module processor_interface (clk,rst,add_bus,data_in,data_out,as,ds,rw,bus_busy,byte_trans,slave_addressed,arb_lost,slave_rw,inter,ack_rec, core_en,inter_en,mode,master_rw,ack,rep_start,data,i2c_data,slave_add,time_out_reg,prescale,irq,time_out,inter_rst,halt,data_en,time_rst); input clk; //System clock input rst; //system reset //signals connecting core to processor ///////////////////////////////////// input [7:0]add_bus; //contains address of internal register input [7:0]data_in; //trnasport the data for i2c core input as; //asserted high indicates vallid address has been placed on the address bus input ds; //asserted high indicates valid data on data bus input rw; //"1" indicates that processor has to write else read output irq; //interrupt to processor output inter_rst; //this bit will be written by processor when it will clear the interrupt. output [7:0]data_out; output halt; output data_en; input time_rst; //signals from core to reflect te status of core and buses /////////////////////////////////////////////////////////// input bus_busy; //signal from core indicates bus is busy input byte_trans; //signal from core indicates byte transfer is in progress input slave_addressed; //signal from core indicares core has been identified as slave input arb_lost; //signal from core indicates bus error input slave_rw; //signal from core indicates operation of slave core input inter; //signal from core.this will interrupt the processor if this bit as well as interrupt enable is high input ack_rec; //signal from core to reflect the status of ack bit input time_out; //bits of control register ////////////////////////// inout core_en; //this bit must be cleared before any other bit of control register have any effect on core inout inter_en; //To intrrupt the core this bit must be set when interrupt is pending inout mode; //Transaction from "0" to "1" directes core to act as master else slave inout master_rw; //set directiion for master either to transmit or receive inout ack; //value of acknowledgment bit to be transmitted on SDA line during ack cycle inout rep_start; //set this bit if processor wants a repeated start //data register //////////////// inout [7:0]prescale; //contains the value for generating SCL frequency inout [7:0]time_out_reg; //contains the value for maximum low period for scl inout [7:0]slave_add; //this is the programmble slave address inout [7:0]data; //data for i2c core input [7:0]i2c_data; //data from core for processor //defining registers addresses ///////////////////////////// `define PRER 8'b0000_0010 `define CTR 8'b0000_0100 `define SR 8'b0000_1000 `define TO 8'b0000_1010 `define ADDR 8'b0000_1100 `define DR 8'b0000_1110 `define RR 8'b0000_0000 /*//defing the machine state ////////////////////////// parameter processor_idle=2'b00; parameter processor_address=2'b01; parameter processor_data=2'b10; parameter processor_ack=2'b11;*/ //Definig internal registers and wires ///////////////////////////////////// wire core_en,inter_en,mode,master_rw,ack,rep_start,inter_rst,halt; wire prescale_reg_en; wire ctr_reg_en; wire sr_reg_en; wire to_reg_en; wire addr_reg_en; wire dr_reg_en; reg [7:0]data_out,sr_reg,ctr_reg,dr_reg,rr_reg; wire [7:0]data_in; //if address on add_bus matches with register address then set this high. wire data_ie; //this is signal used for enaling the data line in read or write cycle. wire as_d; //delay version of address strobe signal for detection of rising and falling edge reg as_delay_sig; //same signal. wire ds_d; //delayed version of data strobe. wire decode; wire rr_reg_en; reg ds_delay_sig; reg prescale_reg_en_sig; assign prescale_reg_en = prescale_reg_en_sig; reg ctr_reg_en_sig; assign ctr_reg_en = ctr_reg_en_sig; reg sr_reg_en_sig; assign sr_reg_en = sr_reg_en_sig; reg to_reg_en_sig; assign to_reg_en = to_reg_en_sig; reg addr_reg_en_sig; assign addr_reg_en = addr_reg_en_sig; reg dr_reg_en_sig; assign dr_reg_en = dr_reg_en_sig; reg as_d_sig; assign as_d = as_d_sig; reg ds_d_sig; assign ds_d = ds_d_sig; reg data_ie_sig; assign data_ie = data_ie_sig; //reg core_en_sig; //assign core_en = core_en_sig; //reg inter_en_sig; //assign inter_en = inter_en_sig; //reg mode_sig; //assign mode = mode_sig; //reg master_rw_sig; //assign master_rw = master_rw_sig; //reg ack_sig; //assign ack = ack_sig; //reg rep_start_sig; //assign rep_start = rep_start_sig; reg [7:0]data_sig; assign data = dr_reg; reg [7:0]prescale_sig; assign prescale = prescale_sig; reg [7:0]time_out_sig; assign time_out_reg = time_out_sig; reg [7:0]slave_add_sig; assign slave_add = slave_add_sig; //reg [7:0]data_out_sig; //assign data_out = data_out_sig; reg decode_sig; assign decode = decode_sig; //reg inter_rst_sig; //assign inter_rst = inter_rst_sig; //reg halt_sig; //assign halt = halt_sig; assign data_en = dr_reg_en_sig; reg rr_reg_en_sig; assign rr_reg_en = rr_reg_en_sig; assign core_en = ctr_reg [7]; assign inter_en = ctr_reg [6]; assign mode = ctr_reg [5]; assign master_rw = ctr_reg [4]; assign ack = ctr_reg [3]; assign rep_start = ctr_reg [2]; assign inter_rst = ctr_reg [1]; assign halt = ctr_reg [0]; //generating delayed version of inputs for detection of rising and falling edge. ////////////////////////////////////////////////////////////////////////////// always@(posedge clk or posedge rst) begin if(rst) begin as_delay_sig<=1'b0; as_d_sig<=1'b0; ds_delay_sig<=1'b0; ds_d_sig<=1'b0; end else begin as_delay_sig<=as; as_d_sig<=as_delay_sig; ds_delay_sig<=ds; ds_d_sig<=ds_delay_sig; end end always@(posedge clk or posedge rst) begin if(rst) decode_sig<=1'b0; else if(!as_d && as) decode_sig<=1'b1; //else //decode_sig<=1'b0; end //address decoding logic /////////////////////// //always@(posedge clk or posedge rst) always@(rst or as or add_bus or posedge time_rst) begin if(rst || time_rst) begin prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; rr_reg_en_sig <= 1'b0; //add_match_sig<=1'b0; end else if(as) begin if(add_bus == `PRER) begin rr_reg_en_sig <= 1'b0; prescale_reg_en_sig<=1'b1; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; //add_match_sig<=1'b1; end else if(add_bus == `CTR) begin rr_reg_en_sig <= 1'b0; prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b1; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; //add_match_sig<=1'b1; end else if(add_bus == `SR) begin rr_reg_en_sig <= 1'b0; prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b1; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; //add_match_sig<=1'b1; end else if(add_bus == `TO) begin rr_reg_en_sig <= 1'b0; prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b1; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; //add_match_sig<=1'b1; end else if(add_bus == `ADDR) begin rr_reg_en_sig <= 1'b0; prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b1; dr_reg_en_sig<=1'b0; //add_match_sig<=1'b1; end else if(add_bus == `DR) begin prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b1; rr_reg_en_sig <= 1'b0; //add_match_sig<=1'b1; end else if(add_bus == `RR) begin rr_reg_en_sig <= 1'b1; prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; //add_match_sig<=1'b1; end else begin rr_reg_en_sig <= 1'b0; prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; //add_match_sig<=1'b0; end end else begin prescale_reg_en_sig<=1'b0; ctr_reg_en_sig<=1'b0; sr_reg_en_sig<=1'b0; to_reg_en_sig<=1'b0; addr_reg_en_sig<=1'b0; dr_reg_en_sig<=1'b0; rr_reg_en_sig <= 1'b0; end end //assigning value of data_ie line ////////////////////////////////// always@(posedge clk or posedge rst) begin if(rst) data_ie_sig<=1'b0; else if(!ds_d && ds) data_ie_sig<=1'b1; end //read data to/from the register specified by processor addrress. //always@(rst or addr_reg_en or ctr_reg_en or dr_reg_en or sr_reg_en or prescale_reg_en or to_reg_en or data_ie or rw or data_in ) always@(posedge clk or posedge rst) begin if(rst) begin sr_reg <= 8'b0; dr_reg <= 8'b0; rr_reg <= 8'b0; //ctr_reg <= 8'b0; end /*else if(ctr_reg_en) begin //sr_reg <= {byte_trans,slave_addressed,bus_busy,arb_lost,time_out,slave_rw,inter,ack_rec}; ctr_reg <= data_in; end*/ else begin sr_reg <= {byte_trans,slave_addressed,bus_busy,arb_lost,time_out,slave_rw,inter,ack_rec}; rr_reg <= i2c_data; end end always@(posedge clk or posedge rst or posedge time_rst) begin if(rst || time_rst) begin //initializing control register ctr_reg <= 8'b0; /*core_en_sig <= 1'b0; inter_en_sig <= 1'b0; mode_sig <= 1'b0; master_rw_sig <= 1'b0; ack_sig <= 1'b0; rep_start_sig <= 1'b0; inter_rst_sig<=1'b0;*/ //initializing data and timer register data_sig <= 8'b00000000; prescale_sig <= 8'b00000000; time_out_sig <= 8'b00000000; data_out <= 8'b00000000; end else if (data_ie) begin //address register if(addr_reg_en) //if address matches with slave address register begin if(rw) //processor write cycle slave_add_sig <= {data_in[7:1] , 1'b0}; else //processor read cycle data_out <= slave_add; end //control register if(ctr_reg_en) //if address matches with cntrol register begin if(rw) //processor write cycle //begin /*core_en_sig <= #2 ctr_reg [7]; inter_en_sig <= #2 ctr_reg [6]; mode_sig <= #2 ctr_reg [5]; master_rw_sig <= #2 ctr_reg [4]; ack_sig <= #2 ctr_reg [3]; rep_start_sig <= #2 ctr_reg [2]; inter_rst_sig <= #2 ctr_reg [1]; halt_sig <= #2 ctr_reg [0];*/ //end //else ctr_reg <= data_in; //processor read cycle else data_out <= ctr_reg; end else if(!byte_trans && bus_busy) ctr_reg[1:0] <= 2'b0; //data register if(dr_reg_en) begin if(rw) dr_reg <= data_in; else data_out <= dr_reg; end if(rr_reg_en) begin data_out <= rr_reg; end //staus register if(sr_reg_en) begin if(!rw) //begin //if(data_in[0]==1'b0) //inter_rst_sig <= 1'b0; //else //inter_rst_sig <= 1'b1; //end //else //begin data_out <= sr_reg; //inter_rst_sig<=1'b0; //end //else //inter_rst_sig<=1'b0; end //prescale register if(prescale_reg_en) begin if(rw) prescale_sig <= data_in; else data_out <= prescale; end //time_out register if(to_reg_en) begin if(rw) time_out_sig <= data_in; else data_out <= time_out_reg; end end end //assigning values to bidirectional bus ////////////////////////////////////// //assign data_bus = (!rw && data_ie) ? data_out : 8'bzzzzzzzz; //assign data_in = (rw) ? data_bus : 8'bzzzzzzzz; //interuupt pin to processor assign irq = (inter && inter_en) ? 1'b1 : 1'b0; endmodule
module core(clk,rst,sda_oe,sda_in,sda_o,scl_oe,scl_in,scl_o,ack,mode,rep_start,master_rw,data_in,slave_add,bus_busy,byte_trans,slave_addressed,arb_lost,slave_rw,time_out,inter,ack_rec,i2c_up,time_out_reg,prescale_reg,inter_rst,inter_en,halt_rst,data_en,time_rst,h_rst); ////////////////////////////////////////////////signal defination//////////////////////////////////////////////////////////////// input clk; //System Clock input rst; //Main Reset output sda_oe; //I2C serial data line output to be connected to control line of bidirectional buffer on physical SDA line input sda_in; //I2C serial data line input output sda_o; //I2C sda line always asssign to zero this is to be connected to input of bidirectional buffer on physical SDA line output scl_oe; //I2C serial clock line output to be connected to control line of bidirectiional buffer on physical scl line input scl_in; //I2C serial clock line input output scl_o; //SCL output line to be connected to input of bidirectional line input ack; //Acknowledgement signal from control register input mode; //master/slave mode select input rep_start; //repeated start input master_rw; //command to core in master mode input [7:0]data_in; //data from processor to be outputed on I2C input [7:0]slave_add; //I2C slave address input data_en; output time_rst; input h_rst; //status signal: output bus_busy; //bus busy inout byte_trans; //transfer of byte is in progress_reg_en inout slave_addressed; //addressed as slave inout arb_lost; //arbitration has lost inout slave_rw; //indicates the operation by slave inout time_out; //indicates that SCL LOW time has been exceeded output inter; //interrupt pending,will be used for interrupting processor input inter_rst; //use to clear the interrupt input inter_en; //processor wants to take interrupt or not //signal for processor input halt_rst; output ack_rec; //indicates that ack has been recieved,will be used to inform if master reciever wants to terminate the transfer output [7:0]i2c_up; //I2C data for micro processor //timing control registers input [7:0]time_out_reg; //max SCL low period. input [7:0]prescale_reg; //clock divider for generating SCL frequency. /////////////////////////////////////////End of port defination////////////////////////////////////////////////////////////////// wire master_slave,arbitration_lost,bb,gen_start,rep_start,byte_trans_delay,byte_trans_fall; //wire scl_out,sda_out,clk_cnt_enable,clk_cnt_rst,bit_cnt_enable,bit_cnt_rst,timer_cnt_enable,timer_cnt_rst,scl_in,sda_in,sda_out_reg,stop_scl_reg,master_sda, gen_stop; wire master_sda,scl_in,gen_stop,sm_stop,detect_stop,detect_start,addr_match,core_rst,stop_scl,scl_out,neg_scl_sig,sda_sig; //reg [7:0]clk1_cnt,bit1_cnt,timer1_cnt; reg posedge_mode,negedge_mode; reg [2:0]scl_state; reg [1:0]state; reg [2:0]scl_main_state; wire [7:0] add_reg,shift_reg; wire [7:0]clk_cnt,bit_cnt; reg [7:0]time_cnt; reg [7:0]i2c_up; wire bit_cnt_enable,bit_cnt_rst,clk_cnt_enable,clk_cnt_rst,data_reg_ld,data_reg_en,sda_in,serial_out,i2c_serial_out,add_reg_ld,add_reg_en,posedge_mode_sig,negedge_mode_sig,interrupt; wire [7:0]zero; wire [7:0]reg_clr; wire slave_sda,sda_out,halt,arb_rst,interrupt_rst,d_detect_stop; shift shift_data(neg_scl,rst,data_reg_ld,data_reg_en,sda_in,data_in,serial_out,shift_reg); //shift register for transferring the data shift shift_add(neg_scl,rst,add_reg_ld,add_reg_en,sda_in,reg_clr,i2c_serial_out,add_reg); //shift register for transferring address counter clock_counter(clk,rst,clk_cnt_enable,clk_cnt_rst,zero,clk_cnt); //This will count number of clock pulses for prescale counter bit_counter(neg_scl,rst,bit_cnt_enable,bit_cnt_rst,zero,bit_cnt); //Implementation of bit counter /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// reg clk_cnt_enable_sig; assign clk_cnt_enable = clk_cnt_enable_sig; reg clk_cnt_rst_sig; assign clk_cnt_rst = clk_cnt_rst_sig; //reg sda_in_sig; //assign sda_in = sda_in_sig; reg sm_stop_sig; assign sm_stop = sm_stop_sig; //reg scl_in_sig; //assign scl_in = scl_in_sig; reg gen_start_sig; assign gen_start = gen_start_sig; reg gen_stop_sig; assign gen_stop = gen_stop_sig; reg master_slave_sig; assign master_slave = master_slave_sig; reg detect_start_sig; assign detect_start=detect_start_sig; reg detect_stop_sig; assign detect_stop=detect_stop_sig; reg byte_trans_sig; assign byte_trans= byte_trans_sig; reg bb_sig; assign bb=bb_sig; reg slave_addressed_sig; assign slave_addressed=slave_addressed_sig; reg slave_rw_sig; assign slave_rw=slave_rw_sig; reg inter_sig; assign inter=inter_sig; assign interrupt=inter_sig; reg time_out_sig; assign time_out=time_out_sig; reg ack_rec_sig; assign ack_rec=ack_rec_sig; reg add_reg_enable_sig; assign add_reg_en=add_reg_enable_sig; reg data_reg_en_sig; assign data_reg_en=data_reg_en_sig; reg data_reg_ld_sig; assign data_reg_ld=data_reg_ld_sig; reg stop_scl_sig; assign stop_scl=stop_scl_sig; reg core_rst_sig; assign core_rst=core_rst_sig; reg sda_out_sig; assign sda_out=sda_out_sig; reg scl_out_sig; assign scl_out=scl_out_sig; reg master_sda_sig; assign master_sda=master_sda_sig; reg slave_sda_sig; assign slave_sda=slave_sda_sig; reg arbitration_lost_sig; assign arbitration_lost=arbitration_lost_sig; reg arb_lost_sig; assign arb_lost=arb_lost_sig; reg byte_trans_delay_sig; assign byte_trans_delay=byte_trans_delay_sig; reg byte_trans_fall_sig; assign byte_trans_fall=byte_trans_fall_sig; reg halt_sig; assign halt = halt_sig; reg arb_rst_sig; assign arb_rst=arb_rst_sig; reg interrupt_rst_sig; assign interrupt_rst=interrupt_rst_sig; reg rep_start_sig; assign time_rst = core_rst; reg d_detect_stop_sig; assign d_detect_stop = d_detect_stop_sig; reg d1_detect_stop_sig; assign bus_busy = bb; assign reg_clr=8'b00000000; assign neg_scl_sig=(~scl_in); assign neg_scl=neg_scl_sig; assign zero=8'b00000000; assign posedge_mode_sig=posedge_mode; assign negedge_mode_sig=negedge_mode; assign sda_o = 1'b0; //assign this to 0 always assign scl_o = 1'b0; parameter scl_idle=3'b000,scl_start=3'b001,scl_low_edge=3'b010,scl_low=3'b011,scl_high_edge=3'b100,scl_high=3'b101; parameter scl_address_shift=3'b001,scl_ack_address=3'b010,scl_rx_data=3'b011,scl_tx_data=3'b100,scl_send_ack=3'b101,scl_wait_ack=3'b110,scl_main_idle= 3'b000; parameter a=2'b00,b=2'b01,c=2'b10; ////////////////////SCL Generator/////////////////////////////// //This machine will generate SCL and SDA when in master mode.It will //also generate START and STOP condition. //always@(scl_state or arbitration_lost or sm_stop or gen_stop or rep_start // or bb or gen_start or master_slave or clk_cnt or bit_cnt or // scl_in or sda_out or master_sda or core_rst) always@(posedge clk or posedge rst or posedge core_rst or posedge h_rst) begin //State machine initial conditions if(rst || h_rst) begin scl_state<=scl_idle; scl_out_sig<=1'b1; sda_out_sig<=1'b1; stop_scl_sig<=1'b0; clk_cnt_enable_sig<=1'b0; clk_cnt_rst_sig<=1'b1; //bit_cnt_rst_sig<=1'b0; //bit_cnt_enable_sig<=1'b0; end else if(core_rst) begin scl_state<=scl_idle; scl_main_state <= scl_main_idle; scl_out_sig<=1'b1; sda_out_sig<=1'b1; stop_scl_sig<=1'b0; clk_cnt_enable_sig<=1'b0; clk_cnt_rst_sig<=1'b1; slave_addressed_sig<=1'b0; end else begin case (scl_state) scl_idle: begin arb_rst_sig <= 1'b1; interrupt_rst_sig<=1'b1; sda_out_sig<=1'b1; stop_scl_sig<=1'b0; if(master_slave && !bb && gen_start) begin scl_state<=scl_start; end end scl_start: begin arb_rst_sig <= 1'b0; interrupt_rst_sig<=1'b0; clk_cnt_enable_sig<=1'b1; //enable the counter as soon as machine enters in this state. clk_cnt_rst_sig<=1'b0; //sda_out_sig<=1'b0; //generating start condition stop_scl_sig<=1'b0; if(clk_cnt == prescale_reg / 3) sda_out_sig<= 1'b0; if(clk_cnt == prescale_reg) //wait for prescale value to over scl_state<=scl_low_edge; else scl_state<=scl_start; end scl_low_edge: begin clk_cnt_rst_sig<=1'b1; //This state will generate only SCL negative edge,and reset all the counters //timer_cnt_enable_sig<=1'b1; //except timer counter which will be enabled at this state. //timer_cnt_rst_sig<=1'b0; //also reseting the timer counter in this state. scl_out_sig<=1'b0; scl_state<=scl_low; stop_scl_sig<=1'b0; end scl_low: begin clk_cnt_enable_sig<=1'b1; //enable the clock counter clk_cnt_rst_sig<=1'b0; scl_out_sig<=1'b0; if(arbitration_lost) stop_scl_sig<=1'b0; else if(rep_start_sig) begin sda_out_sig<=1'b1; stop_scl_sig<=1'b0; end else if((gen_stop) && ((scl_main_state != scl_ack_address) && (scl_main_state != scl_send_ack) && (scl_main_state != scl_wait_ack))) //Ravi remove sm_stop from oring with gen_stop begin sda_out_sig<=1'b0; stop_scl_sig<=1'b1; end /*else if(rep_start) begin sda_out_sig<=1'b1; stop_scl_sig<=1'b0; end*/ else if(clk_cnt == prescale_reg / 3) begin sda_out_sig<=master_sda; stop_scl_sig<=1'b0; end else stop_scl_sig<=1'b0; //determine next state. if(clk_cnt == prescale_reg) begin if(bit_cnt == 8'b0000_0111 && arbitration_lost ) scl_state<=scl_idle; else if(interrupt && inter_en) //uncomenting out for cheking the core in interrupt mode scl_state<=scl_low; else if(halt) scl_state<=scl_low; else scl_state<=scl_high_edge; end else scl_state<=scl_low; end scl_high_edge: begin clk_cnt_rst_sig<=1'b1; scl_out_sig<=1'b1; if(gen_stop) //Ravi sm_stop from oring with gen_stop stop_scl_sig<=1'b1; else stop_scl_sig<=1'b0; if(!scl_in) scl_state<=scl_high_edge; else scl_state<=scl_high; end scl_high: begin clk_cnt_enable_sig<=1'b1; clk_cnt_rst_sig<=1'b0; scl_out_sig<=1'b1; if(clk_cnt == prescale_reg) begin if(rep_start_sig) scl_state<=scl_start; else if(stop_scl) scl_state<=scl_idle; else scl_state<=scl_low_edge; end else scl_state<=scl_high; end endcase end end //Sample the incoming SDA and SCL line with System clock /*always@(posedge clk or posedge rst) begin if(rst) begin //sda_in_sig <= 1'b1; scl_in_sig <=1'b1; end else begin if(!scl) scl_in_sig <= 1'b0; else scl_in_sig <= 1'b1; if(!sda) sda_in_sig <= 1'b0; else sda_in_sig <= 1'b1; //sda_out_sig <= sda; end end*/ //Generartion of control signal from the command based on processor. //This will control generation of start and stop signal. //This will also set the master_slave bit based on MODE signal //if bus is not busy i.e bb = 0 always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) begin gen_start_sig <= 1'b0; gen_stop_sig <= 1'b0; master_slave_sig <= 1'b0; end else begin if(posedge_mode_sig) gen_start_sig <= 1'b1; else if(detect_start) gen_start_sig <= 1'b0; if(!arbitration_lost && negedge_mode_sig) gen_stop_sig <= 1'b1; else if(detect_stop) gen_stop_sig <= 1'b0; if(!bb) master_slave_sig <= mode; else master_slave_sig <= master_slave; end end //State machine for detection of rising and falling edge of input mode for the generation of START and STOP. always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) begin posedge_mode<=1'b0; negedge_mode<=1'b0; state<=a; end else begin case(state) a: if(mode==1'b0) begin state<=b; posedge_mode<=1'b0; negedge_mode<=1'b0; end else begin state<=c; posedge_mode<=1'b1; negedge_mode<=1'b0; end b: if(mode==1'b0) begin state<=b; posedge_mode<=1'b0; negedge_mode<=1'b0; end else begin state<=a; posedge_mode<=1'b1; negedge_mode<=1'b0; end c: if(mode==1'b0) begin state<=a; posedge_mode<=1'b0; negedge_mode<=1'b1; end else begin state<=c; posedge_mode<=1'b0; negedge_mode<=1'b0; end endcase end end //This is the main state machine which will be used as both master as well as slave. //This gets triggered at falling edge of SCL. //If stop codition gets detected then it should work as asyn reset. always@(posedge rst or negedge scl_in or posedge detect_stop or posedge core_rst or posedge h_rst) begin if(rst || core_rst || h_rst) begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end else begin case(scl_main_state) scl_main_idle: if(detect_start) scl_main_state<=scl_address_shift; else if(detect_stop) begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end scl_address_shift: //machine will remain in this state,unless all the bits of address has been transferred. if(bit_cnt == 8'b0000_0111) scl_main_state<=scl_ack_address; else if(detect_stop) begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end scl_ack_address: //if(arbitration_lost) //if arbitration lost then go to idle state releasing buses.remove this because its a //scl_main_state<=scl_main_idle; //software problem if even after arb_lost it is giving wr/rd then it has to go to respective state. if(detect_stop) begin //Go to idle state if there is stop command scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end else if(detect_start) begin scl_main_state<=scl_address_shift; sm_stop_sig<=1'b0; end //else if(!sda_in) //If ack has been received then,check for slave/master else if(master_slave) begin //if master then set the direction for master to either transmit if(!master_rw) //or receive the data. scl_main_state<=scl_rx_data; else scl_main_state<=scl_tx_data; //Ravi: if no detect_stop then check if master send to state depending upon end //tx/rx bit of control register. else begin //If slave then check if received address has matched //if(addr_match) //begin //if address matches then set the direction of communication based if(add_reg[0]) //last bit of shift register of address cycle. scl_main_state<=scl_tx_data; else scl_main_state<=scl_rx_data; end //else //scl_main_state<=scl_main_idle; //end //else //begin // scl_main_state<=scl_main_idle; //If no ack received go to idle state. //if(master_slave) // sm_stop_sig<=1'b1; //end scl_rx_data: if(bit_cnt == 8'b0000_0111) scl_main_state<=scl_send_ack; else if(detect_stop) begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end else if(detect_start) begin scl_main_state<=scl_address_shift; sm_stop_sig<=1'b0; end scl_tx_data: if(bit_cnt == 8'b0000_0111) scl_main_state<=scl_wait_ack; else if(detect_stop) begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end else if(detect_start) begin scl_main_state<=scl_address_shift; sm_stop_sig<=1'b0; end scl_send_ack: if(detect_stop) begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end else scl_main_state<=scl_rx_data; scl_wait_ack: //Ravi: Even in this state machine will goto Tx state,if no ack or arb_lost has occur //if(arbitration_lost) //This is software part to program the control register so that it will generate stop //scl_main_state<=scl_main_idle; //and will go in idle state.So removing all clauses except detect stop. if(detect_stop) begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0; end else scl_main_state<=scl_tx_data; //else //begin //if(master_slave) //sm_stop_sig<=1'b1; //scl_main_state<=scl_main_idle; //end endcase end end //Start and stop detect process ////////////////////////////// always@(sda_in or scl_main_state) begin if(rst || h_rst) detect_start_sig<=1'b0; else if(!sda_in && scl_in) detect_start_sig<=1'b1; else if(scl_address_shift) detect_start_sig<=1'b0; else detect_start_sig<=1'b0; end always@(posedge sda_in or posedge detect_start) begin if(rst || h_rst) detect_stop_sig<=1'b0; else if(detect_start) detect_stop_sig<=1'b0; else if(scl_in) detect_stop_sig<=1'b1; //else if(detect_start) //detect_stop_sig<=1'b0; else detect_stop_sig<=1'b0; end //generate a delay version of byte_trans signal //This will be used for detecting falling edge of byte_trans always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) byte_trans_delay_sig <= 1'b0; else begin byte_trans_delay_sig <= byte_trans; byte_trans_fall_sig <= byte_trans_delay && !byte_trans; end end //Processor status bits///// //byte_trans bit //This indicate data is being transferred,This bit will be one only after all 8 bits has //been tranferred.i.e on rising pulse of SCL in ack cycle. always@(negedge scl_in or posedge rst or posedge halt_rst or posedge core_rst or posedge h_rst) begin if(rst || h_rst) byte_trans_sig<=1'b0; else if(halt_rst) byte_trans_sig <= 1'b0; else if(bit_cnt == 8'b0000_1000) byte_trans_sig<=1'b1; else if(halt_rst || core_rst) // after core_rst negate byte_trans bit byte_trans_sig<=1'b0; end //bus_busy //This indicates that communication is in progress and bus in not free. //This bit will be set on detection of start and will be cleared on STOP always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) bb_sig<=1'b0; else begin if(detect_start) bb_sig<=1'b1; if(detect_stop || core_rst) bb_sig<=1'b0; end end //slave_addressed bit //This indicates that slave has been addressed,and after sending ack //core will switch to slave mode. //This bit will be set if adds matched in add ack state. always@(posedge clk or posedge rst or posedge h_rst) begin if(rst) //Removing h_rst slave_addressed_sig<=1'b0; //else if(scl_main_state == scl_ack_address) else if(byte_trans) slave_addressed_sig<=addr_match; else slave_addressed_sig<=slave_addressed; //slave_addressed_sig<= 1'b0; end //set address match bit if address reg matches with shift register output /*always@(negedge scl or posedge rst) begin if(rst) addr_match_sig<=1'b0; else if( slave_add[7:1] == add_reg[7:1]) addr_match_sig <=1'b1; else addr_match_sig<=1'b0; end*/ assign addr_match = slave_add[7:1] == add_reg[7:1]? 1'b1:1'b0; assign add_reg_ld = 1'b0; //Slave read write //This bit indicates slave has been addressed,this indicates //read or write bit sent by processor. always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) slave_rw_sig<=1'b0; else if(scl_main_state == scl_ack_address) slave_rw_sig<=add_reg[0]; end //interrupt pending //This will cause an interrupt to processor if interrupt enable is set //This bit will be set in following circumstances: //1):Byte transfer has been completed. //2):Arbitration lost. //3):slave has been addressed and and bytes have been transferred. //4):Time out condition has been reached. //5):Repeated start condition. //Only processor can clear the interrupt. always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) inter_sig<=1'b0; else begin //if(interrupt_rst) //inter_sig<=1'b0; if(inter_rst) inter_sig<=1'b0; //in below else if condition anding byte_trans with master_slave also removing add_reg[] condition in next clause else if((byte_trans && master_slave) || arbitration_lost || (slave_addressed && !master_slave && byte_trans) || rep_start) inter_sig<=1'b1; //else //interrupt need to get cleared by processor,so do not reset in else condition //inter_sig<=1'b0; end end //generate delay version of detect_stop always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) d_detect_stop_sig <= 1'b0; else begin d1_detect_stop_sig <= detect_stop; d_detect_stop_sig <= d1_detect_stop_sig; end end always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) halt_sig <= 1'b0; else begin if(halt_rst) halt_sig<=1'b0; else if(byte_trans && master_slave) halt_sig<=1'b1; end end //acknoweldege recieve //This bit indicates the data on SDA line during ack cycle. always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) ack_rec_sig<=1'b0; else if((scl_main_state == scl_wait_ack) || (scl_main_state == scl_ack_address) || (scl_main_state == scl_send_ack)) ack_rec_sig<=sda_in; end //Setting control bits of shift registers and counters ////////////////////////////////////////////////////// //Address shift register will just receive the data after start //condition detection.It wont be get loaded.While data shift register //will receive as well as transmit the data. //address shift register enable bit always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) add_reg_enable_sig<=1'b0; else if(detect_start || scl_main_state == scl_address_shift) add_reg_enable_sig<=1'b1; else add_reg_enable_sig<=1'b0; end //Data shift register. //This register will be enabled every time when it is either transmitting or receiving the data. always @(posedge clk or posedge rst or posedge h_rst) begin if (rst || h_rst) begin data_reg_en_sig <= 1'b0; data_reg_ld_sig <= 1'b0; end else begin if (((master_slave && scl_main_state == scl_address_shift) || (scl_main_state == scl_rx_data) || (scl_main_state == scl_tx_data))) data_reg_en_sig <= 1'b1; else data_reg_en_sig <= 1'b0; /*if ((master_slave && scl_main_state == scl_idle) || (scl_main_state == scl_wait_ack) || (scl_main_state == scl_ack_address && !add_reg[0] && !master_slave) || (scl_main_state == scl_ack_address && master_rw && master_slave))*/ if(((scl_main_state == scl_main_idle) || byte_trans) && data_en) data_reg_ld_sig <= 1'b1; else data_reg_ld_sig <= 1'b0; end end //logic for generating control bits for bit counter //////////////////////////////////////////////////////////////////////////////////////////////// assign bit_cnt_enable = ((scl_main_state == scl_address_shift) || (scl_main_state == scl_rx_data) || (scl_main_state == scl_tx_data)); assign bit_cnt_rst = ((scl_main_state == scl_main_idle) || (scl_main_state == scl_send_ack) || (scl_main_state == scl_wait_ack) || (scl_main_state == scl_ack_address)); ///////////////////////////////////////////////////////////////////////////////////////////// //implementation of timer counter always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) time_cnt<=8'b0000_0000; else if(!scl_in) time_cnt<=time_cnt + 1'b1; else time_cnt<=8'b0000_0000; end always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) begin core_rst_sig<=1'b0; time_out_sig<=1'b0; end else if((time_cnt == time_out_reg) & bb) begin core_rst_sig <= 1'b1; time_out_sig <= 1'b1; end /*else if((time_cnt == time_out_reg) && (scl_state == scl_idle)) begin core_rst_sig <= 1'b0; time_out_sig <= 1'b1; end*/ else begin core_rst_sig <= 1'b0; time_out_sig <= 1'b0; end end //Process for assigning Master and slave SDA. always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) master_sda_sig<=1'b1; else if((scl_main_state == scl_address_shift) || (scl_main_state == scl_tx_data)) master_sda_sig<=serial_out; else if(scl_main_state == scl_send_ack) master_sda_sig<=ack; else master_sda_sig<=1'b1; end always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) slave_sda_sig<=1'b1; else if(scl_main_state == scl_tx_data) slave_sda_sig<=serial_out; else if((addr_match && (scl_main_state == scl_ack_address)) || (scl_main_state == scl_send_ack)) slave_sda_sig<=ack; else slave_sda_sig<=1'b1; end //assigning SCL and SDA lines in output conditions. assign scl_oe = master_slave ? scl_out : 1'b1; assign sda_sig = (((master_slave == 1'b1 && sda_out == 1'b0) || (master_slave == 1'b0 && slave_sda == 1'b0) || stop_scl) ? 1'b1 : 1'b0); assign sda_oe = (sda_sig ?1'b0 : 1'b1); //Presenting data on data_register which is for processor always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) i2c_up<=8'b00000000; else if(scl_main_state == scl_send_ack) i2c_up<=shift_reg; else i2c_up<=i2c_up; end //This process will set arbitration lost signal ////////////////////////////////////////////// // This process checks the master's outgoing SDA with the incoming SDA to determine // if control of the bus has been lost. SDA is checked only when SCL is high // and during the states IDLE, ADD_SHIFT, and TX_DATA to insure that START and STOP // conditions are not set when the bus is busy. Note that this is only done when Master. always @( posedge (clk) or posedge (rst) or posedge (h_rst) ) begin if (rst || h_rst) begin arbitration_lost_sig <= 1'b0; end else begin if (scl_main_state == scl_idle) begin arbitration_lost_sig <= 1'b0; end else if ((master_slave)) // only need to check arbitration in master mode // check for SCL high before comparing data if ((scl_in && scl_oe && (scl_main_state == scl_address_shift || scl_main_state == scl_tx_data || scl_main_state == scl_idle))) // when master, will check bus in all states except ACK_ADDR and WAIT_ACK // this will insure that arb_lost is set if a start or stop condition // is set at the wrong time //if(sda_in == 1'b0 && sda_oe == 1'b1) || (detect_stop if (sda_in == 1'b0 && sda_oe == 1'b1) begin arbitration_lost_sig <= 1'b1; end else begin arbitration_lost_sig <= 1'b0; end else begin arbitration_lost_sig <= arbitration_lost; end end end //setting the arbitration lost bit of status register //////////////////////////////////////////////////// //this bit will be set when: //arbiration has lost. //core is in master mode and a generate strat condition has detected while bus is busy //or a stop conditioin has been detected when not requested //or a repeate start has been detected when in slave mode. always@(posedge clk or posedge rst or posedge core_rst or posedge h_rst) begin if(rst || h_rst) arb_lost_sig<=1'b0; else begin if(arb_rst) arb_lost_sig<=1'b0; else if(master_slave) begin if((arbitration_lost)||(bus_busy && gen_start)) arb_lost_sig<=1'b1; end else if(rep_start) arb_lost_sig<=1'b1; //else if(core_rst && master_slave) //arb_lost_sig<=1'b0; else arb_lost_sig<=1'b0; end end always@(posedge clk or posedge rst or posedge h_rst) begin if(rst || h_rst) rep_start_sig<=1'b0; else if(scl_main_state == scl_address_shift || scl_main_state == scl_ack_address || scl_main_state == scl_send_ack || scl_main_state == scl_wait_ack) rep_start_sig<=1'b0; else rep_start_sig<=rep_start; end endmodule
module block(scl_oe,scl_in,scl_o,sda_oe,sda_in,sda_o,wb_add_i,wb_data_i,wb_data_o,wb_we_i,wb_stb_i,wb_cyc_i,irq,trans_comp,wb_clk_i,wb_rst_i,wb_ack_o); //inout scl; //Bi-directional lines to follow i2c protocol for data transfer. input sda_in; //sda input output sda_oe; //control line for bidirectional buffer output sda_o; //input line for bi_firectional buffer input scl_in; output scl_o; output scl_oe; input [7:0]wb_data_i; //Bi-direction buses for transfering data to/from processor. input [7:0]wb_add_i; //Transfer the addresses of intenal registers. input wb_we_i; //signal from processor to indicate whether its a read or write cycle. input wb_stb_i; //when asserted indicates address is valid. input wb_cyc_i; //when asserted indicates data is valid. output irq; //interupt signal to processor. input wb_clk_i; //system clock. input wb_rst_i; //asynchrnous reset active high. inout trans_comp; //temprory signal for testing the core output [7:0]wb_data_o; output wb_ack_o; //declaratiion of internal signals ////////////////////////////////// // control register wire [7:0] slave_add; // I2C address wire arb_lost; // indicates that arbitration for the i2c bus is lost wire bus_busy; // indicates the i2c bus is busy wire [7:0] i2c_up; // i2c data register wire [7:0] data; // uC data register wire core_en; // i2c enable - used as i2c reset wire inter_en; // interrupt enable wire inter; // interrupt pending wire mode; // i2c master/slave select wire master_rw; // master read/write wire rep_start; // generate a repeated start wire ack_rec; // value of received acknowledge wire slave_rw; // slave read/write wire ack; // value of acknowledge to be transmitted wire byte_trans; // indicates that one byte of data is being transferred wire slave_addressed; // address of core matches with address transferred wire time_out; // max low period for SCL has excedded wire [7:0]time_out_reg; // programmable max time for SCL low period wire [7:0]prescale; wire inter_rst; wire [7:0]wb_data_o; wire halt; wire data_en; wire time_rst; reg wb_ack_o; wire rst; assign trans_comp = byte_trans; always@(posedge wb_clk_i) begin wb_ack_o <= #1 wb_stb_i & wb_cyc_i & ~wb_ack_o; end //port map for i2c controller //////////////////////////// core i2c_core ( .clk(wb_clk_i), .rst(core_en), .sda_oe(sda_oe), .sda_in(sda_in), .sda_o(sda_o), .scl_oe(scl_oe), .scl_o(scl_o), .scl_in(scl_in), .ack(ack), .mode(mode), .rep_start(rep_start), .master_rw(master_rw), .data_in(data[7:0]), .slave_add(slave_add[7:0]), .bus_busy(bus_busy), .byte_trans(byte_trans), .slave_addressed(slave_addressed), .arb_lost(arb_lost), .slave_rw(slave_rw), .time_out(time_out), .inter(inter), .ack_rec(ack_rec), .i2c_up(i2c_up[7:0]), .time_out_reg(time_out_reg[7:0]), .prescale_reg(prescale[7:0]), .inter_en(inter_en), .inter_rst(inter_rst), .data_en(data_en), .halt_rst(halt), .h_rst(wb_rst_i), .time_rst(time_rst)); //port map for controller interface /////////////////////////////////// processor_interface processor_interface ( .clk(wb_clk_i), .rst(wb_rst_i), .add_bus(wb_add_i[7:0]), .data_in(wb_data_i[7:0]), .as(wb_stb_i), .ds(wb_cyc_i), .rw(wb_we_i), .bus_busy(bus_busy), .byte_trans(byte_trans), .slave_addressed(slave_addressed), .arb_lost(arb_lost), .slave_rw(slave_rw), .inter(inter), .ack_rec(ack_rec), .core_en(core_en), .inter_en(inter_en), .mode(mode), .master_rw(master_rw), .ack(ack), .rep_start(rep_start), .data(data[7:0]), .i2c_data(i2c_up[7:0]), .slave_add(slave_add), .time_out_reg(time_out_reg[7:0]), .prescale(prescale[7:0]), .irq(irq), .time_out(time_out), .inter_rst(inter_rst), .halt(halt), .data_en(data_en), .time_rst(time_rst), .data_out(wb_data_o)); //always@(scl or sda) //$display($time,"scl=%b\tsda=%b\t\n",scl,sda); endmodule