 Hello, and welcome on our STM32Cube IDE basics training session. In this module, I will demonstrate to you how to add free RDS middleware software to the project based on STM32 microcontrollers using STM32Cube IDE. So the objectives for this part are the following. First we'll configure two IOS, PI5 as a GPIO output to control green LED and PC13 as a GPIO XT13 to monitor the blue button which is connected to the port. Then we will add a free RDS middleware to our existing project and within this free RDS I would add two tasks and one binary SMF4 which would be controlled by our blue button. Let's start with the new project on STM32Cube IDE. I would use an existing workspace when I've got already some ready projects. I'm creating the new project so I go to File, new STM32 projects. It will start from the device selector. I'm selecting STM32G071RB microcontroller version LQFP64 which is used on our Nucleo board. I press Next and then name of the projects I propose G0G03RTOS. I select the target language as SC, binary type executable and we will use STM32Cube to set project type. I press Finish and now we will be switched to the device configuration window. Okay, so let's start from enabling the debug interface pins. So I go into the system core sys serial wire. I can see that both pins are selected as debug interface ones. Second third step is a proper configuration of our IOs we will use. The first one is PA5 when we've got our green LED connected. If I would put into the search PA5 I can see blinking PA5 pins just to find it more easily. I press left button on this pin and I'm selecting GPIO output. Then I need to specify its label just to have a more easy configuration within the coding process. So I press the right button on mouse, selecting enter user label and I would name it as LED green. The next step is a configuration of our pin connected to blue button. It is PC13 so again left button on mouse and this time we will select GPIO XT13 because it would be an external interrupt. Please do not worry on this red highlight over here. It means that we have used this pin so it will be not available for other functionalities like system wake up tool. If I would go with the mouse over this red component I should see the information what is the reason of highlighting this pin. There is nothing to be worried at the moment. We come back to our pin and over this pin we click the right button on mouse and select user label. We'll name it as a blue button. So this is the second component. So from hardware point of view we configured all of the peripherals. So we go to the middleware, FreeRTOS and we can select the interface. At the moment for the GZero family there is only CMC's V1 library available. The CMC's V1 means that over the original FreeRTOS API we've got an additional layer which is called CMC's OS. So we select CMC's V1 and within the configuration window we can see a lot of new tabs related to FreeRTOS. First two I mean config parameters and include parameters are important because it's in fact creating the skeleton of the operating system and it reflects the main configuration file within the FreeRTOS which is FreeRTOS.config.h file. Using config parameters we can select the type of the kernel whether it will use preemption or not. We can specify the tick rate, maximum number of the priorities of the tasks and minimum stack size for the component. Please be aware that it's given in words. Then the maximum task name, rank, 16 signs. Then we can enable or disable some additional functionalities like mutexes, record, mutexes, counting, semaphores, tickless mode which is used for low power applications. We will not change anything in this area. Important component is a memory management settings where we are specifying the total RAM memory area which would be used for the FreeRTOS. Please be aware that this time it is given in bytes. So three kilobytes we've got at the moment and the memory management scheme. We can select this memory management scheme from HIP1 to HIP5. We've got a dedicated session on the FreeRTOS within our channel so we can have a look for more details on each memory management schemes. The most flexible one is in fact HIP4. If you would like to use the HIP memory which would be allocated on different RAM areas, please have a look on the HIP5 instead. It will be not our case so I would select the most popular one HIP4. Then the important point is the last two parameters. The first one is library lowest interrupt priority. Those two components are used to properly cooperate with the interrupts which are present in the microcontroller world. The first one, library lowest interrupt priority, is the lowest possible interrupt priority which is available in this particular microcontroller. As it is a Cortex M0+, the lowest possible priority is free. This lowest interrupt priority is used for the interrupts related to the context switch and the tick interrupt used by the operating system. To be sure that all of the hardware interrupts are processed in proper way, operating system is operating on the lowest possible priorities, just not to interfere with hardware events. This is the lowest possible priority for the system itself. The second parameter is used to set the maximum interrupt of the priorities which can still execute the functions of operating system. Please remember that in Cortex M devices lowest priority means highest number. In this case I would propose a small change instead of free. So the task switching and the tick interrupt would have lowest possible priority, number three. While interrupts which we would like still to execute the operating system functions would have interrupt priority two. Other interrupts which we would like to be completely independent for the operating system will have interrupt priority zero. So in this case all the hardware interrupts would be not interrupted by the operating system. So this is the basic configuration of the operating system. Let me remind you that all of the operations or the configurations we are doing here would be stored later on in a free RTUS config.h file which is the main configuration file of the free RTS. The next file is used to include some additional functionalities, some additional functions to the operating system. This is used to add some additional functions to the operating system. The drawback of adding new functions is that we would use some additional code space. So if it's not necessary we can remove some functions to save some code space. We will not use any additional new, we will keep everything as default setting at the moment. The next point is to add two tasks. We go to the task and queue tab. At the moment we've got only one task, it is so called default task. Just create it automatically. We will change this default task to our task one. Just double click using the left button on the mouse on this name and you should see the edit window. So we will change the default task name into the task one. We will keep OS priority normal. We've got seven types of priorities starting from priority idle which is the lowest possible and ending with so called real time. Normal is somehow in the middle. So let's use priority normal for both tasks. Stack size is set on 128 words. So let's keep it like this. Enter function which is the function which would be called during the task execution. So instead of this star default task I would use something different. Just task one underscore app. From application the rest I keep as a default. So this is the task one and I would add task two. Just pressing this add button and again I've got a new task. So I change the name task to priority normal. Stack size the same without change 128 words. And the function would be task two app. And okay. We've got two tasks defined with the same priority with different functions which would be called during its execution. So this is the point number one. Now let's add this one binary semaphore which would be connected to our external interrupt triggered by the blue button. To do this we need to go into the timers and semaphores tab and we need to select the binary semaphore. So below this binary semaphore empty space we've got the add button. So again we need to add some binary semaphore. We will change this name into the binary underscore sem. Allocation dynamic. We've got as well in some areas static. If we configure the settings of the operating system we can as well use the static memory allocation. Please have a look that for example in case of the timers and counting semaphores we cannot add anything. Options are not accessible. To the fact that within the config parameters we have not enabled those components. Please have a look if I would come back to the config parameters and I would scroll down. I would scroll down and I would select use timers from disabled to enabled and then come back to timers and semaphores timers became accessible. Let me change this to disable again. Okay, so we are done with all of the settings of the operating system from this device configuration window. Let's try to generate the code. I would just save the project and please have a look. I've got the warning. I've got the warning telling me that I should change the time-based source for HAL library from Cystic, which is the default setting, to some other timer. This is done due to the fact that Cystic is used by the operating system for the static timer and it should not be mixed with the HAL library usage because in HAL Cystic is used to generate all of the delay functions and timeouts and it should not be mixed up. Okay, so this is highly recommended to change the time-based timer for the HAL library. We can use it within the system core and system tab and here at the last point we've got the time-based source. I can select any of the timers which are available in the system. What I would recommend to you is to use either timer 6 or timer 7. Both of those timers contains only the time-based component so they can generate the interrupt on overflow and those timers do not have any input nor output channels, so the potential loss would be minimum in this case. I would select timer 6 and please have a look if now I would go into the timer sections. I can see timer 6 inaccessible, inaccessible because it has been used as a time-base for our application. Okay, let's try to generate the code once again so I would just save the project and now on the left side we should see the project would be generated. We can see that middleware's folder has been added. If I would scroll it down, I can see the subfolder third-party, then three-year-dOS source, and below you can see the main file is at least .c which is in fact the main file which contains the functions related to the scheduler, which is the heart, the core of the operating system. Then the semaphores and the functions for these are stored within the q.c file. All of our tasks are stored within the task.c file. Timers is used for the timer semaphore. Then we've got additionally the stream buffer. We've got event groups to communicate between the tasks and coroutines which are not used in our architecture. Coroutines are used in IDB or 16-bit architecture and requires less resources from the embedded system. In our case we will use full versions, we will use tasks, so this file will be not used. This is the core. It is completely independent from the embedded system, from the application, from the system where it has been added. The connection between our hardware, our STM32G0 and freeR2S is done within the portable folder. Here we can see GCC and memory management folders. In memory management folder we can see only one file, one file with the name which has been selected in the device configuration. And this heap underscore 4.c file contains the functions to allocate and deallocate the RAM memory for operating system components. So this is strictly related to the hardware. And then within the GCC we've got subfolder ARM CM0 so it's for our core which is the heart of our STM32G0. Inside we can see two files port.c and port macro.h. Those two files contains the functions which are connecting the interrupts from the real hardware with the functions from the operating system. So this is the real interface between the embedded system which we are using and the operating system we have just added. We will not modify any of those files. All of the modifications of the code which we will do should be done within one of the two files. The first one is app underscore 3R2S and main.c file. If we go into the main.c file we can see it as a standard cube IDE or cuba mix generated file with some add-ons related to used operating system. So we can see within the private function prototypes for example the two functions would be called when the task 1 or task 2 would be executed. So those names has been defined by us within the task configuration. Tax tasks add-on within the configuration of the 3R2S in the device configurator. So within the main you can see that we are starting with HAL init, core configuration, GPIO init and all the peripherals which we would like to init would be in this area. Then below we can see the preparation of the components of the operating system which we have added. So for example binary semaphore tasks and at the end of this process we've got one single function to start the scheduler. It is OS kernel start. After this call only the tasks which are active would be executed one by one and we should never land below this line. If we land below this line we've got some problems with RAM memory allocation. If we go below we can see both task application functions defined as empty functions with infinite loop inside because tasks functions should be defined in such a way that it contains the infinite loop inside as a mini main functions. This is how it looks like and now this is the time to add some code modification into our generated code. Now let's back to the NVIC settings. Before we will generate the code let's have a look on the NVIC so interrupt configuration. So within the system core NVIC I can see some new settings. So I've got a new column over here uses freer task function which means that I can select which interrupt would be allowed to call the functions of our operating system. As we can see from this configuration the lowest possible priority so number three is assigned to two interrupt procedures. The first one is a system tick timer Solstice tick which is used to generate the tick interrupt and the second one is appendable request for system service so append as V which is used to switch the context from one task to the other. Both of them have the lowest possible priority to do not interfere to do not block any hardware interrupt with an embedded system. Some of the interrupts have the priority number zero as you can see those are very important ones which should not be blocked by the operating system. So we've got non-masculine interrupt we've got half-fold interrupt we've got as well time-based interrupt coming from timer six which would be used by the HAL library. The rest of the interrupts has been set with the priority number two which means that it will be possible to execute the operating system from those interrupt routines. It is visible on this last column over here if I unclick this the interrupt priority would change immediately to zero which means that this function would be above the operating system and this interrupt routine should not interfere with the operating system. I would change it once again and what we are missing here is in fact enabling the interrupt from our blue button so XT line 13 I'm enabling this so it means that we would like to execute functions from the operating systems from this interrupt. Now we can generate the code. Let's come back to our coding and let's change the default task application functions. Within the task one I would like to turn on green LED and then go to the blocked state for one second. So I would go to this for loop and I would just set the green LED the high state. Right pin and then we've got the green port the pin the green pin and the pin state GPIO pin set. So this is turning on our green LED and then we will wait for one second. Please have a look that I'm not using HAL delay but OS delay. The difference is that HAL delay would block us for one second within this function while OS delay is changing the state of our task from running mode to the blocked one which allows operating system to switch to the other task which has some job to be done within this time. So this is not wasting any time. Operating system is immediately changing the active task from our which is going to block state to the other which is much more efficient. So this is the step number one. Step number two would be to do the similar operation with task number two but in task number two we will just switch off the task the LED and this time we will do some modification of OS delay just not to be the same time. So I'm switching it off and waiting for some time. Come back to GPIO configuration after configuring the GPIOs and its mount and labels. Let's have a look whether we've got a proper configuration of external interrupt input. By default it is configured as an external interrupt mode with rising edge trigger detection while in our application the blue button is connected in such a way that it should be active on a falling edge. This is why we need to change it to external interrupt mode with falling edge trigger detection. We will do the following modification. Instead of using OS delay function within the task one we will go into the blocked state waiting for the semaphore so I would command this line and instead of this I would wait for the semaphore so I would use the function OS, se, ma4, control space and then wait we've got the binary sem handle semaphore and milliseconds I would use here the value OS wait forever OS wait forever is in fact if we have a look it's in fact the maximum value for 30-bit variable and how it is how it is working. This function is sending our task into the blocked state inactive blocked state for the time till the semaphore will come will be released or the timeout will collapse in this case it will be quite long this is why this is OS wait forever so we will wait till the semaphore will be released and where we should release the semaphore to release the semaphore we need to go for a while into the g0 underscore itc.c file where we will find the external interrupt routine for our microcontroller I can find this function within the HAL GPIO.c file and I can see that HAL library is clearing all the flags and then once the flag is cleared is calling the proper callback as we are working with this external interrupt following edge this would be the callback which should be used by us it is defined as an empty function with weak attribute so we can redefine it within our piece of code I would copy paste it and within the main.c file in this user code begin for user code and for I would use this callback then we can check whether it was exactly there that the pin we were looking for would put if and then I would use this blue pin label so if our variable so GPIO pin has been this blue button pin I would release the semaphore so OS semaphore control space so we need to release the semaphore it's like with the traffic lights release the semaphore means that I giving something yes which can be used afterwards by other component of the operating system like task 1 so the only argument here is handler for this semaphore this one and that's it one more thing on this on this point using this callback executing code within this callback is still done within the interrupt routine of interrupt from line 13 this is an important point because please remember that our hardware interrupts should not interfere with the operating system the cooperation between hardware interrupts and operating system functions should be done in careful way the big advantage of the CMC's layer is that the CMC's library is taking care of selecting proper function if we are calling the operating system function from the normal code or from the interrupt routines if we have a look into this function if we have a look on this function this CMC's is.C not.H it is coming unfortunately to the header file not we see that it is checking at the beginning if we are in a handler mode so in the interrupt routine or we are in a normal code from interrupt routine it is calling different freeR2S API function from ISRSuffix which is checking whether there was any component, any task woken up by this event, by this semaphore and if yes it is checking whether there is a need to change the context to different task which has been just woken up so this is an important point that using CMC's OS layer we don't need to take care about selecting the proper function it is done automatically by the API ok so coming back to our code we have just added this semaphore let's try to compile the code so now the task one which is responsible for turning on the LED would wait for the semaphores which would be released by the pressing the button in the meantime and only the task which is turning off the LED would be active so now if I will go into the debug mode and run the code ok so we will switch timer to timer 7 please have a look that timer 7 disappeared from available timers and now if we save and generate the code we should have a new file which contains the functions to suspend, take, resume, take all the functions which are used by the HAL library to generate the timeouts and delay functions and now if we compile the code of semaphore added in the meantime we can have a look on interrupt the routine we see that timer 7 IRC handler has been added we will go to the debug mode I start the application I can see my LED turned on for a while and then turn off because the timer, the task 2 is only active, the task 1 which is turning on LED is non-active waiting for the semaphore which can be given by the interrupt triggered by the blue button I press the blue button and for a while the green LED is turned on and then turned off because task 2 is taken into account so that's it for this exercise thank you for watching this video