OpenCores
URL https://opencores.org/ocsvn/powerseq/powerseq/trunk

Subversion Repositories powerseq

[/] [powerseq/] [trunk/] [powerseq_mod.vhd] - Rev 2

Compare with Previous | Blame | View Log

----------------------------------------------------------------------------------
-- Engineer: Istvan Nagy
-- Create Date: 10/06/2024 10:10:13 AM 
---Version 1.0
-- License: 0BSD, no restrictions for use, no need to publish modified versions. 
--   The BSD 0-clause license: Copyright (C) 2024 by Istvan Nagy buenoshun@gmail.com 
--   Permission to use, copy, modify, and/or distribute this software for any purpose 
--   with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND 
--   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.
-- Module Name: powerseq_mod - Behavioral
-- Target devices: Microchip Igloo preferred, due to attributes.
-- This code is a universal power sequencer block used inside glue logic FPGAs,
--  for complex digital boards. It supports up to 128 voltage rails. If less is
--  used, then simply tie the powergood inputs fo the unused rails to constant 1.
--  The top-level code needs to assign the numbered rail enable/pg signals to 
--  actual rail enable/powergood top level ports. For example:
--     P1V8SBY_PCH_EN <= PSEQ_RAIL_EN_LOCAL(6);
--     PSEQ_RAIL_PG(6) <= P1V8SBY_PCH_PG;
--  If a rail failed, the module captures the conditions and shuts all rails down,
--  except if we are in "forced power on" mode, then it turns/keeps all rails on.
--  The rails that failed will have a '1', rail-254 means thermal shutdown.
--  We can slow down the sequence to be able to use TopJtag probe for debugging,
--  by making the tick_counter longer, by commenting/uncommenting at the SIG def.
--  The module communicates with a power master through all_on and all_pgood.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
--entity header  ----------------------------------------------------------------
entity powerseq_mod is
    Port ( 
           clk  : in std_logic; --25MHz clock
           reset_n  : in std_logic; --FPGA reset, needs 1ms from standby 3.3V on
           forcepoweron  : in std_logic; --from dip switch, avoid failure response
           PSEQ_RAIL_EN : out std_logic_vector(127 downto 0); --map to rails
           PSEQ_RAIL_PG : in std_logic_vector(127 downto 0); --map to rails
           thermal_n : in std_logic; --thermal shutdown, externally combine multiple sources 
           failed_rails : out std_logic_vector(255 downto 0); --bits=1 for failed rails
           pfailure : out std_logic; --assers during failure --1 if one or more railes failed.
           tick_out : out std_logic; --available if needed outside, 1pulse in every several thousand clk
           pseqstate_out  : out std_logic_vector(3 downto 0); --we can monitor status through a pin with TopJtag
           all_on  : in std_logic; --power master ordered the sequence to commence on
           all_pgood: out std_logic --tell the power master that all is on
           );
end powerseq_mod;
 
--architecture start ------------------------------------------------------------
architecture Behavioral of powerseq_mod is
 
attribute syn_preserve : boolean;
attribute syn_preserve of Behavioral: architecture is true;
 
-- INTERNAL SIGNALS -------------------------------------------------------------
    SIGNAL tick:  std_logic;
    SIGNAL tick1:  std_logic;
    SIGNAL pseqstate:  std_logic_VECTOR(3 DOWNTO 0);
    SIGNAL delay_counter:  std_logic_VECTOR(15 DOWNTO 0);
    SIGNAL rail_counter:  integer range 0 to 127;
    SIGNAL PSEQ_RAIL_EN_LOCAL : std_logic_vector(127 downto 0);
 
    SIGNAL tick_counter:  std_logic_VECTOR(15 DOWNTO 0); --counts ticks of 40us, normal operation
    --SIGNAL tick_counter:  std_logic_VECTOR(21 DOWNTO 0); --counts ticks of 2.5ms, for board debug
    --SIGNAL tick_counter:  std_logic_VECTOR(3 DOWNTO 0); --counts ticks of 640ns for simulation
 
--architecture body start -------------------------------------------------------
begin
 
pseqstate_out <= pseqstate;
PSEQ_RAIL_EN <= PSEQ_RAIL_EN_LOCAL;
 
