Topic : RIDE printf() in systems without 8051 external RAM

Forum : 8051

Original Post
Post Information Post
January 9, 2008 - 6:59pm
Guest

When a small-model application runs on an 8051 which has only internal RAM, i.e 256 bytes, printf() prints only the format text, no numbers:

printf("Hello"); -> Hello
printf("Hello %d", 1234); -> Hello 0
printf("%d"); -> 0

I presume this is because printf() needs xram for it's format stack. Is this true? If, so, any way round it?

regards Steven Pruzina

Replies
Post Information Post
+1
0
-1
January 10, 2008 - 5:30pm
Guest

This does printfs() on small and tiny systems. No format stack required.

/*---------------------------------------------------------------------------
|
| 8051 Small-Model Printf()
|
| Small RAM footprint, no print buffer. No floating point. Format string
| 255 chars max.
|
| Copyright Pruzina 1/9/08
|
|--------------------------------------------------------------------------*/

#include "common.h"
#include "c8051_firm.h"

/*-----------------------------------------------------------------------------------
|
| putch()
|
| For Silabs C8051, UART0
|
--------------------------------------------------------------------------------------*/

PRIVATE void putch(U8 ch)
{
TI0 = 0;
SBUF0 = ch;
while(!TI0);
}

PRIVATE BIT wrZero; // When set, write a '\0' for 0 when parsing a number
PRIVATE BIT isSigned; // The current 16 bit number is signed

/*-----------------------------------------------------------------------------------
|
| nibbleToASCII()
|
| Convert 0x00 -> 0x09 to '0' -> '9'; convert 0x0A to 'A'; anyhting else becomes '\0'.
|
--------------------------------------------------------------------------------------*/

PRIVATE U8 nibbleToASCII(U8 n)
{
return (n > 0x0A) ? '\0' : ((n == 0x0A) ? 'A' : n + '0');
}

/*-----------------------------------------------------------------------------------
|
| wrHexASCII
|
| Write byte 'n' as uppercase Hex ASCII
|
--------------------------------------------------------------------------------------*/

PRIVATE void wrHexASCII(U8 n)
{
putch(nibbleToASCII(HIGH_NIBBLE(n)));
putch(nibbleToASCII(LOW_NIBBLE(n)));
}

/*-----------------------------------------------------------------------------------
|
| wrHex16
|
| Write word 'n' as uppercase Hex ASCII, prefixed by '0x'
|
--------------------------------------------------------------------------------------*/

PRIVATE void wrHex16(U16 n)
{
putch('0');
putch('x');
wrHexASCII(HIGH_BYTE(n));
wrHexASCII(LOW_BYTE(n));
}

/*-----------------------------------------------------------------------------------
|
| getPwr10
|
--------------------------------------------------------------------------------------*/

PRIVATE U16 CONST powersOf10[] = {1,10,100,1000,10000};

PRIVATE U16 getPwr10(U8 pwr) { return powersOf10[pwr]; }

/*-----------------------------------------------------------------------------------
|
| wrU16Rem
|
| Print the 1's, 10's or 100's etc of 'n', depending on 'pwr'. Return the remainder
| after the printed portion has been subtracted.
|
| E.g if 'n' = 4721 (decimal) and 'pwr' = 3 (1000's), then print '4' and return 721.
|
--------------------------------------------------------------------------------------*/

PRIVATE U16 wrU16Rem(U16 n, U8 pwr)
{
U8 q;

q = n/getPwr10(pwr);

if(q || wrZero)
{
putch(q + '0');
wrZero = 1;
}
return n - (q*getPwr10(pwr));
}

/*-----------------------------------------------------------------------------------
|
| wrU16
|
| Print unsigned decimal
|
--------------------------------------------------------------------------------------*/

PRIVATE void wrU16(U16 n)
{
wrZero = 0;
wrU16Rem(wrU16Rem(wrU16Rem(wrU16Rem( wrU16Rem(n ,4), 3), 2), 1), 0);
}

/*-----------------------------------------------------------------------------------
|
| wrS16
|
| Print 'n' as decimal, signed or unsigned.
|
--------------------------------------------------------------------------------------*/

PRIVATE void wrS16(S16 n)
{
if(n < 0 && isSigned)
{
putch('-');
n = -n;
}
wrU16(n);
}

/*-----------------------------------------------------------------------------------
|
| tprintf
|
| Prints just integers (signed, unsigned or hex) and strings
|
--------------------------------------------------------------------------------------*/

PUBLIC void tprintf(U8 CONST *fmt, ...)
{
va_list arg;

BIT gotPcent = 0;
BIT gotEsc = 0;
U8 idx = 0;
U8 ch;
U8 generic *p;

va_start(arg,fmt);

while((ch = fmt[idx]) != '\0') // Until the end of the format string
{
if(gotPcent) // Parsing a '%'?
{
isSigned = 0; // Unless made 1 below

switch(ch) // What follows the '%'?
{
case 'd': // Signed integer?
isSigned = 1; // then set flag to force signed printout

case 'u': // Unsigned int?
wrS16(va_arg(arg, S16)); // Either way, print the integer now
break;

case 's': // String?
p = va_arg(arg, U8 generic *); // Get ptr to this string
while( (ch = *(p++)) != '\0') { putch(ch); } // and print it
break;

case 'x': // Hex
wrHex16(va_arg(arg, U16));
break;

case '%': // Escaped '%'?
putch('%'); // then print '%'
break;
}
gotPcent = 0; // Done with formatter, clear for next
}
else if(gotEsc) // Got '\'
{
switch(ch) // What's next char?
{
case 'r': putch(0x0D); break; // Print CR
case 'n': putch(0x0A); break; // Print LF
case '\\': putch('\\'); break; // escaped '\' so printf a '\'
}
gotEsc = 0; // and done with '\'
}
else // else we're neither handling and escape ('\') or a formatter ('%')
{
switch(ch) // So what is the next char?
{
case '%': gotPcent = 1; break; // Its a foramtter.. then process the format
case '\\': gotEsc = 1; break; // It's an escape..
default: putch(ch); // else its printable, do just that
}
}
idx++; // Goto next char in format string
}
}

// --------------------------------- eof -------------------------------------------

+1
0
-1
January 21, 2008 - 5:13pm
Guest

That's not correct. Try any of the C example that runs in small memory model. You will see that printf always works without any XDATA byte. Let's start with FIB (simple and close to what you show).