// // Author: lsilvest // Create Date: 10/10/2009 // // // Copyright (c) 2009 Authors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // `include "i2c_controller_const.v" module temp_read( input clk, // 20 MHz input clock input rst_n, // active low board reset, connected to sw1 input temp_sda_in, // oled data in output temp_sda_out, // oled data out output temp_sda_oe, // oled data output enable input temp_scl_in, // oled clock in output temp_scl_out, // oled clock out output temp_scl_oe, // oled clock output enable output temp_sign, // temperature sign output [6:0] temp, // integer part of temperature output [3:0] temp_frac, // fractional part of temperature input temp_go, output temp_done, output reg [2:0] led ); reg [2:0] cmd; wire ack_o; wire ack_e; wire busy; reg [7:0] temp_msb, temp_lsb; reg [4:0] state, next_state; wire [7:0] data_w; reg [7:0] data_w_r; wire [7:0] data_r; wire b_done; localparam temp_slave_addr = 8'h90, temp_ptr1 = 8'h01, temp_ptr2 = 8'h00, temp_cfg_reg = 8'b01100000; // defaults except ADC set to 12 bit localparam idl = 5'b00000, w_a_s1 = 5'b00001, a_rcvd_s1 = 5'b00010, w_ptr1 = 5'b00011, a_rcvd_ptr1 = 5'b00100, w_data = 5'b00101, a_rcvd_w_data = 5'b00110, p1 = 5'b00111, cfg_done = 5'b01000, idl_cfg_done = 5'b01001, w_a_s2 = 5'b01010, a_rcvd_s2 = 5'b01011, w_ptr2 = 5'b01100, a_rcvd_ptr2 = 5'b01101, w_a_s3 = 5'b01110, a_rcvd_s3 = 5'b01111, r_msb = 5'b10000, send_a_msb = 5'b10001, r_lsb = 5'b10010, send_na_lsb = 5'b10011, p2 = 5'b10100, read_done = 5'b10101, wait_busyn = 5'b10110; i2c_controller i2c_cntrl( .clk(clk), .rst_n(rst_n), .data_i(data_w), .data_o(data_r), .sdin_i(temp_sda_in), .sdin_o(temp_sda_out), .sdin_oe(temp_sda_oe), .sclk_i(temp_scl_in), .sclk_o(temp_scl_out), .sclk_oe(temp_scl_oe), .cmd_i(cmd), .cmd_a(cmd_a), .ack_o(ack_o), .ack_e(ack_e), .b_done(b_done), .busy(busy) ); // generate state change always@(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= idl; end else begin state <= next_state; end end // temp i2c state transitions: always@(*) begin case (state) // initial configuration: idl: if (temp_go) next_state = w_a_s1; else next_state = idl; w_a_s1: if (ack_o) next_state = a_rcvd_s1; else next_state = w_a_s1; a_rcvd_s1: if (cmd_a) next_state = w_ptr1; else next_state = a_rcvd_s1; w_ptr1: if (ack_o) next_state = a_rcvd_ptr1; else next_state = w_ptr1; a_rcvd_ptr1: if (cmd_a) next_state = w_data; else next_state = a_rcvd_ptr1; w_data: if (ack_o) next_state = p1; else next_state = w_data; p1: if (cmd_a) next_state = wait_busyn; else next_state = p1; wait_busyn: if (!busy) next_state = cfg_done; else next_state = wait_busyn; cfg_done: next_state = idl_cfg_done; // temperature read: idl_cfg_done: if (temp_go) next_state = w_a_s2; else next_state = idl_cfg_done; w_a_s2: if (ack_o) next_state = a_rcvd_s2; else next_state = w_a_s2; a_rcvd_s2: if (cmd_a) next_state = w_ptr2; else next_state = a_rcvd_s2; w_ptr2: if (ack_o) next_state = a_rcvd_ptr2; else next_state = w_ptr2; a_rcvd_ptr2: if (cmd_a) next_state = w_a_s3; else next_state = a_rcvd_ptr2; w_a_s3: if (ack_o) next_state = a_rcvd_s3; else next_state = w_a_s3; a_rcvd_s3: if (cmd_a) next_state = r_msb; else next_state = a_rcvd_s3; r_msb: if (b_done) next_state = send_a_msb; else next_state = r_msb; send_a_msb: if (cmd_a) next_state = r_lsb; else next_state = send_a_msb; r_lsb: if (b_done) next_state = send_na_lsb; else next_state = r_lsb; send_na_lsb: if (cmd_a) next_state = p2; else next_state = send_na_lsb; p2: if (cmd_a) next_state = read_done; else next_state = p2; read_done: next_state = idl_cfg_done; default: next_state = idl; endcase end // i2c temp command control: always@(*) begin case (state) idl: cmd = `nop_cmd; w_a_s1: cmd = `s_cmd; a_rcvd_s1: cmd = `w_cmd; w_ptr1: cmd = `w_cmd; a_rcvd_ptr1: cmd = `w_cmd; w_data: cmd = `w_cmd; a_rcvd_w_data: cmd = `p_cmd; p1: cmd = `p_cmd; cfg_done: cmd = `nop_cmd; idl_cfg_done: cmd = `nop_cmd; w_a_s2: cmd = `s_cmd; a_rcvd_s2: cmd = `w_cmd; w_ptr2: cmd = `w_cmd; a_rcvd_ptr2: cmd = `s_cmd; w_a_s3: cmd = `s_cmd; a_rcvd_s3: cmd = `r_cmd; r_msb: cmd = `r_cmd; send_a_msb: cmd = `a_cmd; r_lsb: cmd = `r_cmd; send_na_lsb: cmd = `na_cmd; p2: cmd = `p_cmd; read_done: cmd = `nop_cmd; default: cmd = `nop_cmd; endcase end always@(posedge clk or negedge rst_n) begin if (!rst_n) begin temp_msb <= 8'b0; temp_lsb <= 8'b0; end else begin if (state == send_a_msb) temp_msb <= data_r; else temp_msb <= temp_msb; if (state == send_na_lsb) temp_lsb <= data_r; else temp_lsb <= temp_lsb; end end // data control: always@(*) begin data_w_r = 0; case (state) w_a_s1: data_w_r = temp_slave_addr; w_ptr1: data_w_r = temp_ptr1; w_data: data_w_r = temp_cfg_reg; w_a_s2: data_w_r = temp_slave_addr; w_ptr2: data_w_r = temp_ptr2; a_rcvd_ptr2: data_w_r = temp_slave_addr | 8'b1; // get data early since this is a start after a write w_a_s3: data_w_r = temp_slave_addr | 8'b1; default: data_w_r = 0; endcase end always@(posedge clk or negedge rst_n) begin if (!rst_n) led <= 3'b111; else if (state == idl_cfg_done) led <= 3'b001; end assign data_w = data_w_r; assign temp_done = state == cfg_done || state == read_done; assign temp_sign = temp_msb[7]; assign temp = temp_sign ? ~temp_msb[6:0] + 7'b1 : temp_msb[6:0]; // handle 2's complement assign temp_frac = temp_lsb[7:4]; endmodule