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

01:59 - 02:02

happens

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:21 - 04:25

TAA C

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

04:59 - 05:02

and

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

05:55 - 05:58

an airbag

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:23 - 06:27

header file

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:49 - 07:55

airbag

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:32 - 13:34

of your

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:30 - 16:35

LED light

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:13 - 17:17

can fix the

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:39 - 17:43

cortex

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

17:58 - 18:02

in this

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:18 - 19:22

going to

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:51 - 19:56

your

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:52 - 21:55

cause a

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:29 - 22:33

forever

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

23:59 - 24:04

interrupt

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:29 - 24:34

function to

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:26 - 25:29

the name

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:34 - 27:38

Joseph

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:10 - 28:14

numerically

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:56 - 29:01

next lesson

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

29:59 - 30:01

[Music]

Exploring Low Power Sleep Modes in Super Loop Architecture

In the modern embedded systems programming course, Miros Samic delves into the intricacies of the foreground background architecture, also known as the Super Loop. This time, the focus is on integrating it with low power sleep modes, a crucial aspect for battery-operated products. The need to understand this intersection stems from the upcoming lessons on event-driven active objects, setting a solid foundation for efficient power management in embedded systems.

Unpacking Low Power Design Principles

When it comes to the dissipation of power in digital electronics, both static dissipation caused by current leakage and dynamic dissipation due to switching play significant roles. Understanding this dynamic can be likened to a process of filling and tossing out water from buckets – a metaphorical insight into the power consumption during switching cycles. To combat this, modern microcontrollers offer the ability to toggle clock signals for peripherals on and off. However, achieving optimal power efficiency often requires putting the CPU itself to sleep in what is known as a low power sleep mode.

Implementing Low Power Strategies in the Super Loop

The crux of the matter lies in how the background Loop in the foreground-background architecture can detect the ideal moment to transition to low power sleep mode. Task flags play a pivotal role in this process, helping the background Loop quickly assess whether tasks are pending, and if not, proceeds to suspend peripherals and enter sleep mode. Miros Samic guides us through a step-by-step process of implementing and testing a low power superloop on a TAA C Launchpad.

Addressing Challenges and Optimizing Efficiency

While the implementation of low power sleep modes seems straightforward, there are nuances that need addressing, especially when it comes to managing race conditions. Miros highlights the importance of handling shared variables, ensuring critical sections are executed seamlessly to avoid conflicts between interrupts and the background Loop. By incorporating selective interrupt disabling and enabling strategies, developers can navigate these challenges effectively, optimizing the overall efficiency of the system.

Elevating Superloop Architecture with Enhanced Strategies

The journey doesn't stop at basic implementations; Miros introduces advanced techniques to further enhance the Super Loop architecture. By incorporating pointer-to-function concepts and building a robust cooperative scheduler, developers can create a powerful system where tasks are efficiently managed, even in low power sleep modes. By adhering to best practices recommended by experts in the field, a refined Super Loop structure emerges, capable of handling complex tasks effectively while ensuring optimal power management.

Moving Forward with Enhanced Architectures

As the lesson concludes, Miros sheds light on the distinct differences between a simple Super Loop architecture and more advanced systems like preemptive kernels. While the focus remains on the intricacies of low power sleep modes in the Super Loop, the potential for growth into more sophisticated architectures is highlighted, offering a glimpse into the evolution of embedded systems programming.

In the fast-paced world of embedded systems, mastering the art of efficiently integrating low power strategies into architectural designs is key to unlocking the full potential of modern devices. With a deep understanding of these concepts, developers can navigate the complexities of power management while building robust and energy-efficient embedded systems.

So, are you ready to dive into the world of low power sleep modes and superloop architectures? The possibilities are as endless as the tasks waiting to be executed efficiently in your embedded systems.

Stay tuned for more insights and practical lessons in the ever-evolving landscape of embedded systems programming!


By infusing expertise and practical insights into the realm of embedded systems programming, Miros Samic intricately weaves together the nuances of low power sleep modes and superloop architectures, offering a comprehensive guide for developers to enhance their system designs effectively.