URL
https://opencores.org/ocsvn/i2c_master_slave_core/i2c_master_slave_core/trunk
Subversion Repositories i2c_master_slave_core
Compare Revisions
- This comparison shows the changes necessary to convert path
/i2c_master_slave_core/tags/t1/i2c_master_slave_core/verilog
- from Rev 3 to Rev 6
- ↔ Reverse comparison
Rev 3 → Rev 6
/rtl/shift.v
0,0 → 1,52
////////////////////////////Shift.v///////////////////////////////////////////////////////////////////// |
// // |
//Design Engineer: Ravi Gupta // |
//Company Name : Toomuch Semiconductor |
//Email : ravi1.gupta@toomuchsemi.com // |
// // |
//Purpose : Used for shifting address and data in both transmit and recieve mode // |
//created : 22-11-07 // |
// // |
//////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
/*// synopsys translate_off |
`include "oc8051_timescale.v" |
// synopsys translate_on |
|
`include "oc8051_defines.v"*/ |
|
|
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 |
|
/rtl/counter.v
0,0 → 1,41
//////////////////////////counter.v/////////////////////////////////////////////////////////////////////////////// |
// |
//Designed Engineer: Ravi Gupta // |
//Company Name : Toomuch Semiconductor |
//Email : ravi1.gupta@toomuchsemi.com // |
// |
//Purpose : Used for counting clock pulses for prescale register and number of bytes transferred // |
//Created : 22-11-07 // |
// |
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
/*// synopsys translate_off |
`include "oc8051_timescale.v" |
// synopsys translate_on |
|
`include "oc8051_defines.v"*/ |
|
|
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 |
/rtl/controller_interface.v
0,0 → 1,546
////////////////////////////////////////////controller_interface.v//////////////////////////////////////// |
// // |
//Design Engineer: Ravi Gupta // |
//Company Name : Toomuch Semiconductor |
//Email : ravi1.gupta@toomuchsemi.com // |
// // |
//Purpose : This core will be used as an interface between I2C core and Processor // |
//Created : 6-12-2007 // |
// // |
// // |
// // |
// // |
// // |
// // |
// // |
// // |
//Modification : Change the control register,added halt reset and inter_rst in control register |
///////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
/*// synopsys translate_off |
`include "oc8051_timescale.v" |
// synopsys translate_on |
|
`include "oc8051_defines.v"*/ |
|
|
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 |
|
|
|
|
|
|
|
|
|
|
/rtl/i2c_blk.v
0,0 → 1,172
////////////////////////////////////////////////////////////////////////////////////////// |
//Design Engineer: Ravi Gupta // |
//Company Name : Toomuch Semiconductor |
//Email : ravi1.gupta@toomuchsemi.com // |
// // |
// // |
//Purpose : This module will simply interconnect controller interface // // |
// controller_interface with ms_core. // |
// // |
// // |
//Date : 11-12-07 // |
// // |
// // |
// // |
// // |
// // |
// // |
// // |
////////////////////////////////////////////////////////////////////////////////////////// |
/*// synopsys translate_off |
`include "oc8051_timescale.v" |
// synopsys translate_on |
|
`include "oc8051_defines.v"*/ |
|
|
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 |
|
|
|
|
/rtl/ms_core.v
0,0 → 1,1157
///////////////////////////////////////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 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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|