AVR microcontrollers are built using a modified Harvard Architecture. This means the Flash Program Memory space is on a separate address bus than the Static Random Access Memory (SRAM). There are two data bus, one that can access all data and the In/Out data bus with limited access to a small section of memory.
Brief AVR Memory Summary
Program Memory
The AVR microcontrollers contain On-chip In-System Reprogrammable Flash memory for program storage. Since all AVR instructions are 16 or 32 bits wide, the Flash is organized as 32K x 16. For software security, the Flash Program memory space is divided into two sections - Boot Loader Section and Application Program Section in the device. The Flash memory has a typical endurance of at least 10,000 write/erase cycles. Constant tables can be allocated within the entire program memory address space, using the Load Program Memory (LPM) instruction. There is also a library of functions to make this easier AVR Libc Library
EEPROM Data Memory
Data electrically erasable programmable read-only memory (EEPROM) is organized as a separate data space, in which single bytes can be read and written. Access from the CPU to EEPROM is done through the EEPROM Address Registers, the EEPROM Data Register, and the EEPROM Control Register. The EEPROM has an endurance of at least 100,000 write/erase cycles.
SRAM Data Memory
Data can be accessed through the standard data bus. There is a secondary In/Out bus for rapid direct access to select locations.
Data memory consists of :
- Registers
- I/O Memory
- Extended I/O Memory (Device dependent)
- Internal SRAM
Register space - consists of 32 general purpose working 8-bit registers (R0-R31).
I/O Memory - contains addressable space for peripheral functions, such as control registers and other I/O functions.
Extended I/O Memory - Some AVR microcontrollers with more peripherals need more space than the I/O memory can address so some of the SRAM is used as Extended I/O memory to handle the extra peripherals control registers and other I/O functions.
Internal SRAM (Data Memory) - is used for temporarily storing intermediate results and variables within a software application.
There are five different data bus (not In/Out) addressing modes for the data memory:
- Direct - The direct addressing reaches the entire data space.
- Indirect - In the Register File, registers R26 to R31 feature the indirect addressing pointer registers.
- Indirect with Displacement - The Indirect with Displacement mode reaches 63 address locations from the base address given by the Y- or Z-register.
- Indirect with Pre-decrement - The address registers X, Y, and Z are decremented.
- Indirect with Post-increment - The address registers X, Y, and Z are incremented.
In/Out Data bus
This data bus has direct access to the 64-byte I/O Memory section (not Extended) using a 0x00 to 0x1F address. This memory can also be accessed by the standard data bus using a 0x20 address offset in the access command.
I/O Memory
All I/O locations (I/O Memory and Extended I/O Memory) can be accessed by the LD/LDS/LDD and ST/STS/STD assembly instructions using the standard data bus. Data is transferred between the 32 general purpose working registers and the I/O space.
I/O Registers within the In/Out data bus address range 0x00-0x1F (I/O Memory) are directly bit-accessible using the SBI and CBI instructions. In these registers, the value of single bits can be checked by using the SBIS and SBIC instructions.
General Purpose I/O Registers
Three General Purpose I/O Registers, General Purpose I/O Register 0/1/2 (GPIOR 0/1/2) are at the top of the I/O memory (0x020- 0x022). These registers can be used for storing any information, and they are particularly useful for storing global variables and Status Flags. These registers are directly bit-accessible using the SBI, CBI, SBIS, and SBIC instructions through the In/Out data bus. Remaining I/O registers begin after the General Purpose I/O Registers.
Accessing 16-bit Registers
The AVR data bus is 8 bits wide so accessing 16-bit registers requires atomic operations. These registers must be byte-accessed using two read or write operations. 16-bit registers are connected to the 8-bit bus and a temporary register using a 16-bit bus.
For a write operation, the high byte of the 16-bit register must be written before the low byte. The high byte is then written into the temporary register. When the low byte of the 16-bit register is written, the temporary register is copied into the high byte of the 16-bit register in the same clock cycle.
For a read operation, the low byte of the 16-bit register must be read before the high byte. When the low byte register is read by the CPU, the high byte of the 16-bit register is copied into the temporary register in the same clock cycle as the low byte is read. When the high byte is read, it is then read from the temporary register.
This ensures that the low and high bytes of 16-bit registers are always accessed simultaneously when reading or writing the register.