This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

printf to RS232

Hello,

Does any one know how to modify the printf fonction and the UART in a way that when IAR executes a pritnf ("azerty = %d",var), i get the text of the printf fonction in my I/O terminal via an RS 232 link that comes from the MCU hardware board directly? I need this fonction to debug my code when NOT in simulation mode. Please help, any example code will be helpful !

 

William

  • William,

    Luckily, IAR has tried to make this pretty simple.  You don't have to rebuild the whole DLIB or CLIB.  Instead, start with the library copy of putchar.c and modify it for your target.  Then add your modified file to your IAR project.  If you also want to redirect scanf, use your own customized getchar.c too.  These files define the lowest level character I/O for printf and similar functions.  The files are decorated so IAR knows what to do with them when they are in your project.

    In the IAR "Compiler Reference", there is a section called "Overriding Library Modules".

    Jeff

  • hi Jeff,

    Thank you for your answer, so if i go down to the code, i have to put the return field of the printf fonction to the transmit buffer of my uart right?

  • No, actually you want to change the implementation of putchar( ).  The original library version (in putchar.c) writes the character to a logical device, but your customized (modified, hacked) version will write the character to your UART after waiting for it to become available (or perhaps write the character to a queue serviced by a TX ISR).

    The printf( ) function does all of its complicated formatting and then it calls putchar( ) for every output character.  You don't need to mess with printf( ) or change the way you're calling it.  Instead, you are changing putchar( ), the low-level function that sends output characters for printf( ).

    When you look at putchar.c, you'll see the function, and you should see the part you want to modify / hack.  In my copy of the library, the code to be changed is inside the brackets of the following if statement:

    if (c != EOF)

    {

       // Your code here.  Put <c> into the TX buffer or queue.  Then return <c>.

    }

    Jeff

  • Okay, thanks a lot Jeff, i see the solution now !

    This will help me alot to debug in run time,  Because IAR does not update timer register values in real time ! i have  alot of trouble debugging my app !

    thanks again !

    William

  • Jeff Tenney said:

    ...start with the library copy of putchar.c and modify it for your target.  Then add your modified file to your IAR project.

    Where can I find a copy of the putchar.c file?  I looked in the directory where the IAR is installed and I could not find anything there.

     

    -CoryF

  • That's strange.  On my PC, it's at:

    C:\Program Files\IAR Systems\Embedded Workbench X.Y\430\src\lib\dlib\putchar.c.

    And here's the relevant excerpt from the manual.

    Good luck!

    Jeff

  • I found some of the files here: "C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.0 Kickstart\430\src\lib\clib" but there is no putchar.c,  I found a getchar.c but there is no putchar.c which is what I need to put out a string/char to UART_A0.

    My "..\src\lib\dlib" does not contain a file called putchar.c

    -CoryF

  • Hi Cory,

    I wrote this for you.  Put it in a file called putchar.c in your project.  Edit as necessary of course.

    // putchar function to write standard output to serial port

    #include "xstdio.h"
    #include <processor_specific.h>

    _STD_BEGIN

    int (putchar)(int c)
    {
       // **** BEGIN SPECIFIC CODE FOR ANSI TERMINAL ***** //
       //
       // For I/O with ANSI terminal (or equivalent), convert C
       // line end (\n) to carriage-return + linefeed combo (\r\n).
       //
       if (c == '\n') putchar('\r');
       //
       // (**** END SPECIFIC CODE FOR ANSI TERMINAL ***** //

       if (c != EOF)
       {
          while (!(UCA0IFG & UCTXIFG))
          {
             // keep waiting;
          }
          UCA0TXBUF = c;
       }
       return (c);
    }

    _STD_END

    Hope that helps!

    Jeff

  • Nice simple implementation.

    But I don't think it is fully correct.

    Putchar is not supposed to do any end-of-line char conversion (it's the job of the main program or the terminal function driver, if any). The data could be binary, putchar does not know. Only fputc would know that the stream is text mode, and do the conversion. But then, the putchar implementation would be

    int purchar (int char) { return fputc(stdout, char);}

    Also, putchar is not supposed to check c for EOF. it is supposed to return EOF if the put fails (which never happens in this implementation: worst case, it stalls if USCI hasn't been properly initialized and UCTXIFG is never set).

    I'd add

    if(UCA0CTL1 & UCSWRST) return EOF; // USCI not active

    right at the start of putchar.

    However, this implementation can be as complex as one wants, including buffered background transfers, or using I2C/SPI instead of UART or any oither method of pushing data, including a complex handling of a display.

     

    Additional explanation of the missing putchar():

    The MSP does not have a 'standard output', so there cannot be a putchar implementation. The IAR implementaion in DLIB is based on a breakpoint placed in an empty putchar, so the debugger is notified whe someone is calling this funciton and it can silently 'peek' the char from the MSP. (with all side-effects of a debugger interruption). THis is, however, not portable and not usable for communication with own PC software such as putty.

     

  • In IAR, putchar( ) is used only for printf( ).  Low-level stream insertion occurs in __write( ), not putchar( ).  In fact, the default implementation of putchar( ) uses  __write( ) to do the work.  So "hacking" putchar is generally a safe thing to do since you're only affecting printf( ) (and not affecting all stream output).

    Also the std streams are by definition character based, right?  They are not intended to operate in binary mode.

    Also the quick version of putchar( ) above works whether the target application uses CLIB or DLIB and regardless of DLIB configuration.

    Also std streams are not to be closed, so sending EOF over the standard stream is probably not wise.  The stream listener could potentially stop.

    The IAR implementation of putchar in DLIB merely calls fputc( ) (for DLIB with file support) or directly calls __write() otherwise.  The C-Spy terminal mechanism is not normally included.  However, if the developer requests the terminal mechanism at build time, then the linker uses different low-level code to support the breakpoint approach.  Note that this mechanism does not work in putchar( ) since putchar( ) isn't called for "cout".  Instead, the __write( ) function invokes the breakpoint mechanism (among half a dozen other functions).

     

  • Jeff Tenney said:
    In IAR, putchar( ) is used only for printf( ).

    But there' snothing that forbids using putchar() yourself to output a single char. Instead of putch(). Putch() writes to the console, while putchar() writes to stdout (which is usually the same on most standard configurations and has the same non-existent meaning on plain MSP)

    Jeff Tenney said:
    n fact, the default implementation of putchar( ) uses  __write( ) to do the work

    That's an assumption you may only make if you intend to never link to a different CLIB ever. It may change without notice between compiler versions and also across compilers.

    Jeff Tenney said:
    std streams are by definition character based, right?  They are not intended to operate in binary mode.

    Ah, no. character based, yes, but character bases is not the opposite to binary mode. It i svalid to assign a totally different stream to stdout:

    flcose(stdout);
    stdout=fopen(...);

    Whether a CR/LF expansion is to be done depends on the parameter to fopen and is totally unknown to putchar. As well as the existence (or not) of EOF.

    putchar(x) is effectively an alias to fputch(stdout,x), where stdout is not a constant, but a normal stream pointer. Which usually is preloaded with an implicit fopen("con:","w") (for DOS/WIndows) on program start. (or in case of the MSP with a simulated fopen).

    Jeff Tenney said:
    putchar( ) isn't called for "cout".

    Right. Since cout is console output, not stdout. cout uses putch(). Which may be implemented as alias to __write(), but this is an implementation detail and therefore internal to the library.

     

**Attention** This is a public forum