Last Updated : July 9th, 2017

This is a really quick reference for commonly used registers on the ATmega328/P. For further details on the usage of a specific register, relevant links have been provided in the register’s section. For any registers not included here, please refer to the Register Summary (pg 428) of the Atmel ATmega328/P datasheet, which has been the holy grail for writing this article.




General Stuff

You may like to skip this bullshit and get to the point


avr/io.h: This is a stock library that must be included to work around directly with registers.


Register: A register is a memory space inside the CPU itself and can be operated upon rapidly.
The individual bits of a register represent something specific.
Since most registers on an ATmega328 are 8 bit, the chip is termed an 8-bit processor. Registers and their corresponding bits have names.

For example, one register in the chip is identified as ACSR. It stands for Analog compare Control and Status Register.

Register Offset Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
ACSR 0x50 ACD ACBG ACO ACI ACIE ACIC ACIS1 ACIS0


Although we refer to the register by its name, the chip can’t. It communicates with the register on a virtual address. The offset (here, 0x50) is the address on which the register resides. All communication between the chip and ACSR is done on address 0x50.


Ports : Ports on the ATmega328 are bi-directional I/O ports. Ports B and D are 8-bit while Port C is 7-bit.


_BV : _BV is a macro that is used to set a predefined specific bit.

Usage:
register = _BV(any-bit-of-that-register) | _BV(another-bit-of-that-register)
ACSR = _BV(ACIE) | _BV(ACIS1) | _BV(ACIS0);


bitSet : A function that can set a specific bit of an input byte.

Usage:

byte register = 0b00000000;
bitSet(register,6); //sets 6th bit 1 (0b01000000)
ACSR |= register;  //modifies ACSR only if 6th bit was 0.


Unless there is a need of rewriting the whole register (which isn’t a very popular need), it is sensible to use the “OR” operator while manipulating a register. This ensures that previously set bits are not affected.

//*register* = *register* | *8-bit-value*
ACSR = ACSR | 0b01001010;

//it's also acceptable to use hex values
ACSR = ACSR | 0x4A;



Reference Table

Register Offset Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
ADCSRA 0x7A ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0
ADCSRB 0x7B Reserved ACME Reserved Reserved Reserved ADTS2 ADTS1 ADTS0
ADMUX 0x7A REFS1 REFS0 ADLAR Reserved MUX3 MUX2 MUX1 MUX0
PINB 0x23 PINB7 PINB6 PINB5 PINB4 PINB3 PINB2 PINB1 PINB0
DDRB 0x24 DDRB7 DDRB6 DDRB5 DDRB4 DDRB3 DDRB2 DDRB1 DDRB0
PORTB 0x25 PORTB7 PORTB6 PORTB5 PORTB4 PORTB3 PORTB2 PORTB1 PORTB0
PINC 0x26 Reserved PINC6 PINC5 PINC4 PINC3 PINC2 PINC1 PINC0
DDRC 0x27 Reserved DDRC6 DDRC5 DDRC4 DDRC3 DDRC2 DDRC1 DDRC0
PORTC 0x28 Reserved PORTC6 PORTC5 PORTC4 PORTC3 PORTC2 PORTC1 PORTC0
PIND 0x29 PIND7 PIND6 PIND5 PIND4 PIND3 PIND2 PIND1 PIND0
DDRD 0x2A DDRD7 DDRD6 DDRD5 DDRD4 DDRD3 DDRD2 DDRD1 DDRD0
PORTD 0x2B PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0
MCUCR 0x55 Reserved BODS BODSE PUD Reserved Reserved IVSEL IVCE
PRR 0x64 PRTWI0 PRTIM2 PRTIM0 Reserved PRTIM1 PRSPI0 PRUSART0 PRADC
TIFR0 0x35 Reserved Reserved Reserved Reserved OCFB OCFA TOV  
GTCCR 0X43 TSM Reserved Reserved Reserved Reserved Reserved PSRASY PSRSYNC
TCCR0A 0X44 COM0A1 COM0A0 COM0B1 COM0B0 Reserved Reserved WGM01 WGM00
TCCR0B 0X45 FOC0A FOC0B Reserved Reserved WGM02   CS0[2:0]  
TCNT0 0X46       TCNT0[7:0]        
OCR0A 0X47       OCR0A[7:0]        
OCR0B 0X48       OCR0B[7:0]        
TIMSK0 0X6E Reserved Reserved Reserved Reserved Reserved OCIEB OCIEA TOIE



Reference Image

Here’s an image of an SMD ATMega328

atmega328




ADC Control and Status Register A

Register Offset Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
ADSCRA 0x7A ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0


ADEN : ADC Enable
Determines whether the ADC is enabled or not.

ADSC : ADC Start Conversion
The ADC starts approximating a value when ADSC is set to 1. Bit is cleared after the conversion is complete.
Clearing this bit does not make a difference.

ADATE : ADC Auto Trigger Enable
Sets up the ADC to be triggered by the positive edge of the external signal.
The external signal acts as a trigger and can be selected using ADTS in ADSCRB.

ADIF : ADC Interrupt Flag This bit is set when an ADC conversion completes and the Data Registers are updated.
The ADIE bit and the I-bit in SREG must be set, or sei() must have been called before.

ADIE : ADC Interrupt Enable This bit controls whether ADIF is enabled or not.
It serves as an interrupt mask for ADIF.

Bits [2:0] : ADPSn (ADC Prescalar Selection) Selects the prescalar for the ADC clock frequency.

ADPS[2:0] Prescalar
000 2
001 2
010 4
011 8
100 16
101 32
110 64
111 128



ADC Multiplexer Selection Register

Register Offset Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
ADMUX 0x7c REFS1 REFS0 ADLAR Reserved MUX3 MUX2 MUX1 MUX0


Bits [7:6] : REFSn (Reference Selection)
These bits select the voltage reference for the ADC.

REFS[1:0] Voltage Reference Selection
00 AREF, Internal Vref turned off
01 AVcc with external capacitor at AREF pin
10 Reserved
11 Internal 1.1V Voltage Reference with external capacitor at AREF pin


The 1v1 voltage reference has a tolerance of about 10%. This is awful as it produces swings of 100 millivolts. Although it works fine for crude applications with reasonable parameters, do not rely on this reference for sensitive applications. Rather, consider the use of the widely popular TL431 precision shunt regulator.


Bits [3:0] : Determine the analog channel connected to the ADC.

MUX[3:0] AD Channel Input == == MUX[3:0] AD Channel Input
0000 ADC0   1000 Temperature sensor
0001 ADC1   1001 Reserved
0010 ADC2   1010 Reserved
0011 ADC3   1011 Reserved
0100 ADC4   1100 Reserved
0101 ADC5   1101 Reserved
0110 ADC6   1110 1.1V (VBG)
0111 ADC7   1111 0V (GND)



DDRx, PORTx and PINx

DDRx : Data Direction Register for port ‘x’
The DDRx register is responsible for initialising the pins for use either as inputs or outputs.
A 1 bit signifies a pin initialised as output. A 0 bit signifies a pin initialised as input.

DDRD = 0b01000100 initialises pins 2, 6 as output, pin 0,1,3,4,5,7 as input.

PORTx : Defines state of Output Pins on port ‘x’
The PORTx register determines whether the output state of a pin is HIGH or LOW.
A 1 bit signifies HIGH and 0 signifies LOW.
DDRx takes precedence over PORTx. A pin previously defined as input won’t be affected by PORTx. The pin must be initialised as an output by DDRx first to manipulate it through PORTx.

DDRD =  0b01000100
PORTD = 0b01000000  //declares pin 2 LOW and pin 6 HIGH.

PINx : Reads state of Input Pins on port ‘x’
The PINx register simply reads the value from the pins. This value, as obvious, is digital.
Although Port C pins have ADCs attached, they can still be used as digital GPIOs.

For a detailed article, look up Advanced I/O from my Exploiting An Arduino series.


Port D:

Available Registers: PIND (0x29), DDRD (0x2A), PORTD (0x2B)

Each register is 8-bit. [7:0] bits map from GPIO-7 to GPIO-0 respectively.

Port B:

Available Registers: PINB (0x23), DDRB (0x24), PORTB (0x25)

Each register is 8-bit. [5:0] bits map from GPIO-13 to GPIO-8 respectively.
[7:6] bits are reserved for oscillators.

Port C:

Available Registers: PINC (0x26), DDRC (0x27), PORTC (0x28)

Each register is 8-bit. When using as GPIO, [5:0] bits map from A5 to A0 respectively. These pins can be used as regular GPIOs.
[7:6] bits are not accessible on the Uno board.

NOTE: PUD bit in MCUCR register is common to all GPIOs. It must be set to 0 to use Input Pullup resistors on GPIO pins.




Power Reduction Register

The Power Reduction Register (PRR) can minimise power usage by selectively switching off specific hardware on the chip.

PRTWI0: Power Reduction TWI0 (Bit 7)
Setting this bit shuts down the TWI 0 by stopping the clock to the module. When waking up
the TWI again, the TWI should be re initialized to ensure proper operation.

PRTIM2: Power Reduction Timer/Counter2 (Bit 6)
Setting this bit shuts down the Timer/Counter2 module in synchronous mode (AS2 is 0).
When the Timer/Counter2 is enabled, operation will continue like before the shutdown.

PRTIM0: Power Reduction Timer/Counter0 (Bit 5)
Setting this bit shuts down the Timer/Counter0 module. When the Timer/Counter0 is
enabled, operation will continue like before the shutdown.

PRTIM1: Power Reduction Timer/Counter1 (Bit 3)
Setting this bit shuts down the Timer/Counter1 module. When the Timer/Counter1 is
enabled, operation will continue like before the shutdown.

PRSPI0: Power Reduction Serial Peripheral Interface (Bit 2)
If using debugWIRE On-chip Debug System, this bit should not be written to one. Writing a logic one to
this bit shuts down the Serial Peripheral Interface by stopping the clock to the module. When waking up
the SPI again, the SPI should be re initialized to ensure proper operation.

PRUSART0: Power Reduction USART0 (Bit 1)
Setting this bit shuts down the USART by stopping the clock to the module. When waking
up the USART again, the USART should be re initialized to ensure proper operation.

PRADC: Power Reduction ADC (Bit 0)
Setting this bit shuts down the ADC. The ADC must be disabled before shut down. The analog comparator cannot use the ADC input MUX when the ADC is shut down.




TC0 Control Register A

Register Offset Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
TCCR0A 0X44 COM0A1 COM0A0 COM0B1 COM0B0 Reserved Reserved WGM01 WGM00


Bis[7:6]: Compare Output Mode for Channel A.


When WGM bits are selected to CTC (non-PWM):

COM0A1 COM0A0 Description
0 0 Normal port operation, OC0A disconnected
0 1 Toggle OC0A on Compare Match
1 0 Clear OC0A on Compare Match
1 1 Set OC0A on Compare Match


When WGM bits are set to Fast PWM:

COM0A1 COM0A0 Description
0 0 Normal port operation, OC0A disconnected.
0 1 WGM02 = 0: Normal Port Operation, OC0A Disconnected
WGM02 = 1: Toggle OC0A on Compare Match
1 0 Clear OC0A on Compare Match, set OC0A at BOTTOM (non-inverting mode)
1 1 Set OC0A on Compare Match, clear OC0A at BOTTOM (inverting mode)


When WGM bits are set to Phase-Correct PWM:

COM0A1 COM0A0 Description
0 0 Normal port operation, OC0A disconnected.
0 1 WGM02 = 0: Normal Port Operation, OC0A Disconnected
WGM02 = 1: Toggle OC0A on Compare Match
1 0 Clear OC0A on Compare Match, set OC0A at BOTTOM (non-inverting mode)
1 1 Set OC0A on Compare Match, clear OC0A at BOTTOM (inverting mode)



WGM0[2:0]: Waveform Generation Mode. WGM00 and WGM01 are found in TCCR0A and WGM02 in TCCR0B.

Mode WGM02 WGM01 WGM00 Mode of Operation TOP Update of OCR0x at TOV Flag Set on
0 0 0 0 Normal 0xFF Immediate 0xFF
1 0 0 1 Phase Correct PWM 0xFF TOP 0x00
2 0 1 0 CTC OCRA Immediate 0xFF
3 0 1 1 Fast PWM 0xFF 0x00 0xFF
4 1 0 0 Reserved - - -
5 1 0 1 Phase Correct PWM OCRA TOP 0x00
6 1 1 0 Reserved - - -
7 1 1 1 Fast PWM OCRA 0x00 TOP



TC0 Control Register B

Register Offset Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
TCCR0B 0X46 FOC0A FOC0B Reserved Reserved WGM02 CS02 CS01 CS00


Bits[2:0]: Determine Clock Source to be used.

CA02 CA01 CS00 Description
0 0 0 No clock source (Timer/Counter stopped)
0 0 1 clk I/O /1 (No prescaling)
0 1 0 clk I/O /8 (From prescaler)
0 1 1 clk I/O /64 (From prescaler)
1 0 0 clk I/O /256 (From prescaler)
1 0 1 clk I/O /1024 (From prescaler)
1 1 0 External clock source on T0 pin. Clock on falling edge
1 1 1 External clock source on T0 pin. Clock on rising edge



TC0 Interrupt Flag Register

Register Offset Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
TIFR0 0X35 Reserved Reserved Reserved Reserved Reserved OCF0B OCF0A TOV0


Bit 2: Output Compare Flag B
Bit is set when a Compare Match occurs between the timer and the data in OCR0B.
OCF0B is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, OCF0B is cleared by writing a logic one to the flag.

Bit 1: Output Compare Flag A
Bit is set when a Compare Match occurs between the timer and the data in OCR0A.
OCF0A is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, OCF0A is cleared by writing a logic one to the flag.


Bit 0: Timer Overflow
Bit is set when an overflow (increment past 0xFF) occurs in the timer.
TOV0 is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, TOV0 is cleared by writing a logic one to the flag.
This flag is dependent on WGM mode.