Unit 2
Embedded C Programming
Difference Between Von Neumann and Harvard Architecture
Memory Interfacing in 8051:
8051 program Memory
8051 Data Memory
Interfacing Program Link:
LED Interfacing: https://youtu.be/Z2wPyXf2984
Seven Segment Display: https://youtu.be/GM-TVmjvITk
DAC and ADC interface: https://youtu.be/yFIiJ6bJUNE
LCD Interface: https://www.youtube.com/watch?v=PDnPSiblELg
Stepper Motor Interfacing: https://www.youtube.com/watch?v=CZ95RiovT7I
LCD Interface with 8051:
Stepper Motor Interfacing:
Embedded C Programming:
What is Embedded C?
Embedded C is a programming language that is used in the development of Embedded Systems. Embedded Systems
are specialized systems designed to perform very specific functions or tasks. Embedded System is the combination
of hardware and software and the software is generally known as firmware which is embedded into the system
hardware. Embedded C is used to program a wide range of microcontrollers and microprocessors. Embedded C
requires less number of resources to execute in comparison with high-level languages such as assembly
programming language.
Embedded C has some additional data types and keywords. There are some special datatypes in Embedded C like
sbit, sfr which are used for addressing special function registers in memory. Embedded C allows us to work with
hardware devices like sensors, and input-output devices. There are various Embedded C compilers to compile the
embedded C program such as Keil Compiler, SPJ Compiler, Embedded GNU C Compiler, etc. Embedded
Systems can be classified into small-scale, medium-scale, and sophisticated embedded systems. The devices like air
conditioners, printers, and mobile phones that we use in our daily lives are programmed by embedded C.
Difference between C and Embedded C
Parameter C Embedded C
Embedded C is a set of language
C is a versatile programming
extensions for the C programming
Definition language that supports
language designed to program
structured programming
microcontrollers
C is developed by Dennis M. Embedded C is developed by C
Development
Ritchie Standards Committee
C language is hardware Embedded C is hardware dependent
Hardware dependency
independent language
Parameter C Embedded C
Compilers that are capable of
A standard compiler facilitates
generating microcontroller based
Compiler Execution the compilation and execution
output needs to be used to execute
of a program.
Embedded C code
C language generates operating
Embedded C generates hardware
Functionality system dependent executable
dependent files
files
Network drivers, interpreters,
Robots, Vehicle tracking systems,
compilers, operating system
Applications smart monitoring systems are some
and text editors are some of the
of the applications.
applications
Key Characteristics of Embedded C
Efficiency: In Embedded C we can create a efficient code to optimize the limited resources available in embedded
systems. It aims to minimize memory usage and maximize performance.
Direct Hardware Interaction: Embedded C allows programmers to interact directly with hardware components,
such as microcontrollers, sensors, actuators, and other peripherals. This direct interaction facilitates precise control
over the hardware, critical in embedded applications.
Low-level Programming: Embedded C involves low-level programming, which deals with hardware-specific
details like memory addresses, I/O ports, and register manipulation. This level of control is essential for efficiently
managing hardware resources.
Real-time Operations: Embedded systems often operate in real-time environments, requiring precise timing and
response to events. Embedded C allows programmers to handle real-time tasks efficiently.
Structure of Embedded C Program
Comments :Comments are readable text written to help user understand the code easily. They are ignored by
compiler and do not take up any memory in the final code. There are two types of comments, Single line
comments and Multiline comments.
Preprocessor Directive :In Embedded C Preprocessor Directives are represented using #include or #define.
Preprocessor Directives are used to indicate a header file specific to a microprocessor or microcontroller
which contains all the functions, SFR’s and the bits in those SFR’s. reg51 header file is used in case of 8051
microcontroller.
Global Variables :Global variables as the name suggests are global to program that is they can be accessed
any where in the program. Global variables are static variables and are placed in RAM memory locations.
Local Variables :Local variables in contrast to global variables are confined to their respective functions.
Normally these variables are placed in stack or registers. It is only valid within the function in which it is
declared.
Function :Function is a group of statements that together performs a task. A function declaration tells
the compiler about the name, return type and parameter of the function. A function definition provides actual
body of the function.
Main Function :Every Embedded C program has one main function and may contain one or more
functions in the main functions. The program execution starts from the main function and it is a core of every
execution. If more than one main function is written in the code then compiler will confuse from where to start
the program execution.
Standard Embedded C Data Types
Data Type Bits Range
Unsigned char 8 0 – 255
Signed char 8 -128 – +127
Unsigned int 16 0 – 65535
Signed int 16 -32768 – +32767
bit 1 0–1
sbit 1 0–1
sfr 8 0 – 255
sfr16 16 0 – 65535
Block Diagram Explanation of Embedded C
Problem :Problem refers to a challenge or task which needs to be addressed by programming. The problem
defines the purpose and functionality of the Embedded System. The necessary coding solutions should be achieved
by understanding the problem statement. It includes functional requirements, non-functional requirements,
Hardware Interfacing and Expected Output.
Algorithm :Algorithm is a set of instructions that tells us that how the task should be executed in step-wise
manner in order to solve the problem. Algorithm helps us to visualize and design the logic before
implementation of actual program. It is written in step by step order. Let’s take a look at an example for better
understanding.
Algorithm to add two numbers and store the result :
1. Make the Port 1 and Port 2 as Input port .
2. Take the data from Port 1.
3. Take the data from Port 2.
4. Add the content of Port 1 with Port 2
5. Send result of addition to Port 3.
Flowchart : A flowchart is a graphical representation of an algorithm which shows the steps to be followed
using some symbols and arrows. Flowchart makes it easy to understand the structure of program before coding by
visualizing the flow of logic. It shows decision points such as conditional statement, loops and code
terminations. As it uses symbols and shapes, debugging is easy and it takes less efforts in writing the logic of a
program. Flowchart and Algorithm helps in identifying logical errors while troubleshooting the code which is a
difficult process in itself.
Compilation and Uploading of Code :Generally programmers write code using high level languages like C where
human readable syntax is used. This language is not understandable by CPU of computer. We need to translate it
into machine level code which a CPU can easily understand. So a compiler needs to be used for this purpose.
Compiler is a specialized software tool which translates the human readable code (source code) into machine
code (binary code) according to the specific microcontroller architecture.
The machine code is executed by the CPU by carrying out the instructions step-by-step to perform the tasks written
in the actual code written by programmer/use. Machine code consists of instructions which are understandable by
the computer’s CPU. It is a string of 0’s and 1’s representing logical, arithmetic operations. A hex file is generated
after compilation process that contains the machine code which is uploaded in microcontroller’s flash memory
through programmer/debugger. After uploading, the code is tested and verified for correct operation of Embedded
System. In this way the solution for the problem statement is achieved in Embedded C
Basic Embedded C Programming Steps
Requirement Analysis :Understanding the requirements of the Embedded System to be developed according
to the problem | requirement should be done.
Selecting Environment Setup :Selection of proper tools such as choosing Integrated Development
Environment (IDE) ,compiler, debugger and other necessary tools for Embedded C Programming.
Code Development :Writing the Embedded C code based on the system requirements and design
specifications must be done in this step. The program should consume less memory space, must be reliable
and scalable.
Compilation Process :In this stage the compiler translates the embedded C code into assembly language code
or machine level code. The machine level code is in the form of 0’s and 1’s. Also the preprocessor handles the
directives such as #include, #define.
Loading to Target device :Uploading the compiled code onto the target hardware ( microcontroller, FGPA )
using tools like debugger or flash programmers needs to be done.
Execution and Debugging :Run the embedded system and execution of code is performed. Employing
debugging tools to identify and resolve any errors or issues in the code.
Documentation and Maintenance :Creating proper documentation detailing the system architecture, code
functionalities and memory usage. Periodically updating and maintaining the codebase to address issues.
Advanced Techniques for Embedded C
Pointer manipulation: Pointers in C are powerful but can be complex. They allow direct access to
memory locations, aiding in efficient data manipulation. Understanding pointer arithmetic, dynamic
memory allocation (malloc/free), and using pointers accessing hardware registers or structures are crucial in
embedded C programming.
Interrupt handling: In embedded systems, interrupts are used to handle asynchronous events. Mastering
ISR involves understanding how to write interrupt service routines, handle interrupt priorities, manage shared
resources, and minimize interrupt latency to ensure timely response to events.
RTOS (Real-Time Operating Systems): RTOS facilitates multitasking within embedded systems.
Understanding concepts like task scheduling, context switching, inter-process communication (IPC), and
synchronization mechanisms (semaphores, mutexes) is very much important for developing real-time
embedded applications.
Peripheral Interfacing: Embedded systems interact with various peripherals. Knowledge of communication
protocols (UART, SPI, I2C), handling GPIO pins, configuring timers, and managing interrupts related to
peripherals is important for effective interfacing.
Low-power Optimization: Embedded devices often run on limited power. Techniques to reduce power
consumption involve utilizing low-power modes provided by microcontrollers, selectively shutting down
unused peripherals, and optimizing algorithms for energy efficiency.
Memory Management: Embedded systems have limited memory. Efficiently managing memory includes
minimizing memory fragmentation, choosing appropriate data types, implementing memory pooling,
and handling dynamic memory allocation carefully to avoid memory leaks.
Debugging and Testing: Embedded system debugging involves using hardware debuggers, emulators,
simulators, and printf-style debugging.
Embedded C Program Examples
1. Write a Program to read the number 1 from port 1, number 2 from port 2 , then add them ,store the result
,send it to Port 3.
#include<reg.51.h>
void main()
{
unsigned char a,b,c ;
P1 = 0XFF ; //make port 1 as input port
P2 = 0XFF ; //make port 2 as input port
a=P1;
b=P2;
c= a+b ;
P3= c;
}
2. Write a program to Turn on and off the LED with some delay
#include<reg51.h>
sbit LED=P1.1;
void delay(void);
void main(void)
{
while(1)
{
LED=1;
delay();
LED=0;
delay();
}
}
void delay(void)
{
unsigned char i,k;
for(i=0;i<70;i++)
for(k=0;k<255;k++);
}
3. Write a program to transfer the data from port P0 to port P1.
#include<reg51.h>
void main (void )
{
unsigned char X;
P0=0XFF; // P0 as input port
P1=0X00; // P1 as output port
while(1)
{
X = P0; // read port0
P1 = X; // output data to port1
}
Advantages of writing a program in Embedded C
It is easy and less time consuming to write code in Embedded C instead of assembly programming language.
Embedded C program is easier to modify and update.
Code available in function libraries can be used by the programmer.
Embedded C code is portable to other microcontrollers with little or no modifications.
Embedded C code tends to be more readable and maintainable than assembly language.
Disadvantages of Embedded C Programming
It can only perform one task at a time, it cannot perform several activities. We need to update the hardware if
we changed the application.
Only the hardware system is supported.
It is not scalable, scalability is an problem with Embedded C.
It has limitations such as restricted RAM which affects the computer’s compatibility.
FAQs on Embedded C
1. How is memory management handled in Embedded C ?
Memory management in embedded C is crucial task due to reasons such as limited resources. Techniques like static
memory allocation or memory mapping I|O is done to efficiently manage memory in Embedded C.
2. How are timing operations performed in Embedded Systems using Embedded C ?
Timing and Counting operations in Embedded system are performed using in-built timer in microcontroller. In case
of 8051 microcontroller there are two 16-bit timers, Timer 0 and Timer 1. TMOD register, a 8-bit register is used to
set the various timer operation modes for both timers.
3. What is the role of interrupts in Embedded C Programming ?
A interrupt plays an important role in embedded systems by allowing the processor to give service to external events
by setting priorities. An interrupt represents an external or internal occurrence that interrupts the normal operation
of a microcontroller, signaling that a device requires attention. Each interrupt necessitates the presence of an Interrupt
Service Routine (ISR) or handler. Upon occurrence of an interrupt, the microcontroller executes the corresponding
interrupt service routine.
Design Patterns for Embedded Systems in C
When working with embedded systems in C, there are so many design patterns that are particularly very useful. Many
design patterns can be applied to embedded systems development in C.
Important Topics for Design Patterns for Embedded Systems in C
Creational Design Patterns for Embedded Systems in C
o Factory Method Design Pattern
o Object Method Design Pattern
o Opaque Method Design Pattern
o Singleton Method Design Pattern
Structural Design Patterns for Embedded Systems in C
o Callback Method Design Patterns
o Inheritance Method Design Pattern
o Virtual API Method Design Pattern
Other Design Patterns for Embedded System in C
o Bridge Method Design Pattern
o Concurrency Method Design Pattern
o Spinlock Method Design Pattern
o Mutex Method Design Pattern
o Conditional Method Design Pattern
o Behavioral Method Design Pattern
What is a Design Pattern?
Design patterns are defined as the general reusable solutions to the common problems that occur during software development and
software designing.
They provide a template for solving certain types of problems and help the developers structure the code in a way that makes it
more modular, maintainable, and scalable.
Link: https://www.geeksforgeeks.org/design-patterns-for-embedded-systems-in-c/#1-what-is-a-design-pattern
Multiple Tasks and Multiple Processes
Release Time and Dead line:
Aperiodic and Periodic Process:
Context Switching
The Context switching is a technique or method used by the operating system to switch a process from one state to
another to execute its function using CPUs in the system.
When switching perform in the system, it stores the old running process's status in the form of registers and
assigns the CPU to a new process to execute its tasks.
While a new process is running in the system, the previous process must wait in a ready queue.
The execution of the old process starts at that point where another process stopped it.
It defines the characteristics of a multitasking operating system in which multiple processes shared the same CPU to
perform multiple tasks without the need for additional processors in the system.
The need for Context switching
A context switching helps to share a single CPU across all processes to complete its execution and store the system's
tasks status.
When the process reloads in the system, the execution of the process starts at the same point where there is conflicting.
Following are the reasons that describe the need for context switching in the Operating system.
1. The switching of one process to another process is not directly in the system. A context switching helps the operating
system that switches between the multiple processes to use the CPU's resource to accomplish its tasks and store its
context. We can resume the service of the process at the same point later. If we do not store the currently running
process's data or context, the stored data may be lost while switching between processes.
2. If a high priority process falls into the ready queue, the currently running process will be shut down or stopped
by a high priority process to complete its tasks in the system.
3. If any running process requires I/O resources in the system, the current process will be switched by another
process to use the CPUs. And when the I/O requirement is met, the old process goes into a ready state to wait for its
execution in the CPU. Context switching stores the state of the process to resume its tasks in an operating system.
Otherwise, the process needs to restart its execution from the initials level.
4. If any interrupts occur while running a process in the operating system, the process status is saved as registers
using context switching. After resolving the interrupts, the process switches from a wait state to a ready state to resume
its execution at the same point later, where the operating system interrupted occurs.
5. A context switching allows a single CPU to handle multiple process requests simultaneously without the need for
any additional processors.
Example of Context Switching
Suppose that multiple processes are stored in a Process Control Block (PCB). One process is running state to execute its
task with the use of CPUs.
As the process is running, another process arrives in the ready queue, which has a high priority of completing its task
using CPU.
Here we used context switching that switches the current process with the new process requiring the CPU to finish its
tasks.
While switching the process, a context switch saves the status of the old process in registers.
When the process reloads into the CPU, it starts the execution of the process when the new process stops the old process.
If we do not save the state of the process, we have to start its execution at the initial level.
In this way, context switching helps the operating system to switch between the processes, store or reload the process
when it requires executing its tasks.
Context switching triggers
Following are the three types of context switching triggers as follows.
1. Interrupts
2. Multitasking
3. Kernel/User switch
Interrupts: A CPU requests for the data to read from a disk, and if there are any interrupts, the context switching automatic
switches a part of the hardware that requires less time to handle the interrupts.
Multitasking: A context switching is the characteristic of multitasking that allows the process to be switched from the CPU so
that another process can be run. When switching the process, the old state is saved to resume the process's execution at the
same point in the system.
Kernel/User Switch: It is used in the operating systems when switching between the user mode, and the kernel/user mode
is performed.
What is the PCB?
A PCB (Process Control Block) is a data structure used in the operating system to store all data related information to the
process.
For example, when a process is created in the operating system, updated information of the process, switching
information of the process, terminated process in the PCB.
Steps for Context Switching
There are several steps involves in context switching of the processes.
The following diagram represents the context switching of two processes, P1 to P2, when an interrupt, I/O needs, or
priority-based process occurs in the ready queue of PCB.
As we can see in the diagram, initially, the P1 process is running on the CPU to execute its task, and at the same time,
another process, P2, is in the ready state.
If an error or interruption has occurred or the process requires input/output, the P1 process switches its state
from running to the waiting state.
Before changing the state of the process P1, context switching saves the context of the process P1 in the form of
registers and the program counter to the PCB1.
After that, it loads the state of the P2 process from the ready state of the PCB2 to the running state.
The following steps are taken when switching Process P1 to Process 2:
1. First, thes context switching needs to save the state of process P1 in the form of the program counter and the registers to
the PCB (Program Counter Block), which is in the running state.
2. Now update PCB1 to process P1 and moves the process to the appropriate queue, such as the ready queue, I/O queue
and waiting queue.
3. After that, another process gets into the running state, or we can select a new process from the ready state, which is to
be executed, or the process has a high priority to execute its task.
4. Now, we have to update the PCB (Process Control Block) for the selected process P2. It includes switching the process
state from ready to running state or from another state like blocked, exit, or suspend.
5. If the CPU already executes process P2, we need to get the status of process P2 to resume its execution at the same time
point where the system interrupt occurs.
Similarly, process P2 is switched off from the CPU so that the process P1 can resume execution.
P1 process is reloaded from PCB1 to the running state to resume its task at the same point.
Otherwise, the information is lost, and when the process is executed again, it starts execution at the initial level.
Priority Based Scheduling Policies
Priority Scheduling is a process scheduling algorithm based on priority where the scheduler selects tasks
according to priority.
Thus, processes with higher priority execute first followed by processes with lower priorities.
If two jobs have the same priorities, then the process that should execute first is chosen on the basis of round-robin or
FCFS.
Which process should have what priority depends on a process’ memory requirements, time requirements, the ratio of
I/O burst to CPU burst, etc.
Types of Priority Scheduling
Following are the two main types of priority scheduling:
1. Preemptive Scheduling:
Tasks execute according to their priorities.
In case a lower priority task is running and a higher priority task arrives in the waiting state then the lower priority task
is put on hold.
The higher priority task replaces it and once done executing the lower priority task resumes execution from when it was
paused.
This process requires special hardware like a timer.
2. Non-Preemptive Scheduling:
The OS allocates the CPU to a specific process that releases the CPU either through context switching or after
termination.
We can use this method on various hardware platforms because unlike preemptive scheduling it doesn’t require any
special hardware.
Characteristics of Priority Scheduling
Schedules processes on the basis of priority.
Used to perform batch processes.
In the case of two processes with similar priorities, we use FCFS and Round-Robin to choose between them.
A number is given to each process to indicate its priority level.
Lower is the number assigned, higher is the priority level of a process.
If a higher priority task arrives when a lower priority task is executing, the higher priority task replaces the one with
lower priority and the latter is put on hold until it completes execution.
Example of Priority Scheduling
Following five processes have a unique priority, burst time, and arrival time.
Step 0: At time = 0, two processes P1 and P2 arrive. Since P1(with a burst time 4) has higher priority it executes before P2.
Step 1: At time = 1, no new process arrives and execution of P1 continues.
Step 2: At time = 2, no new process arrives, P2 is in the waiting queue, and execution of P1 continues.
Step 3: At time = 3, no new process arrives, P2 is in the waiting queue, and execution of P1 continues.
Step 4: At time = 4, P1 finishes execution, and P2 starts execution.
Step 5: At time = 5, P2 continues execution as no new process arrives.
Step 6: At time = 6, P3 arrives and since it has a higher priority of 1 the OS preempts P2. P3 starts executing.
Step 7: At time = 7, P3 continues executing as no new process arrives and P2 is on hold in the waiting queue.
Step 8: At time = 8, we continue with P3 as no new process arrives.
Step 9: At time = 9, we continue with P3 as no new process arrives.
Step 10: At time = 10, we continue with P3 as no new process arrives.
Step 11: At time = 11, P4 arrives but P3 continues executing as it has a higher priority than P4.
Step 12: At time = 12, P5 arrives but P3 continues executing as it has a higher priority.
Step 13: At time = 13, P3 is done executing. Now there are three processes P2, P4, and P5 in the ready queue. Among these two
processes have higher and similar priorities. These are P2 and P5. Since the arrival time of P2 is less than that of P5, P2 starts
execution.
Step 14: At time = 14, P2 completes execution. In the waiting state between P4 and P5, P5 has a higher priority so it starts
executing.
Step 15: At time = 15, P5 continues executing.
Step 16: At time = 16, P5 completes execution and since P4 is the only process present in the waiting state it starts executing.
Step 17: At time = 20, no process is left for execution as P5 completes execution.
Step 18: Following is the average waiting time: Waiting Time (Wt) = Start Time (St) – Arrival Time (At) + Waiting Time for next
burst
P1 = 0 – 0 = 0
P2 = 4 – 0 + 7 = 11
P3 = 6 – 6 = 0
P4 = 16 – 11 = 5
Thus, the average waiting time is: (0+11+0+5+2)/5 = 18/5 = 3.6
Advantages of priority scheduling
Following are the benefits of priority scheduling method:
Easy to use.
Processes with higher priority execute first which saves time.
The importance of each process is precisely defined.
A good algorithm for applications with fluctuating time and resource requirements.
Disadvantages of priority scheduling
Following are the disadvantages of priority scheduling:
We can lose all the low-priority processes if the system crashes.
This process can cause starvation if high-priority processes take too much CPU time. The lower priority process can
also be postponed for an indefinite time.
There is a chance that a process can’t run even when it is ready as some other process is running currently.
Aging Technique
Aging technique can help prevent starvation of a process.
In this, we can increase the priority of the low-priority processes based on their waiting time.
This ensures that no process waits for an indefinite time to get CPU time.