How Programs Run in Microcontrollers

Introduction

To understand how microcontrollers run programs, it is essential to know the components of a microcontroller. This article takes the 80C51 microcontroller as an example to explain how programs run within a microcontroller.

Components of a Microcontroller

The internal hardware structure of the 8051 microcontroller includes:

  • Central Processing Unit (CPU): It is the core component of the microcontroller, determining its primary functional characteristics, composed of the arithmetic logic unit and the control unit.

  • Memory: The 8051 microcontroller adopts a Harvard architecture, storing programs and data in two separate memory spaces, one for program memory and another for data memory. Physically, there are four independent memory spaces: on-chip ROM, off-chip ROM, on-chip RAM, and off-chip RAM.

  • Timer/Counter (T/C): The 8051 microcontroller has two 16-bit timers/counters, each of which can be set to counting mode or timing mode, controlling the computer based on its timing results.

  • Parallel I/O Ports: The 8051 has four 8-bit parallel I/O ports (P0 to P3) for parallel data input and output.

  • Serial Port: The 8051 microcontroller has a full-duplex serial port for serial communication between microcontrollers or with other devices.

  • Interrupt Control System: The 8051 has five interrupt sources, categorized into high and low priority levels. It can receive external interrupt requests, timer/counter requests, and serial port requests, commonly used for real-time control, fault handling, data transfer between the computer and peripherals, and human-machine interaction.

Startup Process of the Microcontroller

The startup process of the microcontroller begins with powering on, running the inherent program within the chip (this program is inaccessible and unmodifiable by the user), known as the boot code. Once the boot code establishes the running environment, it reads the serial port status to determine whether the user is preparing to download a program through the ports.

If so, the user program is downloaded to the specified address as requested. If not, it jumps to the previously downloaded user program entry, transferring control to the user program. If it is a new chip that has not been programmed, it remains in a loop reading the serial port status.

The boot code is typically burned into flash memory and is executed immediately upon power-up, running before any user C code. Upon power-up, the ARM processor is in ARM mode, running in management mode, with all interrupts disabled, and the PC fetches instructions from address 0.

An executable image file must have an entry point, and the entry address of an image file that can be placed at the start of ROM must be set to 0. In assembly language, a program’s entry point can be defined, and when there are multiple entry points in a project, the linker must use -entry to specify the program’s entry point.

If the user-created program contains a main function, there will also be an entry point corresponding to the C library initialization code. In summary, the boot code primarily performs two tasks: one is to initialize the execution environment, such as the interrupt vector table, stack, I/O, etc.; the second is to initialize the C library and user applications.

In the first stage, the boot code process can be described as follows:

  • Establishing the interrupt vector table;
  • Initializing memory;
  • Initializing the stack register;
  • Initializing I/O and other necessary devices;
  • Changing the processor’s state as needed.

PCs with operating systems, when powered on, undergo a process similar to that of microcontrollers, except they read the BIOS, which completes many initialization operations, ultimately calling the system’s initialization function and transferring control to the operating system, allowing us to see Windows or Linux start up.

If we view the operating system as a large bare-metal program running on the processor (i.e., directly running on hardware since the operating system runs directly on the CPU), then the startup of the operating system closely resembles the startup of MCU programs. The former has a large initialization program that completes complex initialization, while the latter has a short assembly code that completes some simple initialization.

What about the startup of system programs? They are determined by the system. In Linux, after entering ./p in the shell, it first checks whether it is a built-in shell command; if not, the shell assumes it is an executable file (usually in ELF format on Linux), then calls relevant functions to copy the content of the p file from the hard disk to memory (DDR RAM) and establishes a running environment for it (of course, this involves memory mapping, virtual memory, linking, loading, and other processes) to prepare for execution.

From the above, it can be seen that the startup of programs on microcontrollers and those running on systems differs significantly. If we abstract the actions before calling main as initialization, the program startup can be simplified to: establishing the running environment + calling the main function, thus the execution difference is not substantial.

This is because the programs running on microcontrollers (bare-metal programs) run on hardware just like operating systems; they belong to the same level. The reason we did not distinguish the differences between programs on microcontrollers and those on PCs in the past is that we did not understand this point.

Execution of Programs

Regarding the execution of programs, specifically where instructions and data are read from, there was confusion for a long time due to the lack of clarity about the differences between system programs and bare-metal programs.

The operation of a program in a microcontroller consists of fetching instructions, decoding instructions, and executing instructions:

  • The task of fetching instructions is: reading the current instruction from program memory based on the value in the program counter (PC) and sending it to the instruction register.

  • The task during the instruction decoding phase is: extracting the opcode from the instruction register for decoding, analyzing the nature of the instruction. If the instruction requires operands, it searches for the operand addresses.

  • The process of executing a program on a computer is essentially a repetition of the above operations for each instruction until a halt instruction is encountered, at which point it can loop and wait for the next instruction.

