?? i2c_to_gpio.v
字號:
/************************************************************************************************************I2C to GPIO Port expander. Date: December 21, 2006.************************************************************************************************************/`timescale 1us/10ns/* Top module */module I2C_to_GPIO ( sda, sclk, GPIO_input, GPIO_output);inout sda; // Bidirectional SDAinput sclk; // Bidirectional SCLKinput [7:0] GPIO_input; output [7:0] GPIO_output; parameter slave_address = 7'h0; // can be changed as per the protocolparameter n = 8;reg start_stop; // Indicated if the device has detected a start and is busy in some operationreg start, stop; // Goes high temperarily when a start or stop is detectdreg some_other_device; // to reset start_stop, when the adress on the bus is different from the device address;reg repeat_start; // to reset everything if repeat start is detected. reg write_flag; // to set when write oper beginsreg reset; // Used to reset the start , stop registers reg sda_out; // To force the SDA output Low. Remains tristated for sending High Logic.reg done; // To Indicate data transfer donereg [3:0]count; // Down Counter ( 7 to 0 + ack bit ) reg [n-1:0] GPIO_output; // parallel storereg [n-1:0] GPIO_input_reg; // Stores the Values at the input pins before sending to master.reg data_or_address; // high for data, low for addressreg sda_ack, read_oper, add_is_matching; // high for ack; high for master read; high for address matching/********************************************************************************************************?/* Detecting STOP Condition on the SDA Bus */always @ (posedge sda or posedge reset)if (reset) begin stop <= 0;end else if (sclk) begin stop <= 1;end/* Detecting START Condition on the SDA Bus */always @ (negedge sda or posedge reset)if (reset) begin start <= 0;end else if (sclk) begin start <= 1;end/* Tracking START_STOP related status of the device */always @ (negedge sclk) if (start_stop & start) begin repeat_start <= 1; reset <= 1; end else if (start) begin start_stop <= 1; reset <= 1; repeat_start <= 0; end else if (stop) begin start_stop <= 0; reset <= 1; repeat_start <= 0; end else if (some_other_device) begin start_stop <= 0; repeat_start <= 1; end else begin reset <= 0; repeat_start <= 0; end/***********************************************************************************************************/ /* Counting of bits. First eight bits are data and the last one is ack. */ wire sda_is_ack = count[3] & count [2]; // High for ack , count = 1111/* Down Counter, 1111 is ack */always @ (negedge sclk)if (start) begin count <= 4'h7; // it would decreae to 7 on the first pos edge of sclk. endelse if (start_stop) begin if (sda_is_ack) begin // count is restored to 7 count <= 4'h7; end else begin count <= count - 4'h1; // count is decremented until zero. endend /***********************************************************************************************************//* Taking the Inputs from SDA line and Comparing with Address */always @(posedge sclk) if (start_stop) begin if (~sda_is_ack) begin sda_ack <= 0; if (~data_or_address | repeat_start) begin if (repeat_start) begin add_is_matching <= 1; // high means matching data_or_address <= 0; // default is address some_other_device <= 0; // High means that device address does not match with SDA data write_flag <= 0; done <= 0; // Low means Transfer is pending end if (count == 7 & sda != slave_address[6]) add_is_matching <= 0; if (count == 6 & sda != slave_address[5]) add_is_matching <= 0; if (count == 5 & sda != slave_address[4]) add_is_matching <= 0; if (count == 4 & sda != slave_address[3]) add_is_matching <= 0; if (count == 3 & sda != slave_address[2]) add_is_matching <= 0; if (count == 2 & sda != slave_address[1]) add_is_matching <= 0; if (count == 1 & sda != slave_address[0]) add_is_matching <= 0; if (count == 0 & ~sda )begin read_oper <= 0; data_or_address <= 1; end else if (count == 0) begin read_oper <= 1; data_or_address <= 1; end end else if (~read_oper & ~done) begin if (count == 7) GPIO_output[7] <= sda; if (count == 6) GPIO_output[6] <= sda; if (count == 5) GPIO_output[5] <= sda; if (count == 4) GPIO_output[4] <= sda; if (count == 3) GPIO_output[3] <= sda; if (count == 2) GPIO_output[2] <= sda; if (count == 1) GPIO_output[1] <= sda; if (count == 0) begin GPIO_output[0] <= sda; done <= 1; end end else begin if (count == 0) done <= 1; end end else begin if (add_is_matching) begin sda_ack <= 1; if (read_oper) write_flag <= 1; end else begin data_or_address <= 0; some_other_device <= 1; end end end else begin add_is_matching <= 1; // high means matching sda_ack <= 0; // high means ack sent, drives sda low data_or_address <= 0; // default is address some_other_device <= 0; write_flag <= 0; done <= 0; end /***********************************************************************************************************//* Writing ACK and DATA on the SDA Line*/wire ack_flag = (count[3]|count[2]|count[1]|count[0]); //becomes low when count is 0always@(negedge sclk) if (start_stop) begin if (~ack_flag) begin if ( add_is_matching & ~write_flag)begin sda_out <= 1'b0; end else begin sda_out <= 1'bz; end if (read_oper & ~done) GPIO_input_reg <= GPIO_input; end else if (read_oper & data_or_address & ~done) begin if (ack_flag) begin if (~GPIO_input_reg[7]) begin sda_out <= 1'b0; end else begin sda_out <= 1'bz; end GPIO_input_reg <= GPIO_input_reg << 1; end end else begin sda_out <= 1'bz; end endwire sda;assign sda = sda_out;endmodule
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -