Sie sind auf Seite 1von 101

Major Project Report

On

Parameters Estimation and Performance Analysis of


a Single-core processor using FreeRTOS

Submitted in partial fulfilment of the


Requirements for the award of the degree of Bachelor of Technology
In
Electronics and Communication Engineering
By
Mr. Sariki Karthik 16011A0412
Ms. Niharika Rasthapuram 16011A0428
Ms. Vaishnavi Suryapeta 16011A0449

Department of Electronics and Communication Engineering


Jawaharlal Nehru Technological University Hyderabad, College
of Engineering Hyderabad

Kukatpally, Hyderabad – 500085


Jawaharlal Nehru Technological University Hyderabad,
College of Engineering Hyderabad.
Department of Electronics and Communication Engineering

CERTIFICATE
This is to certify that the Major Project entitled “Parameters Estimation and
Performance Analysis of a Single-core processor using FreeRTOS” is submitted

by

Mr. Sariki Karthik 16011A0412

Ms. Niharika Rasthapuram 16011A0428


Ms. Vaishnavi Suryapeta 16011A0449

in partial fulfilment for the award of degree in Bachelor of Technology in Electronics


and Communication Engineering during academic year 2019-2020.

Project Guide

Dr. M. Asha Rani

Professor
Jawaharlal Nehru Technological University Hyderabad,
College of Engineering Hyderabad.
Department of Electronics and Communication Engineering

CERTIFICATE
This is to certify that the Major Project entitled “Parameters Estimation and
Performance Analysis of a Single-core processor using FreeRTOS” is submitted

by

Mr. Sariki Karthik 16011A0412

Ms. Niharika Rasthapuram 16011A0428


Ms. Vaishnavi Suryapeta 16011A0449

in partial fulfilment for the award of degree in Bachelor of Technology in Electronics


and Communication Engineering during academic year 2019-2020.

Head of the Department

Dr. K. Anitha Sheela

Professor

Head of Department
ACKNOWLEDGEMENT
Along with our individual efforts in this project, we are grateful to be receiving
continuous support from our mentor, Dr. M. Asha Rani and the university. We would
like to extend our sincere thanks to all of them.
We are highly indebted to our mentor, Dr. M. Asha Rani, Professor, Department of
Electronics and Communication Engineering, JNTUH-CEH, for the kind co-operation
and encouragement which has helped us in the completion of this project.

We are extremely thankful to Mrs. Dhruva R. Rinku, Associate Professor, Department


of Electronics and Communication Engineering, CVRCE for continuously guiding us
throughout the project.

We are grateful to Mr. Satyanarayana, faculty, Department of Electronics and


Communication Engineering, JNTUH-CEH, for giving us thoughtful insights during the
course of the project.
We would like to express our sincere thanks to Dr. K. Anitha Sheela, HOD,
Department of Electronics and Communication Engineering, JNTUH-CEH for
providing the facilities to complete the dissertation.
We would like to express our gratitude towards Jawaharlal Nehru Technological
University Hyderabad- College of Engineering, Hyderabad (JNTUH-CEH) for
introducing major project as a part of the curriculum, bestowing us an opportunity to
apply our skills in practical applications.
We thank for family and friends for supporting us helping us when required.

Mr. Sariki Karthik 16011A0412

Mr. Niharika Rasthapuram 16011A0428

Ms. Vaishnavi Suryapeta 16011A0449

(i)
DECLARATION

We hereby declare that the major project entitled “Parameters Estimation and
Performance Analysis of a Single-core processor using FreeRTOS” is the work done
during the period from December 2019 to June 2020 and is submitted in the partial
fulfilment of the requirements for the award of degree of Bachelor of Technology in
Electronics and Communication Engineering from JNTUH College of Engineering
Hyderabad. The results embodied in this project have not been submitted to any other
university or Institution for the award of any degree or diploma.

Mr. Sariki Karthik 16011A0412


Ms. Niharika Rasthapuram 16011A0428
Ms. Vaishnavi Suryapeta 16011A0449

(ii)
TABLE OF CONTENTS

S. No: Name Page No


Abstract vi
1 Introduction 1

2 Motivation and Problem 3


Statement
3 Real – Time Operating 5
System
4 FreeRTOS – a detailed 21
study
5 ESP32 - a feature rich MCU 40
board ported with freertos
6 Setting up ESP-IDF 47

7 Software Development 63
and Implementation
8 Results and Discussion 84

9 Conclusion and Future 88


scope

References 90

(iii)
LIST OF FIGURES

Fig 3.1. RTOS Architecture


