Forum Discussion
Unstable fpga programming using HPS(Agilex3)
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity legacy_baseline_top is
port (
-- Clock and Reset
fpga_reset_n : in std_logic;
fpga_clk_100 : in std_logic;
);
end entity legacy_baseline_top;
architecture rtl of legacy_baseline_top is
-- Component declarations
component altera_std_synchronizer is
generic (
depth : integer := 3
);
port (
clk : in std_logic;
reset_n : in std_logic;
din : in std_logic;
dout : out std_logic
);
end component;
component qsys_top is
port (
clk_100_clk : in std_logic := 'X'; -- clk
clock_bridge_0_out_clk_clk : out std_logic; -- clk
o_pma_cu_clk_clk : out std_logic_vector(0 downto 0); -- clk
iopll_0_locked_export : out std_logic; -- export
reset_bridge_0_in_reset_reset_n : in std_logic := 'X'; -- reset_n
reset_reset_n : in std_logic := 'X'; -- reset_n
reset_bridge_pll_in_reset_reset_n : in std_logic := 'X'; -- reset_n
ninit_done_ninit_done : out std_logic; -- ninit_done
h2f_reset_reset : out std_logic -- reset
);
end component qsys_top;
-- Internal signals
signal system_clk_100 : std_logic;
signal pll_clk_100 : std_logic;
signal pll_locked : std_logic;
signal pll_locked_stable : std_logic;
signal ninit_done : std_logic;
signal combined_reset_n : std_logic;
signal system_reset_n : std_logic;
signal pll_reset_n : std_logic;
signal pll_reset_sync_n : std_logic;
signal h2f_reset : std_logic;
begin
-- Concurrent signal assignments
combined_reset_n <= fpga_reset_n and (not h2f_reset) and (not ninit_done);
pll_reset_n <= fpga_reset_n and (not ninit_done);
system_clk_100 <= fpga_clk_100;
-- Reset synchroniser
fpga_reset_n_sync : altera_std_synchronizer
generic map (
depth => 3
)
port map (
clk => system_clk_100,
reset_n => combined_reset_n,
din => '1',
dout => system_reset_n
);
-- Reset synchroniser
pll_reset_n_sync : altera_std_synchronizer
generic map (
depth => 3
)
port map (
clk => system_clk_100,
reset_n => pll_reset_n,
din => '1',
dout => pll_reset_sync_n
);
pll_stable_filter : block
constant CLK_FREQ_HZ : positive := 100_000_000;
constant STABLE_CYCLES : positive := CLK_FREQ_HZ;
signal counter : natural range 0 to STABLE_CYCLES := 0;
signal stable_r : std_logic := '0';
begin
p_filter : process (system_clk_100, pll_reset_sync_n) is
begin
if pll_reset_sync_n = '0' then
counter <= 0;
stable_r <= '0';
elsif rising_edge(system_clk_100) then
if pll_locked = '0' then
counter <= 0;
stable_r <= '0';
elsif counter = STABLE_CYCLES - 1 then
stable_r <= '1';
else
counter <= counter + 1;
stable_r <= '0';
end if;
end if;
end process p_filter;
pll_locked_stable <= stable_r;
end block pll_stable_filter;
soc_inst : qsys_top
port map (
clk_100_clk => system_clk_100,
clock_bridge_0_out_clk_clk => pll_clk_100, --clock out from pll
reset_reset_n => system_reset_n,
iopll_0_locked_export => pll_locked,
reset_bridge_pll_in_reset_reset_n => pll_reset_n, --Reset to pll
reset_bridge_0_in_reset_reset_n => pll_locked_stable, --This goes into a reset bridge in nios with deassert synced to output clock from pll
ninit_done_ninit_done => ninit_done,
h2f_reset_reset => h2f_reset
);Hi, thank you for answering, I have included your suggestions in my code.
Here is the top file of my project, I have removed everything not related to clk/reset.
Everything inside qsys including all HPS bridges is clocked from the pll_clk_100 and reset using the pll_locked_stable after it has been syncronized to pll_clk_100 so it has a syncronized deassert.
Do you see anything wrong with it?
How will the h2f_reset behave during a reconfiguration, do I need to include it in the reset of the pll?
How long do I need to wait for stable locked from pll?, I currently wait 1 second
I also wonder what will happen if I have any in flight transactions on any of the hps bridges when I start programming the FPGA, cause I use the f2sdram as a communication channel between niosV on the fpga and the HPS, do I need to shut this off manually before fpga programming or will the fpga-manager handle this automatically?
Hi,
Thanks for sharing the top-level code, the nINIT_DONE and PLL-lock gating is on the right track. A few items stand out that likely explain why it is still intermittent.
1. Include h2f_reset in PLL reset
You gate fabric logic with h2f_reset, but PLL reset only uses ninit_done:
pll_reset_n <= fpga_reset_n and (not ninit_done) and (not h2f_reset);
During reconfiguration the HPS asserts h2f_reset as part of the bridge warm-reset handshake. The PLL should also be held in reset when h2f_reset is active, so bridge clocking stops cleanly before the fabric is wiped.
2. Avoid clocking HPS bridges from the fabric PLL
You mentioned all HPS bridges are clocked from pll_clk_100. This is the most likely root cause of the remaining intermittent failure.
During overlay programming the fabric PLL is destroyed and rebuilt while the HPS keeps running. nINIT_DONE gating protects logic after user mode is reached, but it cannot prevent the PLL clock from glitching or stopping during the programming window.
Recommended split:
fpga_clk_100 (pin clock) → HPS bridge infrastructure, reset synchronizers, handshake logic PLL outputs → application logic only (Nios, custom IP, derived clocks)
This matches your observation that direct pin clocking is always stable.
3. Connect h2f_reset to bridge AXI reset in Platform Designer
Ensure h2f_reset is connected to f2sdram_axi_reset (and other bridge resets as applicable). The HPS uses this handshake to freeze/reset bridges during reconfiguration.
4. PLL lock wait time
1 second is very conservative. IOPLL lock is typically well below 1 ms. The filter itself is fine, but the intermittent failure is unlikely due to insufficient wait time, it is more related to bridge clocking and in-flight transactions.
5. In-flight f2sdram transactions, manual quiesce required
The Linux fpga-manager disables/freezes bridges before programming, but it does not stop your Nios application or HPS-side protocol.
If either side has active f2sdram traffic when programming begins, in-flight AXI transactions can hang the system (consistent with SMMU timeout and cold reset).
Before each overlay apply:
• Stop HPS-side f2sdram access
• Signal Nios to stop and idle
• Wait until both sides confirm idle
• Apply overlay
• After reconfig (nINIT_DONE deasserted + PLL re-lock), restart communication
Suggested debug steps
• Apply the pll_reset_n fix above
• Move bridge clocking to fpga_clk_100; keep PLL for application logic only
• Add Signal Tap on ninit_done, h2f_reset, pll_locked, pll_clk_100 during overlay apply
• Test reconfig loop with all f2sdram traffic stopped
If you can confirm whether f2sdram is active during the reconfig attempts, that would help narrow this further.
Regards,
Tien Fong