Open In App

CALL Instructions and Stack in AVR Microcontroller

Last Updated : 24 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Introduction :

The AVR microcontroller is a type of microcontroller developed by Atmel Corporation. It is widely used in various embedded systems due to its low power consumption and high performance. In this context, I will discuss the introduction to CALL instructions and the stack in AVR microcontrollers.

CALL instructions are used to call a subroutine or a function in AVR microcontrollers. When the CALL instruction is executed, the current address of the program counter (PC) is pushed onto the stack, and the PC is loaded with the address of the subroutine. Once the subroutine is completed, the RET instruction is executed, which pops the saved address from the stack and loads it back into the PC. This allows the program to resume execution from the point it left off.

The stack is a special region of memory used to store temporary data in AVR microcontrollers. When a subroutine is called, the current values of the registers are saved onto the stack, and the subroutine can use the registers without interfering with the main program. When the subroutine is completed, the saved values are restored, and the program resumes execution from where it left off.

The stack in AVR microcontrollers grows downwards from a high memory address to a lower memory address. The stack pointer (SP) is a register that points to the current top of the stack. The SP is initialized at the beginning of the program, and as the stack grows, the SP is decremented. When the stack is popped, the SP is incremented.

It is essential to manage the stack properly in AVR microcontrollers to prevent stack overflow or underflow. Stack overflow occurs when the stack grows beyond its allocated size, overwriting other critical data. Stack underflow occurs when there are not enough items on the stack to be popped, resulting in undefined behavior.

CALL is a control transfer instruction that is used to call a particular subroutine. A subroutine is a block of instructions that need to be performed frequently. In AVR, there are 4 instructions for the call subroutine as following.

  1. CALL (call subroutine)
  2. RCALL (relative call subroutine)
  3. ICALL (indirect call to Z)
  4. EICALL (extended indirect call to Z)

CALL : In this 4-byte instruction, 10 bits are used for the opcode and the other 22 bits are used for the address of the target subroutine just as in the JMP instruction. In this, 4M address space of 000000-$3FFFFF for AVR and can be used to call subroutines within the given range of address. To make sure that the AVR knows where to come back after the execution of the subroutine, the microcontroller automatically saves the address of the instruction just below the CALL instruction on the stack. After finishing the execution of the subroutine, the RET instruction transfers control back to the caller. Hence, every subroutine has a RET instruction at the end. Stack : Stack is the part in the RAM of CPU to store information temporarily. The CPU needs this storage because there is only a limited number of registers. The register used to access the stack is called the stack pointer (SP) register. In I/O memory space, there are 2 registers named SPL (the low byte of SP) and SPH (the high byte of SP). The SP is implemented by these 2 registers. In AVRs with more than 256 bytes of memory have two 8-bit registers. On the other hand, if the memory is less than 256 bytes, SP is made up of only SPL, as an 8-bit register can only address 256 bytes of memory. The storing of the CPU information on the stack is called the PUSH operation, and the loading of the stack contents back into the CPU is known as POP operation. Pushing onto the stack : The stack pointer (SP) points to the top of the stack. As we push the data onto the stack, the data is saved where the SP is pointing to and the SP is decremented by one. To push a register onto a stack, we use PUSH instruction.

PUSH  Rr; 
Rr can be any general-purpose register (R0 - R31)

Popping from the stack : Popping the contents of the stack back into the register is the opposite function of pushing. When the POP instruction is executed, the SP is incremented by one and the top location of the stack is copied back to the register. This means that the stack is LIFO ( Last In First Out). To retrieve back the data from the stack, we use POP instruction.

POP  Rr; 
Rr can be any general-purpose register (R0 - R31)

Initializing stack pointers : Different AVRs have different amounts of RAM. In the AVR assembler, RAMEND specifies the address of the last RAM location. So, if we want to initialize the SP so that it points to the last memory location, we can simply load RAMEND into the SP. Notice that SP is made up of 2 registers, SPH and SPL. So, we load the high byte of RAMEND into SPH and the low byte of RAMEND into SPL. CALL instruction, RET instruction and the role of stack : When the CALL instruction is executed, the address of the instruction below the CALL instruction is pushed onto the stack. When the execution of that subroutine is finished and RET is executed, the address of the instruction below the CALL instruction is loaded in the program counter and it is executed.

Uses of CALL Instructions and Stack in AVR Microcontroller :

CALL instructions and the stack play a vital role in AVR microcontrollers, and they have several important uses:

  1. Function calls: CALL instructions are used to call subroutines or functions in AVR microcontrollers. This allows programs to be modular and organized, making it easier to write and maintain complex code.
  2. Interrupt handling: Interrupts are used to handle events that occur asynchronously to the program’s normal execution. When an interrupt occurs, the AVR microcontroller saves the current program state on the stack and jumps to the interrupt service routine. After the ISR is completed, the AVR microcontroller restores the saved program state from the stack and resumes the normal program execution.
  3. Recursive functions: Recursive functions are functions that call themselves. The stack is used to store the program state of each recursive call, allowing the AVR microcontroller to return to the previous function call after the current one completes.
  4. Local variables: When a function is called, local variables are stored on the stack. This allows the function to use these variables without affecting other parts of the program.
  5. Parameter passing: When a function is called, parameters are passed to the function through registers or the stack. The stack is used to store the parameters, and the function can access them from the stack.
  6. Context switching: In some embedded systems, it is necessary to switch between different tasks or contexts. The stack is used to store the program state of each task, allowing the AVR microcontroller to switch between them efficiently.

Issues in CALL Instructions and Stack in AVR Microcontroller :

There are several issues that can arise if they are not used or managed properly. Some of the most common issues are:

  1. Stack overflow: If the stack grows beyond its allocated size, it can overwrite other critical data, causing unpredictable behavior or crashing the program.
  2. Stack underflow: If there are not enough items on the stack to be popped, it can cause undefined behavior or even crash the program.
  3. Interrupt latency: When an interrupt occurs, the AVR microcontroller saves the current program state on the stack before jumping to the ISR. If the ISR takes too long to execute, it can increase the interrupt latency, causing other interrupts to be missed or delayed.
  4. Recursive function depth: When a function calls itself recursively, it can quickly consume the available stack space, leading to stack overflow or unpredictable behavior.
  5. Stack pointer corruption: If the stack pointer is accidentally overwritten or corrupted, it can cause stack underflow or overflow, leading to program crashes or undefined behavior.
  6. Interrupt nesting: If interrupts occur while an ISR is already executing, it can lead to interrupt nesting, which can cause unexpected behavior or crashes if not properly managed.

Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads