This Tutorial is a part of the Course : Embedded C Firmware Programming on Atmel AVR 8-bit Atmega328p Microcontroller Please visit the page for further reading.

AVR Input Output Ports Introduction

Atmega328p is used as an example to explain the concepts but they are applicable to all the AVR 8-bit Microcontrollers.

All AVR ports have true Read-Modify-Write functionality when used as general digital I/O ports. This means that the direction of one port pin can be changed without unintentionally changing the direction of any other pin with the SBI and CBI instructions. The same applies when changing drive value (if configured as an output) or enabling/disabling of pull-up resistors (if configured as input). Each output buffer has symmetrical drive characteristics with both high sink and source capability. The pin driver is strong enough to drive LED displays directly. All port pins have individually selectable pull-up resistors with a supply-voltage invariant resistance. All I/O pins have protection diodes to both VCC and Ground.

AVR GPIO I/O Pin Equivalent Schematic
AVR GPIO I/O Pin Equivalent Schematic

All registers and bit references in this section are written in general form. A lower case “x” represents the numbering letter for the port, and a lower case “n” represents the bit number. However, when using the register or bit defines in a program, the precise form must be used. For example, PORTB3 for a bit no. 3 in Port B, here documented generally as PORTxn.

Three I/O memory address locations are allocated for each port, one each for

  • Data Register – PORTx – Read Write
  • Data Direction Register – DDRx – Read Write
  • Port Input Pins – PINx  Read Only

Ports as General Digital I/O

The ports are bi-directional I/O ports with optional internal pull-ups.

AVR I/O Detailed Block Diagram
AVR I/O Detailed Block Diagram
WRx, WPx, WDx, RRx, RPx, and RDx are common to all pins within the same port. clkI/O, SLEEP, and PUD are common to all ports

The DDxn bit in the DDRx Register selects the direction of this pin. If DDxn is written logic one, Pxn is configured as an output pin. If DDxn is written logic zero, Pxn is configured as an input pin.

DDRB – The Port B Data Direction Register
DDRB – The Port B Data Direction Register
DDRC – The Port C Data Direction Register
DDRC – The Port C Data Direction Register
DDRD – The Port D Data Direction Register
DDRD – The Port D Data Direction Register

If PORTxn is written logic one when the pin is configured as an input pin, the pull-up resistor is activated. To switch the pull-up resistor off, PORTxn has to be written logic zero or the pin has to be configured as an output pin. The port pins are tri-stated when the reset condition becomes active, even if no clocks are running.

If PORTxn is written logic one when the pin is configured as an output pin, the port pin is driven high (one). If PORTxn is written logic zero when the pin is configured as an output pin, the port pin is driven low (zero).

PORTB – The Port B Data Register
PORTB – The Port B Data Register
PORTC – The Port C Data Register
PORTC – The Port C Data Register
PORTC – The Port C Data Register
PORTC – The Port C Data Register

Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction can be used to toggle one single bit in a port.

Independent of the setting of Data Direction bit DDxn, the port pin can be read through the PINxn Register bit.

PINB – The Port B Input Pins Address
PINB – The Port B Input Pins Address
PINC – The Port C Input Pins Address
PINC – The Port C Input Pins Address
PIND – The Port D Input Pins Address
PIND – The Port D Input Pins Address
DDxn PORTxn PUD
(in MCUCR)
I/O Pull-up Comment
0 0 X Input No Tri-state (Hi-Z)
0 1 0 Input Yes Pxn will source current if ext. pulled low.
0 1 1 Input No Tri-state (Hi-Z)
1 0 X Output No Output Low (Sink)
1 1 X Output No Output High (Source)
//Refer the table above
unsigned char i;
...
/* Define pull-ups and set outputs high */
/* Define directions for port pins */
PORTB = (1<<PB7)|(1<<PB6)|(1<<PB1)|(1<<PB0);
DDRB = (1<<DDB3)|(1<<DDB2)|(1<<DDB1)|(1<<DDB0);
/* Insert nop for synchronization*/
__no_operation();
/* Read port pins */
i = PINB;
...

If some pins are unused, it is recommended to ensure that these pins have a defined level. Even though most of the digital inputs are disabled in the deep sleep modes as described above, floating inputs should be avoided to reduce current consumption in all other modes where the digital inputs are enabled (Reset, Active mode and Idle mode).

The simplest method to ensure a defined level of an unused pin is to enable the internal pull-up. In this case, the pull-up will be disabled during reset. If low power consumption during reset is important, it is recommended to use an external pull-up or pull-down. Connecting unused pins directly to VCC or GND is not recommended, since this may cause excessive currents if the pin is accidentally configured as an output.

MCUCR - MCU Control Register
MCUCR – MCU Control Register

Bit 4 – PUD: Pull-up Disable
When this bit is written to one, the pull-ups in the I/O ports are disabled even if the DDxn and PORTxn Registers are configured to enable the pull-ups ({DDxn, PORTxn} = 0b01).

This Tutorial is a part of the Course : Embedded C Firmware Programming on Atmel AVR 8-bit Atmega328p Microcontroller Please visit the page for further reading.


Thank You for Reading  You are Awesome ! 👌

Happy Making and Hacking 😊

Liked this content ? Please Donate / Subscribe / Share to support this Website ! 😇

Donate With



Crazy Engineer

MAKER - ENGINEER - YOUTUBER

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.