Fig 3.2. RTOS within the embedded system abstraction layers
Fig 3.3. RTOS task states with pre-empting scheduling
Fig 3.4. Pre-emptive Scheduling
Fig 3.5. Non-pre-emptive Scheduling
Fig 4.1. Multitasking vs
Concurrency Fig 4.2. Context
Switching
Fig 4.3. Scheduler Task
Fig 4.4. Kernel
Fig 4.5. Writing to and reading from queue
Fig 5.1. ESP Board
Fig 5.2. ESP32-D0WDQ6 chip
Fig 5.3. Esp32 Pin Layout
Fig 6.1. Development of applications for ESP32
Fig 6.2. Project Configuration – Home window
Fig 7.1. Folder to store the source code
Fig 7.2. Folder after building the project
Fig 7.3. Buffer
Fig 7.4. Runtime stats
Fig 7.5. Adding tools to the environment
Fig 7.6. Configuring the options
Fig 7.7. Serial Flasher Config Window
Fig 7.8. Component Config Window
Fig 7.9. Building the project
Fig 7.10. Flashing the program to the device
Fig 8.1. Application1
Fig 8.2. Application1
Fig 8.3. Application2
(vi
(i
v)
Fig 8.4. Application2

(vi
(v)
LIST OF TABLES

Table 3.1 Differences between RTOS and GPOS


Table 3.2 Example for pre-emptive scheduling
Table 3.3 Example for Arrival time determination
Table 3.4 Example for Response time
determination Table 3.5 Example for Waiting time
determination Table 3.6 Gnatt Chart
Table 3.7 Example for Waiting time determination
Table 3.8 Gnatt Chart
Table 5.1 ESP32 Pin Specifications
Table 8.1 Summary of the results obtained
ABSTRACT

With the changing needs, modern-day computers are expected to do multitasking,


which is to run more than one process at a time. Consequently, a Real-Time
Operating System (RTOS) came into the picture and hence, executing embedded
applications demanding strict deadlines and handling multiple tasks has become
widely achievable. An RTOS is similar to a general operating system with added
features of time stamping and pre-emption which ensures its highly predictability
and quick response.
There are many types of RTOS available in the market. The popular ones being,
PSOS, VRTX, RT Linux and FreeRTOS. For microcontroller-based IoT
applications, the need for a built-in functionality to connect to local networks or
cloud has made FreeRTOS a reliable option. FreeRTOS is an open-source operating
system for microcontrollers that makes small, low-power edge devices easy to
program, deploy, secure, connect, and manage. FreeRTOS provides both the core
operating system as well as software libraries and hence, it can be greatly used to
run applications feasibly on microcontrollers. The kernel is provided with a
multitasking schedule, multiple memory allocation options, and inter-task
coordination primitives.
This project centers on a detailed study of the FreeRTOS. It aims at running
different applications(two) on a single-core processor and thereby, analyzing the
results. The crucial parameters such as response time, CPU utilization are
assessed on the processor and the performance is analyzed for

8
(vi)
1. INTRODUCTION

When we hear the word operating system, the primary thought that strikes our
mind is that of the operating systems used in laptops & computers. Generally, we
use operating systems like windows XP, Linux, Ubuntu, Windows 7,8.8.1, and 10.
In the smartphones, the operating systems are like KitKat, Jellybean,
Marshmallow, and Nougat. In a digital electronic device, there is some sort of
operating system which is developed by the microcontroller program. There are
different types of operating systems to develop for the microcontroller, but our area
of interest over here is a real-time operating system (RTOS).
Why an RTOS? The obvious choice of an RTOS comes from the wide benefits it
offers. The real difference between an RTOS and a general-purpose OS is that with
an RTOS the designers have taken care to ensure that the response times are
known. This is not as simple as it may sound. Modern general-purpose operating
system kernels are very large, with several million lines of code. It can be difficult
to trace through them to find all the possible sources of delay in response. An
RTOS tends to be much smaller than a general-purpose OS making guarantying the
response time more practical. It is intended to serve real-time applications that
process data as it comes in, typically without buffer delays. At the beginning of this
documentation, we shall briefly scrutinize the advantages and classifications of an
RTOS.
We propose to run the applications on a microcontroller device using an RTOS, to
schedule tasks across its cores. A wide variety of RTOS are available in the market
today. The choice for our project is FreeRTOS. We shall also have an introspection
into its features and what makes it reliable for the project.
In this project, we intend to run one or more applications on the chosen
microcontroller, ESP32- a series of low-cost, low-power system on a chip
microcontroller with integrated Wi-Fi and dual-mode Bluetooth. ESP32 is a go-to
chip for making several devices as they’re small, powerful, have a ton of onboard
features, and they’re relatively easy to program, offering lesser challenges
compared to its vast advantages. We shall also dive into its features and try and
understand the pros and cons of the device. The ESP32 comes with a light
operating system – FreeRTOS. The methods to program this chip don’t replace the
FreeRTOS firmware, but rather deploy applications for it to run.

1
A further peek into this project shows us its aim at running different
applications(two) on the single-core processor and thereby, analysing the results.
The real time statistics are assessed and the performance shall be analysed for
different (two) scenarios.

1.1 Project Scope:

It is possible to re-design the processing algorithm to improve processing


speed. Realtime based system performance is improved comparing to non-
real-time based system. Further real time system performance can be
improved by implementing different RTOS algorithm. Also, same design can
be implement using different RTOS.
Further, the designed applications can be tested upon the dual core
microprocessor to obtain varying results. The comparison thus drawn provides
us with the knowledge on their advantages, disadvantages and reliability.
Moreover, RTOS offers wide areas of benefits. Embedded systems are highly
customized, developed and programmed as per user requirements. Embedded
systems will play an important role in Internet of Things (IoT) due to their
unique characteristics and features such as real time computing, low power
consumption, low maintenance and high availability are becoming the key
enabler of IoT. Major players in embedded system hardware and software
developments are aiming to bring these transformations into their products to
take advantage of growing IoT market. The areas that are going to transform
are Real Time Operating Systems (RTOS) and microprocessors and
microcontrollers, followed by memory footprints and networking, open source
communities and developers. Hence, the study of RTOS provides us with
scientifically stimulating opportunities.
2. MOTIVATION AND PROBLEM STATEMENT

2.1 Motivation:

Necessity is the mother of invention and embedded systems are inventions that
were fueled by the idea of making pre-programs to perform a dedicated narrow
range of functions as part of large systems. Embedded systems are being based
more on instruction-oriented design but not on design-oriented instructions.
Embedded systems and real-time operating systems (RTOS) are fast achieving
ubiquity, blurring the lines between science fiction and hard reality. In general,
an RTOS has features like multitasking, process threads that can be prioritized,
and a sufficient number of interrupt levels. An embedded system is any device
controlled by instructions stored on a chip. These devices are usually
controlled by a microprocessor that executes the instructions stored. With
these systems being widely used in devising many tools, we concern ourselves
with running applications on it, that use the benefits of RTOS.

Among the various RTOS available in the market, one is FreeRTOS. With an
available kernel for it, software developers gain great advantages. Application
code can be developed to be portable and flexible. FreeRTOS is a class of
RTOS that is designed to be small enough to run on a microcontroller –
although its use is not limited to microcontroller applications. Utilizing its
benefits and analyzing the performance is a benchmark initiative.

2.2 Problem Statement:

The project aims at running two applications on a single-core of the


microcontroller, ESP32 and thereupon, studying the results. The two applications
to be developed are a calculator which performs addition, subtraction,
multiplication, division, square, cosine, sine, natural logarithm functions and
conversion of temperature from one unit to other. The real-time statistics, response
time and CPU utilization shall be determined for both the applications. The project
also focusses on building the necessary foundations such as, the study of the real-
time operating system and its usage in the embedded field. For the project, the
choice of the real- time operating system is the FreeRTOS, and a detailed
explanation of why and how
it plays a crucial role in the project is given in the further chapters. We shall also
inspect the advantages and limitations of FreeRTOS. Subsequently, it includes the
installation of ESP-IDF in the Linux environment wherein we shall run the
required codes.
3. REAL-TIME OPERATING SYSTEM

3.1 Introduction:
Beginning with the basic functionality of an Operating System, it hides the difficult
computations performed by hardware, which the software does on the back end.
We are presented a computer screen that we can work on and all other details that
is the communication between software and hardware is hidden form us. So, an
operating system is a type of software which communicates between application
software and hardware. Moving forward, we shall now discuss what is a real-time
operating system and what makes it more reliable.
Table 3.1 shows the differences between a real-time operating system(RTOS) and
a general purpose operating system(GPOS).
An operating system has to provide 3 essential things:

1. Task Scheduling:
The scheduler determines which task to run and when a task will run.
2. Task Dispatching:
The dispatcher handles the necessary operations to get a task ready to go.
3. Inter-task Communication:
This is the mechanism that handles how data and information is
exchanged between tasks and processes on the same machine or from
other machines.

These 3 essential things are what makes up the smallest portion of an OS called the
Kernel. The kernel is considered to be the core of an operating system. Its main
task is to manage the hardware and the processes running on it.

A real time operating system is just a special purpose operating system. The 'real
time' part of the name does not mean that the system responds quickly, it just
means that there are rigid time requirements that must be met. If these time
requirements are not met, the results can become inaccurate or unreliable.
RTOS GPOS

RTOS has unfair scheduling i.e. GPOS has fair scheduling i.e. it can be
scheduling is based on priority. adjusted dynamically for optimized
throughput.

Kernel is pre-emptive either Kernel is non-pre-emptive or has long


completely or up to maximum degree. non-pre-emptive code sections.

Priority inversion is a major issue. Priority inversion usually remains


unnoticed.

It has a predictable behaviour. There is no predictability.

It works under worst case assumptions. It optimizes for the average case.

It does not have a large memory. It has a large memory.

Table 3.1. Differences between RTOS and GPOS

So, the need to use an RTOS is when there is a need to monitor and control
physical processes in a timely manner. The constraints one has to deal with when
using RTOS are tight scheduling, predictability, and robustness.

Fig. 3.1. RTOS Architecture


There are three kinds of RTOS:

1. Hard Real Time OS:


In the hard real-time OS, system delays are known or are at the least,
bounded. It is said to be operating correctly if the system can return
results within any time constraints.
2. Soft Real Time OS:
In the soft real-time OS, critical tasks get priority over other tasks and will
retain priority until the task is completed. This is another way of saying that
real time tasks cannot be kept waiting indefinitely. Soft real time makes it
easier to mix the system with other systems.
3. Firm Real Time OS:
In the firm real-time, an operating system has certain time constraints, they are
not strict ad it may cause undesired effects.

3.2 Working with Real-Time Operating System:


Embedded systems are microcontroller-based systems that are designed to perform
specific functions such as reading sensor data, responding to external events,
communicating with other systems, controlling processes, etc. The tricky part is to
make the distinction of what exactly qualifies such a system as real-time. Aren’t all
embedded systems operating in real-time? In order for an embedded system to be
classified as real-time, it must guarantee a strictly defined response time to the
events it is tasked with observing and controlling. It should be noted that all
systems have a response time (latency). Real-time embedded systems do not react
immediately to every event but can guarantee a worse case response time.

Real-time operating systems (RTOS) provide a framework that enables guaranteed


response times and deterministic behaviour. This is achieved using a scheduling
mechanism. This mechanism is at the heart of every RTOS. We can design a real-
time embedded system without the use of RTOS, however, using one can make the
design process shorter and the whole system easier to manage.

As part of the embedded system abstraction layers, an RTOS is placed above the
low-level device drives and below the user application. The RTOS does not
provide low-level drivers for microcontroller peripherals. Some RTOS may
contain middleware software such as networking, file systems, etc.
Fig 3.2. RTOS within the embedded system abstraction layers

3.3 RTOS Main Components:

3.3.1 Tasks:
A piece of code performing a specific function is usually called a task. A task can
be also referred to as a thread, process, activity, etc. in different operating systems.
An operating system is expected to execute many different tasks at once – reading
inputs, outputting data, reacting to events, etc. A single microprocessor, however,
can execute code from only one task at a time. Achieving the required multitasking
is possible using a mechanism known as time multiplexing. Each task that the
operating system should execute is given a time window in which it can utilize the
CPU, and then the execution of another task proceeds according to a predefined
scheduling algorithm. If the timing requirements of all the tasks are fulfilled, we
can say we have concurrent like executions of multiple tasks without the use of
separate microprocessors for each task.

Multitasking is the way of sharing the processor’s time, so that a number of tasks
can execute pseudo-parallelly by taking turns to use the CPU. At any given point in
time, only one process can be present in the running state.

An RTOS task usually has the following main states:

 Running State: The task’s code is currently being executed by the CPU.
 Ready State: The task is ready to be put into the running state. In the ready
state, the task does not consume any CPU cycles.
 Blocked State: The task is in this state when it waits for the occurrence
of some event. In this state, the task does not consume any CPU cycles.
 Suspended State: Tasks in the suspended state are not active anymore.

Some RTOS implementations may contain additional task states or have a different
naming convention than the ones listed above, but they are all following the same
logic.

The Kernel takes care of the task. It involves the following.

 Creating a task
 Deleting a task
 Changing the priority of the task
 Changing state of the task

Fig 3.3. RTOS task states with pre-emptive scheduling


3.3.2. Scheduler:
The scheduler is an integral part of every RTOS. It controls which task should be
executed at any given point in time. The scheduler may use various types of
algorithms for performing the scheduling of the tasks. Almost all of these
algorithms can be classified into two main types:

 Pre-emptive Scheduling: This algorithm allows the interruption of a


currently running task, so another one with higher priority can be
run.
 Non-pre-emptive Scheduling (Co-operative Scheduling): Once a task is
started it cannot be interrupted, it will run until it decides that it should
release the CPU to another task.

3.3.3 Synchronization and Messaging:

Messaging provides a means of communication with other system and between the
tasks. The messaging services include the following.

 Semaphores
 Event flags
 Mailboxes
 Pipes
 Message queues
Semaphores are used to synchronize access to shared resources, such as common
data areas. Event flags are used to synchronize the inter-task activities. Mailboxes,
pipes, and message queues are used to send messages among tasks.

3.3.4. RTOS Service:

The most important part of the operating system is the Kernel. Tasks are relived of
monitoring the hardware. It’s the responsibility of the kernel to manage and
allocate the resources. As tasks cannot acquire CPU attention all the time, the
kernel must also provide some more services. These include the following.
 Memory management
 I/O system management
 System protection
 Networking
 Command interruption
 Time services
 Device management services

3.4 Features of an RTOS:

Selecting a real-time operating system (RTOS) involves these five key features as
must-haves.

3.4.1. Reliability
Any RTOS must be reliable. This means that it operates for a reasonably long time
without human interference. Reliability also means the configuration to enable the
system to choose the right or most profitable action for current operations. For
example, a system for the telecom or banking industries needs to consider the cost
of terminating or engaging certain actions, compared to a phone or calculator
whose cost is limited to an individual, game, app function, etc.

3.4.2. Predictability
A system must execute actions within a known time frame and produce known
results. Such results are determined by the procedures or operations taking place.
The determination is by targets set during production or procedural planning.

3.4.3. Performance
Real-time operating systems are designed to make work easier. Every system must
solve a problem or reduce the workload. As such, the developer should provide a
system that is easily assimilated with existing software and hardware as well as
aligned to the goals of the organization.

3.4.4. Manageability
This means a system whose veracity or bulkiness is manageable. The software and
hardware required to operate the RTOS must be of reasonable size. Technicians
should also be easy to find and orient. The idea is to reduce the cost of
implementation.
3.4.5. Scalability
The needs of any production or event environment change with time. This means
that a system may require an upgrade or downgrade. Such provisions must be
made during design and installation of any RTOS.

3.5 RTOS Scheduling Algorithms:

Having introduced the basic concepts of real-time operating systems (RTOS), we


now take a deeper look into one of the most important things when designing an
embedded system using an RTOS – the scheduling of the tasks and the algorithms
that are used.

3.5.1 Scheduling Process:

Scheduling is the process of deciding which task should be executed at any point in
time based on a predefined algorithm. The logic for the scheduling is implemented
in a functional unit called the scheduler. The scheduling process is not present only
in RTOS, it can be found in one form or another even in simple “bare-bone”
applications.

Different RTOS distributions may support a variety of scheduling algorithms. It is


important that we choose the algorithm before the development of the user
application starts. Like many things in the engineering field, there is not a universal
algorithm that is suitable for every use case. There are always trade-offs. In this
case, they are mainly related to speed (response times), implementation
complexity, etc. The chosen algorithm should always enable the timing
requirements of the tasks to be met.

3.5.2 Types of Scheduling Algorithms:


There are many scheduling algorithms that can be used for scheduling task
execution on a CPU. They can be classified into two main types: pre-emptive
scheduling algorithms and non-pre-emptive scheduling algorithms.

3.5.2.1 Pre-emptive Scheduling:


Pre-emptive scheduling allows the interruption of a currently running task, so
another one with more “urgent” status can be run. The interrupted task is
involuntarily moved by the scheduler from running state to ready state. This
dynamic switching between tasks that this algorithm employs is, in fact, a form of
multitasking. It requires assigning a priority level for each task. A running task can
be interrupted if a task with a higher priority enters the queue.

Fig 3.4 Pre-emptive Scheduling

As an example, let’s have three tasks called Task 1, Task 2 and Task 3. Task 1 has
the lowest priority and Task 3 has the highest priority. Their arrival times and
execute times are listed in the table below.
Task Name Arrival Time Execute
(microseconds) Time(microseconds)

Task1 10 50

Task 2 40 50

Task 3 40 40

Table 3.2 Example for pre-emptive scheduling

In the table 3.1, we can see that Task 1 is the first to start executing, as it is the first
one to arrive (at t = 10 μs). Task 2 arrives at t = 40μs and since it has a higher
priority, the scheduler interrupts the execution of Task 1 and puts Task 2 into
running state. Task 3 which has the highest priority arrives at t = 60 μs. At this
moment Task 2 is interrupted and Task 3 is put into running state. As it is the
highest priority task it runs until it completes at t = 100 μs. Then Task 2 resumes its
operation as the current highest priority task. Task 1 is the last to complete is
operation.

3.5.2.2 Non-pre-emptive Scheduling (Co-Operative Scheduling):

In non-pre-emptive scheduling, the scheduler has more restricted control over the
tasks. It can only start a task and then it has to wait for the task to finish or for the
task to voluntarily return the control. A running task cannot be stopped by the
scheduler.

Fig 3.5 Non-pre-emptive scheduling


If we take the three tasks specified in the table from the previous chapter and
schedule them using a non-pre-emptive algorithm we get the behaviour shown in
the figure. Once started, each task completes its operation and then the next one
starts.

The non-pre-emptive scheduling can simplify the synchronization of the tasks, but
that is at the cost of increased response times to events. This reduces its practical
use in complex real-time systems.

3.6 Popular Scheduling Algorithms:

We will now introduce some of the most popular scheduling algorithms that are
used in CPU scheduling. Not all of them are suitable for use in real-time embedded
systems. Currently, the most used algorithms in practical RTOS are round-robin
scheduling, and pre-emptive priority scheduling. In an attempt to present the right
explanation, the description and implementation of a few examples in simple C-
language are given.

3.6.1 First Come, First Served (FCFS):

FCFS is a non-pre-emptive scheduling algorithm that has no priority levels


assigned to the tasks. The task that arrives first into the scheduling queue (i.e.
enters ready state), gets put into the running state first and starts utilizing the CPU.
It is a relatively simple scheduling algorithm where all the tasks will get executed
eventually. The response time is high as this is a non-pre-emptive type of
algorithm.

3.6.2 Shortest Job First (SJF):

In the shortest job first scheduling algorithm, the scheduler must obtain
information about the execution time of each task and it then schedules the one
with the shortest execution time to run next.

SJF is a non-pre-emptive algorithm, but it also has a pre-emptive version. In the


pre-emptive version of the algorithm (shortest remaining time) the parameter on
which the scheduling is based is the remaining execution time of a task. If a task
is running it can be interrupted if another task with shorter remaining execution
time enters the queue.

A disadvantage of this algorithm is that it requires the total execution time of a task
to be known before it is run.

3.6.3 Priority Scheduling:

Priority scheduling is one of the most popular scheduling algorithms. Each task is
assigned a priority level. The basic principle is that the task with the highest
priority will be given the opportunity to use the CPU.

In the pre-emptive version of the algorithm, a running task can be stopped if a


higher priority task enters the scheduling queue. In the non-pre-emptive version of
the algorithm once a task is started it can’t be interrupted by a higher priority task.
Of course, not all tasks can have unique priority levels and there will always be
tasks that have the same priority. Different approaches can be used for handling the
scheduling of those tasks (e.g. FCFS scheduling or round-robin scheduling).

3.6.4 Round Robin Scheduling:

Round-robin is a pre-emptive type of scheduling algorithm. There are no priorities


assigned to the tasks. Each task is put into a running state for a fixed predefined
time. This time is commonly referred to as time-slice (aka quantum). A task cannot
run longer than the time-slice. In case a task has not completed by the end of its
dedicated time-slice, it is interrupted, so the next task from the scheduling queue
can be run in the following time slice. A pre-emptied task has an opportunity to
complete its operation once it’s again its turn to use a time-slice.

An advantage of this type of scheduling is its simplicity and relatively easy


implementation.

RTOS is thereby, a preferred choice for many embedded device manufacturers and
embedded programmers. There are many RTOS flavours available. FreeRTOS is
widely followed by practitioners. Further from here, a detailed study on FreeRTOS
and its features is done to analyse what makes it the right choice for the project.

3.7 Parameters involved in Scheduling:

While dealing with some CPU scheduling algorithms, we encounter with


some terms like Burst time, Arrival time, Exit time, Waiting time, Response
time, Turnaround time, and throughput. They are explained in detail in the
coming pages.

3.7.1 Burst Time:

Every process in a computer system requires some amount of time for its
execution. This time is both the CPU time and the I/O time. The CPU time is the
time taken by CPU to execute the process. While the I/O time is the time taken by
the process to perform some I/O operation. In general, we ignore the I/O time and
we consider only the CPU time for a process. So, burst time is the total time
taken by the process for its execution on the CPU.
3.7.2 Arrival Time:
Arrival time is the time when a process enters into the ready state and is ready for
its execution.
Consider the following example.
Process Arrival time (in ms) Burst time (in ms)
P1 0 8
P2 1 7
P3 2 10
Table 3.3 Example for Arrival time determination
Here in the above example, the arrival time of all the 3 processes are 0 ms, 1 ms,
and 2 ms respectively.

3.7.3 Exit Time:

Exit time is the time when a process completes its execution and exit from the
system.

3.7.4 Response Time:

Response time is the time spent when the process is in the ready state and gets the
CPU for the first time. For example, here we are using the First Come First Serve
CPU scheduling algorithm for the below 3 processes:

Process Arrival time (in ms) Burst time (in ms)


P1 0 8
P2 1 7
P3 2 10
Table 3.4 Example for Response time determination
Here, the response time of all the 3 processes are:

 P1: 0 ms
 P2: 7 ms because the process P2 have to wait for 8 ms during the execution
of P1 and then after it will get the CPU for the first time. Also, the arrival
time of P2 is 1 ms. So, the response time will be 8-1 = 7 ms.
 P3: 13 ms because the process P3 have to wait for the execution of P1 and
P2 i.e. after 8+7 = 15 ms, the CPU will be allocated to the process P3 for
the first time. Also, the arrival of P3 is 2 ms. So, the response time for P3
will be 15-2 = 13 ms.
Response time = Time at which the process gets the CPU for the first time -
Arrival time

3.7.5 Waiting Time:

Waiting time is the total time spent by the process in the ready state waiting for
CPU. For example, consider the arrival time of all the below 3 processes to be 0
ms, 0 ms, and 2 ms and we are using the First Come First Serve scheduling
algorithm.

Process Arrival time (in ms) Burst time (in ms)


P1 0 8
P2 0 7
P3 2 10
Table 3.5 Example for Waiting time determination
P1 P2 P3
0ms 8ms 8ms 15ms 15ms 25ms
Table 3.6 Gnatt Chart
Then the waiting time for all the 3 processes will be:

 P1: 0 ms
 P2: 8 ms because P2 have to wait for the complete execution of P1 and
arrival time of P2 is 0 ms.
 P3: 13 ms because P3 will be executed after P1 and P2 i.e. after 8+7 = 15
ms and the arrival time of P3 is 2 ms. So, the waiting time of P3 will be:
15-2 = 13 ms.
Waiting time = Turnaround time - Burst time

In the above example, the processes have to wait only once. But in many other
scheduling algorithms, the CPU may be allocated to the process for some time
and then the process will be moved to the waiting state and again after some time,
the process will get the CPU and so on.

There is a difference between waiting time and response time. Response time is
the time spent between the ready state and getting the CPU for the first time. But
the waiting time is the total time taken by the process in the ready state. Let's take
an example of a round-robin scheduling algorithm. The time quantum is 2 ms.

Process Arrival time (in ms) Burst time (in ms)


P1 0 4
P2 0 6
Table 3.7 Example for Waiting time determination

P1 P2 P1 P2 P2
0ms 2ms 2ms 4ms 4ms 6ms 6ms 8ms 8ms 10ms
Table 3.8 Gnatt Chart

In the above example, the response time of the process P2 is 2 ms because after 2
ms, the CPU is allocated to P2 and the waiting time of the process P2 is 4 ms i.e
turnaround time - burst time (10 - 6 = 4 ms).

3.7.6 Turnaround Time:

Turnaround time is the total amount of time spent by the process from coming in
the ready state for the first time to its completion.

Turnaround time = Burst time + Waiting time

or

Turnaround time = Exit time - Arrival time

For example, if we take the First Come First Serve scheduling algorithm, and the
order of arrival of processes is P1, P2, P3 and each process is taking 2, 5, 10
seconds. Then the turnaround time of P1 is 2 seconds because when it comes at
0th second, then the CPU is allocated to it and so the waiting time of P1 is 0 sec
and the turnaround time will be the Burst time only i.e. 2 seconds. The
turnaround time of P2 is 7 seconds because the process P2 have to wait for 2
seconds for the execution of P1 and hence the waiting time of P2 will be 2
seconds. After 2 seconds, the CPU will be given to P2 and P2 will execute its
task. So, the turnaround time will be 2+5 = 7 seconds. Similarly, the turnaround
time for P3 will be 17 seconds because the waiting time of P3 is 2+5 = 7 seconds
and the burst time of P3 is 10 seconds. So, turnaround time of P3 is 7+10 = 17
seconds.

Different CPU scheduling algorithms produce different turnaround time for the
same set of processes. This is because the waiting time of processes differ when
we change the CPU scheduling algorithm.

3.7.7 Throughput:

Throughput is a way to find the efficiency of a CPU. It can be defined as the


number of processes executed by the CPU in a given amount of time. For
example, let's say, the process P1 takes 3 seconds for execution, P2 takes 5
seconds, and P3 takes 10 seconds. So, throughput, in this case will be (3+5+10)/3
= 18/3 = 6 seconds.
4. FREERTOS - a detailed study

FreeRTOS stands for Free Real-Time Operating System. It is an open-source


operating system targeted on embedded applications that run on a microcontroller
and need real-time event processing. It is basically a real-time operating
system kernel for embedded devices that has been ported to 35 microcontroller
platforms.

4.1 Features of FreeRTOS:


FreeRTOS is designed to be small and simple. To make the code readable, easy to
port, and maintainable, it is written mostly in C, but there are a few assembly
functions included where needed (mostly in architecture-specific scheduler
routines).
FreeRTOS provides methods for multiple threads or tasks, mutexes, semaphores
and software timers. A tick-less mode is provided for low power applications.
Thread priorities are supported. FreeRTOS applications can be completely
statistically allocated. Alternatively, RTOS objects can be dynamically allocated
with five schemes of memory allocation provided:

 allocate only;
 allocate and free with a very simple, fast, algorithm;
 a more complex but fast allocate and free algorithm with memory coalescence;
 an alternative to the more complex scheme that includes memory coalescence
that allows a heap to be broken across multiple memory areas.
 and C library allocate and free with some mutual exclusion protection.

Here are some reasons why FreeRTOS is a good choice for our application:

 Provides a single and independent solution for many different architectures


and development tools.
 Is known to be reliable. Confidence is assured by the activities undertaken
by the SafeRTOS sister project.
 Is feature rich and still undergoing continuous active development.
 Has a minimal ROM, RAM and processing overhead. Typically, an RTOS
kernel binary image will be in the region of 6K to 12K bytes.
 Is very simple – the core of the RTOS kernel is contained in only 3 C files.
The majority of the many files included in the .zip file download relate
only to the numerous demonstration applications.
 Is truly free for use in commercial applications (see license conditions for
details).
 Has commercial licensing, professional support and porting services
available in the form of OPENRTOS from our partner WITTENSTEIN high
integrity systems.
 Has a migration path to SafeRTOS, which includes certifications for the
medical, automotive and industrial sectors.
 Is well established with a large and ever-growing user base.
 Contains a pre-configured example for each port. No need to figure out how
to setup a project – just download and compile!
 Has an excellent, monitored, and active free support forum.
 Has the assurance that commercial support is available should it be required.
 Provides ample documentation.
 Is very scalable, simple and easy to use.

Before understanding the terminology used, we shall consider an example to


magnify where and till when the usage of FreeRTOS becomes necessary.

Consider a Simple Digital Watch. Its only functionality is that it tells time. Such a
product can be developed using a simple 8-bit microcontroller and an operating
system is of very little use here as it only runs a single thread continuously. A
thread is basically a step by step process.

Now let’s add a little bit more complexity, Let’s add a stopwatch to the timer, and
an alarm clock and a count-down timer. Now the system has to run multiple tasks
at the same time. These tasks include

 it has to keep track of the time,


 if a stopwatch is running it has to run count the number of seconds that
have expired since the start button has been clicked and
 if it’s time to ring the alarm to wake you up it needs to start beeping.
For such an application there are effective software design patterns that can be
used so that interrupts and loops can be used to implement this without an
operating system on a microcontroller.
Yes, using an operating system can certainly help ease the development process as
it will take care of task priorities and the timing needs. But these devices are
usually resource-constrained in terms of memory and processing power as an
attempt to keep the cost low to keep up with the competition. The software
complexity without an operating system is still considered manageable and hence
they are usually built without an OS.

Now let’s add more functionality to our digital watch, let’s put in a pedometer, an
altimeter and a temperature sensor. Now the tasks that it needs to compute
parallelly includes

 Keeping track of time


 Stopwatch
 Alarm clock
 Pedometer signal processing
 Temperature sensing
 Altitude sensing
 Display information on an LCD/LED screen
So, on one side it has to do the job of a normal digital watch, on the other hand it
needs to do some smart features by taking in raw accelerometer and gyroscope
values from an IMU sensor and do some signal processing to calculate the steps,
continuously read the temperature values from the temperature sensor, read altitude
measurements and display it all on the screen.
Even this application can be designed without an operating system, by just
architecting some good design patterns, but usually, this kind of system can be
benefited by adding a simple embedded operating system as the software
complexity without an operating system is usually considered to be not very easy
to develop and maintain. Also, such a system is usually built using 32-bit
microcontrollers with enough resources to accommodate an operating system and
this makes engineers of such products to go for an operating system-based
software. This is where simple real-time operating systems like FreeRTOS comes
in.
Let’s go a bit further and look at a more complex device to see where the benefits
of FreeRTOS ends.
Let’s now add-in a few more features, let’s add in a heart rate monitor, a sleep
monitor, a Bluetooth communication system to communicate with your phone, an
mp3 player to stream music to your Bluetooth earphones and a notification system
to make your smartwatch vibrate every time you receive a call on your paired
smartphone. Essentially all the features of smartwatches these days.

Now the system is not simple enough to be made using simple embedded operating
systems like FreeRTOS. It is still possible to do it but then the added complexity is
not easy for the development and maintenance of the system. Now we will
probably need a much more sophisticated Operating system like Embedded
Linux to accomplish our tasks.

This example gives us a brief idea of the places where simple embedded operating
systems like FreeRTOS fit in.

4.2 Concepts to understand FreeRTOS:

There are 7 concepts and associated terminology to start developing using


FreeRTOS, they include the following.

 Tasks
 Multitasking
 Context switching
 Schedulers
 Kernels
 Inter-task communications
 Interrupts

We have previously looked into a few concepts like Tasks, Schedulers in the
previous chapter, Real-Time Operating System.

4.2.1 Tasks:

In the examples above of using a digital watch, each separate activity/feature is a


Process.
Process is a single line of actions, that are executed one after the other.
In FreeRTOS these processes are called Tasks. Each such task has its own stack in
combination with another block of memory to store information about itself
known as a Task Control Block which is used by FreeRTOS kernel to manage the
task.
In FreeRTOS, these tasks are implemented as C functions with a never-ending
loop.
A task defined by a simple C function, taking one void* argument and returning no
thing.
void ATaskFunction( void *pvParameters );

Any created task should never end before it is destroyed. It is common for task’s
code to be wrapped in an infinite loop, or to invoke vTaskDestroy(NULL) before it
reaches its final brace. As any code in infinite loop can fail and exit, it is safer even
for a repetitive task, to invoke vTaskDelete() before its final brace.
The task created using vTaskCreate() takes the following arguments.
 pvTaskCode: A pointer to the function where the task is implemented.
 pcName: It is the name given to the task. This is useless to FreeRTOS but is
intended for debugging purpose only.
 usStackDepth: It is the length of the stack for this task in words. The actual
size of the stack depends on the microcontroller.
 pvParameters: A pointer to arguments given to the task. A good practice
consists in creating a dedicated structure, instantiate and fill it then give its
pointer to the task.
 uxPriority: Priority given to the task.
 pxCreatedTask: A pointer to an identifier that allows to handle the task. If the
task does not have to be handled in the future, this can be leaved NULL.

A task is destroyed using xTaskDestroy() routine. It takes an argument


pxCreatedTask which is given when the task was created.
void vTaskDelete( xTaskHandle pxTask );

When a task is deleted, it is responsibility of idle task to free all allocated memory
to this task by kernel. Notice that all memory dynamically allocated must be
manually freed.

4.2.2 Multitasking and state changes:

Multitasking is the way of sharing the processor’s time, so that a number of tasks
can execute pseudo-parallelly by taking turns to use the CPU. At any given point in
time, only one process can be present in the running state. Other processes are
usually in one of the following 3 states. Ready state, Blocked state or Suspended
state. They have been discussed in detail in the previous chapter, Real-Time
Operating System.

The use of a multitasking operating system can simplify the design of what would
otherwise be a complex software application:

 The multitasking and inter-task communications features of the operating


system allow the complex application to be partitioned into a set of smaller
and more manageable tasks.
 The partitioning can result in easier software testing, work breakdown
within teams, and code reuse.
 Complex timing and sequencing details can be removed from the
application code and become the responsibility of the operating
system.

Multitasking Vs Concurrency

A conventional processor can only execute a single task at a time – but by rapidly
switching between tasks a multitasking operating system can make it appear as if
each task is executing concurrently. This is depicted by the diagram below which
shows the execution pattern of three tasks with respect to time. The task names are
colour coded and written down the left hand. Time moves from left to right, with
the coloured lines showing which task is executing at any particular time. The
upper diagram demonstrates the perceived concurrent execution pattern, and the
lower the actual multitasking execution pattern.

Fig 4.1 Multitasking vs Concurrency


4.2.3 Context Switching:

As a task executes it utilizes the processor / microcontroller registers and accesses


RAM and ROM just as any other program. These resources together (the processor
registers, stack, etc.) comprise the task execution context.

Fig 4.2 Context Switching


A task is a sequential piece of code – it does not know when it is going to get
suspended (swapped out or switched out) or resumed (swapped in or switched
in) by the kernel and does not even know when this has happened. Consider the
example of a task being suspended immediately before executing an instruction
that sums the values contained within two processor registers. While the task is
suspended other tasks will execute and may modify the processor register values.
Upon resumption the task will not know that the processor registers have been
altered – if it used the modified values the summation would result in an incorrect
value.

To prevent this type of error it is essential that upon resumption a task has a
context identical to that immediately prior to its suspension. The operating system
kernel is responsible for ensuring this is the case – and does so by saving the
context of a task as it is suspended. When the task is resumed its saved context is
restored by the operating system kernel prior to its execution. The process of
saving the context of a task being suspended and restoring the context of a task
being resumed is called context switching.

4.2.4 Schedulers:

Tasks are made to change from running state to one of the inactive states by
the scheduler by the process of pre-empting.
A currently running task is stopped without any notice, in favour of a higher
priority task, and its contents and status information are stored in memory so that
when it runs again, it can start from where it left off.
It is a task from the FreeRTOS operating system, whose task is to manage the state
of the other tasks.
It is the most important part of any real-time operating system. Its duty is to make
sure no lower priority tasks can be in running state while a higher priority task is in
the ready state so that the timing requirements can be met.

But as we just saw, the scheduler is also a task, which means it can only take a
limited amount of processor’s time, else it will do more harm than good as the
actual application needs to run on top of the operating system.

So, the scheduler usually runs once every fixed duration of time, say for example
once every 10 milliseconds. The scheduler occupies the CPU, say for 0.5ms and
during this time, it will see the manage the tasks so that only the highest priority
task in the ready state gets the next slot in time.

In the Fig 4.3, the green task is the scheduler. It starts at 0ms and runs till 0.5ms
and chooses Task1 to run till 10ms. Then at 10ms the scheduler comes back again
and this time picks another task to run from the ready queue which is Task 2 and
now Task 2 runs till 20ms.
Fig 4.3 Scheduler Task
If both the tasks of the same priority are in the ready state, then the scheduler will
choose the one that hasn’t had a chance to run for the longest period of time and
give it the next 9.5ms period to use the processor. Once that’s done the scheduler
comes in again and gives the CPU to the other same priority task. Thus, both these
tasks can take turns running of using the processor.

As an application designer, we need to architect our application with proper


priority levels, so that the most important tasks that are ready to run are always
getting executed when needed, but at the same time, we do not let the lower
priority tasks starve too much for CPU time. In FreeRTOS the higher the number,
the higher the priority.

4.2.5 Kernel:
The kernel is considered to be the core of an operating system. Its main task is to
manage the hardware and the processes running on it.
The scheduler we saw above is the most important part of a kernel. Other
important parts include inter-task communications and synchronizations.

Fig 4.4 Kernel


As seen in the figure above, the operating system can have device drivers, file
systems, networking stacks like TCP/IP, file systems, etc., The central part of any
operating system is its kernel and it consists of the scheduler and inter-task-
communication systems.

4.2.6 Inter-task Communications:

There are several options available for tasks to communicate with each other
through the kernel of FreeRTOS like queues, mutex, semaphores and notifications.

Queues:

Queues are the primary form of inter-task communications. They can be used to
send messages between tasks, and between interrupts and tasks. In most cases they
are used as thread safe FIFO (First In First Out) buffers with new data being sent to
the back of the queue, although data can also be sent to the front.
Fig 4.5 Writing to and reading from a queue. In this example the queue was created
to hold 5 items, and the queue never becomes full.

The FreeRTOS queue usage model manages to combine simplicity with flexibility
– attributes that are normally mutually exclusive. Messages are sent through
queues by copy, meaning the data (which can be a pointer to larger buffers) is
itself copied into the queue rather than the queue always storing just a reference to
the data. This is the best approach because:

 Small messages that are already contained in C variables (integers, small


structures, etc.) can be sent into a queue directly. There is no need to
allocate a buffer for the message and then copy the variable into the
allocated buffer. Likewise, messages can be read from queues directly
into C variables.

Further, sending to a queue in this way allows the sending task to


immediately overwrite the variable or buffer that was sent to the queue, even
when the sent message remains in the queue. Because the data contained in
the variable was copied into the queue the variable itself is available for re-
use. There is no requirement for the task that sends the message and the task
that receives the message to agree which task owns the message, and which
task is responsible for freeing the message when it is no longer required.

 Using queues that pass data by copy does not prevent queues from being
used to pass data by reference. When the size of a message reaches a point
where it is not practical to copy the entire message into the queue byte for
byte, define the queue to hold pointers and copy just a pointer to the
message into the queue instead. This is exactly how
the FreeRTOS+UDP implementation passes large network buffers around
the FreeRTOS IP stack.
 The kernel takes complete responsibility for allocating the memory used
as the queue storage area.
 Variable sized messages can be sent by defining queues to hold structures
that contain a member that points to the queued message, and another
member that holds the size of the queued message.
 A single queue can be used to receive different message types, and messages
from multiple locations, by defining the queue to hold a structure that has a
member that holds the message type, and another member that holds the
message data (or a pointer to the message data). How the data is interpreted
depends on the message type. This is exactly how the task that manages
the FreeRTOS+UDP IP stack is able to use a single queue to receive
notifications of ARP timer events, packets being received from the Ethernet
hardware, packets being received from the application, network down
events, etc.
 The implementation is naturally suited for use in a memory protected
environment. A task that is restricted to a protected memory area can pass
data to a task that is restricted to a different protected memory area
because invoking the RTOS by calling the queue send function will raise
the microcontroller privilege level. The queue storage area is only accessed
by the RTOS (with full privileges).
 A separate API is provided for use inside of an interrupt. Separating the API
used from an RTOS task from that used from an interrupt service routine
means the implementation of the RTOS API functions do not carry the
overhead of checking their call context each time they execute. Using a
separate interrupt API also means, in most cases, creating RTOS aware
interrupt service routines is simpler for end users than when compared to
alternative RTOS products.
 In every way, the API is simpler.

Blocking the Queues:

Queue API functions permit a block time to be specified.

When a task attempts to read from an empty queue the task will be placed into the
Blocked state (so it is not consuming any CPU time and other tasks can run) until
either data becomes available on the queue, or the block time expires.

When a task attempts to write to a full queue the task will be placed into the
Blocked state (so it is not consuming any CPU time and other tasks can run) until
either space becomes available in the queue, or the block time expires.

If more than one task block on the same queue then the task with the highest
priority will be the task that is unblocked first.

See the Queue Management section of the user documentation for a list of queue
related API functions. Searching the files in
the FreeRTOS/Demo/Common/Minimal directory will reveal multiple examples of
their usage.

Note that interrupts must NOT use API functions that do not end in “FromISR”.

Queue Creation function is as follows.

xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength,


unsigned portBASE_TYPE uxItemSize
);
 uxQueueLenght gives the number of elements this queue will be able to
handle at any given time.

 uxItemSize is the size in byte of any element stored in the queue.

 xQueueCreate returns NULL if the queue was not created due to lack of
memory available; if not, the returned value should be kept to handle the
newly created queue.
Mutex:

Mutex is used for controlling access to the shared resource. It is used to avoid
extended priority inversion using priority inheritance technique.

Priority inheritance can be implemented in two ways: changing the priority of the
task trying to access the mutex

1. to the priority equal to the priority of the task acquiring the mutex or
2. to the higher priority than the priority of the task acquiring the mutex
so that the task trying to access the mutex will immediately get the mutex

when another task releases the mutex.

The first way as adopted in FreeRTOS.

Mutexes are designed to prevent mutual exclusion or deadlocking. A mutex is used


similarly to a binary semaphore, except the task which take the semaphore must
give it back. This can be though with a token associated with the resource to access
to. A task holds the token, works with the resource then gives back the token; in
the meanwhile, no other token can be given to the mutex.

The usual use case of a mutex is as shown in the Fig 4.6.

Semaphore:

Semaphores are just an extended version of mutexes. The shared resource guarded
by a mutex has only one key. On the other hand, the resource guarded by
semaphores can have multiple keys, so that a number of processes can access that
particular resource simultaneously.
Fug 4.6. Use case of a matrix

As an example, we can consider an elevator, which can support only four people at
a time. Here the elevator is the shared resource. If you need access to it, you need
to press the button outside the elevator signalling the elevator system that you need
to use it. Now if there is space in the elevator once it opens, say only one person is
already inside, then you can go in. But if there are already 4 people inside the
elevator, then you can either wait and take the next one.

Semaphores work much the same way. The elevator control system is analogous to
the kernel and the number of spaces available at any given time is analogous to the
number of free keys available to our shared resource at a given instant. If a key is
needed, it is asked for, from the kernel and if one is available, it will be given.

Since mutex and semaphores are so similar to each other, mutexes are also called
binary semaphores. Collectively mutexes, semaphores, queues, etc., are called
communication objects as they are used to communicate events, statuses and data
from one task to another task.

Creation of Semiphore:

void vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore );


