FreeRTOS Lecture 32 – Understanding ARM Semi-hosting feature

 

Understanding ARM Semi-hosting feature

 

 

Now, let’s print some data by the task handlers, and let’s use some printf statements in order to print some logs. For that, you have to use ARM semihosting.

ARM semihosting:

ARM semihosting is a feature of the ARM Cortex M platform. As the name itself indicates, this feature takes the help of host software (Figure 1).

We are using STM32 system workbench IDE with debugger and other features as host software. You have to take the help of the host software to exchange some debug-related information or message.

Figure 1. Overview of semihosting.
Figure 1. Overview of semihosting.

 

For example, if you use printf in your embedded software, which is running on the target hardware. Let’s say the target hardware is a Nucleo board. Then there is no need to implement printf library code in your embedded software, which runs on the target. That would consume lots of space. So, the technique here is you can use printf without using the native printf library on your embedded software. But take the help of the printf library present in the host or to be specifically present in the host debugging software, which is your eclipse. This technique is called ARM semihosting.

We actually use the technique of message transfers from embedded software running on your hardware to the IDE to implement some of the C library functions such as printf, scanf, etc. This is what we call as semihosting.

The semihosting is a mechanism that allows target boards to exchange messages from the embedded software to the host computer, which is running a debugger. Remember that this semihosting works only when you put the IDE in debugging mode.

 

There is a small document, as shown in Figure 2. Please download that. There you will see the project settings you have to do in order to enable the ARM semihosting. There are three important steps:

  1. You have to send some arguments to the GCC linker.
  2. Do some debug configuration for your application. That means you have to send monitor arm semihosting enable command.
  3. After that, in the main.c you have to call the initialise_monitor_handles() function.

The combination of all the above things will configure the semihosting in the openSTM32 system workbench.

Figure 2. Settings to be made in order to enable the semihosting.
Figure 2. Settings to be made in order to enable the semihosting.

 

Now let’s do all these settings one by one.

1. First, let’s set the linker arguments to enable the semihosting feature. For that, just copy the line shown in Figure 3 and go to the eclipse.

Now let’s terminate the debugging session by clicking on the option shown in Figure 4.

Then go to the C/C++ perspective (Figure 5).

After that, right-click on the project, go to properties (Figure 6), then go to C/C++ build, go to settings (Figure 7), click on MCU GCC linker, then go to miscellaneous (Figure 8) and in linker flags tab just paste the copied line, as shown in Figure 9, after that click apply and ok (Figure 10).

Figure 3. Linker settings to enable the semihosting.
Figure 3. Linker settings to enable the semihosting.

 

Figure 4. Option to terminate the debugging mode.
Figure 4. Option to terminate the debugging mode.

 

Figure 5. Option for entering into C/C++ perspective.
Figure 5. Option for entering into C/C++ perspective.

 

Figure 6. Properties of current STM32 project.
Figure 6. Properties of current STM32 project.

 

Figure 7. C/ C++ build settings.
Figure 7. C/ C++ build settings.

 

Figure 8. Miscellaneous folder of MCU GCC linker.
Figure 8. Miscellaneous folder of MCU GCC linker.

 

Figure 9. Making required linker settings.
Figure 9. Making required linker settings.

 

Figure 10. Applying the changes made.
Figure 10. Applying the changes made.

 

2. After that, let’s do the second step, i.e., debug configuration of your application.

For that, right-click on your project, go to debug as and then go to debug configurations (Figure 11). Select your project, go to startup, just browse here, you will see run commands as shown in Figure 12 there you just write the monitor arm semihosting enable command.

Now click apply. After that, click close.

Figure 11. Debug configurations of current STM32 project.
Figure 11. Debug configurations of current STM32 project.

 

Figure 12. Running semihosting enable command in debug configurations.
Figure 12. Running semihosting enable command in debug configurations.

 

3. Now the third step is in the main.c use the code marked in Figure 13.

First, let’s call the initialise_monitor_handles() function as a very first function, as shown in Figure 14. It need not be the very first function, but it is better to call this before calling any printf statements.

Also, copy the extern of that function, i.e., extern void initialise_monitor_handles() and paste it in the main.c, as shown in Figure 15.

Figure 13. Functions to be called in main.c.
Figure 13. Functions to be called in main.c.

 

