 Hello! Within this part we'll focus on context switching within pre-artists. Important part of each operating system is context switching. Let's have a look more in details how does it look like within pre-artists. Here on the screen we can see two types of context switching. Pre-emptive, which is a default one within pre-artists, and allows to switch the context between tasks on time slice or on higher priority event. The second one is a cooperative, which allows context switch only in case when the active task decides to finish its job. On next slides we will analyze both scenarios one by one. Let's start with pre-emptive context switching. On the screen we can see the configuration where we have five tasks. Idol task with lowest possible priority, zero, A, B and C tasks with the same priority one, and the D task with priority two. At the beginning task D is in block state, and it is waiting for the semaphore. Task A has been selected by scheduler for execution. It has been selected from ready list. Task B and C are within ready list. After defined time slice, by default it is one millisecond, assisting within its interrupt is triggering PentSV to switch the context to another task from ready list. Task B is selected for run mode, task A and task C are in a ready state. Before next time slice, task B decides to finish earlier its job by executing OS thread yield function. It triggers PentSV interrupt to switch the context to task C. After this we have task A and B in ready list, task C continues within remaining time slice of task B. Then SysTick is triggering PentSV to switch the context to task A again. As we've got the round robin algorithm. Within task A execution an interrupt is coming. All interrupts has higher priority than PentSV and SysTick interrupts, and within this interrupt its function body in fact there is a semaphore release. It is the semaphore which was requested by blocked task B. Scheduler detects this fact, so it moves task D from blocked to ready state and as this has higher priority than preempted task A, scheduler is triggering PentSV to switch context to task D instead of return to task A. Task D performs its operations quite fast and is sending itself to blocked state for given timeout using OS delay function. It cannot use OS thread yield as it would send it to ready state and it would be selected immediately by scheduler as it is the task of highest priority. Once task D decides to go to the blocked state scheduler is triggering PentSV interrupt to switch the context to task A for the remaining time slot. Then SysTick will trigger PentSV to switch task A to task D which is the next one on the ready list. Now let's have a look what would be the difference of system behavior once we will select cooperative mode. In this mode there is no context switch within time slices. PentSV interrupt is triggered only if running task decides to finish earlier or it puts itself on to ready list by calling OS thread yield function or it waits for something or for some time calling OS delay function. In this case interrupt still can preempt any working task as it has higher priority versus any other OS operating system components. This time even if an interrupt will unblock any other task even having higher priority it will not preempt active task. Let's have a closer look on the context switch and the time it is taking. Context switch time depends on the port so the architecture we are running our operating system used compiler and the configuration. With an STM32 devices we need to add additionally 12 CPU clock cycles on each interrupt and transcend exit which is a quite big contributor to the switching time as we are using at least one interrupt PentSV and sometimes additionally SysTick. We should remember that context switch is performed within PentSV interrupt which can be triggered either by SysTick on each time slice or scheduler where it is necessary to change the active task. Some examples of booting time can be found on Friartos web page with FAQs for example within topic memory usage boot time and context switch times. Context switch time can be much longer in Cortex-M4 and Cortex-M7 based devices with floating point unit due to necessity of stacking FPU registers. So additional 17 32-bit registers S0 to S15 and FPSCR. Rest of the FPU registers so S16 to S31 should be handled by software. In PentSV handler there is a check done whether floating point unit instruction has been used and based on this those registers are stacked unstucked from our own current task or not. We can see it on below part of the code. There is an instruction TST which is a testing R14 whether it contains value 10 hexadecimal. If yes, it means that we need to store the FPU registers as FPU code has been executed within the current task. The same condition is checked after we switch the task. More information about this feature can be found within one of the ARM application nodes. It is application node 298 within ARM web page. Friartos context switching tick source standby step. So let's have a closer look how does it look the interrupt from the sys tick while the time slides is elapsing. So there is a time to switch the context from one task to the other. So the tick timer within the Cortex M devices it is sys tick and this timer interrupt causes execution of export sys tick handler. It is located within port.c file. This handler is written usually in assembly language just to be fully suited for the architecture we are using. So at the beginning we can see that all of the interrupts which are using the operating system functions are blocked. For this the macro port disable interrupt is called. It is defined within port macro.h file. Then there is a trigger to pentSV software interrupt which is responsible for the context switch. It is done once this interrupt is called. The export pentSV handler is called which is in fact the interrupt procedure function of this interrupt. It is again stored within port.c file. Within this interrupt vector from pentSV we are calling xv task switch context function. It is again stored within task.c file and this function is switching the context by starting from calling the macro task select highest priority task again from task.c file and this macro is selecting the ready task within the highest possible priority list. At the end once we selected the proper task everything is configured for the new one the interrupt procedure of pentSV is unblocking all interrupts using port enable interrupt macro defined within port macro.h file and we are continuing execution with the newly selected task. Context switching time. A part of the theory I just presented let me show to you some methods which we can use to verify what is real time needed to switch the context between the tasks. To do this we need some modifications to be added within our current project. Here I am taking into the consideration the nuclear board which we are using for rest of the hands-ons and I am selecting the pins which are very easy to be accessed so the right and bottom side of the universal connector so PA2 and PA3. PA2 will configure as a GPIO output without an enable and PA3 will be configured as event out. Event out configuration is giving the full control of the pin to the core and then the core while we execute the instruction SEV will send the one positive pulse the pulse of length of one clock cycle, CPU clock cycle as a result of this function. So it is very effective method to measure the time distance between some parts of the code. So we will do those two modifications only then we regenerate the code and then we can put some small add-ons within our generated free R2S based project to set or to reset pin PA2 or to generate the one the pulse of length of one clock cycle on PA3 using this SEV instruction what you can see at the moment at the screen. We can put those lines in various places in the code to measure the intervals between the actions of the task switching. You will see it on next slides the result of it. We can place it for example within the sys-tick handler so this is within stm32l4-it.c file. We can put it as well within the export-pent-sv handler function so for example just before the jump to user task so this is the line BXLR and you can check. You can check how much time you need for your implementation. What I would recommend to you is to test the various scenarios. So for example the task switching not only caused by the sys-tick but as well by releasing the semaphore error queue which is unblocking the task with higher priority you can check as well how much time you would need if your task will decide to go into the blocked state and is giving the space to the other one or if your task is deciding to go to the ready list using the yield function. So there are many possibilities the method is quite simple you need only two channel scope to verify the timing. On the next slides you will find an example which I did for stm32l4 working on 4 MHz system clock. Here you can see an example of the context switch time and in fact the time measured between the beginning of the sys-tick procedure and the user code execution so the new task execution. It is 65 microseconds assuming that we are working on 4 MHz system clock. And here below on the scopes you can see two channels the blue channel it is the new code execution so when my new task I'm just changing the state of one of the Ios from high to low level so this is the blue line and the yellow channel so channel 1 is reflecting the similar operation which is done at the beginning of the sys-tick. So the distance between rising edge of operation within sys-tick and falling edge which is executed at the beginning of my new task is 65 microseconds. In performing similar operation between beginning of pentSV and my new task code execution it is 37 microseconds so I have moved the procedure of changing the state of one of the Ios from low to high level so yellow channel from sys-tick to pentSV beginning of pentSV interrupt procedure and having the same clock so 4 MHz I obtained 37 microseconds from beginning of pentSV and beginning of our code execution within new task. Just to have the complete picture I measured as well the time between the sys-tick so beginning of the sys-tick and the first instruction within pentSV so it's more or less 30 microseconds and in this case I made the toggle change the state of the pin within sys-tick beginning of the sys-tick on a second channel so the blue one so there is a change from low to high level and within the beginning of pentSV I used SEV instruction which is generating the single clock cycle pulse on a selected pin and the distance between those two events is measured 30 microseconds. Then I measured the time between the jump to user task within pentSV so almost the end of pentSV and user task code it is taking 5 microseconds more or less and here below on the screen you can see it. Yellow channel is the single pulse generated by instruction SEV at the end of pentSV so just before the jump to user task called from this interrupt and the switch from high to low level within the second channel the blue channel is done within the user task so the difference the time distance is 5 microseconds with the core clock on the level of 4 megahertz. At the end just an illustration using the yellow channel I measured the length of the pulse generated by SEV instruction so send event instruction it should be always one clock cycle assuming that we are working on 4 megahertz system clock we have 250 nanoseconds so it is like we expected. Let's focus a while on stack pointers and stack management within 3 year task based application. So within Cortex M-based devices in particular STM32L4 which we used within this exercise within this training two stack pointers are in use so the first one so called main stack pointer MSP it is default stack pointer which is available and configured after the reset of any application run on STM32L4 devices so when 3 RDS based one main stack pointer MSP is used for interrupts and in particular for interrupts for 3 year tasks so cistik and pentSV the second one is much more important because this is the interrupt which is needed to switch the context and what we can see on the screen this is how it is done within context switch what is the split between main stack pointer and the second one which I'll mention in a minute so main stack pointer is used really within the interrupt and it is used to switch the data from one task to the other the second stack pointer which should be enabled by the user from the code it is so-called process stack pointer PSP and it is dedicated for the application of the user adjust to separate the important part of the system so interrupts from the user code within 3 year tasks it is used as well so the split is the following main stack pointer is used for interrupts and the kernel so the context switch pentSV and the process stack pointer is used to manage the task stack so the stack of the tasks and what we can see on the screen is please have a look once we are executing task one and we need to switch the context to task two so the task one is storing its data on its own stack within its own area allocated during its creation and to do this it is using the process stack pointer which is loaded with the data from the task one control block area which contains the current state of the stack pointer and this current state of stack pointer refers to this process stack pointer PSP so the task one before we will switch the context is storing its current data on its own stack using process stack pointer then within pentSV interrupt all of the other operations not related directly to none of the stacks so for example the information intermediate in intermediate data which is done within this interrupt is stored on MSP so main stack pointer so it can be used for example for the situation when the higher priority interrupt will pop up during the task switch then in the next part after task one will clean up all of its resources pentSV is switching the context to the second task but before the second task will be executed we need to restore its state to do this we are using again process stack pointer and using process stack pointer and its current state within task two is taken from task control block of task two so at the beginning the task control block is read then it is taken from their information about the process stack pointer location within the task to own stack and the context is read from there just to be just to be in the state which was the last state before the previous context switch after these operations task two is continuing its execution this is let's say how it is done within three years and other operating systems which are run on cortex and base devices and STM32 in particular thank you for watching this video