Taking a Semiphore:
portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore,
portTickType xTicksToWait );

Giving a Semiphore:
portBASE_TYPE xSemaphoreGive( xSemaphoreHandle xSemaphore );

The semaphore is not available, so the task is blocked, wating for the semaphore.

xSemaphoreTake()

An interrupt occurs and gives a semaphore

xGiveSemaphoreFromISR() xSemaphoreTake()

Which unblocks the task

xGiveSemaphoreFromISR() xSemaphoreTake()

And allows it to take succesfully the semaphore.

xSemaphoreTake()

Another interrupt occurs and gives another semaphore. In the meanwhile, the task is processing
the first interrupt.

xGiveSemaphoreFromISR() xSemaphoreTake()
When the task has finished to preccess its first work, it waits for another semaphore and gets it
directly, since an interrupt occurred. The task is now able to process the second interrupt.

xSemaphoreTake()

Fig 4.7. A binary semaphore is equivalent to a queue which can


contain one element
Priority inheritance is actually the only difference between a binary semaphore
and a mutex. When several tasks ask for a mutex, the mutex holder's priority is
set to the highest waiting task priority. This mechanism helps against priority
inversion phenomenon although it doesn't absolutely prevent it from happening.
The use of a mutex raises the application global complexity and therefore should
be avoided whenever it is possible.

4.2.7 Interrupts:

Interrupts behave in a way similar to the task switching mechanism available in the
scheduler so that the currently running code is pre-empted if an interrupt occurs,

Interrupts should not be confused with task switching.

 task switching is done by the scheduler through software to make sure that a
lower priority task cannot run while another higher priority task is ready to run.
 Interrupts are produced by hardware events like a user pressing a button.
 Interrupts are used to capture events from the physical world the device is
working in while the task switching is done primarily for multitasking.

4.3 Parameters to measure:

One of our tasks in this project is to determine the execution time and CPU
Utilization for the applications.

4.3.1 Execution Time:

The execution time or CPU time of a given task is defined as the time spent by the
system executing that task, including the time spent executing run-time or system
services on its behalf. The execution time is implementation defined. It is
implementation defined which task, if any, is charged the execution time is
consumed by interrupt handlers and run-time services on behalf of the system.

4.3.2 CPU Utilization:

CPU utilization is the sum of work handled by a Central Processing Unit. It is also
used to estimate system performance. CPU utilization can vary according to the
type and amount of computing task because some tasks require heavy CPU time
while others require less CPU time. Process time is another name for CPU time
and is the amount of time used by a CPU for processing instruction of an operating
system or a computer program. CPU time is quantified in clock ticks or
seconds. CPU utilization shows the burden on a processor in terms of percentage
that indicates if any changes are to be made in the system otherwise it may get
exhausted of capacity.
5. ESP32 – A FEATURE RICH MCU BOARD PORTED WITH FREERTOS