process (clk, reset_n)                               
begin                                 
if (reset_n='0') then                               
   pseqstate <= (others => '0');                          
   tick <= '0';
   tick1 <= '0';  
   tick_out <= '0';  
   tick_counter <= (others => '0');                          
   delay_counter <= (others => '0');                          
   rail_counter <= 0;                          
   all_pgood <= '0';                            
   PSEQ_RAIL_EN_LOCAL <= (others => '0');                          
   failed_rails <= (others => '0');                          
   pfailure <= '0';                         
else                                 
  if (clk'event and clk = '1') then                         
     tick_counter <= tick_counter +1;                         
     if (tick_counter = 0) then tick1 <= '1'; else tick1 <= '0'; end if;   
     tick <= tick1;       
     tick_out <= tick1;     
     if (tick='1') then                          
        case ( pseqstate ) is                     
 
              when "0000" => --after reset (S5 standby)             
                if (all_on='1' or forcepoweron='1') then pseqstate <= "0001"; end if; --master commanded power up    
                all_pgood <= '0';               
                delay_counter <= (others => '0');             
                rail_counter <= 0;             
                pfailure <= '0';               
                failed_rails <= (others => '0'); 
 
              when "0001" => --sequencing up temporary state (S5->S0)            
                all_pgood <= '0';      
                PSEQ_RAIL_EN_LOCAL(rail_counter) <= '1';           
                if (PSEQ_RAIL_PG(rail_counter)='1') then  --rail pg is asserted          
                    delay_counter  <= (others => '0');   
                    if (rail_counter = 127) then --last one       
                       pseqstate <= "0011";  --fully on state    
                    else --not the last one yet, step to next     
                       rail_counter <= rail_counter +1;             
                    end if;            
                elsif (delay_counter="0111111111111111") then --rail failed with 1.3s timeout          
                  if (forcepoweron='1') then --if forced then continue after timeout       
                    delay_counter  <= (others => '0');       
                    if (rail_counter = 127) then --last one       
                       pseqstate <= "0011";  --fully on state    
                    else --not the last one yet, step to next     
                       rail_counter <= rail_counter +1;          
                    end if;            
                  else  --if not forced then make it fail after timeout     
                    pseqstate <= "0111"; --failed state         
                    delay_counter  <= (others => '0');        
                    pfailure <= '1';           
                    failed_rails(rail_counter) <= '1';           
                  end if;              
                else --waiting                
                   delay_counter <= delay_counter +1;           
                end if;                
 
              when "0011" => --fully on stable state (S0)            
                delay_counter <= (others => '0');             
                all_pgood <= '1';               
                if (forcepoweron='0' and all_on='0') then  --master commanded power down        
                    pseqstate <= "0010";
                    rail_counter <= 127;
                elsif (forcepoweron='0' and PSEQ_RAIL_PG /= PSEQ_RAIL_EN_LOCAL) then --a rail that was already on now failed    
                    failed_rails(127 downto 0) <=  not PSEQ_RAIL_PG;          
                    pseqstate <= "0111";     
                    pfailure <= '1';       
                elsif (forcepoweron='0' and thermal_n = '0') then  --overheating shutdown
                    failed_rails(254) <= '1'; --rail-254 means thermal       
                    pseqstate <= "0111"; 
                    pfailure <= '1';                    
                end if;                
 
              when "0010" => --sequencing down temporary state (S0->S5)            
                --all_pgood <= '0';   --if we want pgood to go away sooner     
                PSEQ_RAIL_EN_LOCAL(rail_counter) <= '0';
                if (delay_counter="0000000001111101") then --5ms delay             
                    delay_counter  <= (others => '0');        
                    if (rail_counter = 0) then --last one       
                       pseqstate <= "0000";  --standby state     
                    else --not the last one yet, step to next     
                       rail_counter <= rail_counter -1;
                    end if;            
                else --waiting                
                   delay_counter <= delay_counter +1;           
                end if;                
 
              when "0111" => --error state               
                all_pgood <= '0';               
                PSEQ_RAIL_EN_LOCAL <= (others => '0'); --turn off stay off until input pcycle     
                if (all_on='0') then pseqstate <= "0000"; end if; --master commanded power down    
 
              when others =>                 
                  pseqstate <= "0000";             
         end case;                       
      end if;                          
   end if;                             
end if;                                
end process;                                
 
--end file ----------------------------------------------------------------------
end Behavioral;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.