Using lib_small_printf_m0

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Using lib_small_printf_m0

3,105 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by robert.palmer on Tue Jun 19 09:35:49 MST 2012
Ok,  I'm very well aware of the issues of using the RedLib or NewLib with printf support - it's too darned big for the LPC1114.  So, I WANT to use lib_small_printf_m0.  But I can't figure out how.

Does anyone know of or have a short tutorial or at least a basic set of steps that will allow me to use the lib_small_printf_m0 in both semihost mode and direct to UART?  Alternatively a sample project would be fine also.

I'm familiar with overriding the __write() in semihost to make it go to the UART.  I've done that in other projects.  I just can't seem to figure out what the lib_small_printf_m0 wants.

- What's the entry point?  The TEST_PRINTF shows using "printf()" but the library never defines printf(), only printf_format() and func_printf()

- do I need to define my own printf() and call the func_printf() or printf_format()?

- what is the difference between the two (func_printf() and printf_format())?

- is it possible to use the semihost and print the output to the host debug console, or can I ONLY print to a UART (or other physical hardware) using lib_small_printf_m0

I've searched the forum and other places for the answer, but there is no documentation on USING lib_small_printf_m0.

Thanks in advance.
0 Kudos
Reply
13 Replies

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by waynemcl on Tue May 28 15:16:44 MST 2013

Quote: robert.palmer
Hi all.

I'll post an example at some point, but wanted to at least post a "how to" as soon as possible since I was able to effectively get this working. 



Hi Robert. Thanks for the comprehensive example. Did you post that example project? I'd be grateful for that, as I'm wrestling with the toolchain at the moment, and it'd be very helpful to have a known running example.
Cheers, W
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by robert.palmer on Mon Jan 07 08:43:05 MST 2013

Quote: riscy00
Hi Robert

Where is the code example?, sorry for being dim.

Thanks



What kind of code example are you wanting?
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by riscy00 on Sat Jan 05 10:38:34 MST 2013
Hi Robert

Where is the code example?, sorry for being dim.

Thanks
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by robert.palmer on Wed Jun 20 17:05:05 MST 2012

Quote: js-nxp
:confused: That's an integral part of stdio.h or at least it has always been with other compilers I have used.



Sorry, I wasn't exactly clear.  Yes, printf() is declared in stdio.h, but that's just the declaration.  Whatever you link against (RedLib(none), RedLib(semihost), etc.) must actually have the code implemented for the printf.  RedLib(semihost) does, but we don't want to use that implementation because it's too big. 

What I meant was that lib_small_printf_m0 doesn't redefine printf in such a way that your code can use 'printf()' and the lib_small_printf_m0 implementation will be called.

NXP had two choices when they customized lib_small_printf_m0:
  1. create a printf() function (this is what the original code, on which this library is based, did).
  2. create a function that implements printf() functionality but call it something else - this is what NXP did

Case #1 will work if the main library you link against does not have a definition for printf() (e.g. RedLb (none))  However, if you link against a standard library that DOES include printf() (e.g. RedLib(semihost)) You'll get a link error because you would have two definitions of printf(), one in the RedLib(semihost) and one in the lib_small_printf_m0

Case #2 - NXP created printf_format() so there is no link conflict and you can still use the semihost library so you can send the output to the debug console.  What NXP did NOT do is add a preprocessor define to replace the printf() in your code with printf_format() (the smaller implementation).

As a developer using the lib_small_printf_m0, you have two choices:
  1. #define printf() to the NXP printf_format() - this is what I did
  2. use printf_format() in your code when you want to print instead of printf()

Case #1 allows you to easily port your code to other implementations and use standard libraries when possible without changing your code.  You're just using printf() in your code

Case #2  instead of printf() you use printf_format() which means if you move to another compiler or library and want to use the standard C library printf() you'll have to change your code.

I chose to implement Case #1
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by js-nxp on Wed Jun 20 14:47:32 MST 2012

Quote:
printf is NOT defined anywhere, YOU must define it in your code

:confused: That's an integral part of stdio.h or at least it has always been with other compilers I have used.
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by robert.palmer on Wed Jun 20 13:32:43 MST 2012
Oh, I still don't fully understand the difference between the func_printf() and the printf_format() maybe someone from NXP can chime in on that.
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by robert.palmer on Wed Jun 20 13:26:47 MST 2012
Hi all.

I'll post an example at some point, but wanted to at least post a "how to" as soon as possible since I was able to effectively get this working.  I've included a couple of extra pieces to handle:
- using a UART port instead of the debug console
- dealing with both newer and older versions of the LPCXpresso IDE

First off, IGNORE the comments on putchar/outbyte, and the commented section that contains "main.c" - they're from the original code and do NOT apply to the NXP modified code.  NXP took the approach of providing a function pointer parameter to the printf function.  This function pointer should be a function that takes a char, prints it and then returns an int (see the typedef in small_printf.h)

Second, printf is NOT defined anywhere, YOU must define it in your code and reference it to the func_printf_nofloat() or fund_printf_float() (depending on whether you want float support or not)