The ESP32 is a low-cost system-on-chip (SoC) series created by Espressif


Systems. It is an improvement on the popular ESP8266 that is widely used in IoT
projects. The ESP32 has both Wi-Fi and Bluetooth capabilities, which make it an
all-rounded chip for the development of IoT projects and embedded systems in
general. ESP32 has become the go-to chip for making several devices. They’re
small, powerful, have a ton of onboard features, and they’re relatively easy to
program. Powered by 40 nm technology, ESP32 provides a robust, highly
integrated platform, which helps meet the continuous demands for efficient power
usage, compact design, security, high performance, and reliability.

5.1 ESP32 Specifications:


Coming to ESP32 chip specifications, they are as follows.

 As mentioned previously, it has Wi-Fi and Bluetooth built-in.


 It runs 32-bit programs.
 Single or Dual core Tensilica Xtensa 32-bit LX6 microprocessor.
 The clock frequency can go up to 240MHz and it has a 512 kB RAM.
 This particular board has 30 or 36 pins, 15 in each row.
 It also has wide variety of peripherals available, like: capacitive touch,
ADCs, DACs, UART, SPI, I2C and much more.
 It comes with built-in hall effect sensor and built-in temperature sensor.

Fig 5.1 ESP Board


ESP32 is a very popular chip used for the internet of things applications. The main
part of this module is ESP32-D0WDQ6 chip.

Fig 5.2 ESP32-D0WDQ6 chip

5.2 ESP32 Pin Layout:

There are totally 39 digital Pins on the ESP32 out of which 34 can be used as
GPIO and the remaining are input only pins. The device supports 18-channels for
12-bit ADC and 2-channel for 8-bit DAC. IT also has 16 channels for PWM signal
generation and 10 GPIO pins supports capacitive touch features. The ESP32 has
multiplexing feature, this enables the programmer to configure any GPIO pin for
PWM or other serial communication though program. The ESP32 supports 3 SPI
Interface, 3 UART interface, 2 I2C interface, 2 I2S interface and also supports
CAN protocol.
Pin Pin Name Details
Category

Power Micro-USB, 3.3V, Micro-USB: ESP32 can be powered through


5V, GND
USB port
5V: Regulated 5V can be supplied to this pin
which is we be again regulated to 3.3V by on
board regulator, to power the board.
3.3V: Regulated 3.3V can be supplied to this
pin to power the board.
GND: Ground pins.

Enable En The pin and the button resets


the microcontroller.

Analog Pins ADC1_0 to ADC1_5 Used to measure analog voltage in the range of
and ADC2_0 to 0-3.3V.
ADC2_9
12-bit 18 Channel ADC

DAC pins DAC1 and DAC2 Used for Digital to analog Conversion

Input/Output GPIO0 to GPIO39 Totally 39 GPIO pins, can be used as input or


Pins output pins. 0V (low) and 3.3V (high). But
pins 34 to 39 can be used as input only

Capacitive T0 to T9 These 10 pins can be used a touch pins


Touch pins normally used for capacitive pads
RTC GPIO RTCIO0 to RTCIO17 These 18 GPIO pins can be used to wake up
pins the ESP32 from deep sleep mode.

Serial Rx, Tx Used to receive and transmit TTL serial data.

External All GPIO Any GPIO can be use to trigger an interrupt.


Interrupts

PWM All GPIO 16 independent channel is available for PWM


any GPIO can be made to work as PWM
though software

VSPI GPIO23 (MOSI), Used for SPI-1 communication.


GPIO19(MISO),
GPIO18(CLK) and
GPIO5 (CS)

HSPI GPIO13 (MOSI), Used for SPI-2 communication.


GPIO12(MISO),
GPIO14(CLK) and
GPIO15 (CS)

IIC GPIO21(SDA), Used for I2C communication.


GPIO22(SCL)

AREF AREF To provide reference voltage for input voltage.

Table 5.1 ESP32 Pin Specifications


Fig 5.3 ESP32 Pin Layout
In this project, as we shall run programs on to the board, we shall simply connect
the esp32 board to the system using a USB cable.
5.3 Applications:

 Prototyping of IoT devices.


 Low power battery operated applications.
 Network projects.
 Easy to use for beginner level DIYers and makers.
 Projects requiring Multiple I/O interfaces with Wi-Fi and Bluetooth
functionalities.

5.4 ESP32 – An ideal choice:


On comparing ESP32 with Arduino, we find that both are advantageous and
functional on its own. In terms of power and features obviously the dual cored
microprocessor powered ESP32 will surely take down the microcontroller powered
Arduino UNO. The ESP32 has built in Bluetooth and Wi-Fi with good number of
GPIO pins and communication protocols for a very cheap price. The Arduino
might look a bit handicapped when competing with ESP32 but it has a large
number of shields in the market which can be readily used, also advanced Arduino
boards like Yun has good processing power as well.
The ESP32 operates on 3.3V and can be programmed with ESP-IDF or with
Arduino IDE; the Arduino operates at 5V and is known for its easy to use Arduino
IDE and strong community support. So, to conclude, if one has prior experience
with programming and the project really requires some heavy processing with IoT
capabilities then ESP32 can be preferred over Arduino.
Both the ESP32 and ESP8266 are Wi-Fi development boards from Espressif
systems. They can be programmed using the ESP-IDF or the Arduino IDE. The
main difference would be that ESP8266 does not have an in-built Bluetooth
module and also does not feature CAN protocol and has no SRAM. The ESP8266
is inferior in terms of performance compared with the ESP32. Hence, ESP32
remains as the go- to chip for the project.
5.5 Powering the board:
There are totally three ways to power the ESP32 board.
Micro USB Jack: Connect the mini USB jack to a phone charger or computer
through a cable and it will draw power required for the board to function.
5V Pin: The 5V pin can be supplied with a Regulated 5V, this voltage will again be
regulated to 3.3V through the on-board voltage regulator.
3.3V Pin: If we have a regulated 3.3V supply then we can directly provide this to
the 3.3V pin of the ESP32.

5.6 ESP32 and FreeRTOS:

There are several use cases for wanting to multitask on a microcontroller. For
instance: you might have a microcontroller that reads a temperature sensor, shows
it on an LCD, and send it to the cloud. One can do all three synchronously, one
after the other. But what if one is using an e-ink display that takes a few seconds to
refresh? Luckily the implementation for the ESP32 includes the possibility to
schedule tasks with FreeRTOS. These can run on a single core; many cores and
one can even define which is more important and should get preferential treatment.

5.7 Programming:

Before programming this chip, it’s crucial to understand that, unlike other
embedded systems, the ESP32 comes with a light operating system - FreeRTOS.
The following methods to program this chip don’t replace the FreeRTOS firmware,
but rather deploy applications for it to run.

There are currently two methods to program the ESP32: the ESP-IDF and the
ESP32 Arduino Core. Using the Arduino IDE is easier. On the other hand, using
ESP-IDF gives more power. If we need more control over the hardware, like power
management, wireless power configuration or CPU core management, we’ll need
the ESP-IDF. Hence, we shall opt for ESP-IDF. Expressif included FreeRTOS in
its latest version ESP – IDF. In the subsequent chapters, we shall look into the
setting up of ESP-IDF environment., to be used in the project.

5.8 ESP-IDF RTOS:

The vanilla FreeRTOS is designed to run on a single core. However, the ESP32 is
dual core containing a Protocol CPU (known as CPU 0 or PRO_CPU) and an
Application CPU (known as CPU 1 or APP_CPU). The two cores are identical in
practice and share the same memory. This allows the two cores to run tasks
interchangeably between them.

The ESP-IDF FreeRTOS is a modified version of vanilla FreeRTOS which


supports symmetric multiprocessing (SMP).

5.9 ESP32 for the project:

Given the specifications and features of the ESP32 board, one can see that it is
efficient, lighter and commercially reliable. The advantage that it comes with
FreeRTOS plays a crucial role, and thus, floats out to be the right choice for the
project.
6. SETTING UP ESP-IDF

The native software development framework for the ESP-32 is called the Espressif
IoT Development Framework (ESP-IDF). It provides maximum functionality and
compatibility. It is a bit hard core than some of the other programming options but
it gives a better understanding of what is happening under the hood.

The ESP-IDF functionality includes menu-based configuration, compiling and


firmware download to ESP32 boards.

The following are needed to begin the installation process.

Hardware:

 An ESP32 board.
 USB cable – USB A / micro USB B.
 Computer running Windows, Linux, or mac

OS. Software:

 Toolchain to compile code for ESP32.


 Build tools – CMake and Ninja to build a full application for ESP32.
 ESP-IDF that essentially contains API (software libraries and source code)
for ESP32 and scripts to operate the Toolchain.
 Text editor to write programs (Projects) in C, e.g.., Eclipse.

Fig 6.1 Development of applications for ESP32


The quickest way to start development with ESP32 is by installing a prebuilt
toolchain. For this, we shall head over to the Espressif site and follow the provided
instructions.

6.1 Installation Process:


This is a detailed roadmap for the installation process.
Setting up the Development Environment:
 Step 1: Install prerequisites for Windows.
 Step 2: Get ESP-IDF.
 Step 3: Set up the tools.
 Step 4: Set up the environment variables.

Creating the First Project:


 Step 5: Start a Project.
 Step 6: Connect the device.
 Step 7: Configure.
 Step 8: Build the Project.
 Step 9: Flash onto the device.
 Step 10: Monitor.

Step 1: Install prerequisites for Windows:


Some tools need to be installed on the computer before proceeding to the next step.
Standard Setup of Toolchain for Windows:
Currently, only 64-bit versions of Windows are supported.
The prerequisite tools required to build firmware include Python, Git, cross-
compilers, CMake and Ninja build tools.
For this Getting Started we’re going to use the Command Prompt, but after ESP-
IDF is installed you can use Eclipse or another graphical IDE with CMake support
instead.

ESP-IDF Tools Installer:

The easiest way to install ESP-IDF’s prerequisites is to download the ESP-IDF


Tools installer from this URL:
https://dl.espressif.com/dl/esp-idf-tools-setup-2.3.exe

The installer includes the cross-compilers, OpenOCD, CMake and Ninja build tool.
The installer can also download and run installers for Python 3.7 and Git For
Windows if they are not already installed on the computer.

The installer also offers to download one of the ESP-IDF release versions.

Using the Command Prompt:

For the remaining Getting Started steps, we’re going to use the Windows
Command Prompt.

ESP-IDF Tools Installer creates a shortcut in the Start menu to launch the ESP-IDF
Command Prompt. This shortcut launches the Command Prompt (cmd.exe) and
runs export.bat script to set up the environment variables
( PATH , IDF_PATH and others). Inside this command prompt, all the installed
tools are available.

Note that this shortcut is specific to the ESP-IDF directory selected in the ESP-IDF
Tools Installer. If you have multiple ESP-IDF directories on the computer (for
example, to work with different versions of ESP-IDF), you have two options to use
them:

