Configuring the ATtiny2313 Pins as Outputs

Created on: 6 February 2013

Part 3 of the ATtiny2313 Tutorial

Pins on the ATtiny2313 AVR microcontroller are configured as outputs in this part of the tutorial. LEDs interfaced to the microcontroller are then switched on and off by writing to registers in the ATtiny2313 from a C program.

Before building a microcontroller circuit, interfacing LEDs to it and writing a C program, we need to know how much current the pins of the ATtiny2313 can source or sink. We therefore first look at the electrical characteristics of the microcontroller pins.

ATtiny2313 Pin Current Drive (Sink / Source)

We can find out how much current the pins of the ATtiny2313 can sink or source by looking at the datasheet for the ATtiny2313.

From the datasheet, the absolute maximum DC current that I/O pins can handle (source or sink) is 40mA each.

We do not want to use the absolute maximum value when designing a circuit as any current drawn beyond this value can cause permanent damage to the microcontroller. Any design must ensure that current drawn from any pin will be much less than the 40mA absolute maximum.

I/O pin current capabilities from the datasheet:

  • The sum of all IOL, for all ports, should not exceed 60 mA. (current sinking)
  • The sum of all IOH, for all ports, should not exceed 60 mA. (current sourcing)

The datasheet also states that a port can source or sink 20mA at 5V (these were test conditions used):

  • Output Low Voltage (Port A, Port B, Port D) IOL = 20 mA, VCC = 5V
  • Output High-voltage (Port A, Port B, Port D) IOH = -20 mA, VCC = 5V
  • If IOL exceeds the test condition, VOL may exceed the related specification. Pins are not guaranteed to sink current greater than the listed test condition.
  • If IOH exceeds the test condition, VOH may exceed the related specification. Pins are not guaranteed to source current greater than the listed test condition.

So any one port must not source or sink more than 20mA.

To keep within the specified current limits of the ATtiny2313, this means that:

  • A good design should not draw more than about 10mA from any pin. A maximum of 6 pins would be able to draw 10mA each at any one time (60mA ÷ 6). This would have to be limited to 2 pins at 10mA per port to keep within the 20mA port limit.
  • Despite the above statement, it should be safe to source/sink 20mA from a pin as this is half of the absolute maximum rating for a pin. In this case, only one pin per port could source/sink 20mA to keep within the 20mA per port limit.
  • If you set up all 18 pins as outputs, to stay within the 60mA limit and the 20mA per port limit, each pin can source/sink the following: Port A pins – 6.667mA per pin (20 mA ÷ 3 pins), Port B pins – 2.5mA per pin (20 mA ÷ 8 pins), Port D pins – 2.857mA per pin (20 mA ÷ 7 pins).

Interfacing LEDs to the ATtiny2313

Two example circuits are used to show how to set up pins on the ATtiny2313 as outputs.

LED Flasher Circuit

In this circuit, two pins from port D of the ATtiny2313 are interfaced to LEDs (current sourcing).

ATtiny2313 LED flasher circuit
ATtiny2313 LED Flasher Circuit - click for a bigger image

LED Knight Rider Display Circuit

This circuit is used to make a five LED knight rider display. The LEDs are also interfaced in a current sourcing configuration, but are connected to port B this time.

ATtiny2313 LED interfacing circuit diagram
ATtiny2313 Interfaced to Five LEDs - click for a bigger image

For a current sinking example, see the circuit diagram and C source code from the Starting AVR 8-bit Development tutorial.

Writing to the ATtiny2313 Configuration and Port Registers in C

A C program that sets up the LED pins of the microcontroller as outputs and writes to a register to switch the LEDs on and off can be found below for the two example circuits.

LED Flasher Example

This C program sets up pins PD0 and PD5 as outputs by setting the corresponding bits (bits 0 and 5) in the DDR register for port D (DDRD register).

After setting up the output pins, the program execution drops into a continuous while loop. In the loop, the LEDs are switched on and off by writing either a 1 (on) or 0 (off) to the corresponding bit in the PORT register for the D port (PORTD register).

#include <avr/io.h>

void Delay(void);

