Good news: using an external pull-up [resistor](https://www.onzuu.com/category/resistors) with an [FPGA](https://www.ampheo.com/c/fpgas-field-programmable-gate-array) is simple. The trick is to think in terms of who drives the line and when you let the resistor do its job.

I’ll split it into the two common cases:
1. Input pin with external pull-up (buttons, status lines, etc.)
2. Open-drain / wired-OR signal with external pull-up (I²C-style, interrupt lines, etc.)
**1. Input pin with an external pull-up**
**Hardware:**
* Signal pin ↔ FPGA input
* Same signal pin → resistor (e.g. 10 kΩ) → VCC
* Optional: button / switch to GND, or an open-collector output from another device.
**What happens electrically:**
* When nobody pulls the line low → resistor pulls it HIGH.
* When button/device pulls the line to GND → the input reads LOW.
**FPGA side (HDL):**
Just declare the pin as a normal input; nothing special in the code:
```
// Verilog
input wire btn_in; // externally pulled up
```
```
-- VHDL
btn_in : in std_logic; -- externally pulled up
```
You then interpret it in logic, e.g. active-low button:
`wire button_pressed = (btn_in == 1'b0);`
**Constraints / pin settings:**
* Map btn_in to the correct package pin.
* IO standard: e.g. LVCMOS33.
* Usually disable the internal pull-up (you already have one outside). If you leave it on, it just forms a parallel resistor (not fatal, but wastes current and changes the effective pull-up value).
Example (Xilinx .xdc):
```
set_property PACKAGE_PIN W5 [get_ports btn_in]
set_property IOSTANDARD LVCMOS33 [get_ports btn_in]
set_property PULLUP FALSE [get_ports btn_in]
```
**2. Open-drain / shared line with external pull-up**
This is the more interesting case. Here the external pull-up defines HIGH, and one or more devices (including the FPGA) can pull the line LOW. Example use-cases:
* I²C-like bus
* Shared interrupt line (multiple devices can pull low)
* “READY/BUSY” lines wired-OR with other devices
**Hardware:**
* Signal ↔ FPGA pin
* Signal → resistor → VCC
* Possibly several other devices on the same net that can pull it low.
**Key idea for FPGA:**
You never drive a 1 against the pull-up.
You either:
* Drive 0 → force the line LOW
* Drive Z (high-impedance) → let the pull-up make it HIGH
**2.1 Verilog open-drain pattern**
```
// Top-level
inout wire od_line; // open-drain line with external pull-up
reg drive_low; // 1 = pull low, 0 = release
wire line_in; // what we read from the pin
// Drive logic: 0 or Z, never 1
assign od_line = drive_low ? 1'b0 : 1'bz;
// Read back the line
assign line_in = od_line;
```
Usage:
* To output LOW: drive_low <= 1'b1;
* To output HIGH: drive_low <= 1'b0; (tri-state, pull-up takes it high)
* To read the bus: use line_in.
Constraint example (Xilinx):
```
set_property PACKAGE_PIN U4 [get_ports od_line]
set_property IOSTANDARD LVCMOS33 [get_ports od_line]
set_property DRIVE 8 [get_ports od_line] ; drive strength for low
set_property SLEW SLOW [get_ports od_line]
set_property PULLUP FALSE [get_ports od_line] ; because we use external
```
**2.2 VHDL open-drain pattern**
```
-- Top-level
od_line : inout std_logic;
signal drive_low : std_logic;
signal line_in : std_logic;
-- Drive logic
od_line <= '0' when drive_low = '1' else 'Z';
-- Read back
line_in <= od_line;
```
**3. When not to use open-drain style**
If the external pull-up is just there for safety and the FPGA is the only active driver on that net, you can treat it as a normal push-pull output:
* Configure the pin as a plain output.
* Drive 0 and 1 as usual.
* The resistor is then basically just a weak “failsafe” if the pin is high-Z during reset.
But if another device may pull it low, then you must treat it as open-drain (0/Z only) to avoid bus contention ([FPGA](https://www.ampheoelec.de/c/fpgas-field-programmable-gate-array) driving 1 while someone else drives 0 → big current spike).
**4. Quick checklist**
To “use an externally pulled-up resistor in FPGA” correctly:
**1. Decide the role of the pin:**
* Input only → just declare it as input; external circuitry + pull-up define the level.
* Open-drain I/O → use inout and drive 0/Z, never 1.
**2. Set constraints:**
* Correct package pin + I/O standard.
* Turn off internal pull-up if you already have an external one (optional but cleaner).
**3. Check the circuit:**
* Resistor size in a sensible range (e.g. 2.2–10 kΩ depending on speed/fanout).
* Ensure no active driver ever forces HIGH against someone else forcing LOW (unless you intentionally design a push-pull bus and guarantee exclusive ownership).