📄 ms_core.v
字号:
///////////////////////////////////////ms_core.v////////////////////////////////////////////////////////////////////////// // //Design engineer: Ravi Gupta // //Company Name : Toomuch Semiconductor //Email : ravi1.gupta@toomuchsemi.com // // // //Purpose : This is the core which will be used to interface I2C bus. // //Created : 23-11-07 // // //Modification : Changes made in data_reg_ld // // //Modification : Change byte_trans generation bit // // //Modification : Implemented a halt bit that will be generated at the completion of 9th scl pulse in master_mode only // // //Modification : After core reset(time out feature) core will go in idle escaping stop generation so need to clear ////all ////of status register. // ////Modification : Remove the sm_state clause,so that even if there is no acknowledegement it will not stop the ////generation of SCL and SDA // //untill it gets command to generate stop from processor. // // //Modification : Now also checking for detect_start in acknowledgement state for repeted start condition. // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 Clockinput rst; //Main Resetoutput sda_oe; //I2C serial data line output to be connected to control line of bidirectional buffer on physical SDA lineinput sda_in; //I2C serial data line inputoutput sda_o; //I2C sda line always asssign to zero this is to be connected to input of bidirectional buffer on physical SDA lineoutput scl_oe; //I2C serial clock line output to be connected to control line of bidirectiional buffer on physical scl lineinput scl_in; //I2C serial clock line inputoutput scl_o; //SCL output line to be connected to input of bidirectional lineinput ack; //Acknowledgement signal from control registerinput mode; //master/slave mode selectinput rep_start; //repeated startinput master_rw; //command to core in master modeinput [7:0]data_in; //data from processor to be outputed on I2Cinput [7:0]slave_add; //I2C slave addressinput data_en;output time_rst;input h_rst;//status signal:output bus_busy; //bus busyinout byte_trans; //transfer of byte is in progress_reg_eninout slave_addressed; //addressed as slaveinout arb_lost; //arbitration has lostinout slave_rw; //indicates the operation by slaveinout time_out; //indicates that SCL LOW time has been exceededoutput inter; //interrupt pending,will be used for interrupting processorinput inter_rst; //use to clear the interruptinput inter_en; //processor wants to take interrupt or not//signal for processorinput halt_rst;output ack_rec; //indicates that ack has been recieved,will be used to inform if master reciever wants to terminate the transferoutput [7:0]i2c_up; //I2C data for micro processor//timing control registersinput [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 datashift shift_add(neg_scl,rst,add_reg_ld,add_reg_en,sda_in,reg_clr,i2c_serial_out,add_reg); //shift register for transferring addresscounter clock_counter(clk,rst,clk_cnt_enable,clk_cnt_rst,zero,clk_cnt); //This will count number of clock pulses for prescalecounter 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 alwaysassign 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 conditionsif(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;endelse 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;endelsebegin 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 endcaseendend //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; endend*///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 = 0always@(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; endend//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 endcaseendend//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)beginif(rst || core_rst || h_rst)begin scl_main_state<=scl_main_idle; sm_stop_sig<=1'b0;endelsebegin 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -