Basic AVR

Useful functions

  • _BV(bit) : Converts a bit number into a byte value.
#define _BV(bit)   (1 << (bit))
  • bit_is_clear(sfr,bit) : Test whether bit bit in IO register sfr is clear.
#define bit_is_clear(sfr, bit)   (!(_SFR_BYTE(sfr) & _BV(bit)))
  • bit_is_set(sfr,bit) : Test whether bit bit in IO register sfr is set.
#define bit_is_set(sfr, bit)   (_SFR_BYTE(sfr) & _BV(bit))
  • loop_until_bit_is_set(sfr,bit) : Wait until bit bit in IO register sfr is set.
#define loop_until_bit_is_set(sfr, bit)   do { } while (bit_is_clear(sfr, bit))
  • loop_until_bit_is_clear(sfr,bit) : Wait until bit bit in IO register sfr is clear.
#define loop_until_bit_is_clear(sfr, bit)   do { } while (bit_is_set(sfr, bit))
  • cbi(sfr, bit) : Clear bit bit in register sfr.
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
  • sbi(sfr, bit) : Set bit bit in register sfr.
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
  • _SFR_BYTE(sfr) : De-reference sfr : to get the contents of the address sfr.
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
#define _SFR_WORD(sfr) _MMIO_WORD(_SFR_ADDR(sfr))
#define _SFR_DWORD(sfr) _MMIO_DWORD(_SFR_ADDR(sfr))

#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define _MMIO_WORD(mem_addr) (*(volatile uint16_t *)(mem_addr))
#define _MMIO_DWORD(mem_addr) (*(volatile uint32_t *)(mem_addr))

ATMega328P Registers

Name Address Purpose
SREG 0x5F AVR Status Register
PORTB 0x25 PORT B Data Register [PORTB7..0]
DDRB 0x24 PORT B Data Direction Register [DDB7..0]
PINB 0x23 PORT B Input Pins Address [PINB7..0]
PORTC 0x28 PORT C Data Register [PORTC7..0]
DDRC 0x27 PORT C Data Direction Register [DDC7..0]
PINC 0x26 PORT C Input Pins Address [PINC7..0]
PORTD 0x2B PORT D Data Register [PORTD7..0]
DDRD 0x2A PORT D Data Direction Register [DDD7..0]
PIND 0x29 PORT D Input Pins Address [PIND7..0]
  • Every PIN has 3 associated registers: PORT, DDR & PIN.
  • DDR sets the direction: 1 sets the pin as output, 0 as input.
  • If PORT is written as logic 1 when pin is configured as input, the pull-up resistor is activated.
  • If pin is configured as output, then PORT = 1 sets the pin HIGH, 0 sets the pin LOW.
  • Writing logic 1 to PIN toggles the value of PORT, independent of value of DDR.
  • Independent of the value of DDR, the port pin can be read via PIN register.
  • When reading back a software assigned pin value, a NOP instruction must be inserted.


At reset all PINs are tri-stated. What is tri-state? Wikipedia explains it as such: In digital electronics three-state, tri-state, or 3-state logic allows an output port to assume a high impedance state in addition to the 0 and 1 logic levels, effectively removing the output from the circuit.

This is achieved by setting DDR = 0 & PORT = 0. And so we have the following cases:

  0   0 tri-state (high impedance) – no pull-up
  0   1 high impedance with pull-up
  1   0 Output LOW
  1   1 Output HIGH


Type Description #Bytes
 int8_t / uint8_t  signed / unsigned char    8
 int16_t / uint16_t  signed / unsigned int   16
 int32_t / uint32_t  signed / unsigned long int   32
 int64_t / uint64_t  signed / unsigned long long int   64
 (u)intptr_t ((u)int16_t)  pointer variables   16

Dealing with Interrupts

  • Clear interrupts: cli()
  • Set interrupts: sei()
  • Clear interrupts, then restore original state of interrupts
// Save original value from register
uint8_t oldSREG = SREG;
// Clear interrupts
// Do any work
// Restore original values

Interrupt Handling

ISR(vector,attributes): ISR introduces an interrupt handler function (interrupt service routine) that runs with global interrupts initially disabled by default with no attributes specified.

