I use atmega32u4 (but believe it applies to all models). Here is the datasheet.

Consider the following C program (I use AVR-GCC 5.4.0):

#include <avr/io.h>
int main(void)
{
  PORTB |= 1 << PB5; /* pullup */
  DDRB |= 1 << PB0; /* LED */
  if (!(PINB & 1 << PB5))
    PORTB |= 1 << PB0; /* turn on LED */
  while (1) ;
}

There are two situations:

  • connect a 10cm wire to PB5 pin (the other end of the wire is in the air): the result is that sometimes after poweron the led is on, sometimes the led is not on.

  • do not connect anything to PB5 pin: the result is that after poweron led is never on.

I have a standard setup. Nothing tricky. If it does not work reliably, this gotcha MUST be documented in datasheet. This setup is supposed to deal with a stupid button. But sometimes it detects a keypress while there is no keypress.

The question is: where in datasheet there is a warning about this gotcha? And did somebody come across such case, or I'm the first in the world?

EDIT See also this question.

  • 1
    the internal pullup is pretty weak ... there may be too much radio interference in your area .... try using an external 1k resistor for pullup .... increase the value until failure occurs again, then use the largest value resistor that provides correct functionality – jsotola Aug 1 at 2:24
  • @jsotola ok, but I need to know where it is mentioned in datasheet (remember: it is a standard button, and I doubt that a 10 cm wire can have any influence even if "there may be too much radio interference in my area") – Igor Liferenko Aug 1 at 2:37
  • 3
    It's not in the datasheet because it's a basic characteristic of all CMOS circuits, and should have been covered in Digital Electronics 101. – Ignacio Vazquez-Abrams Aug 1 at 2:50
  • @jsotola OK, put it in the answer please. Now (as a newbie) I know that internal pullup is not useful for anything. Good to know this. – Igor Liferenko Aug 1 at 2:55
  • 1
    I know that internal pullup is not useful for anything ... that is not true ... it works great for switches .... also you abused the intended usage of the chip .... you should not have an antenna connected to the input pin – jsotola Aug 1 at 3:17
up vote 6 down vote accepted

did somebody come across such case, or I'm the first in the world?

You are not the first. I recently got bitten by the very same issue.

However, unless you are close to an unusually strong radio source, I do not think it has anything to do with electromagnetic interference. In my experience, the internal pullup is perfectly reliable for reading switches and push buttons, even on a breadboard with jumper wires acting as antennas. If you use pinMode() and digitalRead() instead of direct port access, you too will find the internal pullup is perfectly fine.

Before I give you the answer (suspense...), let's look closely at what your code does. The disassembly looks like this:

main:
    sbi  PORTB, PB5 ; turn on pullup on PB5
    sbi  DDRB,  PB0 ; set LED pin as output
    sbis PINB,  PB5 ; read PB5, if it is LOW then:
    sbi  PORTB, PB0 ;   turn on LED
0:  rjmp 0b         ; hang in an infinite loop

In the situation when the LED turns on, every instruction there executes in two CPU cycles, save for sbis, which takes a single cycle in this case. Now, let's look at the timings, and specifically at the states of the pullup and the input circuitry during each of the first seven CPU cycles:

cycle   instruction   pullup latch PINB5
----------------------------------------
   1   sbi PORTB, PB5   off    X     X
   2      cont.         off    X     X
   3   sbi DDRB,  PB0   on     X     X
   4      cont.         on    LOW    X
   5   sbis PINB, PB5   on     X    LOW
   6   sbi PORTB, PB0   on     X     X
   7      cont.         on     X     X

In the table above, “X” means “don't care”. Each instruction takes effect at the beginning of the next CPU cycle, when the clock's rising edge commits the result of the instruction to the affected flip-flops. That's why the pullup turns on only at the beginning of cycle 3. Now, since the pin did read LOW, that means the PB5 flip-flop was LOW while the CPU was reading it, during cycle 5. This in turn means that the synchronizing latch before that flip-flop was LOW during cycle 4.

Your expectation was for the pin to read HIGH. So let's see: how fast should the pin voltage have risen in order for the pin to indeed read HIGH? Since the input latch is transparent during the first half of each cycle, this means that the voltage should raise past the Schmitt trigger's threshold during cycle 3 and the first half cycle 4. So the rise time should be less than 1.5 cycles. Or rather 1.5 cycles minus the combined propagation delay of the PORTB5 flip-flop and the logic that controls the pullup from that flip-flop's output. Probably around 90 ns. That's short!