Also, if you DO want float support, you must define LIB_FLOAT_PRINTF, I would recommend doing this in the compiler settings (project/properties/C/C++ Build/Settings/MCU C Compiler/Symbols)

The code relies on the linker to strip unused code.  Both float and non-float appear to be compiled, but because only one of them is referenced (through the define in small_printf.h), the other will not get linked in.

So here's what I did:

define USE_SMALL_PRINTF to enable small printf
define USE_UART_DEBUG_PORT to use a UART instead of the debug console

This chunk is from Red Code and provides a way to handle older and newer versions of the LPCXpresso IDE
WRITEFUNC and READFUNC will be the names you use later in the code.  This should go in the same header file as the code chunk below.
//------------------------------------------
// support for semihosting
// Include stdio.h to pull in __REDLIB_INTERFACE_VERSION__
#include <stdio.h>

#if (__REDLIB_INTERFACE_VERSION__ >= 20000)
// We are using new Redlib_v2 semihosting interface
    #define WRITEFUNC __sys_write
    #define READFUNC __sys_readc
#else
// We are using original Redlib semihosting interface
    #define WRITEFUNC __write
    #define READFUNC __readc
#endif

This is the main piece for using lib_small_printf_m0.  It should go in a header file, to be included by any code that will use printf.  This code chunk allow you to choose between sending the printf to the debug console (you must select a semihost library) or to the UART. 
//--------------------------------------------
// support for lib_small_printf_m0
// must define a char output function and redefine printf
#if defined(USE_SMALL_PRINTF)
#include <small_printf.h>

int _debuguart_putchar(char c);
int _debugconsole_putchar(char c);
int _debug_buf_printf(char *format, ...);

#if defined(USE_UART_DEBUG_PORT)
#define printf(S,...)   func_printf(_debuguart_putchar, S, ##__VA_ARGS__)
#else
#define printf(S,...)   _debug_buf_printf(S, ##__VA_ARGS__)
#endif
#endif

Now in a C file, include the following code:

#if defined(USE_SMALL_PRINTF)
extern int WRITEFUNC(int zero, char *s, int len);

#if defined(USE_UART_DEBUG_PORT)
int _debuguart_putchar(char c)
{
    // your favorite flavor of function that will send a char to the UART of your choice
    return UARTPutChar(DEBUG_UART_PORT, c); 
}
#else
// This version of _putchar generates output on the debug console
// ONE CHAR AT A TIME - VERY SLOW!
int _debugconsole_putchar(char c)
{
    return WRITEFUNC(0, &c, 1);
}
#endif
#endif

As you can see from the comment, this is VERY slow.  A modified version that buffers the chars, then writes them all to the output can be done using the following:

Put this in your 'C' file
// This version generates output on the debug console, one BUFFER at a time
char debug_printf_buf[128];
int _debug_buf_printf(char *format, ...)
{
    va_list args;
    va_start( args, format );

    nsprintf_write_init((char *) debug_printf_buf, sizeof(debug_printf_buf));
    printf_format( nsprintf_write, format, args );

    return WRITEFUNC(0, debug_printf_buf, sizeof(debug_printf_buf));
}

and change your '.h' file to redefine printf as:
#define printf(S,...)   _debug_buf_printf(S, ##__VA_ARGS__)

This only allows an output string of 128 chars, but that should be enough in most cases.  This is noticeably faster, but still not as fast as code red's printf to the console.  The advantage is that this is only a little over 1K whereas code red's printf add about 12k

Hope this helps some of you.  At some point, I'll post a complete example.
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Tue Jun 19 23:23:29 MST 2012
John,

add me to your list too ;)
I've actually almost given up on small_printf - that is for using it as a plain printf replacement. But I'll have a look at Zero's stuff first.

One of the things is that printf calls _write() for each character separately making it not the most optimal implementation (speed wise).
Another thing is that, when using it as sprintf(), it uses global vars to store buffer info making it inherently thread unsafe. And again: speed wise it seems strange to call a function for each character that has to be written to a buffer.

This plus missing documentation, not the best looking code, exporting functions that are of no importance to the user at all ... all this made me almost strip away small_printf from my projects.

Rob
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by js-nxp on Tue Jun 19 22:35:48 MST 2012
Hey that was meant for the OP, there is an extra charge for you Larry. ;)
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by larryvc on Tue Jun 19 21:46:12 MST 2012
Thanks js,  I was looking for that.
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by js-nxp on Tue Jun 19 16:07:41 MST 2012
The post from Zero (2nd last post) maybe of help
http://knowledgebase.nxp.com/showthread.php?t=2887
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by robert.palmer on Tue Jun 19 09:54:09 MST 2012
By defining the symbol CR_INTEGER_PRINTF, you remove the floating point support in the printf that is part of the RedLib library.  Only integer values are allowed. (%f would no longer be a valid format flag)

see:
http://support.code-red-tech.com/CodeRedWiki/UsingPrintf
0 Kudos
Reply

3,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ex-kayoda on Tue Jun 19 09:46:24 MST 2012

Quote: robert.palmer
Ok,  I'm very well aware of the issues of using the RedLib or NewLib with printf support...



And also reducing code size with CR_INTEGER_PRINTF :confused:
0 Kudos
Reply