1. Create a copy of the shortcut created by the ESP-IDF Tools Installer, and
change the working directory of the new shortcut to the ESP-IDF directory you
wish to use.
2. Alternatively, run cmd.exe , then change to the ESP-IDF directory you wish to
use, and run export.bat . Note that unlike the previous option, this way requires
Python and Git to be present in PATH . If you get errors related to Python or
Git not being found, use the first option.

Step 2: Get ESP-IDF:

To build applications for the ESP32, we need the software libraries provided by
Espressif in ESP-IDF repository.
To get ESP-IDF, navigate to the installation directory and clone the repository with
git clone . In addition to installing the tools, for Windows introduced in Step 1 can
also download a copy of ESP-IDF.

Step 3: Set up the tools:

Aside from the ESP-IDF, you also need to install the tools used by ESP-IDF, such as
the compiler, debugger, Python packages, etc. for Windows introduced in Step 1
installs all the required tools.

In order to install the tools without the help of ESP-IDF Tools Installer, open the
Command Prompt and follow these steps:
cd %userprofile%\esp\esp-idf install.bat

Linux commands are as follows


cd ~/esp/esp-idf
./install.sh
Customizing the tools installation path:

The scripts introduced in this step install compilation tools required by ESP-IDF
%USERPROFILE%\.espressif
inside the user home directory:on Windows andon Linux . To install the tools
$HOME/.espressif
into a different directory, set
IDF_TOOLS_PATH
the environment variablebefore running the installation
scripts. Make sure that the user account has sufficient permissions to read and
write this path.

If changing the IDF_TOOLS_PATH , make sure it is set to the same value


time the Install script ( install.bat , install.ps1
every or install.sh ) and an Export script
(,export.bat export.ps1 or export.sh ) are executed.

Step 4: Set up the environment variables:


The installed tools are not yet added to the PATH environment variable. To make
the tools usable from the command line, some environment variables must be set.
ESP-IDF provides another script which does that.

ESP-IDF Tools Installer for Windows creates an “ESP-IDF Command Prompt”


shortcut in the Start Menu. This shortcut opens the Command Prompt and sets up
all the required environment variables. We can open this shortcut and proceed to
the next step.

Alternatively, to use ESP-IDF in an existing Command Prompt window, we can


run:

%userprofile%\esp\esp-idf\export.bat

On Linux, in the terminal where you are going to use ESP-IDF, run:

. $HOME/esp/esp-idf/export.sh
Step 5: Start a Project:
We are now ready to prepare the first application for ESP32.

Let us begin with project from directory in IDF.

Copy to ~/esp directory:

cd %userprofile%\esp
xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world

On Linux,

cd ~/esp
cp -r $IDF_PATH/examples/get-started/hello_world .

Step 6: Connect the device:


Connect the ESP32 board to the computer and check under what serial port the
board is visible. For Windows, it contains names like COM1
Step 7: Configure:
Navigate to the hello_world directory from Step 5. Start a Project, set ESP32 chip
as the target and run the project configuration utility menuconfig.
cd %userprofile%\esp\hello_world
idf.py set-target esp32
idf.py menuconfig
Setting the target with idf.py set-target {IDF_TARGET} should be done once,
after opening a new project. If the project contains some existing builds and
configuration, they will be cleared and initialized.

On Linux,

cd ~/esp/hello_world
idf.py set-target esp32
idf.py menuconfig

The following menu appears:

Fig 6.2 Project configuration - Home window


This menu is used to set up project specific variables, e.g. Wi-Fi network name and
password, the processor speed, etc. Setting up the project with menuconfig may be
skipped for “hello_world”. This example will run with default configuration.
Step 8: Build the Project:
Build the project by running:

idf.py build
This command will compile the application and all ESP-IDF components, then it
will generate the bootloader, partition table, and application binaries.

$ idf.py build
Running cmake in directory /path/to/hello_world/build
Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"...
Warn about uninitialized values.
-- Found Git: /usr/bin/git (found version "2.17.0")
-- Building empty aws_iot component due to configuration
-- Component names: ...
-- Component paths: ...

... (more lines of build system output)

[527/527] Generating hello-world.bin


esptool.py v2.3.1

Project build complete. To flash, run this command:


../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash
--flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-
world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000
build/partition_table/partition-table.bin
or run 'idf.py -p PORT flash'
If there are no errors, the build will finish by generating the firmware binary .bin
file.

Step 9: Flash onto the device:


Flash the binaries that we just built onto your ESP32 board by running:

idf.py -p PORT [-b BAUD] flash


Replace PORT with your ESP32 board’s serial port name from .

When flashing, we will see the output log similar to the following:
...
esptool.py --chip esp32 -p /dev/ttyUSB0 -b 460800 --before=default_reset --
after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB
0x8000 partition_table/partition-table.bin 0x1000 bootloader/bootloader.bin
0x10000 hello-world.bin
esptool.py v3.0-dev
Serial port /dev/ttyUSB0
Connecting......._
Chip is ESP32D0WDQ6 (revision 0)
Features: WiFi, BT, Dual Core, Coding Scheme None
Crystal is 40MHz
MAC: 24:0a:c4:05:b9:14
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Compressed 3072 bytes to 103...
Writing at 0x00008000. . .(100 %)
Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.0 seconds (effective
5962.8 kbit/s)...
Hash of data verified.
Compressed 26096 bytes to 15408...
Writing at 0x00001000. . .(100 %)
Wrote 26096 bytes (15408 compressed) at 0x00001000 in 0.4 seconds (effective
546.7 kbit/s)...
Hash of data verified.
Compressed 147104 bytes to 77364...
Writing at 0x00010000. . .(20 %)
Writing at 0x00014000. . .(40 %)
Writing at 0x00018000. . .(60 %)
Writing at 0x0001c000. . .(80 %)
Writing at 0x00020000. . .(100 %)
Wrote 147104 bytes (77364 compressed) at 0x00010000 in 1.9 seconds (effective
615.5 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
Done
If there are no issues by the end of the flash process, the board will reboot and start
up the “hello_world” application.

Step 10: Monitor:


To check if “hello_world” is indeed running, type idf.py -p PORT monitor (Do
not forget to replace PORT with your serial port name).

This command launches the IDF Monitor application:

$ idf.py -p /dev/ttyUSB0 monitor


Running idf_monitor in directory [...]/esp/hello_world/build
Executing "python [...]/esp-idf/tools/idf_monitor.py -b
115200 [...]/esp/hello_world/build/hello-world.elf"...
--- idf_monitor on /dev/ttyUSB0 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
ets Jun 8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)


ets Jun 8 2016 00:22:57
...
After startup and diagnostic logs scroll up, you should see “Hello world!” printed
out by the application.

...
Hello world!
Restarting in 10 seconds...
This is esp32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 2MB
external flash
Restarting in 9
seconds... Restarting in
8 seconds... Restarting
in 7 seconds...
To exit IDF monitor use the shortcut Ctrl+] .

With this, we are set to execute our applications.


6.2 Hello World code:
Before getting into the software implementations of our project, we run our first
task, “hello world” and later, multitask it with “blink”. The Espressif Internet
Development Framework (ESP-IDF) uses FreeRTOS to make better use of the two
high speed processors and manage the numerous built-in peripherals. It is done by
creating tasks.
This hello world prints the string on UART (eventually on the computer terminal).
We will first look at the ESP-IDF structure. Then look at the hello world example
and modify it blink an LED while still continuously printing the 'hello world'
string.

1.
2. +--esp-
idf 3.|
4. |
5. + - - components
6. |
7. + - - docs
8. |
9. + - - examples
10. |
11. + - - make
12. |
13. + - - tools

The components directory holds all the 'C' code for the ESP32. It contains all the
'components' that make up the ESP32. It includes Drivers for numerous
peripherals, the bootloader, bt(bluetooth), freeRTOS etc. If we expand the
components the tree looks like so:

1. +---components
2. | +---app_update
3. | | | component.mk
4. | | | esp_ota_ops.c
5. | | |
6. | | \---include
7. | | esp_ota_ops.h
8. | |
9. +---bootloader
| | | | component.mk
10.
11. | | | README.rst
12. | | |
13. | | +---include
14. | | | esp_image_format.h
15. | | | esp_secure_boot.h
16. | | |
17. | | +---include_priv
18. | | | bootloader_flash.h
19. | | |
20. | | \---src
21. | | bootloader_flash.c
22. | | esp_image_format.c
23. | | secure_boot.c
24. | | secure_boot_signatures.c
25. | |
26. | +---bt
27. | | | bt.c
28. . .
29. | |
30. | +---driver
31. | | | component.mk
32. | | | gpio.c
33. . .
34. | |
35. | +---esp32
36. | | | abi.cpp
37. . .
38. | |
39. | +---esptool_py
40. | | | Kconfig.projbuild
41. . .
42. | |
43. | +---ethernet
44. | | | component.mk
45. . .
46. | |
47. | +---expat
48. . .
49. | |
50. | +---freertos
51. | | | component.mk
52. . .
53. | |
54. | +---idf_test
55. . .
56. | |
57. | +---newlib
58. . .
59. | |
60. | +---nghttp
61. . .
62. | |
63. | +---nvs_flash
64. | | | .gitignore
65. | |
66. . .
67. | |
68. | +---openssl
69. | |
70. . .
71. | |
72. | +---partition_table
73. . .
74. | |
75. | +---spi_flash
76. | |
77. . .
78. | |
79. | +---tcpip_adapter
80. . .
81. | |
82. | +---ulp
83. | |
84. . .
85. | |
86. | +---vfs
87. | |
88. . .
89. | +---wpa_supplicant
90. | |
91. | \---xtensa-debug-module
92. | | component.mk
93. . .
94. |
95. |
96. +--- docs

6.2.1 The Includes:


As you notice each of the component folders one or more .c and .h files. To include
a component, we need to include the corresponding .h file in our code. Our hello
world example needs four of these components.
1. #include <stdio.h>
2. #include "freertos/FreeRTOS.h"
3. #include "freertos/task.h"
4. #include "esp_system.h"

 freertos/FreeRTOS.h: Inclusion of this set’s configuration required to


run freeRTOS on ESP32.
 freertos/task.h: The tasks provide the multitasking functionality, which we
will explore in the ‘blinky’ with ‘hello world’ example in some time.
 esp_system.h: This inclusion configures the peripherals in the ESP system. It is
similar to system initialization. It's like setting up all the components of your
bike, before we could fire the engine.

6.2.2 The main() function:


app_main(), is just like good old main(). This is the first function that gets called
automatically.
1. void app_main()
2. {
3. nvs_flash_init();
4. xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, N
ULL);
5. }

 Initialize Flash: nvs_flash_init(): As said earlier the ESP32 Modules


run code from an external flash. Unless we are using directly the ESP32 chip,
the module/board maker will taker of the flash initialization and access.
 xTaskCreate(): This function has 5 arguments. The first parameter is address of
the function which execute, when this task is scheduled to run. The second
parameter hello_task is the name given to the task. This could be any name. It
used to obtain handle or while debugging the task. The next parameter 2048 is
the memory allocated to the task in word (2 Bytes).

6.2.3 The hello_task:


The function that is called from the task created above is a simple function as
shown below. It simply prints the string to the UART. The Print stream is
configured to the UART0 of the ESP32.
1. void hello_task(void *pvParameter)
2. {
3. printf("Hello world!\n");
4. for (int i = 10; i >= 0; i--) {
5. printf("Restarting in %d seconds...\n", i);
6. vTaskDelay(1000 / portTICK_RATE_MS);
7. }
8. printf("Restarting now.\n");
9. fflush(stdout);
10. esp_restart();
11. }

Now, let’s look at the complete code.


1. #include <stdio.h>
2. #include "freertos/FreeRTOS.h"
3. #include "freertos/task.h"
4. #include "esp_system.h"
5.
6. void hello_task(void *pvParameter)
7. {
8. printf("Hello world!\n");
9. for (int i = 10; i >= 0; i--) {
10. printf("Restarting in %d seconds...\n", i);
11. vTaskDelay(1000 / portTICK_RATE_MS);
12. }
13. printf("Restarting now.\n");
14. fflush(stdout);
15. esp_restart();
16. }
17.
18. void app_main()
19. {
20. nvs_flash_init();
21. xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5
, NULL);
22. }

6.3 Multitasking Blink with Hello task:


The blinky code is basically turning ON an LED, waiting for a second, turning it
OFF and waiting for another second. If the requirement is to continuously send a
string, say every 100 milliseconds while the LED is still blinking, it can be easily
accomplished using the RTOS. So, the code below, creates two tasks. Whenever
one enters delay state (vTaskDelay function), the other runs and vice-versa. Since
we are slow and ESP32 is fast, it switches between the tasks numerous times and
we see both the tasks happening simultaneously.

