0:07
hello everyone welcome to controllers
0:11
tech this is the third video in the
0:14
series of free RTOS and in this video I
0:18
am going to show you guys how to use
0:20
binary semaphore so semaphores are used
0:24
to synchronize tasks with other tasks or
0:27
with the interrupts you should create a
0:30
semaphore before using it a semaphore
0:33
can be taken or released using the
0:36
respective functions in three RTOS the
0:40
semaphore are four types and they are
0:44
binary semaphore counting semaphore
0:47
mutex and recursive we will cover all of
0:51
them one by one we will start with
0:54
binary semaphore today I will try to
0:57
explain the concept of binary semaphore
0:59
in the simplest possible way imagine
1:03
there are three people in a group
1:04
discussion they want to talk about their
1:07
opinion on some topic if we will allow
1:11
all of them to speak there will be some
1:13
set of problems first we won't be able
1:17
to understand anything
1:19
second the loudest person will always
1:22
take over other's opinion so to avoid
1:26
this we will bring in the talking chair
1:28
the person who sits on the chair can
1:32
speak and others have to just wait for
1:35
their turn think of the binary semaphore
1:38
as this chair and the three people as
1:41
three tasks if a task want to execute it
1:45
have to acquire the semaphore first
1:48
binary semaphore simply means that
1:50
either it can be 1 or 0 so either the
1:54
tasks have the semaphore or it doesn't
1:57
there is no third stage here now the
2:01
very important part not having the chair
2:04
does not mean that the people can't talk
2:07
of course they can still speak but we
2:09
have to make this rule about the chair
2:12
similarly if you let a task execute
2:15
without waiting for the semaphore it
2:17
will execute considering it of higher
2:19
priority so to use the semaphore
2:22
properly we must always make the task
2:25
wait for the semaphore and once the task
2:27
acquires the semaphore it is allowed to
2:29
run if all of its sound complicated to
2:33
you don't worry you will get this during
2:36
the programming so let's start by
2:39
creating the project in stm32 cube ide i
2:43
am using stm32f4 for 6r ii controller
2:48
give a name to the project and click
2:51
finish first of all i am enabling the
2:55
external crystal in the SIS option
2:58
choose the time source other than Cystic
3:00
i am choosing timer 1 enable the free RT
3:06
o s leave the setup as default we don't
3:11
need to change anything
3:19
go to tasks and queues here one default
3:24
task is already defined I am going to
3:27
modify this task its name is going to be
3:31
normal task priority is going to be
3:34
normal only stack size as default one I
3:38
am changing entry function also start
3:43
normal task I am creating two more tasks
3:54
high task with priority above normal and
4:02
a low task with priority below normal
4:10
now go to timers and semaphores here we
4:14
are going to create a binary semaphore
4:31
I am enabling UART to in order to
4:33
communicate with the computer also there
4:40
is a button connected to PC 13 and
4:42
therefore it must be selected as input
4:45
now go to the clock setup I have a 8
4:49
megahertz crystal on my new Clio board
4:52
and I want the controller to run at
4:55
maximum clock possible click Save and
5:01
the project will be generated
5:11
as you can see here the handlers for all
5:15
three tasks and the semaphore is defined
5:18
we have entry functions for the three
5:21
tasks here tasks are created inside the
5:29
main function and here we have to write
5:33
the functions of these tasks let's start
5:37
with high priority tasks first
5:43
as soon as the control enters the high
5:46
task this statement will be sent to the
5:58
and after sending the exit statement the
6:02
control will exit the high task I am
6:05
just trying to show the working of these
6:07
tasks first before we go to the binary
6:10
semaphore the same will happen in the
6:23
and same in the low priority tasks also
6:25
I am using 500 milliseconds delay for
6:29
these tasks so each task will run once
6:32
and then go to the suspended State for
6:34
500 milliseconds let's build the project
6:39
there are no errors so let's debug the
6:42
code choose stm32 application and click
6:47
OK I am using Hercules for the serial
7:04
run the program for a few seconds let's
7:08
see what do we get so at the beginning
7:13
edge Allah have three tasks of different
7:15
priorities therefore it will run the
7:18
high priority task first here you can
7:22
see the statements from the high task
7:24
being printed on this console then the
7:28
high task will go in the suspense State
7:30
for 500 milliseconds and the scheduler
7:33
will run the medium priority task
7:36
similarly it will run the low task at
7:39
the end after 500 milliseconds all three
7:43
tasks will be available again scheduler
7:46
will again run them in the same order
7:49
and this cycle will continue forever so
7:52
the tasks are running properly
8:02
now I am going to wait for some specific
8:05
event inside the medium task so until
8:10
the pin PC 13 goes low the medium task
8:13
is going to wait PC 13 is connected to
8:17
an input button on board let's build
8:20
this code and see what happens I am
8:25
going to run it for few seconds now as
8:31
expected the higher task runs first and
8:34
then the control goes in the medium task
8:45
basically this instruction has been
8:48
executed and the medium task is waiting
8:51
for the button to be pressed if I do not
8:54
press the button this instruction will
8:56
never execute the higher task will
9:02
resume after 500 milliseconds and
9:04
preempt the medium task this will keep
9:08
happening as the priority of the high
9:10
task is higher than the medium task on
9:13
the other hand low task can not preempt
9:16
the medium task because of lower
9:18
priority so it will also wait for the
9:21
medium task to complete now once I press
9:25
the button the rest of the medium task
9:27
will run and therefore the control will
9:29
go inside the low task and back to high
9:39
it will enter the medium task and wait
9:42
for the event once again you can see in
9:53
the result whenever I am pressing the
9:55
button the medium task will exit and low
9:58
task and run as we saw the higher
10:02
priority task can preempt the lower
10:04
priority tasks even when the low task is
10:07
running to avoid this preemption and to
10:11
safeguard the shared resources we use
10:13
the semaphores I am just going to modify
10:25
this statement a little
10:44
these are some important functions
10:46
available for semaphores OS semaphore
10:50
create creates the semaphore OS
10:54
semaphore wait waits for the semaphore
10:57
to become available the first parameter
11:00
is the ID of the semaphore handle and
11:02
the second parameter is the waiting time
11:06
if you enter 0 that would mean that it
11:09
is not going to wait at all and the
11:11
execution of the task will continue
11:13
irrespective of whether it have the
11:17
OS semaphore release releases the
11:20
semaphore so that it becomes available
11:22
for the other tasks as the semaphore was
11:26
already created when we set up the
11:28
project at the beginning I will just
11:30
start by acquiring the semaphore we have
11:34
to wait for the semaphore to become
11:36
available and we are going to wait
11:38
forever if the semaphore would be
11:41
available this will acquire it this
11:44
statement would ensure that the
11:46
semaphore has been acquired
11:55
and after the task is complete we are
11:59
going to release the semaphore
12:09
I am going to write the same rules in
12:12
the high priority task and the
12:14
statements accordingly so wait for the
12:18
semaphore acquire it and then release
12:21
the semaphore on the other hand let's
12:24
leave the low priority task as it is
12:27
just to show that the task can still
12:29
execute without the need for the
12:31
semaphores let's debug our code now note
12:40
that I am not stopping the execution
12:42
this time so the height ask will run
12:45
first it will acquire the semaphore and
12:48
release it the semaphore will become
12:51
available for the other tasks the medium
12:55
task will acquire it now the medium task
12:58
will wait for the button to be pressed
13:00
the high task will resume from
13:03
suspension and preempt the medium task
13:06
it will again try to take the semaphore
13:10
but the semaphore has been acquired by
13:12
the medium task and has not been
13:15
released yet high task can't continue
13:18
without the semaphore so it have to wait
13:20
for it to become available now all three
13:24
tasks are waiting at this point so an
13:26
idle task will be running in the
13:28
background also note that even the low
13:32
task does not need any semaphore to run
13:34
it still can't preempt the medium task
13:37
and therefore it have to wait for the
13:39
medium task to finish its execution as
13:42
soon as the button is pressed the medium
13:45
task will resume and it will release the
13:52
and then go back in the suspension state
13:57
for 500 milliseconds once the semaphore
14:01
becomes available the high task will
14:03
acquire it and continue its execution
14:13
from the point it was stopped after the
14:19
high task is executed the low task will
14:22
run because the medium task is still in
14:25
the suspended State once again the loop
14:28
continues from high task executing then
14:32
the medium task acquiring the semaphore
14:34
high task trying to preempt the medium
14:37
task but it have to wait for the
14:39
semaphore to be released by the medium
14:42
task and once the key is pressed
14:45
semaphore is released the higher task
14:48
and the lower task can run
14:50
although the binary semaphore might
14:52
seems like the perfect solutions for the
14:55
task operations it have its own
14:57
shortcomings one of those and probably
15:01
the most important one is priority
15:03
inversion priority inversion is pretty
15:06
simple to understand when a low priority
15:09
task preempts the higher priority task
15:13
it's called priority inversion take this
15:16
picture for example let's say the low
15:20
task is running in some critical section
15:22
and it have acquired the semaphore high
15:25
task also needs to run in their critical
15:28
sections and it needs the semaphore to
15:30
do that it have to wait obviously for
15:34
the semaphore to be released by the low
15:36
task now if a medium priority tasks
15:40
start running it can preempt the low
15:42
task this way now the higher priority
15:45
tasks have to wait for both the medium
15:48
and the low task to finish even the
15:52
priority of the high task is highest it
15:54
have to wait for the medium task to
15:57
this scenario is called priority
16:00
inversion I will show it in the working
16:04
state let's take the contents of the
16:07
medium task and replace them with the
16:09
low task I just need to change these
16:38
let's build the code and debug it
16:53
as expected the higher task will run
16:57
first it will acquire and release the
17:01
semaphore next the medium priority task
17:04
will run now the control goes in the low
17:08
task it will acquire the semaphore and
17:12
wait for the button to be pressed let's
17:20
call it the critical section by this
17:23
time the higher task will resume and
17:26
preempt the low task as the semaphore is
17:30
still acquired by the low task high
17:33
tasks have to wait for it the medium
17:36
task will resume and preempt the low
17:39
task the medium task does not need any
17:42
semaphore to run so it will keep
17:44
executing every 500 milliseconds now the
17:48
important point is even if I press the
17:51
button the low task have to wait for the
17:53
medium task to finish its execution this
17:57
high task will also have to wait for the
17:59
medium task to finish and we have a
18:02
priority inversion scenario here we will
18:05
cover the methods to avoid priority
18:07
inversion in the upcoming videos let's
18:11
continue this execution
18:13
now once the button is pressed the low
18:16
task will continue its execution it will
18:20
release the semaphore and high task will
18:22
continue from the waiting point now the
18:29
medium task will run again the high task
18:33
will get the control and it will execute
18:35
acquiring and releasing semaphore the
18:39
time it took to do this is of course way
18:41
less than 500 milliseconds because of
18:45
this the low task will run as the medium
18:48
task is still suspended and waiting for
18:50
500 milliseconds to complete low task
18:54
will acquire the semaphore and wait for
18:56
the event medium task will come out of
18:59
suspension and preempt the low task
19:02
at this point the high task is waiting
19:05
for its 500 milliseconds of weight
19:07
period to complete now the high task
19:11
will resume and try to acquire the
19:13
semaphore and it have to wait this
19:17
onward the medium task will keep
19:19
pre-empting the low task ever 500
19:22
milliseconds and the same thing will
19:26
whenever the key is pressed this is it
19:29
guys I hope you understood the concept
19:33
of binary semaphore we will cover
19:35
counting semaphore in the next video
19:38
regarding priority inversion you can
19:41
read about it I will explain the methods
19:44
to deal with it in the upcoming videos
19:47
you can download the code from the link
19:50
in the description leave comments if you
19:54
have any doubt keep watching