Attributes: ISR_BLOCK (same as when no attributes are specified), ISR_NOBLOCK (ISR runs with global interrupts initially enabled. The interrupt enable flag is activated by the compiler as early as possible within the ISR to ensure minimal processing delay for nested interrupts.),

List of vectors for ATMega328

/* Interrupt Vectors */
/* Interrupt Vector 0 is the reset vector. */
#define INT0_vect         _VECTOR(1)   /* External Interrupt Request 0 */
#define INT1_vect         _VECTOR(2)   /* External Interrupt Request 1 */
#define PCINT0_vect       _VECTOR(3)   /* Pin Change Interrupt Request 0 */
#define PCINT1_vect       _VECTOR(4)   /* Pin Change Interrupt Request 1 */
#define PCINT2_vect       _VECTOR(5)   /* Pin Change Interrupt Request 2 */
#define WDT_vect          _VECTOR(6)   /* Watchdog Time-out Interrupt */
#define TIMER2_COMPA_vect _VECTOR(7)   /* Timer/Counter2 Compare Match A */
#define TIMER2_COMPB_vect _VECTOR(8)   /* Timer/Counter2 Compare Match B */
#define TIMER2_OVF_vect   _VECTOR(9)   /* Timer/Counter2 Overflow */
#define TIMER1_CAPT_vect  _VECTOR(10)  /* Timer/Counter1 Capture Event */
#define TIMER1_COMPA_vect _VECTOR(11)  /* Timer/Counter1 Compare Match A */
#define TIMER1_COMPB_vect _VECTOR(12)  /* Timer/Counter1 Compare Match B */ 
#define TIMER1_OVF_vect   _VECTOR(13)  /* Timer/Counter1 Overflow */
#define TIMER0_COMPA_vect _VECTOR(14)  /* TimerCounter0 Compare Match A */
#define TIMER0_COMPB_vect _VECTOR(15)  /* TimerCounter0 Compare Match B */
#define TIMER0_OVF_vect   _VECTOR(16)  /* Timer/Couner0 Overflow */
#define SPI_STC_vect      _VECTOR(17)  /* SPI Serial Transfer Complete */
#define USART_RX_vect     _VECTOR(18)  /* USART Rx Complete */
#define USART_UDRE_vect   _VECTOR(19)  /* USART, Data Register Empty */
#define USART_TX_vect     _VECTOR(20)  /* USART Tx Complete */
#define ADC_vect          _VECTOR(21)  /* ADC Conversion Complete */
#define EE_READY_vect     _VECTOR(22)  /* EEPROM Ready */
#define ANALOG_COMP_vect  _VECTOR(23)  /* Analog Comparator */
#define TWI_vect          _VECTOR(24)  /* Two-wire Serial Interface */
#define SPM_READY_vect    _VECTOR(25)  /* Store Program Memory Read */

ATMega328P Clock & Timer Registers

Name Purpose Details
 TCCR2A  Timer/Counter Control Register A
– use to set CTC
 0: Normal Operation
COM2[A:B][0:1]: Manage OC2A, OC2B
 TCCR2B  Timer/Counter Control Register B
– use to set prescaler
0: Timer stopped
CS20: No prescaling
CS21, CS22: Prescaling
TCNT2 Timer/Counter Register Running counter
OCR2A Output Compare Register A Continuously compared with counter value.
CTC mode – can trigger interrupt.
Generate waveform on OC2A pin.
OCR2B Output Compare Register B
TIMSK2 Timer/Counter2 Interrupt Mask Register TOIE2 – overflow interrupt is enabled.
OCIE2A – Compare Match A interrupt.
OCIE2B – Compare Match B interrupt.

ATMega328P Pin Change Interrupt Registers

Name Purpose Details
 PCICR  Pin Change Interrupt Control Register  PCIE0: enables for PCINT[7:0]
PCIE1: enables for PCINT[14:8]
PCIE2: enables for PCINT[23:16]
 PCMSK0  Pin Change Mask Register 0  PCINT[0:7]
 PCMSK1  Pin Change Mask Register 0  PCINT[8:14]
 PCMSK2  Pin Change Mask Register 0  PCINT[16:23]

Pin Mapping

ATMega168 Pin Mapping

References & Credits

One thought on “Basic AVR

  1. Pingback: Registers, registers & registers… | Hobby Electronics

Leave a Reply