1. #include <stdio.h>
2. #include "freertos/FreeRTOS.h"
3. #include "freertos/task.h"
4. #include "esp_system.h"
5. #include "driver/gpio.h"
6.
7. #define BLINK_GPIO 13

8. void hello_task(void *pvParameter)


9. {
10.
11. while(1)
12. {
13. printf("Hello world!\n");
14. vTaskDelay(100 / portTICK_RATE_MS);
15. }
16. }
17.
18. void blinky(void *pvParameter)
19. {
20.
21. gpio_pad_select_gpio(BLINK_GPIO);
22. /* Set the GPIO as a push/pull output */
23. gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
24. while(1) {
25. /* Blink off (output low) */
26. gpio_set_level(BLINK_GPIO, 0);
27. vTaskDelay(1000 / portTICK_RATE_MS);
28. /* Blink on (output high) */
29. gpio_set_level(BLINK_GPIO, 1);
30. vTaskDelay(1000 / portTICK_RATE_MS);
31. }
32. }
33.
34.
35. void app_main()
36. {
37. nvs_flash_init();
38. xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5
, NULL);
39. xTaskCreate(&blinky, "blinky", 512,NULL,5,NULL );
40. }
7. PROJECT DEVELOPMENT AND IMPLEMENTATION

7.1 Development:

Before getting in to the program development, let us take a look at the folder where
the source code is to be stored and additional documents are required for the
program to function properly.
The folder is as shown below:

Fig 7.1 Folder to store the source code

From the above picture, one can see that the program folder consists of a main
folder, cmakeLists.txt, makefile, README.md,sdkconfig.defaults.
1.CMakeLists.txt file contains a set of directives and instructions describing the
project's source files and targets (executable, library, or both).

2.A makefile is a special file, containing shell commands, that you create and
name makefile (or Makefile depending upon the system). While in the directory
containing this makefile, you will type make and the commands in the makefile
will be executed.

3.A README file contains information about other files in a directory or archive
of computer software. A form of documentation, it is usually a simple plain text
file called READ.ME, README.TXT, README.md.

4.sdkconfig.defaults contains the default configuration details set in the menu


configuration.
5.The main folder contains the soure code for the project.

After building the project, the project folder will be as shown below:

Fig 7.2 Folder after building the project

A new folder called as build has been created which stores all the details related to
building the project.
An additional sdkconfig.old document is created which contains the default
configuration details and the sdkconfig folder is updated to the recent developments.

7.2 Program:
Since we are now familiar with the structure of the program as seen in the Hello
World task earlier, let us proceed to the program development.
The source code of the project for the single core processor is given below:
#include <stdio.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"

#define pi 3.14159265

void division(void *pvParameter)


{
int a=6,b=3;
while(1)
{
float c;
c=((float)a/(float)b);
printf("Quotient of %d and %d is %f\n",a,b,c);
a+=1; b+=1;
}
} vTaskDelay(200 / portTICK_RATE_MS);

void mul(void *pvParameter)


