Table of Contents

Introduction to the Arduino Uno programming in Assembler

The following chapter assumes that you are familiar with basic assembler operations for AVR microcontrollers. Below, we explain the most important construction elements and assembler instructions for manipulating the Arduino Uno's (figure 1) GPIOs, based on the ATmega328P microcontroller.

Figure 1: Arduino Uno development board

GPIO and Ports

The Arduino Uno exposes a number of GPIOs that can serve as binary inputs and outputs, analogue inputs, and many of them provide advanced, hardware-accelerated functions, such as UART, SPI, I2C, PWM, and ADC. In fact, not all of the pins on the development board are such “general-purpose”: some of them provide specific features, while others do not: there is no internal multiplexer, so functions such as UART, I2C, SPI, PWM and ADC are bound to particular GPIOs and cannot be changed.

On the programming level, GPIO ports are grouped into 3 “ports” (figure 2), and it is how you can access them:

A bit in the port corresponds to a single GPIO pin, e.g. bit 5 (6th, zero-ordered) of PortB corresponds to GPIO D13 and is connected to the built-in LED.

Figure 2: Arduino ports

IO Registers

Each Port has assigned three 8-bit registers:

Instructions

There is a set of assembler instructions that operate on Ports (I/O registers), as shown in table 1.

Assembler-level operations using ports are much faster than DigitalRead, DigitalWrite, and other instructions in C++, roughly 50 times faster.
Table 1: Common GPIO-related, I/O instructions
Instruction Description
SBI Set bit in register
CBI Clear bit in register
SBIS Skif if bit in register is set (1)
SBIC Skip if bit in register is clear (0)
IN Read hardware register to the general-purpose register (R0-R31)
OUT Write the general-purpose register to the hardware register.
ANDI Masks a bit
ORI Sets a bit

A common scenario is to first set either the GPIO is input or output (using the correct DDRx register), then either set (SBI), reset (CBI), check (SBIS, SBIC), read the whole register (IN) or write the whole register (OUT).

IN and OUT instructions operate on whole, 8-bit registers rather than on single bits. Those are general-purpose instructions, covering the whole range of IO registers (0-63), beyond aforementioned DDRx, PORTx and PINx registers.

Examples

Below are sections representing common usage scenarios:

Reading analogue values

Reading of the analogue values is not so straightforward as in the case of binary ones. Built-in ADC converter uses 10-bit resolution, has 6 channels (A0-A5, respectively). It also uses a reference voltage (configurable), typically 5V.
The low-level ADC register-based operations use the following formula to obtain an ADC value (figure 3, based on the input value Vgpio and the reference value Vref).

Figure 3: ADC value calculation based on the input voltage and reference voltage

Analogue reading uses a complex setup of ADC-related registers as presented in table 2:

Table 2: ADC-related registers used for reading the analogue values of GPIOs
Register Description
ADMUX Selects voltage reference and