---
# System prepended metadata

title: How to use an external pull up resistor in FPGA?
tags: [FPGA]

---

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.

![usb-fpga-2.14-1600](https://hackmd.io/_uploads/Bk8kQ-XbWx.jpg)

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).