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 :-).
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:
- Kinetis Design Studio (http://www.freescale.com/kds)
- GNU Tools for ARM Embedded Processors (launchpad) (https://launchpad.net/gcc-arm-embedded, Q3 2014 release)
- The GNU ARM Eclipse plugins
- GDB server from Segger (http://segger.com/)
- GDB server from P&E (http://pemicro.com/)
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
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.
š” _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:
While debugging, there is a ‘Semihosting Console’ in the Debug View:
The output is printed to the Eclipse 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 š
> 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).
LikeLiked by 1 person
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
LikeLike
Thanks for that hint. I was under the impression that initialise_monitor_handles() will be part of the _start() function.
Thanks for the hint about *iprintf().
LikeLike
“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. š
LikeLike
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. š
LikeLike
Pingback: Semihosting for Kinetis Design Studio V3.0.0 and GNU ARM Embedded (launchpad) | MCU on Eclipse
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.
LikeLike
You are welcome, and thanks for your great postings too! I very well know your feelings. I was struggling a lot with semihosting. And just as a heads-up:
thing are again something different with the latest launchpad libraries (at least in my experience). See https://mcuoneclipse.com/2015/07/26/using-kinetis-design-studio-v3-0-0-with-the-launchad-4-9-2015-q2-release/. If using printf()/semihosting with the 4.9-q2 2015, you might need to provide your own _sbrk() routine, otherwise it crashes inside the library. Maybe there is a better solution for this, but at least I have found/described a solution in that article.
LikeLike
Hi Erich. Having trouble again with semihosting on Eclipse Mars. I noticed you had a blog post on setting up Mars as well. I am using a FRDM K64F board and as you can see in my previous comment I had semihosting working nicely not to long ago. Now when I use a printf statement, I get a hard fault with a Imprecise data bus error. Any advice on this issue?
LikeLike
Hi Centaurian :-),
are you using newlib or newlib-nano? Additionally, I had to define my own _sbrk() routine with the latest launchpad tools, see https://mcuoneclipse.com/2015/07/26/using-kinetis-design-studio-v3-0-0-with-the-launchad-4-9-2015-q2-release/
Maybe this is your problem, as malloc() can be used by printf(), and if the pointer returned by malloc() is NULL, your code will crash/create a hard fault.
I hope this helps?
LikeLike
Thanks Erich. Managed to get it to work using the _sbrk function. initially I got a compile error saying undefined reference to _end. I used this post of yours to fix that issue: https://mcuoneclipse.com/2015/05/30/problem-undefined-reference-to-__end__-if-using-semihosting/. Except I had to tweak it slightly in my case to:
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
PROVIDE ( __end__ = . );
__heap_addr = .;
__HeapBase = .;
. = . + HEAP_SIZE;
__HeapLimit = .;
. = . + STACK_SIZE;
. = ALIGN(4);
} > m_data
My Heap size and stack size variables where defined differently.
LikeLike
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.
LikeLike
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.
LikeLike