-- ---------------------------------------------------------------------------
--  IrDA Fuse - A digital fuse to protect high current pulsed IR LED        --
-- ---------------------------------------------------------------------------
--
--  File   :   'irdafuse.vhd'
--  Author :    Lars Larsson 
-- 
--  Date   :    November 29, 1998
--
--  Description : The fuse locks the TXD signal to '0' if it is '1' for more 
--                than 85 us or if the duty cycle of TXD reaches 1:4 (25%). A
--                constant LIMIT defines a fuse look threshold time 
--   
--                      t[s] = (LIMIT+1) / clk[Hz]. 
--
--                With a clock frequency of 16 MHz and LIMIT = 1360 the 
--                threshold time is about 85 us. A revival signal unlocks
--                the fuse after a latency phase of 1:5 for DUTY=3.
-- 
--                This design has been used in a FPGA course to protect
--                IrDA transceivers (HP HSDL-1100 # 018) from student's 
--                and educator's IrDA encoder FPGA designs.
--
--
--  Hint   :      File 'components.vhd' (package components) is required.
--
-- ---------------------------------------------------------------------------
--
-- Copyright (C) 1998 Lars Larsson, Dept. of Computer Science
--                                  University of Hamburg
--                                  Vogt-Koelln-Str. 30
--                                  D - 22041 Hamburg, Germany
--                                  larsson@informatik.uni-hamburg.de
--                                  http://tech-www.informatik.uni-hamburg.de/~larsson
--
-- 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 2 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, write to the Free Software Foundation, Inc.,
-- 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
--
-- ---------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

use work.components.all;

-- entity írdafuse is -- REALLY BAD :-( ERROR CAUSED BY THE í CHARACTER !!!
   entity irdafuse is
     port(       
                  clk :  in std_ulogic;  -- clock = 16 MHz
                 nrst :  in std_ulogic;  -- *reset  
                txdin :  in std_ulogic;  -- IrDA TXD signal (high active)
               txdout : out std_ulogic;  -- fused IrDA TXD signal
                alive : out std_ulogic;  -- assumed that infrared emitter diode is ok (GREEN LED)
               killed : out std_ulogic;  -- fuse locked, IR LED would have been killed  (RED LED)
              revival :  in std_ulogic   -- revive fused IrDA signal, with a pull up resistor R, 
                                         -- it unlocks automatically after resting state
          );
   end irdafuse;

architecture behavior of irdafuse is

  type state_type is ( cool, ouch );                       -- cool : irdafuse is transparent to TXD and feels cool enough
                                                              -- ouch : fuse locked, infrared diode protected

  constant LIMIT : integer := 1360;                        -- LIMIT defines a fuse look threshold time t[s]. It is in
                                                           -- seconds given by t[s] = (LIMIT+1) / clk[Hz] = 85.05 us
  constant  DUTY : integer :=    3;                        -- DUTY defines duty cycle 1:n threshold with LIMIT = (n-1)
                                                           -- For duty cycle 1:n threshold with (n-1) = 1:4

  signal clr_s, cin_s, up_s, mincount_s, maxcount_s : std_ulogic;
  signal current_state, next_state : state_type; 
  signal cnt_s : integer range 0 to LIMIT; 
  signal div_s : integer range 0 to  DUTY; 

  begin

    clr_s <= '0';                                          -- synchronous clear signal not used yet

    sync_p: process ( nrst, clk, txdin )                   -- synchronize txdin signal for internal use
            begin
              if (nrst='0') then
                  up_s <= '0';
              elsif (clk'event and clk='1') then
                  up_s <= txdin;                           -- count down slowly while TXDin = '0' and 
              end if;                                      -- count up fast while TXDin = '1'
            end process;

     div_p: process ( nrst, clk, up_s )                    -- divide clk and generate carry signal for
            begin                                          -- the counter process cnt_p
                if (nrst='0') then
                     div_s <=  0;
                elsif (clk'event and clk='1') then
                    if (div_s/=DUTY) then                  -- definition of duty cycle 1:4 (1:(3+1)) with DUTY=3 
                        div_s <= div_s + 1;                 -- (3:16 < 1:5 < 1:4 but 1:4 required for PPM)
                    else
                        div_s <= 0;
                    end if;
                end if;
            end process;            

     up_p: process ( up_s, div_s ) 
           begin
                if (up_s='1') then
                    cin_s <= '1';                           -- cin_s always '1' for fast up count
                elsif (div_s/=DUTY) then 
                       cin_s <= '0';                        -- cin_s = '1' each 1/(3+1) clock for slow down count
                   else
                       cin_s <= '1';
                end if;
            end process;

     cnt_p: process ( nrst, clk, clr_s, cin_s, up_s )      -- synchronous up/down counter with synchronous clear and carry in
                                                           -- LIMIT defines a fuse look threshold time t = (LIMIT+1)/clk[Hz]
                                                           -- counter stops down count at 0 and stops up count at LIMIT
            begin                                          -- up count is faster than down count - see cin_s @ div_p: process
               if (nrst='0') then
                   cnt_s <=  0;
               elsif (clk'event and clk='1') then
                      if (clr_s = '1') then                -- if clear = '1' then clear counter
                          cnt_s <= 0;
                      elsif (cin_s='1') then               -- if carry in = '1' then count up/down
                             if (up_s='1') then            -- if up_s = '1' then count up
                                 if (cnt_s/=LIMIT) then    -- if count < LIMIT then count up
                                     cnt_s <= cnt_s + 1;
                                 end if;
                             else                          -- if up_s = '0' then count down
                                 if (cnt_s/=0) then        -- if count > 0 then count down
                                     cnt_s <= cnt_s - 1;
                                 end if;
                             end if;
                      end if;
               end if;
            end process;

    cmp_p: process (cnt_s)                                 -- counter comparator to check limits (0,LIMIT)
           begin
             if (cnt_s=LIMIT) then maxcount_s <= '1'; else maxcount_s <= '0'; end if;
             if (cnt_s=0)     then mincount_s <= '1'; else mincount_s <= '0'; end if;          
           end process;

    reg_p: process ( nrst, clk )
            begin
              if (nrst='0') then
                  current_state <= cool;
              elsif (clk'event and clk='1') then
                     current_state <= next_state;
              end if;
            end process;
    
    fuse_p: process ( current_state,maxcount_s,mincount_s,txdin,revival,clr_s,nrst )  -- fuse process state diagram
            begin                                                                     -- depends on up/down counter

              case current_state is                                               

                   when   cool => txdout <= txdin and (not clr_s) and nrst; killed <= '0'; alive <= '1';  -- feed through
                   
                                  if (maxcount_s='0') then 
                                      next_state <= cool;
                                  else 
                                      next_state <= ouch;
                                  end if;

                   when   ouch => txdout <=  '0';   killed <= '1'; alive <= '0';      -- lock fuse and switch infrared
                                                                                      -- transmitter diode off (TXD='0')
                                  if (mincount_s='0') then 
                                      next_state <= ouch;
                                  elsif (revival='1') then     
                                          next_state <= cool;
                                   else 
                                          next_state <= ouch;
                                end if;

                   when others => txdout <=  '0';   killed <= '1'; alive <= '0';      -- to secure the design
                   
                                  next_state <= cool;

                   -- WARNING : (mincount_s='1' AND maxcount_s='1') would results in an 
                   -- oscillation between both states : cool <-> ouch on any raising_edge(clk)
                   -- and this would result in a IR LED killing oscillation of the TDXOUT !!!

              end case;

            end process;
              
end behavior;

-- -----------------------------------------------------------------------------

<div align="center"><br /><script type="text/javascript"><!--
google_ad_client = "pub-7293844627074885";
//468x60, Created at 07. 11. 25
google_ad_slot = "8619794253";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />&nbsp;</div>