Although in the “Principles of Microcomputers” course, we learned that during program execution, instructions and data are read from memory for execution and write-back. However, a microcontroller only has a few kilobytes of RAM, while flash typically has tens of kilobytes or even 1 megabyte. Does this mean that instructions and data are all in memory?

Here, the term memory refers only to RAM. Because when we commonly refer to memory on PCs, we mean DDR RAM memory, leading to the assumption that microcontrollers also function this way without realizing that both RAM and Flash are types of memory.

This is not possible because the instructor only mentioned memory, but on a PC, memory generally refers to DDR RAM, not the hard disk, which is where data is stored. This analogy led to confusion, as one might think that the RAM in a microcontroller corresponds to DDR RAM, and whether Flash corresponds to the hard disk. In CSAPP, it became clear that the reason programs run on DDR RAM on PCs is due to speed considerations.

The speed of hard disks is too slow, and even the upcoming SSDs are several orders of magnitude slower than DDR RAM, necessitating copying to DDR RAM. At this point, a program’s code and data are stored consecutively, where the code segment is read-only, and the data segment is writable (this is determined by the operating system’s memory management mechanism).

During runtime, they are copied to faster SRAM for improved execution speed. For microcontrollers, the working frequency is only a few megahertz or tens of megahertz, so the difference between reading from Flash and RAM may not be noticeable and will not become a bottleneck for program execution. For PCs, however, the speed of Flash is too slow, and the speed of DDR RAM is also slow, so even SRAM is considerably slower, thus increasing the CPU working frequency does not enhance program execution speed, leading to a bottleneck where CPU working frequencies peaked around 2003.

Example

Upon booting, the program counter (PC) is set to 0000H. The microcontroller then automatically enters the execution process under the influence of the timing circuit. The execution process is essentially a cyclical process of fetching instructions (fetching previously stored instructions from memory) and executing instructions (decoding and executing instructions).

For example, executing the instruction: MOV A,#0E0H, with the machine code 74H E0H, this instruction’s function is to send the operand E0H into the accumulator. The 0000H unit contains 74H, and the 0001H unit contains E0H. When the microcontroller starts running, it first enters the instruction fetch phase, and the order is as follows:

  • The content of the program counter (currently 0000H) is sent to the address register;

  • The content of the program counter is automatically incremented by 1 (changing to 0001H);

  • The content of the address register (0000H) is sent to memory via the internal address bus, enabling the address decoding to select the memory unit at 0000H;

  • The CPU activates the read control line;

  • Under the read command control, the selected memory unit’s content (which should be 74H at this time) is sent to the internal data bus, and since this is the instruction fetch phase, this content is sent to the instruction register via the data bus.

Multithreading Execution of Programs

To improve CPU utilization, let’s think from another angle: since we cannot reduce the execution time of a program, we can execute more programs in the same time frame—one core executes one program, and two cores can execute two programs, making multi-core CPUs the mainstream today.

Thus, bare-metal program instructions are stored in Flash (Flash memory), while data is stored in RAM (Flash has limited write cycles, and its speed is still much slower than RAM). More broadly, on microcontrollers, RAM stores the data segment, BSS segment, stack segment; ROM (EPROM, EEPROM, Flash, and other non-volatile storage devices) stores the code and read-only data segments.

Essentially, this is similar to how programs are stored in RAM on PCs, where the operating system defines read and write permissions, while microcontrollers rely on different storage devices to distinguish between readable and writable.

Of course, modern Flash is writable; if Flash had no write cycle limitations and its speed matched that of RAM, would it be sufficient to have only Flash on microcontrollers (equivalent to DDR RAM on PCs)? This would lower costs compared to having one RAM and one Flash, making it more economical for manufacturers.

Data Storage and Retrieval

Regarding the storage and retrieval of instructions and data during the execution of programs on microcontrollers, it can be understood as follows:

After programming a microcontroller, the code segment, data segment, BSS segment, and read-only data segment are all stored in Flash. When the microcontroller is powered on, the initialization assembly code copies the data segment and BSS segment to RAM and establishes the stack before beginning to call the main function of the program.

Subsequently, there is a distinction between program memory and data memory, where instructions are read from Flash (the instruction memory, code memory) and data is read from and written to RAM. The significance of RAM lies in its faster speed.

Whether for microcontrollers or PCs, the pyramid of existing memory is consistent, with speed factors and cost limitations leading to progressively faster storage at higher costs. Understanding them should be viewed through the lens of the memory pyramid.How Programs Run in Microcontrollers

Conclusion

This concludes our discussion on the execution process of programs in microcontrollers. I believe that after reading this article, you will gain a deeper understanding of how programs operate. If this article has enhanced your understanding of program execution, remember to like and share!

How Programs Run in Microcontrollers

END

Source: Embedded Yu Xiang Garden
Copyright belongs to the original author. If there is any infringement, please contact for deletion.
Recommended Reading
Zhi Hui Jun is making big moves again!
The principle of automatic baud rate recognition of STM32 serial port
After 7 years of coding, I encountered such a ridiculous bug for the first time!

→Follow to stay updated←

Leave a Comment

×