UDRE doesn't do what I thought it did

I was having a very frustrating problem trying to make my Arduino behave as the keyboard for my XT - one particular piece of code (a 1ms delay loop) seemed to be taking much longer to run on the Arduino than it should, causing the Arduino to think that the clock low pulse from the XT was shorter than it was, causing it to fail to recognize the "reset keyboard" command.

After much hair-pulling, I tracked it down to the UDRE (UART (Univeral Asynchronous Receiver/Transmitter) Data Register Empty) interrupt, which fires to tell the program that a space has been cleared in the UART transmission buffer so the program can queue up the next byte that needs to be sent over serial (which is usually nothing, since the Arduino doesn't need to send anything to the host PC at that point). Or at least, that's what I thought it did - however, it turns out that it's not "a space has been cleared" but "a space is available" - i.e. it's level triggered, not edge triggered. That means that if we don't put anything out onto the serial line when the interrupt is received, it'll just fire again as soon as interrupts are turned on again. That explains why my 1ms delay loop was taking 20ms - it was spending most of its time servicing spurious interrupts instead of counting down. The fix was simple, just use the "transmit complete" interrupt instead of UDRE.

One reason that this was so hard to debug was that every time I tried to add code to debug it (by sending debugging information over the serial line) it went away (which is obvious in retrospect - if the serial line is busy most of the time, it doesn't interrupt so much). Sometimes thinking hard about what the problem could be is actually quicker than doing experiments to debug a problem.

Having found that, I realized that I had written some other code which assumes the UDRE was edge-triggered - the code for my Physical Tone Matrix. I made the same change there and now the menu screen appears and disappears instantly rather than sweeping down the screen like a DOS directory listing on an 8088. Unfortunately that means that the menu switch is now too sensitive - it flickers on an off while you're pressing the switch so you sometimes have to press it a few times to get it into the state you want. I'll change the capacitor for a larger one next time I have it open.

One Response to “UDRE doesn't do what I thought it did”

  1. [...] Reenigne blog Stuff I think about « UDRE doesn't do what I thought it did [...]

Leave a Reply