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;