{
int a=6,b=3;

while(1) {
long c;
c=a*b;
printf("Multiplication of %d and %d is %ld\n",a,b,c);
a+=1;
b+=1;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void add(void *pvParameter)
{
int a=6,b=3;

while(1) {
long c;
c=a+b;
printf("sum of %d and %d is %ld\n",a,b,c);
a+=1;
b+=1;

vTaskDelay(200 / portTICK_RATE_MS);
}
}
void sub(void *pvParameter)
{
int a=6,b=3;
while(1) {
int c;
c=a-b;
printf("subtraction of %d and %d is %d\n",a,b,c);
a+=2;
b+=1;

vTaskDelay(200 / portTICK_RATE_MS);
}
}

void square(void *pvParameter)


{
int a=3;
while(1)
{ long
b=a*a;
printf("The square of %d is %ld\n",a,b);
a+=1;
vTaskDelay(200/portTICK_RATE_MS);
}
}

void sqart(void *pvParameter)


{
int a=4;
float b;
char stats_buffer[4096];
char list_buffer[4096];
while(1){
b=sqrt(a);
printf("The squareroot of %d is %f\n",a,b);
a+=2;
vTaskList(list_buffer);
printf("************************************************************
******\n");
printf("Task\t State\t Prio\t Stack\t Num\t CoreID\n");
printf("************************************************************
******\n");
printf(list_buffer);
printf("************************************************************
******\n\n\n\n");
vTaskGetRunTimeStats(stats_buffer);
printf("**********************************************\n");
printf("Task\t Runtime\t Percentage\n");
printf("**********************************************\n");
printf(stats_buffer);
printf("**********************************************\n");
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void logarithimic(void *pvParameter)
{
double a=2;
while(1)
{ double
res;
res=log(a);
printf("The natural logarithm of %.2lf is %lf\n",a,res);
a+=3;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void trig(void *pvParameter)
{

double x,rescos,ressine,restan,val;
x=30;
while(1)
{ val=pi/180.0;
rescos=cos(x*val);
ressine=sin(x*val);
restan=tan(x*val);
printf("The cosine of %lf degrees is %lf\n",x,rescos);
printf("The sine of %lf degrees is %lf\n",x,ressine);
printf("The tangent of %lf degrees is %lf\n",x,restan);
x+=15;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void compadd(void *pvParameter){
int a1=2,b1=4,a2=3,b2=1;
int a3,b3;
while(1)
{
a3=a1+a2;
b3=b1+b2;
printf("The sum of %d+i%d and %d+i%d is %d+i%d\n",a1,b1,a2,b2,a3,b3);
a1+=1;
a2+=2;
b1+=-1;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void compsub(void *pvParameter){
int a1=2,b1=4,a2=3,b2=1;
int a3,b3;
while(1)
{
a3=a1-a2;
b3=b1-b2;
printf("The difference of %d+i%d and %d+i%d is %d+i%d\n",a1,b1,a2,b2,a3,b3);
a1+=3;
a2+=1;
b1+=2;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void compmul(void *pvParameter){
int a1=2,b1=4,a2=3,b2=1;
int a3,b3;
while(1)
{
a3=(a1*a2-b1*b2);
b3=(a1*b2+a2*b1);
printf("The multiplication of %d+i%d and %d+i%d is
%d+i%d\n",a1,b1,a2,b2,a3,b3);
a1+=3;
a2+=1;
b1+=2;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void temp(void *pvParameter){
float c=23;
while(1)
{
float f,k;
f=((c*1.8)+32.0);
k=c+273.15;
printf("The farenheit temperature for given %f celcius is %f farenheit\n",c,f);
printf("The kelvin temperature for given %f celcius is %f kelvin\n",c,k);
c=c+1.5;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void app_main()
{
xTaskCreatePinnedToCore(&division, "division", 2048, NULL, 10, NULL, 0);
xTaskCreatePinnedToCore(&mul, "mul", 2048,NULL,8,NULL ,0);
xTaskCreatePinnedToCore(&add, "add", 2048,NULL,6,NULL,0);
xTaskCreatePinnedToCore(&sub, "sub", 8192,NULL,5,NULL,0 );
xTaskCreatePinnedToCore(&square, "square", 4096,NULL,3,NULL,0 );
xTaskCreatePinnedToCore(&sqart, "sqart", 16384,NULL,15,NULL,0);
xTaskCreatePinnedToCore(&logarithimic, "logarithimic", 4096,NULL,2,NULL,0
);
xTaskCreatePinnedToCore(&trig, "trig", 8192,NULL,2,NULL,0 );
xTaskCreatePinnedToCore(&temp, "temp", 2048,NULL,2,NULL,0 );
xTaskCreatePinnedToCore(&compadd, "compadd", 2048,NULL,3,NULL,0 );
xTaskCreatePinnedToCore(&compsub, "compsub", 2048,NULL,4,NULL,0 );
xTaskCreatePinnedToCore(&compmul, "compmul", 2048,NULL,5,NULL,0 );

#include <stdio.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/gpio.h"

void even(void *pvParameter)


{
int n=6,i;
while(1)
{
printf("The even numbers from 1 to %d are:\n",n);
for(i=1;i<=n;i++)
{ if(i
%2==0)
{
printf("%d\n",i);
}
}
n+=3;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void natural(void *pvParameter)
{
int n=7,i;
long sum=0;
while(1)
{
sum=0;
for(i=1;i<=n;i++)
{
sum=sum+i;
}
printf("The sum of first %d natural numbers is %ld\n",n,sum);
n=n+7;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void fibonacci(void *pvParameter)
{
int a=0,b=1,n=4,i,c;
while(1)
{a=0;
b=1;
printf("The fibonacci series for %d terms is:\n",n);
for(i=1;i<=n;i++)
{
printf("%d\n",a);
c=a+b;
a=b;
b=c;
}
n=n+2;
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void perfect(void *pvParameter)
{
long n=356,sum=0,i,rem;
char stats_buffer[4096];
char list_buffer[4096];
while(1)
{sum=0;
for(i=1;i<=(n-1);i++){
rem=n%i;
if(rem==0)
sum=sum+i;
}
if(sum==n)
printf("The number %ld is a perfect number\n",n);
else
printf("The number %ld is not a perfect number\n",n);
n=n+23;
vTaskList(list_buffer);
printf("************************************************************
******\n");
printf("Task\t State\t Prio\t Stack\t Num\t CoreID\n");
printf("************************************************************
******\n");
printf(list_buffer);
printf("************************************************************
******\n\n\n\n");
vTaskGetRunTimeStats(stats_buffer);
printf("**********************************************\n");
printf("Task\t Runtime\t Percentage\n");
printf("**********************************************\n");
printf(stats_buffer);
printf("**********************************************\n");
vTaskDelay(200 / portTICK_RATE_MS);
}
}
void app_main()
{
xTaskCreatePinnedToCore(&even, "even", 4096, NULL, 5, NULL, 0);
xTaskCreatePinnedToCore(&natural, "natural", 4096, NULL, 6, NULL, 0);
xTaskCreatePinnedToCore(&fibonacci, "fibonacci", 4096, NULL, 7, NULL, 0);
xTaskCreatePinnedToCore(&perfect, "perfect", 16384, NULL, 10, NULL, 0);
}

Now, let us understand the program:


The Includes:
As the program requires usage of more than one component, we inclde the
corresponding .h files in the header section.
 stdio.h,math.h the C libraries are included so as to facilitate the
input/output and mathematical operations function smoothly.
 freertos/FREERTOS.h facilitates the inclusion of this set's configuration
required to run freeRTOS on ESP32.
 freertos/task.h facilitates the inclusion of multitasking finctionality.
 esp_system.h configures the peripherals in the ESP System which is similar
to system initialization.

main function:
The program execution starts with the app_main(), just like good old main(). This
is the first function that gets called automatically.

Example:
void app_main()
{

xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL);


xTaskCreatePinnedToCore(&blink_task, "blink_task", 2048, NULL, 5,
NULL,0);
}

xTaskCreate():

xTaskCreate( TaskFunction_t pvTaskCode,


const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
);

Each task requires RAM that is used to hold the task state, and used by the task as
its stack. If a task is created using xTaskCreate() then the required RAM is
automatically allocated from the FreeRTOS heap.
Parameters:
 pvTaskCode: Pointer to the task entry function i.e; the address of the
task.Tasks are normally implemented as an infinite loop, and must never
attempt to return or exit from their implementing function. Tasks can
however delete themselves.

 pcName: A descriptive name for the task. This is mainly used to facilitate
debugging, but can also be used to obtain a task handle.The maximum
length of a task’s name is set using the configMAX_TASK_NAME_LEN
parameter in FreeRTOSConfig.h.

 usStackDepth: The number of words (not bytes!) to allocate for use as the
task’s stack.

 pvParameters: A value that will passed into the created task as the task’s
parameter.If pvParameters is set to the address of a variable then the variable
must still exist when the created task executes – so it is not valid to pass the
address of a stack variable.

 uxPriority : The priority at which the created task will execute.

 pxCreatedTask: Used to pass a handle to the created task out of the


xTaskCreate() function. pxCreatedTask is optional and can be set to NULL.

 Returns:
If the task was created successfully then pdPASS/pdTRUE is returned. Otherwise
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned.

xTaskCreatePinnedToCore():

Create a new task with a specified affinity.

This function is similar to xTaskCreate, but allows setting task affinity in SMP
system.
xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask
const BaseType_t xCoreID
);
Parameters:

 pvTaskCode: Pointer to the task entry function i.e; the address of the
task.Tasks are normally implemented as an infinite loop, and must never
attempt to return or exit from their implementing function. Tasks can
however delete themselves.

 pcName: A descriptive name for the task. This is mainly used to facilitate
debugging, but can also be used to obtain a task handle.The maximum
length of a task’s name is set using the configMAX_TASK_NAME_LEN
parameter in FreeRTOSConfig.h.

 usStackDepth: The number of words (not bytes!) to allocate for use as the
task’s stack.

 pvParameters: A value that will passed into the created task as the task’s
parameter.If pvParameters is set to the address of a variable then the variable
must still exist when the created task executes – so it is not valid to pass the
address of a stack variable.

 uxPriority: The priority at which the created task will execute.

 pxCreatedTask: Used to pass a handle to the created task out of the


xTaskCreate() function. pxCreatedTask is optional and can be set to NULL.
 xCoreID: If the value is tskNO_AFFINITY, the created task is not pinned
to any CPU, and the scheduler can run it on any core available. Values 0 or
1 indicate the index number of the CPU which the task should be pinned to.
Specifying values larger than (portNUM_PROCESSORS - 1) will cause the
function to fail.
 Returns: If the task was created successfully then pdPASS/pdTRUE is
returned. Otherwise
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY is returned.

The task:
Consider a task from the above program and the structure is as shown below:
void add(void *pvParameter)
{
int a=6,b=3;

while(1) {
long c;
c=a+b;
printf("sum of %d and %d is %ld\n",a,b,c);
a+=1;
b+=1;

vTaskDelay(200 / portTICK_RATE_MS);
}
}

Here, the functionality of the task is written in the while loop that run infinitely as
a task in the freertos should run infinitely and it should never attempt to return or
exit from the implementing function.
Now, inorder to facilitate the executio of other tasks, we introduce a delay in the
task through vTaskDelay.

vTaskDelay:
void vTaskDelay( const TickType_t xTicksToDelay );
vTaskDelay() specifies a time at which the task wishes to unblock relative to the
time at which vTaskDelay() is called. For example, specifying a block period of
100 ticks will cause the task to unblock 100 ticks after vTaskDelay() is called.
Parameters:
 xTicksToDelay: The amount of time, in tick periods, that the calling task
should block.

Example usage:

void vTaskFunction( void * pvParameters )


{
/* Block for 500ms. */

for( ;; )
{
/* Simply toggle the LED every 500ms, blocking between each toggle. */
vToggleLED();
vTaskDelay(500 / portTICK_PERIOD_MS;);
}
}

Runtime Stats:
In order to get the information about the tasks running and the run time statistics of
the program, two APIs are used. Their functionality is described below:

vTaskList():

void vTaskList( char *pcWriteBuffer );


configUSE_TRACE_FACILITY and
configUSE_STATS_FORMATTING_FUNCTIONS must be defined as 1 in
FreeRTOSConfig.h for this function to be available.
vTaskList() calls uxTaskGetSystemState(), then formats the raw data generated by
uxTaskGetSystemState() into a human readable (ASCII) table that shows the state
of each task, including the task’s stack high water mark.

In the ASCII table the following letters are used to denote the state of a task:

‘B’ – Blocked
‘R’ – Ready
‘D’ – Deleted (waiting clean up)
‘S’ – Suspended, or Blocked without a timeout

Parameters:
 pcWriteBuffer : A buffer into which the above mentioned details will be
written, in ASCII form. This buffer is assumed to be large enough to
contain the generated report. Approximately 40 bytes per task should be
sufficient.

Fig 7.3 Buffer


vTaskGetRunTimeStats():

void vTaskGetRunTimeStats( char *pcWriteBuffer );


configGENERATE_RUN_TIME_STATS,
configUSE_STATS_FORMATTING_FUNCTIONS and
configSUPPORT_DYNAMIC_ALLOCATION must all be defined as 1 for this
function to be available.
Fig 7.4 Runtime stats
vTaskGetRunTimeStats() calls uxTaskGetSystemState(), then formats the raw data
generated by uxTaskGetSystemState() into a human readable (ASCII) table that
shows the amount of time each task has spent in the Running state (how much
CPU time each task has consumed).The resolution of the absolute value is
dependent on the frequency of the run time stats clock provided by the application.

Parameters:
 pcWriteBuffer: A buffer into which the execution times will be written,
in ASCII form. This buffer is assumed to be large enough to contain the
generated report. Approximately 40 bytes per task should be sufficient.

7.3 Implementation:
The following are the steps to be followed for implementing the project in a
LINUX based system:
1) Adding tools to the environment
Before proceedingg to compiling and building the projet ensure that all the tools
must be added to the path so as to function. For this to be done, navigate to the
folder where the esp-idf software is stored and then type the command .
./export.sh. This will ensure that all the tools are added to the path for smooth
functioning of the build process.
Fig 7.5 Adding tools to the environment

2) Configuring the options


Now, navigate to the folder where the project is stored through the terminal and type
make menuconfig. The following window appears:

Fig 7.6 Configuring the options

Now, navigate to the serial flasher config(shown below), at the top is the name of
the serial port to which the component is to attached, now set the flash size to
2MHz
and the baud rate to 115200bps and the flash SPI speed to 40MHZ(These are to be
done according to the board that one uses).

Fig 7.7 Serial Flasher Config Window


Now, go to freeRTOS under the component config and set the options as shown
below. These are set to enable the APIs vTaskList and vTaskGetRunTimeStats that
are used in the project and also to to do various other funcyions like to limit the
size of the taskname, tick rate etc.
After setting the options as per requirement, press S to save the coices and press Esc
to exit from the configuration window.

Fig 7.8 Component Config Window Fig


3) Building the project
Now, type in the command make to build the project. This build the project and
generates the binary file that can be flashed to the device. A folder called as build
is created in the project folder and all the information pertaining to building the
project is stored there.

Fig 7.9 Building the project

4) Flashing the program to the device


For this, type the command make flash which flashes the binaries to the device.

Fig 7.10 Flashing the program to the device

5) Viewing the output


The program eventually prints the data on a UART, we ca see the output on the
terminal by typing the command make monitor. This results in the output being
printed on the console continuously since all the tasks run in an infinite loop. In
order
to exit from this, press ctrl+] this will exit from the output and restores the terminal
to normal form.
8. RESULTS AND DISCUSSIONS

The project converges to a study on FreeRTOS, installation of ESP-IDF and


executing two applications on the ESP32As demonstrated in the previous chapter,
we ran two applications whose results are shown below.
The first application is a implementing a calculator.

Fig 8.1 Application1


In the Fig 8.1. we can see that the expected values of the outcome match with the
obtained results. It shows the list of all the tasks performed.
In the Fig 8.2. the tasks along with their runtime and percentage of CPU utilization
are determined.
We can now calculate the real-time statistics which are execution time of the
program and percentage of CPU utilization for the application.
The formulae to determine the above parameters are as follows.
Fig 8.2 Application1

Execution time of the program:


The execution time of the program is the sum of execution time of the individual
tasks.
Hence, Execution time(te) = 1201500+ 29546+ 30053+ 19967+ 43097+ 26704+
37843+ 31665+ 20590+ 130097+ 38653+ 119233+
3249935+ 1465122+ 50+ 48+ 9588+ 4624
= 6458315 microseconds
CPU Utilization:
CPU Utilization is the sum of work handled by a Central Processing Unit.
CPU Utilization = 100- (%time for which the CPU is idle)
From the above results we know that, CPU is idle for 49% for IDLE1 and 22% for
IDLE2.
Hence, CPU Utilization = 100 – (49+22) = 29%
The second application is determining the even numbers, Fibonacci series, perfect
numbers from the given set and the sum of n natural numbers.
Fig 8.3 Application2
In the Fig 8.3. we can see that the expected values of the outcome match with the
obtained results. It shows the list of all the tasks performed.

Fig 8.4 Application2


In the Fig. 8.4. the tasks along with their runtime and percentage of CPU utilization
are determined.
We can now calculate the real-time statistics which are execution time of the
program and percentage of CPU utilization for the application.

Execution time of the program:


The execution time of the program is the sum of execution time of the individual
tasks.
Hence, Execution time(te) = 100095+ 339943+ 192384+ 3672+ 3831+ 4528+ 48+
37+ 9596+ 4644
= 658778 microseconds
CPU Utilization:
CPU Utilization is the sum of work handled by a Central Processing Unit.
CPU Utilization = 100- (%time for which the CPU is idle)
From the above results we know that, CPU is idle for 47% for IDLE1 and 26% for
IDLE2.
Hence, CPU Utilization = 100 – (47+26) = 27%
Let us summarize the results.
S.No. Application Number of Execution CPU
Tasks Time Utilization
(in (%)
microseconds)
1. Calculator 18 6458315 29%

2. Identifying even 10 658778 27%


numbers, Fibonacci
series, perfect numbers
from the given set and
the sum of n natural
numbers.
Table 8.1 Summary of the results obtained
The parameters execution time and CPU utilization vary with applications, the
tasks involved and their complexity. The values can be compared from the table
and the inferences drawn are mentioned in the next chapter.
9. CONCLUSION AND FUTURE SCOPE

In the present project, the performance of the FreeRTOS kernel using ESP32 board
was analysed through different parameters. The explanation about the importance
of using RTOS in critical time systems was also accomplished and proved.
Considering the circumstances of the experiments, it is possible to conclude that
the FreeRTOS kernel really presented determinism and reliability. Such kernel
may be considered useful and flexible with free open source libraries. The
FreeRTOS libraries are written in C programming language, being very easy to
become acquainted with.
The embedded system ESP32 demonstrated a good performance with simplicity,
low cost reliability, and feasibility. The board has a very small size, demonstrating
a good capability of being installed in any further projects, when portability is
necessary. As displayed in the project, this device may be considered useful for the
proposed application and other applications involving RTOS. ESP32 is a dual-core
processor and the project successfully runs the application on one of the two cores.
From the results, we can conclude that the performance varies with the number of
tasks involved in the application. The first application takes longer execution time
than the second as the number of tasks are more. When coming to the CPU
Utilization, though the number of tasks in both the applications differ by a
significant amount, there is only a slight change in the percentage of CPU
Utilization. The first application runs 18 tasks utilizing 29% whereas the second
applications runs 10 tasks utilizing 27%. This proves that CPU Utilization depends
not just on the number of tasks but also on the complexity and type of the
computing task.

Single core processor consumes less. With more cores, it is found that battery
drains quickly. The number of applications we can run on the core before the
battery drains are comparatively more. Because single-core processor consumes
less power, the entire system being run by it remains cooler. A single core
processor is still good for most of applications because many of them aren’t built
for multiple core processor. The disadvantage steps in as it is comparatively a slow
processor. It takes more time as the time taken by every task counts in and the CPU
utilization cannot be directly told by the tasks involves in the application.

From this project we conclude that, RTOS is very important to handle critical time
systems, which become useless after missing the deadline. Also, we have seen the
capabilities of the ESP32 board, and up to what extent a single-core processor is
reliable. For simpler applications which do not rely on the time required to obtain
the results, it is easy to use the single processor as it adds very few lines to the
original code. Moreover, it consumes lesser power. But on the other hand, when
projects are to have quick results, the reliability on the processor ends. If a single
core processor is assigned with two difference things, it cannot do them both
simultaneously. Because modern apps require a lot of processing power, a single-
core processor operating them can get frozen. It simply means that the entire
system can become unresponsive. Depending on the needs required to meet the
project, one can choose to whether or not go for the single-core. From this project,
it is also possible to conclude that there is a very rich field involving RTOS
applications for embedded tasks.

Future Scope:

Microprocessors have found their way in almost every electronic device that is
available today. Microprocessors and microcontrollers enable the modern world to
produce devices that comprehend the environment and react to situations
producing a much-desired effect. The operating speed of modern day computers
has increased over a thousand times in the past twenty years.
It’s not hard to predict that next-generation processors will have smaller details,
more transistors on each square millimeter of silicon, and do more clever things,
such as powering down under-used sections even between keystrokes. They will
also have many cores or CPUs.
Even now, Intel has given hardware and software developers a peek at a
prototype 80-core processor with one teraflop of computational ability. The
company, however, has set no launch date. Nvidia Corp. sells a Quadro Plex
graphic processor sporting 128 cores. And Cisco Systems Inc., sensing a coming
surge in network traffic, is toying with a 188-core router.
REFERENCES

(1) https://www.freertos.org/FreeRTOS-quick-start-guide.html
(2) https://www.freertos.org/a00019.html
(3) https://www.freertos.org/a00021.html#vTaskList
(4) https://www.freertos.org/a00021.html#vTaskGetRunTimeStats
(5) https://www.freertos.org/RTOS-message-buffer-API.html
(6) Using the FreeRTOS Real-time Kernel- A Practical Guide by Richard Barry
(7) ESP-IDF Programming Guide — ESP-IDF
Programming Guide documentation
(8) https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-
started/linux- setup.html
(9) https://docs.aws.amazon.com/freertos/latest/userguide/what-is-
freertos.html