Internal pullup in BX


A newbie here, to TinyFPGA and to Verilog (I’m an Ada programmer by trade)

My first attempt is to control an LED via a pushbutton, as in this discussion but inverted (push button to light LED).

All is OK so long as I use a 100k external pullup, but as I read the documentation

  • the FPGA provides an internal (weak?) pullup,
  • the default is for all pins to be set to input with internal pull-up.

This isn’t happening; without the external pullup, the input pin is just seeing noise (the LED is fully on when the button is pushed, half intensity when not).

How do I configure the internal pullup, if indeed that’s possible? advisable? I’ve looked on the web but most of the resources are for much more complex configurations, & I’d rather start small!


The pullup is not the default - I don’t know what documentation you read.

To configure the pin with the pullup, you use the SB_IO directive:

wire button;

SB_IO #(
  .PIN_TYPE(6'b 0000_01),
  .PULLUP(1'b 1)
) button_input(

Then you use button instead of PIN_1 to access the pin.


Thanks so much, worked a treat.

As to the doc I read - clearly brain fade, sorry.

Is there some documentation which says “you need to read these if you’re using Lattice FPGAs”?


I don’t really know of definitive documentation. The Lattice Ice40 documentation describes the directives like SB_IO and is useful for some other things but is not an easy read and tends to describe things from a Lattice tools perspective. For some things you need to read icestorm documentation as not everything that Lattice’s or other variants of Verilog support, is supported by icestorm. There are then a lot of useful Verilog tutorials.

(BTW, I didn’t know there were so many Ada programmers stil around, with you and @Fabien on this forum).


@Fabien’s postings on Twitter & the Adacore blog were what got me here!

Will check out the icestorm doc (already found the Ice40 docs & several tutorials), thanks


How can we enable many pullups with this notation? For example I want to enable pullups on the inputs PIN_1 through PIN_8 for eight total button inputs.


Yes, just change button_input to button_input[7:0] or whatever and declare the PACKAGE_PIN and D_IN_0 wires or registers with the same dimensions.

PACKAGE_PIN({PIN_8, PIN_7, PIN_6, PIN_5, PIN_4, PIN_3, PIN_2, PIN_1} ) probably works as well.

Or you can do each one separately.


Here’s the behaviour from the iCE40 LP/HX Family Data Sheet. You did read it somewhere :slight_smile:

Typical I/O Behavior During Power-up

The default configuration of the I/O pins in a device prior to configuration is tri-stated with a weak pull-up to VCCIO. The I/O pins will maintain the pre-configuration state until VCC and VCCIO (for I/O banks containing configuration I/Os) have reached levels, at which time the I/Os will take on the software user-configured settings only after a proper download/configuration. Unused I/Os are automatically blocked and the pull-up termination is disabled.


… but that describes what happens during power-up, not the default after configuration.


Another option, if you don’t want to change the Verilog, is to enable pullups in the PCF file thus:

set_io -pullup yes [port] [pin]


I had forgotten that that was supported, but I should have known -


Dave, Is there any way to switch the internal pullup resistor on and off dynamically? For my Arduino implementation I would like to be able to implement pinMode(pin, INPUT_PULLUP);


There are two I3C pins on the UltraPlus that have dynamic pullup control (with SB_IO_I3C). No other iCE40 pins have controllable pullups.



The UltraPlus supports different pullup resistor values. Is there a way to define the resistor value you want in the PCF file or as a SB_IO parameter ?
I tried a lot and was not able to switch the value, but that was some month ago.
The Icecube syntax in the PCF file is:
-pullup_resistor 10K
for a 10k Ohm, but there are also 3.3k, 6.6k and so on…



Latest nextpnr supports the -pullup_resistor in the PCF like icecube.

Both arachne-pnr and nextpnr should also support the PULLUP_RESISTOR attribute on an SB_IO:

SB_IO #(


Thank you Dave, that works, also with my old Arachne-pnr version. I tried:
/* synthesis PULLUP_RESISTOR = “10K” */
which did not work.

It’s a bit offtopic here, but the other thing I could not get to work with UltraPlus and Yosys/Arachne was the HFOSC Trimming. Can you show me the Primitive name and the portnames/parameters for that? That would by awesome…



Those synthesis comments are horrible non-standard Verilog from the early 90s, and quite frankly belong there.

Use the proper Verilog-2001 (* *) attribute syntax and everything (Yosys, iCEcube, etc) will be happy.

As for trimming, see