Caution when switching between input and output?

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From an AVR datasheet:

Quote:
Switching Between Input and Output

When switching between tri-state ({DDxn, PORTxn} = 0b00) and output high ({DDxn, PORTxn}
= 0b11), an intermediate state with either pull-up enabled {DDxn, PORTxn} = 0b01) or output
low ({DDxn, PORTxn} = 0b10) must occur. Normally, the pull-up enabled state is fully acceptable,
as a high-impedance environment will not notice the difference between a strong high
driver and a pull-up. If this is not the case, the PUD bit in the MCUCR Register can be set to disable
all pull-ups in all ports.
Switching between input with pull-up and output low generates the same problem. The user
must use either the tri-state ({DDxn, PORTxn} = 0b00) or the output high state ({DDxn, PORTxn}
= 0b11) as an intermediate step.

I've never paid any attention to this before. Is this important? I take it to mean that I have to insert an extra step in the two indicated transitions, but I don't recollect having ever done this nor having any problems. For instance it implies that when you come out of rest and a pin is tristate that if you immediately set it to output high you'll get a problem. What problem? Anyone want to 'splain what this really means in practical application?

Smiley

Last Edited: Thu. Sep 1, 2011 - 07:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just ran into this myself. I have a SW UART on an ATtiny84. Switching the Tx pin from input to output causes a start condition. I do this by setting DDRxn to 1 (making the pin an output) then setting PORTxn to a 1 to put the Tx pin into the idle (high) state. This results in one cycle where the Tx pin is an output and low.

Although I chose another way to avoid this problem, I could have first set PORTxn to a 1 (enabling the Tx pin pullup), then set DDRxn to a 1 (making the Tx pin an output and high). At this point, I could leave the Tx pin pullup set or disable it (by writing a 1 to PINxn which will toggle PORTxn).

EDIT: Just wanted to correct an error here on my part. I mentioned disabling the Tx pin pullup once the pin was set as an output. Not only can't you do this but you don't need to. The pullup is automatically disabled when a pin is configured as an output. As Martin states in the following post, if you switch the pin from an output back to an input and leave PORTxn set, you'll cause the pullup to be enabled (unless PUD is set).

Don

Last Edited: Mon. Aug 29, 2011 - 07:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Whether or not it is important depends on the external circuitry. If it can tolerate opposite logic state for a few CPU clocks without doing bad things, then don't bother. Don outlines a situation where it IS important. Similar cases are possible on SPI or TWI ports.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You also have to be careful, if you need an open drain output (0=output low, 1=input with pullup).
When switching from 1 to 0, you need to clear the port-register first, otherwise will you switch from 1(open drain) to 1(push-pull) to 0.

/Martin.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm thinking maybe I'll write some macros to cover each of these possibilities with a good indicative name for each so that once I get this running properly again I'll not have to think about it.

I decided to take care of this with a port_pin_mode(PORTx,pin,MODE) macro (where MODE is INPUT or OUTPUT) which will always deactivate the pull-up and set the output to 0 before setting the data direction to output.

Any more suggestions?

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know only one applicaton, which need such a special sequence, the QTouch principle.

On software I2C ore 1-wire, you should use an external pullup.
And then let the output bit constantly at low and change only the direction bit accordingly.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It may not be needed very often, but since we so rarely set the pin direction and it takes so little time I was thinking that doing this as a matter of course will at least take care of the cases where it is necessary without me having to think about it too hard. I'm going to guess that anyone who would care about a couple of cycles when they set the pin direction wouldn't need to use my macros anyway. But if anyone can think of an application where you change pin direction frequently or need the speed I'd like to hear it.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is kind of on the same topic. When running at 20MHz and using assembly, 2 NOPs are needed after turning the port around to read. At less than 10MHz, 1 NOP will work. I have never run an AVR less than 10MHz, so I am not sure if it is needed at lower speeds.

No doubt, this is probably covered in the thick of the data sheet, but I leaned it the old fashioned way... late night hacking.

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are a lot of occasions where you need to be certain that pin states are never illegal in your application. For instance you might have two high current devices like bus drivers or some H-bridge or push-pull stage on two IO pins, and of course enabling both at the same time causes smoke.

The hardware is able to boot because pull-up resistors keep the bus drivers or whatever disabled when AVR is in reset.

But AVR ports default to high-Z inputs, meaning both PORT and DDR bits are 0.

If you first configure the port as output, then outputs are set output low. If this enables the both external devices at the same time, smoke ensues.

Therefore, one must first set the PORT bits to high before setting the DDR for output, so that there are no shorts.

So it is just as important during boot time configuration. The serial port being a very good example too, it prevents the transmission of a low pulse that can be interpreted as a bogus start pulse and then data is 0xFF.

The capacitance measurements (qtouch, or for example using a LED as both emitter and detector)and other funky stuff needs the correct sequence so that it does not accidentally discharge the capacitance. Also open-collector buses like I2C or 1-Wire are possible, but one should use external pull-ups and just toggle the port as output low and high-z input with the DDR port, never touching PORT.