 Hello, in this part we will continue tickless mode within 3RTOS using CMC's OS. This time we will try to involve, say, the semaphores to wake up our system bit before than expected. We will create a simple example using one task, one semaphore, and stop mode, which would be used once the task is in block state. For my exercise I would use two boards, one is NL476HG, this is the white one, which you can see on the screen. Then, to measure the current consumption on real time, I would use XNLPM01 board. Both boards are connected by two wires, which you can see, this is, let's say, black and red one. The black one is connecting GNDs of both boards on, let's say, XNLPM01 board. I'm using CN14 connector, pin 1, counting from the glass LCD, and on NL476HG I'm using the GND pins, which are located on both sides on the USB connector on top of the board. Then the plus wire, the red one, is connecting CN14 pin number 3, counting from the glass LCD, and the left pin of JP6, which has been removed for this exercise. In case you would like to use the multimeter, you can connect the multimeter configured within the current measurement section, one microamp range, and you can connect it directly to JP6 on a NL476HG board. Okay, for the software, I would use STM32QP IDE for the configuration and code manipulation, and STM32QP monitor power to monitor the power consumption of the board. I would start with STM32QP IDE by creating a new project. So I go to File, New, see, STM32 project. You can use as well STM32QP mix and your preferred toolchain. I'm creating a new project for STM32L476HG board. RG. Yes. I would name it as 14 underscore T-class, underscore stop, underscore sem from semaphore. Okay. Okay, so from hardware point of view, we would need the following peripherals. First, I would start from the debug. So system, core, sys, and debug the last option. So trace ascentral-nose SWO to have debug interface SWD and serial wire output. Then I will change the timebase source from sys-tick to timer-6. This would be the timer used by the HALA library functions. And with an RCC, I would enable LSE clock, which would be used by the low-power timer. Then the next stop, next point would be to enable and configure low-power timer. So I go to Timers section. I would select low-power timer 1 in mode counts internal clock events. Then I would enable its interrupt. And within its parameter settings, I would change the clock prescaler to divide by 32. I would like to have the clock source for this timer LSE 32 kHz oscillator. And then I would divide it by 32. So the timebase for my low-power timer would be 1 kHz clock. To change the timebase to clock source for this low-power timer, I will go to clock configuration tab. So you can see we are working on 4 MHz. Below I can see the multiplexer for low-power timer clock selection. Instead of peripheral clock 1, I would select LSE. I will come back to pinouts and configuration. And within the pinouts, I would select PC 13. So I click left button on mouse and select the last option, GPIO XT13. As I would like to use this pin as an external interrupt, which would be used to give the semaphore, which we would wait for. Okay, to finalize this point, I would go to NVIC section, so system core NVIC. And I would enable this interrupt line by taking this field. I would like to use this function within 3R2S, so I would change its priority to level 5. I would explain it in a while why it is number 5. Next point, it's selection of 3R2S. So I go to middleware, 3R2S, interface CMC's V2. Within the, let's say, config parameters, I would enable tickless idle to build in functionality. Then within tasks and kios, I would rename this default task to task1. I would change its tax size to 256 words and its entry name to start task1. I would keep the same priorities as always, priority normal. Then I would add as well the semaphore. So, within timers and semaphores and binary semaphores tab, I would add the semaphore, I would keep the default name. Okay, let's come back for a while to this config parameters. If I scroll down, I can see that I've got two interrupt nesting behavior configuration parameters. The first one is related to SysTick, PentSV and those two interrupts responsible for context switch. And this is the lowest possible priority within this architecture. The second one is related to the interrupts which would be able to call operating system functions. So, all of the interrupts with priority from 5 to 15 would be able to call the interrupt operating system functions. Those with higher priority, so 0, 1, 2, 3 and 4, should not do this due to the safety of the complete system. This is why I selected for my external interrupt number 5 because I would like to use one of the operating system functions, semaphore give in fact from this interrupt routine. That's it concerning the configuration of the complete system and hardware components. So, I would generate the code now. Okay, we can open main.c file, it should be done automatically. If not, please go to core, source, main.c and now we will do some code processing. Let's start from main.c file and our task entry function. So, I would start from our famous sign of life application code, so it will be task action. And we will implement it within section user code for this after main function. Okay, so it is here and I would use itm interface, send char and let's say it will be first message and sign of new line. That's it. Then we need to implement our delay task 1 function body. Instead of OS delay, which has been used in previous exercises, I would just wait for the semaphore. So, semaphore acquire. So, we'll try to get the semaphore for maximum 5 seconds. So, the effect would be very similar to what we've got in the past. So, we will wait maximum 5 seconds for the semaphore. If not, we will wake up and give the sign of life and we'll stay for half a second in either run or ready state. If semaphore will be available before this, let's say time out occurs, we will wake up earlier and perform the same operations. So, this is first part of our job. The second part would be implementation of the external interrupt callback. To do this, I will go for a while into the stm42l4xx underscore it.c file. And here is our external interrupt handler. So, I go click on write button and mouse open declaration. And you see that we would need this callback. It is defined as the week, so we can copy paste it within our code. We can put it in the same section like, let's say, task connection. And within this, we will just, let's say, release the semaphore. So, OS, semaphore release. And this is our handler. We can add here as well a sign of life. That's it. So, concerning main.c file, those are, let's say, all modifications. We need to configure a bit, let's say, press slip mode and post slip mode within freeRTOS.c file. This would be our next step. Let's go to freeRTOS.c file. And within this, I would start with export of my low power timer handler. And then we can implement our code like in previous exercises. So, first, I would like to suspend tick. So, our timer six, so it will not generate wake up signals. And then we need to specify timeout function to, let's say, configure our low power timer one. Two, let's say, wake up us on some configured delay. Timeout. So, let's use it in interrupt mode handler, period. So, auto-reload register maximum value. And then the expected idle time, it would be this one. And similar operation, so I will do in opposite way below. So, first, I will stop low power timer one. Not using, of course, a start but stop. Only one argument is needed. And we will resume our timer six. So, tick timer for HAL. HAL underscore resume tick. And that's it. So, there are all modifications within freeRTOS.c file. So, I can switch to port.c file when I need to, let's say, replace the sleep mode into the stop one. So, I go to middleware's third party freeRTOS source, portable gcc arm cm4f and port c. First, I would add main.c.h, sorry. And then, let's say line 500 something. I need to first stop this system of this line and replace this line with the stop call to stop. So, HAL P-W-R-E-X. And we need to enter stop one mode. And stop entry. In case we are not sure, we can go to the declaration. And in our case, it will be WFI, so interrupt. That's it. So, after those modifications, I can try to compile the code. Okay, no worries, no warnings. Let's try to start the debug session. Before we will start the debug session, I would start the cube monitor power. Just to do it together with you, I would start it from scratch. So, I click on the cube monitor power icon. It is visible at the beginning like this. So, we need first to configure to select, let's say, the COM or our XNUCLEO-LPM-01 is connected. In my case, it is 21st. Then I need to press take control, specifying the sampling frequency to maximum possible value and acquisition time infinite just to not be stopped in the middle of the measurement. I can press start acquisition. And now I can start the debug session. So, I go to the cube IDE, I click on the back icon. I will check whether everything is configured properly. So, I select the debugger. I would disable debug in low power mode to save some power. I will not enable, let's say, serial wire viewer in this case. So, you will not see anything on ITM interface. This is why it would be better for the exercise to toggle LED. Anyway, we will see some activity, even without any sign of life. I would start the debug session. Then let's resume, then terminate. As we will not observe anything on the debugger, as it is using stop mode. And let's have a look what we can see on the cube monitor power. As you can see, the application is working like expected. So, we can see the five seconds of delay where we are within the stop one mode. In between there is this wake up after more or less, let's say, four seconds due to the overflow of the cystic. And our activity lasts half a second where this task action function is executed. And now I would press the button. So, you will see an effect. I pressed the button and you can see we have been woken up a bit before. And after this, let's say, the operations have been performed. So, let's say, giving the semaphore from the interrupt callback and then sending sign of life. We are performing, let's say, the code from the task which has been waiting for the semaphore. So, it is, let's say, if we add this execution time of the interrupt callback and, let's say, our task. It is visible as, let's say, a bit longer time in active mode. So, let me stop it for a while. And now you can see the first, let's say, wake up is due to the press of the button. Then there is a short time used by the interrupt. And after this interrupt, we are waking up the system for half a second. And this, let's say, we've got this half a second of our task execution. I pressed the button much before, let's say, the maximum timeout we are expecting. So, we can see the same procedure just after. And then I was not pressing anything. This is why we can see this overflow that the interrupt caused by the overflow of the SysTick. And then just after we could see, let's say, the wake up due to that, let's say, this maximum delay specified in the wait for semaphore function call. So, as you can see, it is working like expected. Tickless mode is, let's say, working. So, we are in a low power mode all the time for the specified delay, unless there is some interrupt coming which could wake up us and we could perform some other operations within our active tasks. So, that's all for this exercise. Thank you for watching this video.