STM32 printf() redirect

10,262

... 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).

  1. 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.

  1. 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.

  1. 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.

  1. 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.

Share:
10,262
Hart22
Author by

Hart22

Updated on June 13, 2022

Comments

  • Hart22
    Hart22 almost 2 years

    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");
    }
    
    1. What exactly does __FILE do? I do not see it used.
    2. Why does __stdout have two '_'s before it?
    3. Why is the FILE typedef'd data type get assigned to __stdout?
    4. Does code need to be added to /* Your implementation of fputc(). */?
    • Admin
      Admin over 6 years
      Redirect it to what?
    • 0___________
      0___________ over 6 years
      Sorry - deleted my answer as I do not use Keil and Keil libraries.
    • 0___________
      0___________ over 6 years
      @duskwuff does it matter?
    • Admin
      Admin over 6 years
      @PeterJ Yes! If the OP wants to redirect printf() to semihosted I/O, for instance, there's a specific procedure to accomplish that which would be different from directing it to a USART or whatnot.
    • Hart22
      Hart22 over 6 years
      I am trying to redirect it to a USART port, which I am going to connect to my PC through a UART to USB converter.
    • 0___________
      0___________ over 6 years
      To redirect to anything there are some steps too. But the general idea is the same.
    • 0___________
      0___________ over 6 years
      google keil printf redirection uart - you have 100s instructions and ready examples
    • old_timer
      old_timer over 6 years
      easier to avoid printf, second easiest is to find a printf designed for this kind of work, that doesnt have such a heavy system backend.
  • Hart22
    Hart22 over 6 years
    Thank you very much for this detailed answer, very informative and useful!