int main(void)
{

initialise_monitor_handles();

//1. Reset the RCC clock configuration to the default reset state.
//HSI ON, PLL OFF, HSE OFF, system clock = 16MHz, cpu_clock = 16MHz
RCC_DeInit();

Figure 14. Call for initialise_monitor_handles() function.
Figure 14. Call for initialise_monitor_handles() function.

 

Understanding ARM Semi-hosting feature
Figure 15. Prototype of initialise_monitor_handles() function.

 

After that, you can get rid of syscalls.c, which is added by the OpenSTM32 system workbench.

Just right-click on that, go to the properties (Figure 16), and exclude that from the build (Figure 17) because we don’t need that file. Click apply and then ok.

Understanding ARM Semi-hosting feature
Figure 16. Properties of syscalls.c.

 

Understanding ARM Semi-hosting feature
Figure 17. Excluding syscalls.c from the build.

 

Now let’s try to build the project (Figure 18) and see whether it gives any error or not.

Understanding ARM Semi-hosting feature
Figure 18. Building the project.

 

See the logs in Figure 19. The project was built successfully without any errors.

Understanding ARM Semi-hosting feature
Figure 19. Result of compilation.

 

Summary:

To enable the semihosting, you have to just do three things.

The first one is you have to provide linker arguments in order to work with semihosting. Figure 2 shows the linker arguments, which must be supplied to the linker.

The second step is to include the monitor arm semihosting enable command in the debug configurations of your project. That means whenever you debug the project, this command will be executed, which enables the semihosting feature.

After that, in the main function include the function call and prototype of the initialise_monitor_handles() function. 

 

After that, you can use your printf statement. Let’s write “This is hello world example code \n” inside the printf function. Since you are using printf, include #include<stdio.h> header file, as shown in Figure 20. It is always better if you include stdint.h.

#include "stm32f4xx.h"
#include "FreeRTOS.h"
#include "task.h"

TaskHandle_t xTaskHandle1=NULL;
TaskHandle_t xTaskHandle2=NULL;

//Task functions prototypes
void vTask1_handler(void *params);
void vTask2_handler(void *params);

//used for semihosting
extern void initialise_monitor_handles();


int main(void)
{
    initialise_monitor_handles();
    printf("This is hello world example code\n");

    //1. Reset the RCC clock configuration to the default reset state.
    //HSI ON, PLL OFF, HSE OFF, system clock = 16MHz, cpu_clock = 16MHz
    RCC_DeInit();

 

Understanding ARM Semi-hosting feature
Figure 20. Including the header files.

 

Build the project once again. Now the project is compiled successfully without any error.

Now in the task function, let’s write printf(“Hello-World: From Task-1\n”), as shown in Figure 21. In task 2 handler also again print the same thing and write “Hello-World: From Task-2\n”.

void vTask1_handler(void *params)
{
    while(1)
    {
        printf("Hello-world: From Task-1\n");
    }
}

void vTask2_handler(void *params)
{
    while(1)
    {
        printf("Hello-world: From Task-2\n");
    }
}

Use of printf statements in task handlers

 

Now let’s test this code:

  • First, let’s build the project.
  • Just flash the code (Figure 21 and 22). Now the code is running. But in order to see the logs, you have to get into the debugger mode because that works based on the semihosting technique.
Understanding ARM Semi-hosting feature
Figure 21. Flashing the code into the hardware board (step 1).

 

Understanding ARM Semi-hosting feature
Figure 22. Flashing the code into the hardware board (step 2).

 

  • In order to see semihosting in action, you have to be in debugger mode. Your firmware will be exchanging the information with the debugger of the IDE. That’s why you have to first trigger the debugger. To trigger the debugger, first, you have to get into the debugging mode (Figure 23).
Understanding ARM Semi-hosting feature
Figure 23. Entering into the debugging mode.

 

Figure 24 is showing that the semihosting is enabled. Now let’s hit run and see whether our print statements are printing the messages or not.

Understanding ARM Semi-hosting feature
Figure 24. Debug mode.

 

  • Now your project is printing the message “The hello world example code”, as shown in Figure 25. The execution is actually halted at line 46 (Figure 25) because we have kept the breakpoint there. 
Understanding ARM Semi-hosting feature
Figure 25. Result of project execution.

 

  • Let’s remove all the breakpoints, as shown in Figure 26.
Understanding ARM Semi-hosting feature
Figure 26. Removing the breakpoints.

 

  • Now hit resume once again (Figure 27). Now in Figure 28, you can observe that task 1 is running for some time quanta, and after that, task 2 will run for some time.
Figure 29. Option to run the code.
Figure 27. Option to run the code.

 

Understanding ARM Semi-hosting feature
Figure 28. Execution of tasks in round-robin fashion.

The execution of tasks looks very slow because the debugger is involved here. The software has to exchange the information with the debugger, and the debugger is printing those messages, which it got from the board. So, it looks very slow.

In this example, for the demonstration purpose, we used the semihosting technique. This will be helpful when you debug the code. Whenever you debug the code, if you want to take the help of printf to see what’s going on, you can use this technique. For production and all, we will never use this arm semihosting technique.

 

FastBit Embedded Brain Academy Courses

click here: https://fastbitlab.com/course1

FastBitLab

The FastBit Embedded Brain Academy uses the power of internet to bring the online courses related to the field of embedded system programming, Real time operating system, Embedded Linux systems, etc at your finger tip with very low cost. Backed with strong experience of industry, we have produced lots of courses with the customer enrolment over 3000+ across 100+ countries.