By now you have probably guessed: the culprit is not electromagnetic interference, it's stray capacitance. A simple calculation will show you that about three picofarads is enough to produce the effect you are seeing. This is the kind of stray capacitance you will find everywhere, even between the PCB traces of your Arduino board. Note that electromagnetic noise can add some unpredictability to what you see, as the pin is susceptible to it when it's completely floating, i.e. before you turn on the pullup, which makes the initial voltage (at the beginning of cycle 3) unpredictable. But once the pullup is on and the pin has settled, you won't care about noise anymore, unless it's unusually strong.

The solution to your problem is simply to wait for the pullup to charge the stray capacitance. A microsecond delay should be enough to fix the issue. Alternatively, use the Arduino functions instead of direct port access: they are so slow that you will not need any extra delay.

where in datasheet there is a warning about this gotcha?

In section 18.2.4 – Reading the Pin Value: “[The synchronizing latch] is needed to avoid metastability if the physical pin changes value near the edge of the internal clock, but it also introduces a delay.” (emphasis mine).

Edit: In a previous version of this answer, I incorrectly stated that sbi is a single cycle instruction, which required the voltage to rise in half a cycle instead of 1.5 cycles. The corrected timing is still short enough for stray capacitance to be a valid explanation of the observed behavior.


In summary:

  • The stray capacitance attached to the pin, together with the pullup resistor, for an RC circuit.
  • As the pin is initially floating, it's initial voltage is unpredictable.
  • When the pullup is turned on, the voltage starts to rise from whatever initial value it had to 5 V.
  • After some time, which can be typically of the order of the RC time constant, the input Schmitt trigger turns HIGH.
  • After some extra delay introduced by the synchronizer, the PINxn flip-flop turns HIGH.
  • If the CPU reads the PINx register before that happens, it gets a LOW reading.
  • Could you explain in a couple of words what this "latch" and "synchronizer" stuff is all about? Or recommend a resource which explains it in a more understandable way than the datasheet? – Igor Liferenko Aug 2 at 1:02
  • @IgorLiferenko: This is common electronics knowledge. The latch is a D latch, similar to a D flip-flop, but sensitive to clock levels instead of clock edges. The synchronizer synchronizes the input signal with the internal clock in order to prevent metastability, i.e. the “undecided” states in between LOW and HIGH. It's a non-trivial topic. You can try a Web search or this in depth tutorial (warning: not a light reading). – Edgar Bonet Aug 2 at 7:56
  • To sum it up: the delay from metastability synchronization input circuit sometimes is enough for the stray capacitance to settle, and sometimes not. And the stray capacitance has more chance (with other conditions being equal) to affect the input pin when reading of pin is delayed by 1/2 cycle than when by 1.5 cycles. Is it correct? – Igor Liferenko Aug 2 at 9:22
  • @IgorLiferenko: I couldn't understand your summary, so I added my own. – Edgar Bonet Aug 2 at 10:08

A test with an Arduino Uno.

I used the usb connector to power-on the arduino uno. The led is at PB5, so I have exchanged PB0 and PB5. My test is therefor not the same.

#define LED_PB  PB5   // pin 13, onboard led
#define INP_PB  PB0   // pin 8, antenna

void setup(void)
{
  noInterrupts();
  PORTB |= 1 << INP_PB; /* pullup */
  DDRB |= 1 << LED_PB; /* LED */
  if (!(PINB & 1 << INP_PB))
    PORTB |= 1 << LED_PB; /* turn on LED */
  while (1) ;
}

void loop()
{
}

Using it next to my computer and phone, sometimes the led stays on. I can even find a spot behind my computer monitor (with CCFL backlight) where the led always turns on.

Then I went outside, away from metals, wifi, and so on. The air humidity outside is 70% at the moment, which is high. I put it on a wooden table, so there is no charge by plastic. I used a battery to power the arduino uno. Then the led never turns on.

In such a clean environment, the internal pullup resistor was probably strong enough to pull the pin high during that very short time.

@IgorLiferenko, @sa_leinad gave the right answer. What you noticed is normal. It is totally normal. That behaviour can be expected. It will be worse when your circuit is not well designed.
A oscilloscope will not help. As soon as you connect a oscilloscope, you have changed something. It will also be very hard to detect that very short time (less than a microsecond).

