Reputation: 133
I have a STM32VL Discovery board, which uses the STM32F100RB microcontroller. I am using Keil uVision 5.24.2.0. I am using the compiler option 'ARM compiler 'Use default compiler version 5''.
I am trying to figure out how to use/redirect the printf()
function on it.
I understand the UART initialisation process, but I am really struggling to understand how to re-direct printf()
. I have read multiple sources that I need to.
Consider the following example at http://www.keil.com/forum/60531/:
#include <stdio.h>
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef’d in stdio.h. */
FILE __stdout;
int fputc(int ch, FILE *f)
{
/* Your implementation of fputc(). */
return ch;
}
int ferror(FILE *f)
{
/* Your implementation of ferror(). */
return 0;
}
void test(void)
{
printf("Hello world\n");
}
__FILE
do? I do not see it used.__stdout
have two '_'s before it?FILE
typedef'd data type get assigned to __stdout
?/* Your implementation of fputc(). */
?Upvotes: 1
Views: 12387
Reputation: 93446
... how to re-direct printf(). I have read multiple sources that I need to.
You only need to retarget the library if you are using the functions that require retargeting (printf()
being one of them).
- What exactly does
__FILE
do? I do not see it used?
In this case, nothing; it just needs to be there to conform to the standard library stdio function signatures. And resolve references to FILE
type objects (such as stdout
in the standard library).
If you were to support multiple stream devices, then this structure would be needed and could be customised.
- Why does
__stdout
have two '_' before it?
Because it is a compiler/system reserved symbol and that is the convention defined for such symbols by the ISO C standard. Internally the library references the stdout stream through that symbol, but does not instantiate it - that is what your retargeting layer does, so it is necessary to define it for the library to link.
- Why is the
FILE
typedef'd data type get assigned to__stdout
?
See (2) above.
The standard streams are stdout, stdin and stderr, printf
outputs to stdout, (essentially printf()
is a wrapper around fprintf()
but with the FILE
parameter implicitly being the pre-defined stdout
stream; this is where that predefined stream is instantiated.
- Does code need to be added to
/* Your implementation of fputc(). */
?
That is what the comment suggests! It is the only function you need to explicitly implement to support printf()
. If for example you already have serial I/O code to output to the UART, a minimalist implementation that would work is:
int fputc(int ch, FILE *f)
{
f = f ; // unused warning prevention
uartOutCh( ch ) ; // your character output function.
return ch;
}
It is as simple as that - all the FILE
, __stdout
stuff etc is important only if you need to implement full support for stdio with multiple stream devices I/O devices that can be opened using fopen()
for example. They do need to at least exist in these minimal implementations however because the standard library references them and will not link if they are missing (although there are possibly weak-link implementations in the library that are used if no alternative implementation exists).
The basics of retargeting the C library are described at http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0378g/chr1358938930366.html.
More sophisticated retargetting implementations including UART support are described at http://www.keil.com/pack/doc/compiler/RetargetIO/html/index.html. A great deal of out-of-the box support via "DevPacks" is available for a number iof targets. It is perhaps a lot simpler that it used to be with earlier versions of uVision/MDK-ARM where you were more-or-less on your own; I have not tried the DevPacks methods described since I have been using the ARM-MDK and STM32 for a long time since before all that support was provided.
Upvotes: 7