Semihosting with GNU ARM Embedded (Launchpad) and Kinetis Design Studio

A while back I wrote two articles about Semihosting: “Semihosting with GNU ARM Embedded (LaunchPad) and GNU ARM Eclipse Debug Plugins” and Semihosting with Kinetis Design Studio. With using the GNU ARM Embedded (lauchpad) in my Kinetis Design Studio, time for a ‘summary’ post :-).

Semihosting Output in Console

Semihosting Output in Console

What is Semihosting?

Semihosting is using the debugger connection to ‘tunnel’ printf() style output (and input) between the host and the board. Compared to a ‘traditional’ UART connection, using semihosting only needs an active debugger connection, and not a physical UART. This is very useful e.g. to write debug output. Basically any printf() style calls get routed to the debugger, and vice versa.

In this post I’m using the following:

Enabling Semihosting in the Libraries

To use semihosting, the linker needs to overwrite the low-level character read/write functions and replace them with functions interfacing with the debugger. For this, the following linker option needs to be used:

-specs=rdimon.specs
-specs=rdimon.specs Linker Option

-specs=rdimon.specs Linker Option

Printf() and Scanf() with Floating Point

If I want to print floating point numbers, the following options needs to be added to the linker flags:

-u _printf_float

To support scanf() with floating point, add the following linker flag:

-u _scanf_float

_start() and Startup Code

In order to have printf() and other standard library functions working, it is important that your startup code is calling _start(). _start() will initialize the library or anything else necessary, and then call main(). So do *not* call main() directly from the startup code if you need library functions.

calling _start() from startup code

calling _start() from startup code

💡 _start() is as well responsible to call C++ constructors, see “C++ with Kinetis Design Studio“. You might need to verify if _start() is indeed called in the startup code, as earlier versions of Kinetis Design Studio might not have it correctly called.

Source Example

Below is an example which uses printf():

#include <stdio.h>

static void print(float f) {
  printf("float value: %f\r\n", f); /* for floating point, make sure -u _printf_float is present in the linker flags! */
  printf("hello\r\n");
}

Debugger Setting

In the debug/launch configuration, enable semihosting so things get routed to the console in Eclipse. Screenshot shows the setting for P&E, the dialog for Segger is very similar:

P&E Semihosting Settings

P&E Semihosting Settings

While debugging, there is a ‘Semihosting Console’ in the Debug View:

P&E Semihosting in Debug View

P&E Semihosting in Debug View

The output is printed to the Eclipse Console:

Semihosting Output in Console

Semihosting Output in Console

Summary

To enable semihosting with the GNU launchpad tools, it requires an option for the linker, plus options if using floating point. In the debugger I need to enable semihosting, and then I have a nice way to print debug messages or read in console data from my application.

Happy FullyHosting 🙂

13 thoughts on “Semihosting with GNU ARM Embedded (Launchpad) and Kinetis Design Studio

  1. > Semihosting is using the debugger connection to ‘tunnel’ printf() style output (and input) between the host and the board.

    Semihosting indeed allows to redirect trace messages to the debugger (via the debug channel), but in fact semihosting is a bit more, it is an interface that allows to implement a minimal POSIX layer on embedded devices.

    You can get the command line arguments, use the standard input, standard output and standard error, you can read/write files, you can get some timing information, and so on.

    More info in the ARM documents (http://infocenter.arm.com/help/topic/com.arm.doc.dui0471c/CHDJHHDI.html).

    The main purpose of the full semihosting interface is to allow running unit tests on actual hardware (or emulated hardware, like QEMU), similarly to running the same tests on the development platform (assuming they are portable).

    Liked by 1 person

  2. As far as I know with gcc you may also need this (in particular if doing file I/O?):

    #include
    extern void initialise_monitor_handles(void);

    int main() {

    initialise_monitor_handles();


    }

    Maybe also worth noting that newlib integer only *iprintf() functions pull in less library overhead than the full blown versions.

    https://sourceware.org/newlib/libc.html#siprintf

    Like

      • “I was under the impression that initialise_monitor_handles() will be part of the _start() function.”

        Oh – perhaps it is in some startup code implementations but it’s not in the one that I tend to use so an explicit call is needed. I guess you should check the implementation of _start()/startup code and if it’s there then no need for an explicit call. 🙂

        Like

  3. Sorry – “#include” should read “#include stdio.h” with stdio.h surrounded in less than and greater than characters. I guess they get stripped out as potential HTML or something. 🙂

    Like

  4. Pingback: Semihosting for Kinetis Design Studio V3.0.0 and GNU ARM Embedded (launchpad) | MCU on Eclipse

  5. I don’t know why I been struggling so much to get semihosting to work on my K64F but finally I got it working today thanks to another one of your great blog posts. Thanks Erich.

    Like

  6. Erich,

    I recently was trying to get semihosting to work in KDS 3.2.0 and ran into the _sbrk issue when using printf with FreeRTOS. Thank you for the solution!

    One interesting thing I found (before locating your solution) is that if I put a printf in main.c before starting the FreeRTOS scheduler it would work correctly as would all printf calls inside my tasks. However, commenting out that initial printf in main.c would lead to a hard fault when the first printf was encountered in a task. I’m not clear on why this would occur and was wondering if you might have any insight.

    Like

    • Hi Eric,
      I have not seen something like this. And it might depend if you are using newlib or newlib-nano. I suspect a problem with the stacks. The main() is running on the startup stack (MSP stack pointer) while the tasks are running with the PSP (Process Stack Pointer). At the first call, printf() might need more stack for its internal data structure setup (maybe?), so if you do that from main(), it does not consume that on the PSP. I suspect if you increase both the FreeRTOS task stack plus make sure that you have enough stack for main() (at least 1 KByte for each), then you should be fine.

      Like

What do you think?

This site uses Akismet to reduce spam. Learn how your comment data is processed.