In my opinion the influence by radio waves is only half of the problem. I think the electrical charge of the air, and the capacitive coupling of the wire with the air might have a larger effect.

You have made an antenna with the 10cm wire and are receiving radio waves which is translating to voltages on your input pin. This is why you don't have the same trouble when the wire is not connected.

According to www.csgnetwork.com/freqwavelengthcalc.html your 10cm wire is picking up frequencies of 750 MHz based on a quarter wavelength calculation.

The datasheet states that the internal pull up resistance is roughly between 20K - 50K ohms. As mentioned in the comments, this is quite weak.

There are two things that you can do that I can see:

The reason that this is not in the datasheet is because this is a general electronics/physics knowledge, not a characteristic of the micro-controller itself.

  • Is there any explanation to the fact that this effect manifests itself only right after enabling pullup, never after a delay (I used 10ms to check)? – Igor Liferenko Aug 1 at 6:13
  • 1
    @IgorLiferenko, how many explanations do you want? The radiowaves are reflected by metals and can be unpredictable. Perhaps the air is dry and is charged. The internal multiplexer might have influence. How scientific was your test? Did you try it with an other computer and other arduino board in another location? Have you made your own circuit with a atmega32u4, did you forget to decouple the vcc or are the crystal and 22pf capacitors not close to the atmega? Maybe the voltage is too low or there is a grounding error. I can think of about 20 explanations, and others perhaps another 80. – Jot Aug 1 at 6:28
  • @Jot If you are interested, try the simple setup as I described in OP - I'm sure you will get the same results. I just thought somebody came across such problem before... Now I'm sure that the only way for me to find out what is going on, is to get an oscilloscope... – Igor Liferenko Aug 1 at 6:37
  • @IgorLiferenko I did, see my answer. – Jot Aug 1 at 10:20

This actually is documented in the datasheet and illustrated by the logic diagram of the typical GPIO, to see what is really going on behind your compiled code you need to look at the generated assembly code and which registers are being accessed:

enter image description here

When you change one bit of an IO port, you are either modifying the 8 bit register on which that bit is mapped using the WRx signal or just the 1 bit register for the pin alone using the WPx signal. When you use the WPx signal to set or clear the bit, you don't need to know the states of the other pins so the discussion ends here. However, when you use the WRx signal to MODIFY a single bit, you need to know the states of the other 7 bits which means that your need to read the 8 bit port. You can either read the port LATCH using the RRx signal or you can read the actual physical pins using the RPx signal. Now when using the RRx signal, no amount of loading or noise on the pins themselves will affect what is read from the output of the port latch but when using the RPx signal, if a previous write to the port is followed by a read of the port, any parasitics or noise on the OUTPUT pins may cause a pin that you think that you just set to a one suddenly becomes a zero.

The reason this happens is because of how opcodes are pipelined. Writes to ports happen at the end of the last instruction clock but reads happen at the beginning so that there is essentially zero time between when you set that bit to a 1 and when you change some other bit (Read-modify-write fashion) so that bit is still a zero when it is read and then immediately written as a zero.

As illustrated below, this can be rectified by inserting a delay between write and read-modify-write opcodes to let the pin states stabilize. The delay must take into account the capacitive loading and noise environment

enter image description here

  • The WRx vs WPx distinction has nothing to do with whether you are writing a single bit or the whole register: WRx is the signal for writing the PORTxn flip-flop, whereas WPx is for writing PINxn (which is actually used to toggle PORTxn). And note that the OP did include a two-cycle delay between writing and reading. – Edgar Bonet Aug 10 at 8:17
  • You have apparently missed the entire point: When read-modify-write reads from the pins and then writes the latch, noise or delay on outputs can be re-written to the output and possibly changing the output's state unintentionally. Adding one cycle, tow cycles or a thousand cycles of delay may not be sufficient and understanding the mechanism of this uncertainty is the only way to build robust platforms that operate predictably under ALL circumstances. – John Taylor Aug 11 at 18:07
  • You also missed my point. I told you about a factual error in your answer. The appropriate response in this case is to edit the answer and fix the error. Your point that I still don't get is the one about “When read-modify-write reads from the pins and then writes the latch [...]”. Do you actually mean “reads from PINx and writes to PORTx”? If so, it's irrelevant. Nobody does that. Certainly not the OP. – Edgar Bonet Aug 11 at 19:33

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.