00:02 - 00:07
hello and welcome to the modern embedded
00:04 - 00:09
systems programming course I am miros
00:07 - 00:11
samic and in this lesson I go back to
00:09 - 00:14
the foreground background architecture
00:11 - 00:17
also known as the super Loop this time I
00:14 - 00:20
focus on combining it with the low power
00:17 - 00:22
sleep modes of the
00:20 - 00:24
CPU if you are new to the quantum leaves
00:22 - 00:25
Channel and the modern embedded
00:24 - 00:27
assistance programming course I
00:25 - 00:30
introduced the foreground background
00:27 - 00:32
architecture in lesson 21
00:30 - 00:34
however I still need to explain the use
00:32 - 00:36
of low power sleep modes in the
00:34 - 00:39
superloop because it is tricky and many
00:36 - 00:42
developers including myself in the past
00:39 - 00:44
get it wrong the need to explain these
00:42 - 00:47
aspects came up while I planned future
00:44 - 00:50
lessons about the various ways of
00:47 - 00:52
executing event-driven active objects so
00:50 - 00:55
this lesson lays some groundwork for the
00:52 - 00:57
next one however the subject of today's
00:55 - 00:59
lesson is important in its own right
00:57 - 01:01
especially because the super Loop also
00:59 - 01:03
known as the bare metal firmware
01:01 - 01:06
structure is applied in such a wide
01:03 - 01:09
range of products many of them battery
01:06 - 01:12
operated so let's begin today with the
01:09 - 01:14
basic principles of low power design the
01:12 - 01:16
power dissipated by general purpose
01:14 - 01:19
Digital Electronics consists of static
01:16 - 01:21
dissipation due to current leakage and
01:19 - 01:23
dynamic dissipation due to switching
01:21 - 01:25
Dynamic dissipation typically dominates
01:23 - 01:27
and is caused by charging and
01:25 - 01:30
discharging internal parasitic
01:27 - 01:33
capacitances as the circuit switches
01:30 - 01:35
from 0 to 1 and 1 to zero perhaps a
01:33 - 01:38
useful mental model of the process is
01:35 - 01:41
that switching from 0 to one is like
01:38 - 01:44
filling a bucket capacitance with water
01:41 - 01:46
electric charge and switching from one
01:44 - 01:48
to zero is like tossing the water out
01:46 - 01:50
discharging the
01:48 - 01:53
capacitor this happens at every clock
01:50 - 01:55
tick meaning at megahertz frequencies
01:53 - 01:56
the amount of wasted power is
01:55 - 01:59
proportional to how many such buckets
01:56 - 02:00
are filled and how frequently that
02:00 - 02:05
that's why modern microcontrollers allow
02:02 - 02:08
the software to turn the clock signal on
02:05 - 02:10
and off for various peripherals however
02:08 - 02:12
to achieve really low power consumption
02:10 - 02:15
the clock signal must be turned off for
02:12 - 02:17
the CPU itself which is called a low
02:15 - 02:19
power sleep mode this poses an
02:17 - 02:22
interesting problem because the CPU
02:19 - 02:25
stops executing instructions so the
02:22 - 02:28
software is no longer in control the CPU
02:25 - 02:31
must thus be woken up by external means
02:28 - 02:33
typically an interrupt
02:31 - 02:35
which brings us to the foreground
02:33 - 02:37
background software architecture where
02:35 - 02:38
the foreground consists of interrupts
02:37 - 02:41
and the background consists of the
02:38 - 02:43
endless loop inside the main function as
02:41 - 02:45
usual the interrupt should be short and
02:43 - 02:48
fast and the bulk of the work should be
02:45 - 02:50
performed in the background Loop but now
02:48 - 02:53
the background Loop must also enter the
02:50 - 02:56
CPU sleep mode the critical design
02:53 - 02:58
decision is how exactly the background
02:56 - 03:01
Loop should detect that the CPU can be
02:58 - 03:04
safely stopped in the low power sleep
03:01 - 03:07
mode well many people ask this question
03:04 - 03:10
here for example is a post on the stm32
03:07 - 03:13
community Forum how to work within wraps
03:10 - 03:16
and low power modes when using the H
03:13 - 03:18
Hall means Hardware abstraction layer
03:16 - 03:21
and in the context of stm32 it implies
03:18 - 03:23
the superloop architecture the person
03:21 - 03:26
asking this question provides his sample
03:23 - 03:28
code which is based on the global bit
03:26 - 03:31
mask of flags where each bit is
03:28 - 03:33
associated with the task to be performed
03:31 - 03:35
in the background Loop the flags are set
03:33 - 03:37
in the foreground like here in the
03:35 - 03:39
Callback functions invoked from the
03:37 - 03:41
interupt service
03:39 - 03:44
routines the advantage of having all the
03:41 - 03:46
task Flags grouped together in a single
03:44 - 03:48
bait mask is that the background Loop
03:46 - 03:50
can quickly check whether all the flags
03:48 - 03:53
are cleared meaning there are no tasks
03:50 - 03:55
to perform in that case the background
03:53 - 03:58
Loop suspends some peripherals and
03:55 - 04:00
enters sleep mode this stops the code
03:58 - 04:03
execution until the in
04:00 - 04:05
occurs when the CPU wakes up the
04:03 - 04:08
background Loop resumes and checks which
04:05 - 04:10
individual flags are set for all set
04:08 - 04:12
bits the loop calls the associated
04:10 - 04:15
Handler functions and also clears the
04:12 - 04:17
bits to indicate that the tasks are
04:15 - 04:19
done this looks like a reasonable
04:17 - 04:21
starting point so let's actually
04:19 - 04:22
implement this design and run it on your
04:22 - 04:27
Launchpad for this you can copy the
04:25 - 04:30
original project for lesson 21 about the
04:27 - 04:33
super Loop and rename it to lesson
04:30 - 04:34
52 here let me quickly explain the new
04:33 - 04:36
structure of the companion code
04:34 - 04:38
downloads which now are self-contained
04:36 - 04:41
and include all the dependencies and
04:38 - 04:43
projects for various boards not just the
04:41 - 04:46
tasi Launchpad for example many code
04:43 - 04:51
downloads come with projects for the STM
04:46 - 04:54
nucleo c031 C6 board the work to support
04:51 - 04:57
this cortex m0 Plus board and perhaps
04:54 - 04:59
others as well in the future is ongoing
04:57 - 05:00
but the downloads are gradually updated
05:00 - 05:05
maintained but going back to the code
05:02 - 05:07
for this lesson let's get into the tm4c
05:05 - 05:09
Kyle directory and double click on the
05:07 - 05:12
microvision project
05:09 - 05:15
lesson now let's copy the low power
05:12 - 05:17
superloop sud sudo code from the STD
05:15 - 05:21
discussion forum and paste it into the
05:17 - 05:23
main. C file in your microvision project
05:21 - 05:25
since this is just pseudo code I need to
05:23 - 05:27
make it more specific and improve its
05:25 - 05:29
formatting in the
05:27 - 05:34
process the initialization is board
05:29 - 05:37
specific so it'll be a call to bsp in it
05:34 - 05:37
now inside the
05:39 - 05:44
superloop all steps related to entering
05:42 - 05:48
the sleep mode will be accomplished in
05:44 - 05:48
the bsp go to sleep
05:48 - 05:55
function in the task activation section
05:52 - 05:58
the first task will for example deploy
06:03 - 06:11
the second task will for example engage
06:07 - 06:11
an anti-lock breaking system
06:16 - 06:23
ABS once I know what bsp facilities will
06:20 - 06:27
be needed I must declare them in bsp Doh
06:40 - 06:44
now in the bp. C source file I must
06:43 - 06:47
provide the board specific
06:44 - 06:51
implementation of all these facilities
06:47 - 06:51
plus the interrupt service routines
06:52 - 06:57
isrs the interrupts will be triggered by
06:55 - 07:01
the onboard buttons which are connected
06:57 - 07:04
to the gpiof port specifically pressing
07:01 - 07:08
s sw1 will activate task one and
07:04 - 07:11
pressing s sw2 will activate task
07:08 - 07:13
two I should not forget to provide the
07:11 - 07:18
definitions of the button pins and most
07:13 - 07:18
importantly the global bit mask of task
07:19 - 07:25
Flags the bsp init function needs to be
07:23 - 07:28
extended to initialize the gpiof pins
07:25 - 07:33
for the buttons and it also needs to
07:28 - 07:33
configure and enable the GPI F
07:43 - 07:49
interrupt the bsp deploy airbag function
07:47 - 07:51
will turn the onboard red LED to emulate
07:51 - 07:58
deployment similarly the bsp engaged ABS
07:55 - 08:00
function will turn the onboard blue LED
07:58 - 08:03
to emulate the ABS
08:00 - 08:06
engagement finally the most interesting
08:03 - 08:09
for today bsp go to sleep function will
08:06 - 08:12
put the CPU to sleep by means of the arm
08:09 - 08:14
cortex M wfi instruction wait for
08:12 - 08:17
interrupt this is equivalent to the
08:14 - 08:20
original function H power entry sleep
08:17 - 08:22
mode with the Power Sleep entry wfi
08:20 - 08:24
argument Additionally the go to sleep
08:22 - 08:27
function will count the number of its
08:24 - 08:30
invocations using a global counter which
08:27 - 08:32
will be helpful for debugging
08:30 - 08:33
this would be all for now so let's try
08:32 - 08:38
to build the
08:33 - 08:38
project all right so let's run
08:38 - 08:43
it so here is my arrangement of the
08:41 - 08:46
various debugger views I have CPU
08:43 - 08:49
registers source code this assembly
08:46 - 08:52
window the call stack and watch view
08:49 - 08:57
with two critical variables the global
08:52 - 08:57
ISR Flags bit mask and the go to sleep
08:58 - 09:04
counter my first test is just to run the
09:01 - 09:05
code free you can see that the go to
09:04 - 09:09
sleep counter has immediately
09:05 - 09:11
incremented but only once when I break
09:09 - 09:14
into the code I find it inside the bsp
09:11 - 09:16
go to sleep function called from Main
09:14 - 09:18
this plus the value of the go to sleep
09:16 - 09:20
counter means that the CPU was indeed
09:18 - 09:23
stopped at the wait for interrupt
09:20 - 09:26
instruction if the CPU was not stopped
09:23 - 09:28
the go to sleep counter would be in the
09:26 - 09:31
millions I can repeat it but every time
09:28 - 09:34
I find the code stopped at wfi inside
09:31 - 09:34
the go to sleep
09:35 - 09:42
function now I add a break point in the
09:38 - 09:46
GP F interrupt Handler and let the code
09:42 - 09:49
Run next I press the S sw1 button on the
09:46 - 09:51
board my break point is immediately hit
09:49 - 09:53
so I step through the code to verify
09:51 - 09:58
that the task one flag is set in the
09:53 - 09:58
global ISR Flags bit mask
09:59 - 10:03
I keep stepping to find out where the
10:01 - 10:07
interrupt returns and what happens
10:03 - 10:07
inside the background super
10:09 - 10:15
Loop indeed the loop continues from go
10:12 - 10:18
to sleep to checking the global bit mask
10:15 - 10:20
it finds the task one flag clears it and
10:18 - 10:23
calls the deploy airbag
10:20 - 10:27
function that function turns on the red
10:23 - 10:31
LED and Returns the test two flag is not
10:27 - 10:31
set so the loop WS up and goes back to
10:35 - 10:41
sleeping I can repeat it and it works as
10:43 - 10:49
before now I remove the break point and
10:46 - 10:52
run the code free pressing the S sw1
10:49 - 10:55
button increments the goto sleep counter
10:52 - 10:57
but sometimes by more than once which is
10:55 - 11:00
expected due to the bouncing of the
10:57 - 11:03
mechanical switch now I break into the
11:00 - 11:03
code and reset the target to start
11:05 - 11:10
over pressing s W1 turns the red
11:12 - 11:18
LED and pressing s sw2 turns the blue
11:15 - 11:22
LED which verifies that my second task
11:18 - 11:26
engage ABS also works as
11:22 - 11:29
expected so far so good what's not to
11:26 - 11:32
like well for starters if you want
11:29 - 11:34
lesson number 20 about race conditions
11:32 - 11:37
you should immediately realize that this
11:34 - 11:40
code is chalk full of them specifically
11:37 - 11:42
the ISR Flags bit mask is shared between
11:40 - 11:44
the background Loop and interrupts so
11:42 - 11:46
every time it is accessed you have a
11:44 - 11:48
potential race
11:46 - 11:50
condition but in lesson 20 you also
11:48 - 11:53
learned that you can avoid such race
11:50 - 11:55
conditions by making sure that every
11:53 - 11:57
access to the shared variable occurs
11:55 - 12:00
within the critical section that is with
11:57 - 12:02
interrupts disabled
12:00 - 12:04
so let's try to apply this to the
12:02 - 12:06
background Loop whereas the functions
12:04 - 12:08
for interrupt disabling and enabling
12:06 - 12:11
will be defined in the
12:08 - 12:13
bsp starting from the top of the loop
12:11 - 12:16
you disable interrupts right before
12:13 - 12:18
testing the shared ISR Flags bit mask
12:16 - 12:20
now it seems obvious that you must
12:18 - 12:22
enable interrupts before going to sleep
12:20 - 12:25
because only interrupts can wake the CPU
12:22 - 12:27
up you will see why this is problematic
12:25 - 12:30
in a minute but I've done something like
12:27 - 12:33
that in the early days of my career and
12:30 - 12:35
I keep seeing this published in books so
12:33 - 12:37
this must be popular in the field and
12:35 - 12:39
therefore requires
12:37 - 12:42
explanation but for now let's press on
12:39 - 12:45
with your immediate goal of eliminating
12:42 - 12:47
race conditions so after go to sleep
12:45 - 12:49
returns your disable interrupts to
12:47 - 12:52
proceed to the testing of the shared
12:49 - 12:54
variable in The Next Step please not
12:52 - 12:57
that in case the if Branch wasn't taken
12:54 - 13:00
interrupts remain disabled so all
12:57 - 13:03
possible execution paths are
13:00 - 13:05
covered you repeat the same pattern of
13:03 - 13:07
enabling interrupts before calling the
13:05 - 13:11
task function and disabling them after
13:07 - 13:13
it returns to proceed to the next task
13:11 - 13:16
of course you keep clearing the task bit
13:13 - 13:16
inside the critical
13:25 - 13:30
section after the last task you enable
13:28 - 13:32
interrupts so so that they can be
13:30 - 13:34
serviced before looping back to the top
13:38 - 13:44
superloop now you still need to add the
13:41 - 13:48
new bsp function prototypes to the bp.
13:44 - 13:51
header file and for the implementation
13:48 - 13:54
in bp. C you define the interrupt
13:51 - 13:56
disabling and enabling functions by
13:54 - 14:01
means of the intrinsic functions disable
13:56 - 14:01
irq and enable irq which
14:03 - 14:09
respectively the project builds cleanly
14:06 - 14:09
so let's see how it
14:10 - 14:15
works the first order of business is to
14:13 - 14:17
check that this version works at least
14:15 - 14:21
as well as the previous so you run the
14:17 - 14:23
code free and press the S sw1 button red
14:21 - 14:27
LED means that the first deploy airbag
14:23 - 14:30
task was called now you press s sw2 and
14:27 - 14:34
the blue LED lights up proving that the
14:30 - 14:36
second engage ABS task was also called
14:34 - 14:39
when you break into the code you can see
14:36 - 14:41
that it sits inside go to sleep and the
14:39 - 14:45
ISR Flags bit mask is cleared which
14:41 - 14:49
means that no tasks are ready so far so
14:45 - 14:51
good but now let's investigate deeper
14:49 - 14:53
reset Target to start from scratch and
14:51 - 14:56
set a break point at the first test of
14:53 - 14:59
the shared ISR Flags variable when you
14:56 - 15:02
run the code and stop at the breakpoint
14:59 - 15:05
verify that premask register is one
15:02 - 15:06
which means that interrupts are disabled
15:05 - 15:11
Now set a second breakpoint at the
15:06 - 15:11
beginning of the gpiof interrupt
15:11 - 15:19
Handler and move the first breakpoint to
15:14 - 15:19
the in disable function just after go to
15:20 - 15:26
sleep press the S sw1 button this
15:24 - 15:29
emulates interrupt occurring at this
15:26 - 15:32
precise in the code I mean the button
15:29 - 15:35
press can occur at any time so why not
15:32 - 15:38
here when you run the code the first
15:35 - 15:40
breakpoint hit is inside the interrupt
15:38 - 15:41
this makes sense because the interrupt
15:40 - 15:43
was serviced immediately after
15:41 - 15:46
interrupts got enabled in the
15:43 - 15:51
superloop step inside the ISR to see
15:46 - 15:51
that it sets the task one flag
15:59 - 16:06
and continue to see what happens next
16:03 - 16:09
and nothing else happens in particular
16:06 - 16:12
the breakpoint downstream from sleeping
16:09 - 16:15
is not hit indeed when you break into
16:12 - 16:18
the code you find it sleeping in the go
16:15 - 16:21
to sleep function but the ISR Flags bit
16:18 - 16:23
mask is still one which means that task
16:21 - 16:26
one is ready to
16:23 - 16:28
run only now when you continue you hit
16:26 - 16:30
the first break point and when you
16:28 - 16:32
continue continue again you see the red
16:32 - 16:37
up all this is really bad because it
16:35 - 16:40
literally means that the CPU fell asleep
16:37 - 16:43
at the switch specifically the airbag
16:40 - 16:47
was not deployed on time and instead the
16:43 - 16:50
CPU was put to sleep until some other
16:47 - 16:53
completely unrelated interrupt woke it
16:50 - 16:55
up the mechanism of this failure is
16:53 - 16:57
quite simple if the interrupt occurs
16:55 - 16:59
during the first critical section it
16:57 - 17:02
will be serviced in immediately after
16:59 - 17:05
interrupts are re enabled however due to
17:02 - 17:07
its simplistic nonpreemptive nature the
17:05 - 17:10
superloop is committed to going to sleep
17:07 - 17:13
no matter what and so it
17:10 - 17:14
does so let's now discuss the ways you
17:14 - 17:20
problem it turns out that on the cortex
17:17 - 17:22
M CPUs this superloop structure can be
17:20 - 17:26
salvaged by replacing the weight for
17:22 - 17:26
interrup instruction with waight for
17:27 - 17:33
event as the described in the definitive
17:30 - 17:37
guide to arm cortex M3 M4 processors by
17:33 - 17:39
J view WF is conditional and relies on
17:37 - 17:41
some internal Flags maintained by the
17:41 - 17:46
mcpu to work around some Hardware
17:43 - 17:48
defects in early cortex M3s Joseph view
17:46 - 17:51
recommends applying WF in a more
17:48 - 17:53
elaborate sequence that's why you see
17:51 - 17:56
this sequence in the stm32
17:53 - 17:58
implementation of the hull power enter
17:56 - 18:00
sleep mode function referenced earlier
18:00 - 18:05
video however I will not investigate
18:02 - 18:08
this solution any further because it
18:05 - 18:11
only applies to arm CeX m in most other
18:08 - 18:14
CPUs enabling interrupts before entering
18:11 - 18:16
low power sleep mode can be made to work
18:14 - 18:19
safely in a superloop
18:16 - 18:23
architecture on the other hand virtually
18:19 - 18:25
all CPUs including arm cortex M support
18:23 - 18:27
entering low power sleep modes
18:25 - 18:31
atomically with interrupts still
18:27 - 18:34
disabled in indeed several years ago in
18:31 - 18:37
2007 I surveyed various embedded
18:34 - 18:40
microcontrollers many outdated by now in
18:37 - 18:43
my article use an MCU slow power modes
18:40 - 18:45
in foreground background systems the
18:43 - 18:47
motivation for that article was
18:45 - 18:49
precisely to avoid the problem caused by
18:47 - 18:52
disabling interrupts before going to
18:49 - 18:54
sleep my old article is not alone of
18:52 - 18:56
course as the various microcontroller
18:54 - 18:59
vendors also publish techniques for
18:56 - 19:02
entering sleep mode with interrupts
18:59 - 19:05
disabled one notable example is the
19:02 - 19:07
msp430 microcontroller family from Texas
19:05 - 19:10
Instruments one of the industry's lowest
19:07 - 19:13
power designs the application nodes and
19:10 - 19:16
code example for MSP 430 always enter
19:13 - 19:18
the sleep mode with interrupts disabled
19:16 - 19:20
and reenable interrupts atomically when
19:20 - 19:24
sleep this way of implementing low power
19:22 - 19:28
mode in the superloop is also
19:24 - 19:30
recommended for cortex M indeed let's go
19:28 - 19:32
back to the TM support Forum to find the
19:30 - 19:35
original question I used at the
19:32 - 19:38
beginning of this video the question has
19:35 - 19:41
an answer where an st expert provides
19:38 - 19:43
the recommended code structure for a low
19:41 - 19:46
power superloop the expert recommended
19:43 - 19:48
architecture differs in some essential
19:46 - 19:51
aspects from what you have at this point
19:48 - 19:53
so let's copy paste and adapt it for
19:53 - 19:58
project the recommended top of the
19:56 - 20:00
superloop is essentially the same where
19:58 - 20:03
your version just HIDs the Sleep
20:00 - 20:05
transition in the bsp go to sleep
20:03 - 20:08
function enter it with interrupts
20:05 - 20:10
disabled and reenable interrupts after
20:08 - 20:12
they wait for interrupt
20:10 - 20:15
instruction however the recommended task
20:12 - 20:17
processing code does not follow directly
20:15 - 20:20
but rather is executed in the else
20:17 - 20:23
Branch it also differs in other aspects
20:20 - 20:25
so let's adapt
20:23 - 20:27
it the main difference here is that
20:25 - 20:30
there is only one critical section where
20:27 - 20:33
you are supposed to select only one task
20:30 - 20:36
to execute and clear the task bit in the
20:33 - 20:39
bit mask regarding the selection of the
20:36 - 20:41
task to execute this is an ideal use
20:39 - 20:44
case for a pointer to function which I
20:41 - 20:46
will name task if you don't remember
20:44 - 20:49
what pointer to functions are they were
20:46 - 20:51
used extensively in lesson 39 about the
20:49 - 20:53
optimal State machine
20:51 - 20:56
implementation since you are supposed to
20:53 - 21:00
choose only one task you need to put the
20:56 - 21:00
other selection in the else branch
21:17 - 21:22
now regarding the task execution I use
21:19 - 21:24
the explicit syntax with pointer D
21:22 - 21:26
referencing to make it absolutely clear
21:24 - 21:30
that this is a call via the pointer
21:26 - 21:33
named task but I still need to define
21:30 - 21:36
the task variable and the type def for
21:33 - 21:36
its task Handler
21:39 - 21:45
type finally I need to do something in
21:42 - 21:47
case none of the if branches are taken
21:45 - 21:49
because this will leave the task pointed
21:47 - 21:52
to function uninitialized so the
21:49 - 21:53
subsequent task execution will certainly
21:53 - 21:57
crash this should never happen in a
21:55 - 22:00
correctly running scheduler that you've
21:57 - 22:02
just built so that is an ideal place to
22:00 - 22:04
use an assertion if you are unfamiliar
22:02 - 22:07
with embedded assertions they were
22:04 - 22:09
covered in lessons 47 and
22:07 - 22:12
48 here I just call the assession
22:09 - 22:15
Handler already defined in the
22:12 - 22:18
bsp this should be all so let's try to
22:15 - 22:19
build the project all right I still need
22:18 - 22:22
to provide the assertion Handler
22:19 - 22:22
prototype in
22:26 - 22:30
pp. and I have to delete the Superfluous
22:30 - 22:37
directive no errors and no warnings so
22:33 - 22:39
let's test this as usual for today the
22:37 - 22:41
first order of business is to verify
22:39 - 22:45
that it works in a nominal case I just
22:41 - 22:49
run the code free and press S sw1 button
22:45 - 22:52
red LED and S sw2 button additional blue
22:49 - 22:52
LED so far so
22:54 - 22:59
good now let's look deeper reset the
22:57 - 23:01
target to start over and set a break
22:59 - 23:04
point inside the critical section at the
23:01 - 23:07
top of the super Loop run the code free
23:04 - 23:10
and when it hits the breako verify that
23:07 - 23:13
premask is set meaning interrupts are
23:10 - 23:16
disabled set a breakpoint in GPI
23:13 - 23:18
interrupt Handler and at the wfi
23:16 - 23:22
instruction in bsp go to
23:18 - 23:25
sleep only now press the S sw1 button
23:22 - 23:25
and run the code
23:25 - 23:31
free this time the first breakpoint hit
23:28 - 23:33
is the wfi instruction and quite
23:31 - 23:36
specifically not in the interrupt
23:33 - 23:39
Handler because interrupts are still
23:36 - 23:42
disabled move the breakpoint from wfi to
23:39 - 23:42
the next instruction
23:43 - 23:48
Downstream when you run the code free
23:46 - 23:50
your new breakpoint is hit and the
23:48 - 23:55
interrupt is still not called because
23:50 - 23:57
interrupts are only now just about to be
23:55 - 23:59
enabled when you run the code free you
23:57 - 24:01
finally hit the the brake point in the
24:01 - 24:07
Handler step through to verify that it
24:04 - 24:07
sets the task one
24:08 - 24:13
flag and watch where it
24:10 - 24:15
returns eventually you end up at the top
24:13 - 24:18
of your superloop with interrupts
24:15 - 24:20
disabled the ISR flag bit mask is not
24:18 - 24:23
zero meaning some of your tasks are
24:20 - 24:26
ready to run use keep going to sleep
24:23 - 24:29
find that the task one flag is set clear
24:26 - 24:31
it and select bsp deploy airbag task
24:31 - 24:37
execute finally you enable interupts and
24:34 - 24:37
call the task
24:41 - 24:45
function all right so this is the
24:43 - 24:47
generally recommended superloop
24:45 - 24:51
structure that incorporates low power
24:47 - 24:54
sleep modes it took a while to build but
24:51 - 24:56
as the St expert mentioned in his post
24:54 - 24:59
what you have just built is quite a
24:56 - 25:01
powerful Cooperative scheduler
24:59 - 25:03
the task functions can be activated by
25:01 - 25:06
setting the corresponding bit in the
25:03 - 25:09
global bit mask not just from interrupts
25:06 - 25:13
but also from other tasks therefore the
25:09 - 25:15
name ISR Flags is a bit of a misnomer a
25:13 - 25:18
better name would be task Flags or
25:15 - 25:20
perhaps Ready Set because this bit mask
25:18 - 25:23
represents the set of all tasks that are
25:20 - 25:26
ready to run in fact let me just
25:23 - 25:29
refactor The Code by globally replacing
25:37 - 25:42
all right so this is all regarding the
25:39 - 25:44
general superloop structure however in
25:42 - 25:46
the remaining few minutes of this lesson
25:44 - 25:49
I still need to address the cortex M
25:46 - 25:52
specific issue of disabling interupts
25:49 - 25:54
selectively with a base pre-register
25:52 - 25:58
rather than indiscriminately with pre
25:54 - 26:02
mask base pre is only available in our
25:58 - 26:04
v7m and higher architectures such as M3
26:02 - 26:08
and higher and is not available in
26:04 - 26:12
cortex m0 m0 plus here I must defer
26:08 - 26:14
again to Joseph 's definitive guide but
26:12 - 26:17
basically base pre disables interrupts
26:14 - 26:19
only up to the specified priority level
26:17 - 26:22
and does not affect higher priority
26:19 - 26:25
interrupts which run with a so-called
26:22 - 26:27
zero latency please note however that
26:25 - 26:29
the high priority interrupts are not
26:27 - 26:32
allowed to access any resources used by
26:29 - 26:35
your superloop or the lower priority
26:32 - 26:37
interrupts so let's apply the base pre
26:35 - 26:40
interrupt disabling strategy to today's
26:37 - 26:44
code fortunately all necessary changes
26:40 - 26:46
will be confined to the bsp as it should
26:44 - 26:49
be first you define the base pre-
26:46 - 26:54
priority cut off level the level of hex
26:49 - 26:56
3F should work for any arm v7m CPU with
26:54 - 26:58
three or more bits of interrupt
26:56 - 27:01
priority at this point point it's also
26:58 - 27:03
convenient to define the simus priority
27:01 - 27:06
cut off useful for setting the interrupt
27:03 - 27:09
priorities with simis
27:06 - 27:11
functions now you reimplement interrupt
27:09 - 27:15
disable by setting the base pre-register
27:11 - 27:18
to the previously defined cutof value
27:15 - 27:20
interrupt enable becomes Now setting
27:18 - 27:23
base pre back to
27:20 - 27:25
zero now most interestingly for today
27:23 - 27:27
the transition to sleep mode will need
27:25 - 27:30
to combine the use of premask and base
27:27 - 27:34
pre registers to take advantage of the
27:30 - 27:35
special properties of prask described by
27:35 - 27:41
U specifically the go to sleep function
27:38 - 27:45
is now entered with base preset but
27:41 - 27:48
premask clear so before the wfi
27:45 - 27:55
instruction you must set prask and clear
27:48 - 27:57
Bas pre after the wfi you clear prask
27:55 - 27:58
four the last set of changes involves
27:57 - 28:00
the interrup
27:58 - 28:02
because once you apply the base
28:00 - 28:04
pre-critical section policy it is
28:02 - 28:06
crucial to explicitly set the priority
28:04 - 28:10
of the interrupts that interact with
28:06 - 28:11
your scheduler to the cutof level or
28:11 - 28:15
higher if you don't do this the
28:14 - 28:19
interrupts will not respect your
28:15 - 28:22
critical sections and you'll have raise
28:19 - 28:25
conditions also now that your interrupts
28:22 - 28:27
can have different priorities they can
28:25 - 28:29
preempt each other so you need to
28:27 - 28:32
protect the shared task set with a
28:29 - 28:32
critical section as
28:40 - 28:46
well and this concludes this lesson
28:43 - 28:49
about using low power sleep modes in the
28:46 - 28:51
ubiquitous superloop architecture safely
28:49 - 28:54
it turns out that adding sleep modes
28:51 - 28:56
required creating a small Cooperative
28:54 - 28:59
scheduler which will be useful in the
28:59 - 29:04
finally please note that the requirement
29:01 - 29:06
for entering the sleep mode atomically
29:04 - 29:08
applies only to the simple superloop and
29:06 - 29:10
does not apply when you use a more
29:08 - 29:13
advanced architecture such as a
29:10 - 29:15
preemptive kernel or a preemptive Aros
29:13 - 29:17
the main difference between a preemptive
29:15 - 29:19
kernel and a superloop is that the
29:17 - 29:23
kernel enters the low power sleep mode
29:19 - 29:25
from the lowest priority idle thread
29:23 - 29:27
this idle thread is not committed to
29:25 - 29:29
entering sleep mode because it gets
29:27 - 29:31
immediately pre Ed by any threats that
29:29 - 29:33
might become ready to
29:31 - 29:36
run if you like this Channel and would
29:33 - 29:38
like to see more lessons like that
29:36 - 29:40
please give this video a like And
29:38 - 29:44
subscribe to stay tuned you can also
29:40 - 29:46
visit stat machine.com svideos course
29:44 - 29:48
for the class noes and project file
29:46 - 29:51
downloads finally all the projects are
29:48 - 29:54
also available on GitHub in a quum leaps
29:51 - 29:59
repository modern embedded programming
29:54 - 29:59
course thanks for watching