int main(void)
{
    // LEDs are on pins PD0 and PD5
    DDRD |= ((1 << PD0) | (1 << PD5));
    
    while(1)
    {
        PORTD &= ~(1 << PD0);           // switch PD0 LED off
        PORTD |=  (1 << PD5);           // switch PD5 LED on
        Delay();
        PORTD &= ~(1 << PD5);           // switch PD5 LED off
        PORTD |=  (1 << PD0);           // switch PD0 LED on
        Delay();
    }       
}

void Delay(void)
{
    volatile unsigned int del = 40000;
    
    while(del--);
}

LED Knight Rider Display Example

In this example, bits PB0 to PB4 in the DDRB register are set to logic 1. This enables pins PB0 to PB4 as outputs.

In the continuous loop in this program, the LEDs are first all switched off by clearing bits 0 to 4 in the PORTB register. Immediately after clearing the bits, the data in the data variable is written to the LEDs. Because there is no delay between clearing the LEDs and writing the data, the LEDs will never all appear to be off.

The data variable contains 1 bit that is set and is shifted to the left and then to the right making the corresponding LED switch on in turn.

#include <avr/io.h>

void Delay(void);

int main(void)
{
    char forward = 1;   // flags the direction of the knight rider display
    char data = 1;      // data to write to knight rider display
    // set up pins PB0 to PB4 as output pins
    DDRB |= ((1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
    
    while(1)
    {
        PORTB &= 0xE0;              // switch all LEDs off
        PORTB |= data;              // write data to the LEDs
        Delay();
        if (forward) {              // moving LEDs from right to left
            if (data == 0x10) {
                forward = 0;        // change direction
                data = 0x08;        // prevent writing to same LED twice
            }
            else {
                data <<= 1;         // move to next LED
            }
        }
        else {                      // moving LEDs left to right
            if (data == 0x01) {
                forward = 1;        // change direction
                data = 0x02;        // prevent writing to same LED twice
            }
            else {
                data >>= 1;         // move to next LED
            }
        }
    }
}

void Delay(void)
{
    volatile unsigned int del = 10000;
    
    while(del--);
}

Switching Bits on and Off in C

Both the above examples use the C OR operator | to switch bits on and the C AND operator & to switch bits off.

In this line of code, the |= operator performs a read-modify-write.

DDRD |= ((1 << PD0) | (1 << PD5));

The contents of the DDRD register are read (read), the value that was read is then ORed with the value to the right of the |= operator (modify). The new value is then written back to the DDRD register (write).

Switching an LED On and Off

On

The read-modify-write shown below performs a C bitwise OR operation which sets bit 0 of the PORTD register.

PORTD |=  (1 << PD0);           // switch PD0 LED on

This code reads the PORTD register and then changes only the PD0 bit in the byte read from it by setting it to 1. The modified byte is then written back to the register. Because the OR operator is being used, all other bits in the register, whether 1's or 0's will remain unchanged as they are all being ORed with 0. Only the PD0 bit is being ORed with 1.

Off

To switch a bit off, the C bitwise AND operator must be used. To prevent changing any other bit in the register when performing an AND operation, all the other bits must be ANDed with 1, except the bit that is to be cleared. The bit to be cleared is ANDed with 0.

PORTD &= ~(1 << PD0);           // switch PD0 LED off

In the above line of code, the PD0 bit is cleared. The C bitwise invert operator ~ is used to invert all the bits in the value that is ANDed with PORTD. This makes the bit to be cleared 0 and all the rest of the bits 1 so that the corresponding bits will remain unchanged in the register (bits 7 to 1 will remain unchanged, bit 0 will be cleared).

In this example, the value ANDed with the PORTD register would be 00000001b, but after inverting the value it becomes 11111110b, so that only bit 0 is cleared when the AND operation is performed.

Atmel Studio Source Code

The above code listings can be copied and pasted into your own Atmel Studio project, or you can download the Atmel Studio projects that include the source and hex files for the two circuits.

Example 1: LED Flasher – LED_flasher.zip (14.5kB)

Example 2: LED Knight Rider – knight5.zip (15.3kB)