// // Copyright (C) 2015-2016 Markus Hiienkari // // This file is part of Open Source Scan Converter project. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // `define STATE_IDLE 2'b00 `define STATE_LEADVERIFY 2'b01 `define STATE_DATARCV 2'b10 module ir_rcv ( input clk27, input reset_n, input ir_rx, output reg [15:0] ir_code, output reg ir_code_ack, output reg [7:0] ir_code_cnt ); // ~37ns clock period parameter LEADCODE_LO_THOLD = 200000; //7.4ms parameter LEADCODE_HI_THOLD = 100000; //3.7ms parameter LEADCODE_HI_TIMEOUT = 160000; //5.9ms parameter LEADCODE_HI_RPT_THOLD = 54000; //2.0ms parameter RPT_RELEASE_THOLD = 3240000; //120ms parameter BIT_ONE_THOLD = 27000; //1.0ms parameter BIT_DETECT_THOLD = 7628; //0.28ms parameter IDLE_THOLD = 141480; //5.24ms reg [1:0] state; // 3 states reg [31:0] databuf; // temp. buffer reg [5:0] bits_detected; // max. 63, effectively between 0 and 33 reg [17:0] act_cnt; // max. 9.7ms reg [17:0] leadvrf_cnt; // max. 9.7ms reg [17:0] datarcv_cnt; // max. 9.7ms reg [21:0] rpt_cnt; // max. 155ms // activity when signal is low always @(posedge clk27 or negedge reset_n) begin if (!reset_n) act_cnt <= 0; else begin if ((state == `STATE_IDLE) & (~ir_rx)) act_cnt <= act_cnt + 1'b1; else act_cnt <= 0; end end // lead code verify counter always @(posedge clk27 or negedge reset_n) begin if (!reset_n) leadvrf_cnt <= 0; else begin if ((state == `STATE_LEADVERIFY) & ir_rx) leadvrf_cnt <= leadvrf_cnt + 1'b1; else leadvrf_cnt <= 0; end end // '0' and '1' are differentiated by high phase duration preceded by constant length low phase always @(posedge clk27 or negedge reset_n) begin if (!reset_n) begin datarcv_cnt <= 0; bits_detected <= 0; databuf <= 0; end else begin if (state == `STATE_DATARCV) begin if (ir_rx) datarcv_cnt <= datarcv_cnt + 1'b1; else datarcv_cnt <= 0; if (datarcv_cnt == BIT_DETECT_THOLD) bits_detected <= bits_detected + 1'b1; if (datarcv_cnt == BIT_ONE_THOLD) databuf[32-bits_detected] <= 1'b1; end else begin datarcv_cnt <= 0; bits_detected <= 0; databuf <= 0; end end end // read and validate data after 32 bits detected (last bit may change to '1' at any time) always @(posedge clk27 or negedge reset_n) begin if (!reset_n) begin ir_code_ack <= 1'b0; ir_code <= 16'h00000000; end else begin if ((bits_detected == 32) & (databuf[31:24] == ~databuf[23:16]) & (databuf[15:8] == ~databuf[7:0])) begin ir_code <= {databuf[31:24], databuf[15:8]}; ir_code_ack <= 1'b1; end else if (rpt_cnt >= RPT_RELEASE_THOLD) begin ir_code <= 16'h00000000; ir_code_ack <= 1'b0; end else ir_code_ack <= 1'b0; end end always @(posedge clk27 or negedge reset_n) begin if (!reset_n) begin state <= `STATE_IDLE; rpt_cnt <= 0; ir_code_cnt <= 0; end else begin rpt_cnt <= rpt_cnt + 1'b1; case (state) `STATE_IDLE: begin if ((act_cnt >= LEADCODE_LO_THOLD) & ir_rx) state <= `STATE_LEADVERIFY; if (rpt_cnt >= RPT_RELEASE_THOLD) ir_code_cnt <= 0; end `STATE_LEADVERIFY: begin if (leadvrf_cnt == LEADCODE_HI_RPT_THOLD) begin if (ir_code != 0) ir_code_cnt <= ir_code_cnt + 1'b1; rpt_cnt <= 0; end if (!ir_rx) state <= (leadvrf_cnt >= LEADCODE_HI_THOLD) ? `STATE_DATARCV : `STATE_IDLE; else if (leadvrf_cnt >= LEADCODE_HI_TIMEOUT) state <= `STATE_IDLE; end `STATE_DATARCV: begin if (ir_code_ack == 1'b1) ir_code_cnt <= 1; if ((datarcv_cnt >= IDLE_THOLD)|bits_detected >= 33) state <= `STATE_IDLE; end default: state <= `STATE_IDLE; endcase end end endmodule