Please help me understand the different Output Modes of pin.configure

Please help me understand the different Output Modes of pin.configure (or tell me a basic tutorial I can read). I have an LED and a 2.2K resistor connected to pin 1 of my new imp, and device code that toggles pin 1 output.

With an Output Mode of DIGITAL_OUT,
voltage at pin 1 is 3.23 volts when ON, 0 when Off, and LED blinks normally

With an Output Mode of DIGITAL_OUT_OD,
voltage at pin 1 is .395 volts when ON, 0 when Off, and LED does not blink

With an Output Mode of DIGITAL_OUT_OD_PULLUP,
voltage at pin 1 is 1.668 volts when ON, 0 when Off, and LED blinks dimly.

Why is the imp’s behavior different with the different Output Modes, and under what circumstances would you use the different output modes ?
Thanks for any response.

It helps to imagine the pin is driven (hard) high or low by two switches; one connects the pin to the power supply, one connects it to ground. At most, one of these switches is turned on concurrently, but it’s also valid for neither switch to be on.

On the imp, each pin also has pull-up and pull-down switches - imagine two switches, each in series with a resistor (~50k), one to power and one to ground.

When a pin is an input, neither hard switch is on. The pin is generally driven externally, or can be weakly pulled up or down by the pull-up/pull-down switches (DIGITAL_IN_PULLDOWN or DIGITAL_IN_PULLUP). The idea here is that the pin will stay in a known state unless the external input is driven by another piece of circuitry.

DIGITAL_OUT is “push-pull” mode. This uses the hard switches, and either drives the pin high as hard as possible, or low as hard as possible. The pin gets close to the supply rail as you noted, and current is sourced to light the LED.

This is most often used to drive output signals that need to source and sink current; you must never connect two push-pull outputs together though, because if you do and one party tries to drive the line high whilst the other one is trying to drive low, large currents will flow through each parties’ output drivers and bad things can happen.

DIGITAL_OUT_OD is “open drain” mode (it’s called open drain because the switches are FETs, and the pin is effectively only connected to the bottom FET’s drain pin). This is where only the bottom hard switch is used (so the pin can get pulled hard low, but if you write 1 to the pin, it just floats). You could use it to light the LED if you connected the anode of the LED to 3.3v, and the cathode (via the resistor) to the pin - then writing low would, just as writing high does now, allow enough current to flow to light the LED. You’re just seeing leakage through the pin, which is what is giving you the 0.395v.

The useful thing about DIGITAL_OUT_OD is that open drain signals (even from multiple chips) can be connected together safely; as each party can only pull the signal low, two or more of them pulling low at the same time is harmless - and you’d have a pull-up resistor somewhere to ensure the line is high if nobody is pulling it down. This type of wiring used to be used extensively to combine interrupt signals, for example, and nowadays you see it on I2C buses, allowing safe connection of many devices together (the imp automatically configures pins as open drain when you set up an I2C bus).

DIGITAL_OUT_OD_PULLUP is open drain, but with the pull-up resistor switch turned on. This means writing zero to the pin pulls hard low, as before, but if 1 is written the pin is pulled up weakly through the resistor, limiting the current that can flow. The LED is lighting, which means you’ve just got to the Vf (forward voltage) of the LED, but very limited current is flowing.

This isn’t used terribly often, but can be helpful now and then.

Thank you Hugo. Your response is very helpful and informative. One final question - you said “you must never connect two push-pull outputs together” I’m sure you mean a direct connection. If I connected two push-pull outputs together with a 2.2K resistor (for testing purposes), then current flow is limited to about 1.5 ma and I assume this would work OK. Is that correct? Thanks again for your response.

@Rfarmer

Logic levels … zero or one, low or high, whatever you wish to call it, are not necessarily at the voltages you think they should be. Going back to the earlier days of transistors and TTL, you never really knew what the circuit would consider “high”. The threshold was ‘uncertain’. Pullup resistors kept the inputs “high” to a known voltage.

This might explain it better:
http://www.allaboutcircuits.com/textbook/digital/chpt-3/logic-signal-voltage-levels/

Modern improvements to hardware have made things a little bit cleaner and better defined. When you get into digital inputs (contact switches, pushbuttons, relays), you’ll discover that the high/low switch-over threshold gets hit multiple times with each button push. Maybe a little bit of dirt on the contact, or tarnished copper. That is called “switch bounce”, and there is actually an imp class that deals with “debouncing” inputs.

This is all interesting stuff for the ‘tinkerers’.

@rfarmer yep, if you have a current limiting resistor you’re fine, but there’s still the question of why connect two outputs together :slight_smile:

@mlseim TTL did absolutely have real high and low levels - you can see them in datasheets, Vih(min) - the voltage at which an input will be read as logic 1 for sure, and Vil(max) - the voltage at which an input will be read as logic 0 for sure. These limits are different for each logic family, and for all families if the voltage is above Vil(max) but below Vih(min), you’re in no-man’s land and you could read either way.

If you’re in the middle, you can get high leakage currents within the receiving chip, where internal transistors are partially turned on. This is why you use pull-ups or pull-downs on (a) unused inputs and (b) inputs that need a default state when un-driven.

Thanks again Hugo for your explanation. The only reason for connecting two outputs together is for my own testing purposes. I’ve written a lot of software but not done a lot of hardware, so I want to make sure I understand how the hardware works by testing the various input/output levels. thanks again.