1 |
2 |
buenos |
----------------------------------------------------------------------------------
|
2 |
|
|
-- Engineer: Istvan Nagy
|
3 |
|
|
-- Create Date: 10/06/2024 10:10:13 AM
|
4 |
|
|
---Version 1.0
|
5 |
|
|
-- License: 0BSD, no restrictions for use, no need to publish modified versions.
|
6 |
|
|
-- The BSD 0-clause license: Copyright (C) 2024 by Istvan Nagy buenoshun@gmail.com
|
7 |
|
|
-- Permission to use, copy, modify, and/or distribute this software for any purpose
|
8 |
|
|
-- with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND
|
9 |
|
|
-- THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.
|
10 |
|
|
-- Module Name: powerseq_mod - Behavioral
|
11 |
|
|
-- Target devices: Microchip Igloo preferred, due to attributes.
|
12 |
|
|
-- This code is a universal power sequencer block used inside glue logic FPGAs,
|
13 |
|
|
-- for complex digital boards. It supports up to 128 voltage rails. If less is
|
14 |
|
|
-- used, then simply tie the powergood inputs fo the unused rails to constant 1.
|
15 |
|
|
-- The top-level code needs to assign the numbered rail enable/pg signals to
|
16 |
|
|
-- actual rail enable/powergood top level ports. For example:
|
17 |
|
|
-- P1V8SBY_PCH_EN <= PSEQ_RAIL_EN_LOCAL(6);
|
18 |
|
|
-- PSEQ_RAIL_PG(6) <= P1V8SBY_PCH_PG;
|
19 |
|
|
-- If a rail failed, the module captures the conditions and shuts all rails down,
|
20 |
|
|
-- except if we are in "forced power on" mode, then it turns/keeps all rails on.
|
21 |
|
|
-- The rails that failed will have a '1', rail-254 means thermal shutdown.
|
22 |
|
|
-- We can slow down the sequence to be able to use TopJtag probe for debugging,
|
23 |
|
|
-- by making the tick_counter longer, by commenting/uncommenting at the SIG def.
|
24 |
|
|
-- The module communicates with a power master through all_on and all_pgood.
|
25 |
|
|
----------------------------------------------------------------------------------
|
26 |
|
|
library IEEE;
|
27 |
|
|
use IEEE.STD_LOGIC_1164.ALL;
|
28 |
|
|
use IEEE.NUMERIC_STD.ALL;
|
29 |
|
|
library IEEE;
|
30 |
|
|
use IEEE.STD_LOGIC_1164.ALL;
|
31 |
|
|
use IEEE.STD_LOGIC_ARITH.ALL;
|
32 |
|
|
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
33 |
|
|
--entity header ----------------------------------------------------------------
|
34 |
|
|
entity powerseq_mod is
|
35 |
|
|
Port (
|
36 |
|
|
clk : in std_logic; --25MHz clock
|
37 |
|
|
reset_n : in std_logic; --FPGA reset, needs 1ms from standby 3.3V on
|
38 |
|
|
forcepoweron : in std_logic; --from dip switch, avoid failure response
|
39 |
|
|
PSEQ_RAIL_EN : out std_logic_vector(127 downto 0); --map to rails
|
40 |
|
|
PSEQ_RAIL_PG : in std_logic_vector(127 downto 0); --map to rails
|
41 |
|
|
thermal_n : in std_logic; --thermal shutdown, externally combine multiple sources
|
42 |
|
|
failed_rails : out std_logic_vector(255 downto 0); --bits=1 for failed rails
|
43 |
|
|
pfailure : out std_logic; --assers during failure --1 if one or more railes failed.
|
44 |
|
|
tick_out : out std_logic; --available if needed outside, 1pulse in every several thousand clk
|
45 |
|
|
pseqstate_out : out std_logic_vector(3 downto 0); --we can monitor status through a pin with TopJtag
|
46 |
|
|
all_on : in std_logic; --power master ordered the sequence to commence on
|
47 |
|
|
all_pgood: out std_logic --tell the power master that all is on
|
48 |
|
|
);
|
49 |
|
|
end powerseq_mod;
|
50 |
|
|
|
51 |
|
|
--architecture start ------------------------------------------------------------
|
52 |
|
|
architecture Behavioral of powerseq_mod is
|
53 |
|
|
|
54 |
|
|
attribute syn_preserve : boolean;
|
55 |
|
|
attribute syn_preserve of Behavioral: architecture is true;
|
56 |
|
|
|
57 |
|
|
-- INTERNAL SIGNALS -------------------------------------------------------------
|
58 |
|
|
SIGNAL tick: std_logic;
|
59 |
|
|
SIGNAL tick1: std_logic;
|
60 |
|
|
SIGNAL pseqstate: std_logic_VECTOR(3 DOWNTO 0);
|
61 |
|
|
SIGNAL delay_counter: std_logic_VECTOR(15 DOWNTO 0);
|
62 |
|
|
SIGNAL rail_counter: integer range 0 to 127;
|
63 |
|
|
SIGNAL PSEQ_RAIL_EN_LOCAL : std_logic_vector(127 downto 0);
|
64 |
|
|
|
65 |
|
|
SIGNAL tick_counter: std_logic_VECTOR(15 DOWNTO 0); --counts ticks of 40us, normal operation
|
66 |
|
|
--SIGNAL tick_counter: std_logic_VECTOR(21 DOWNTO 0); --counts ticks of 2.5ms, for board debug
|
67 |
|
|
--SIGNAL tick_counter: std_logic_VECTOR(3 DOWNTO 0); --counts ticks of 640ns for simulation
|
68 |
|
|
|
69 |
|
|
--architecture body start -------------------------------------------------------
|
70 |
|
|
begin
|
71 |
|
|
|
72 |
|
|
pseqstate_out <= pseqstate;
|
73 |
|
|
PSEQ_RAIL_EN <= PSEQ_RAIL_EN_LOCAL;
|
74 |
|
|
|
75 |
|
|
process (clk, reset_n)
|
76 |
|
|
begin
|
77 |
|
|
if (reset_n='0') then
|
78 |
|
|
pseqstate <= (others => '0');
|
79 |
|
|
tick <= '0';
|
80 |
|
|
tick1 <= '0';
|
81 |
|
|
tick_out <= '0';
|
82 |
|
|
tick_counter <= (others => '0');
|
83 |
|
|
delay_counter <= (others => '0');
|
84 |
|
|
rail_counter <= 0;
|
85 |
|
|
all_pgood <= '0';
|
86 |
|
|
PSEQ_RAIL_EN_LOCAL <= (others => '0');
|
87 |
|
|
failed_rails <= (others => '0');
|
88 |
|
|
pfailure <= '0';
|
89 |
|
|
else
|
90 |
|
|
if (clk'event and clk = '1') then
|
91 |
|
|
tick_counter <= tick_counter +1;
|
92 |
|
|
if (tick_counter = 0) then tick1 <= '1'; else tick1 <= '0'; end if;
|
93 |
|
|
tick <= tick1;
|
94 |
|
|
tick_out <= tick1;
|
95 |
|
|
if (tick='1') then
|
96 |
|
|
case ( pseqstate ) is
|
97 |
|
|
|
98 |
|
|
when "0000" => --after reset (S5 standby)
|
99 |
|
|
if (all_on='1' or forcepoweron='1') then pseqstate <= "0001"; end if; --master commanded power up
|
100 |
|
|
all_pgood <= '0';
|
101 |
|
|
delay_counter <= (others => '0');
|
102 |
|
|
rail_counter <= 0;
|
103 |
|
|
pfailure <= '0';
|
104 |
|
|
failed_rails <= (others => '0');
|
105 |
|
|
|
106 |
|
|
when "0001" => --sequencing up temporary state (S5->S0)
|
107 |
|
|
all_pgood <= '0';
|
108 |
|
|
PSEQ_RAIL_EN_LOCAL(rail_counter) <= '1';
|
109 |
|
|
if (PSEQ_RAIL_PG(rail_counter)='1') then --rail pg is asserted
|
110 |
|
|
delay_counter <= (others => '0');
|
111 |
|
|
if (rail_counter = 127) then --last one
|
112 |
|
|
pseqstate <= "0011"; --fully on state
|
113 |
|
|
else --not the last one yet, step to next
|
114 |
|
|
rail_counter <= rail_counter +1;
|
115 |
|
|
end if;
|
116 |
|
|
elsif (delay_counter="0111111111111111") then --rail failed with 1.3s timeout
|
117 |
|
|
if (forcepoweron='1') then --if forced then continue after timeout
|
118 |
|
|
delay_counter <= (others => '0');
|
119 |
|
|
if (rail_counter = 127) then --last one
|
120 |
|
|
pseqstate <= "0011"; --fully on state
|
121 |
|
|
else --not the last one yet, step to next
|
122 |
|
|
rail_counter <= rail_counter +1;
|
123 |
|
|
end if;
|
124 |
|
|
else --if not forced then make it fail after timeout
|
125 |
|
|
pseqstate <= "0111"; --failed state
|
126 |
|
|
delay_counter <= (others => '0');
|
127 |
|
|
pfailure <= '1';
|
128 |
|
|
failed_rails(rail_counter) <= '1';
|
129 |
|
|
end if;
|
130 |
|
|
else --waiting
|
131 |
|
|
delay_counter <= delay_counter +1;
|
132 |
|
|
end if;
|
133 |
|
|
|
134 |
|
|
when "0011" => --fully on stable state (S0)
|
135 |
|
|
delay_counter <= (others => '0');
|
136 |
|
|
all_pgood <= '1';
|
137 |
|
|
if (forcepoweron='0' and all_on='0') then --master commanded power down
|
138 |
|
|
pseqstate <= "0010";
|
139 |
|
|
rail_counter <= 127;
|
140 |
|
|
elsif (forcepoweron='0' and PSEQ_RAIL_PG /= PSEQ_RAIL_EN_LOCAL) then --a rail that was already on now failed
|
141 |
|
|
failed_rails(127 downto 0) <= not PSEQ_RAIL_PG;
|
142 |
|
|
pseqstate <= "0111";
|
143 |
|
|
pfailure <= '1';
|
144 |
|
|
elsif (forcepoweron='0' and thermal_n = '0') then --overheating shutdown
|
145 |
|
|
failed_rails(254) <= '1'; --rail-254 means thermal
|
146 |
|
|
pseqstate <= "0111";
|
147 |
|
|
pfailure <= '1';
|
148 |
|
|
end if;
|
149 |
|
|
|
150 |
|
|
when "0010" => --sequencing down temporary state (S0->S5)
|
151 |
|
|
--all_pgood <= '0'; --if we want pgood to go away sooner
|
152 |
|
|
PSEQ_RAIL_EN_LOCAL(rail_counter) <= '0';
|
153 |
|
|
if (delay_counter="0000000001111101") then --5ms delay
|
154 |
|
|
delay_counter <= (others => '0');
|
155 |
|
|
if (rail_counter = 0) then --last one
|
156 |
|
|
pseqstate <= "0000"; --standby state
|
157 |
|
|
else --not the last one yet, step to next
|
158 |
|
|
rail_counter <= rail_counter -1;
|
159 |
|
|
end if;
|
160 |
|
|
else --waiting
|
161 |
|
|
delay_counter <= delay_counter +1;
|
162 |
|
|
end if;
|
163 |
|
|
|
164 |
|
|
when "0111" => --error state
|
165 |
|
|
all_pgood <= '0';
|
166 |
|
|
PSEQ_RAIL_EN_LOCAL <= (others => '0'); --turn off stay off until input pcycle
|
167 |
|
|
if (all_on='0') then pseqstate <= "0000"; end if; --master commanded power down
|
168 |
|
|
|
169 |
|
|
when others =>
|
170 |
|
|
pseqstate <= "0000";
|
171 |
|
|
end case;
|
172 |
|
|
end if;
|
173 |
|
|
end if;
|
174 |
|
|
end if;
|
175 |
|
|
end process;
|
176 |
|
|
|
177 |
|
|
--end file ----------------------------------------------------------------------
|
178 |
|
|
end Behavioral;
|