EmbeddedRelated.com
Forums

printf to UART - Revisited - CCSv4

Started by Jim July 31, 2011
I have spent a lot of time trying to get printf() linked to
my low-level output-to-uart routines, and failed at several
different methods touted on this and other forums/user groups.
I finally arrived at a working solution using sprintf() and
MyPuts() (my low-level output routine). Porting a rather
large program from IAR (where I had replaced the write()
routine to get printf to uart) would require a lot of editing
(appx 300 instances of printf), with the possibility of
missing something. So, I started looking into using a #define
to handle the situation. Needless to say, I tried many things
that failed, but finally stumbled onto the fact that I needed
to "Enable Support for GCC extensions" in order to do what I
wanted.

So, here it is, plain and simple:

//---- Bgn my method of handling printf to uart ----------------
char pbuf[128]; // used by sprintf()
//----- MyPuts() -----------
int MyPuts(char *str) {
register int i = 0;
while(str[i]) { // in-line code instead of MyPutchar()
while(!(IFG2 & UCA0TXIFG));
UCA0TXBUF = str[i++];
}
return (i); // return number of chars sent
} // End MyPuts()

#define printf(...) sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
//---- End my method of handling printf to uart ----------------

Be aware of the size of pbuf, you may need to increase it for
your application.

To enable GCC extensions (required for Variadic macros),
Right-click on your project, select properties | C/C++ Build |
Language Options. Then put a check-mark in the box for
"Enable support for GCC extensions".

If anyone has a working CCSv4 device driver for MSP430 UART,
which works with add_device() and freopen() to redirect
stdout to the uart, I would very much like to see your code!

jhilory33

Beginning Microcontrollers with the MSP430

On Sun, Jul 31, 2011 at 2:25 AM, Jim wrote:

> **
> I have spent a lot of time trying to get printf() linked to
> my low-level output-to-uart routines, and failed at several
> [...]
> to "Enable Support for GCC extensions" in order to do what I
> wanted.
>
> [...]
> #define printf(...) sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
>
You should change that to:

#define printf(...) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
Or some people may even suggest:

#define printf(...) if (1) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }

so that the sprintf() and MyPuts() appear as a single block. Consider
the case where the pre-existing code is:

if (foo)
printf("Hello World!);

I'm not a CCS user, so I can't show you how to fix this in a non-grotesque
way, all I can do is slightly improve your kludge.
--
Andy


Thanks, Andy. I like the idea of brackets around the two functions in the
#define.

But, if I use:

#define printf(.) { sprint(pbuf, __VA_ARGS__); MyPuts(pbuf) }

I get errors about ';' expected. If I add ';' following both the printf()
statement

and the MyPuts() statement, then all seems to work well:

#define printf(...); { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf); }

So, until I find something better, this last #define is what I plan to use.

Jim



On Sun, Jul 31, 2011 at 9:48 AM, Jim Smith wrote:

> **
> Thanks, Andy. I like the idea of brackets around the two functions in the
> #define.
>
Yeah - cut and paste too early on a Sunday morning.
Stupid error on my part.
--
Andy


On 31 Jul 2011, at 14:45, Andy Warner wrote:

> On Sun, Jul 31, 2011 at 2:25 AM, Jim wrote:
>
>> **
>>
>>
>> I have spent a lot of time trying to get printf() linked to
>> my low-level output-to-uart routines, and failed at several
>> [...]
>> to "Enable Support for GCC extensions" in order to do what I
>> wanted.
>>
>> [...]
>> #define printf(...) sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
>>
> You should change that to:
>
> #define printf(...) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
> Or some people may even suggest:
>
> #define printf(...) if (1) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
>
> so that the sprintf() and MyPuts() appear as a single block. Consider
> the case where the pre-existing code is:
>
> if (foo)
> printf("Hello World!);

This will not work as you expect. Extending your example:

if (foo)
printf("it's foo\n");
else
printf("it's not foo");

That will not work as you expect. I'll leave you to figure out why.

The best way to do this is simply to implement printf yourself if you want to:

static char buf[128];

int printf(char *format, )
{
va_list va;
int n;
va_start(va, format);
n = vsprintf(buf, format, va); // ... or something more elegant
" do your output using but"
va_end(ap);
return n;
}

-- Paul.

On Sun, Jul 31, 2011 at 10:53 AM, Paul Curtis wrote:
>[...]
> That will not work as you expect. I'll leave you to figure out why.
>
> The best way to do this is simply to implement printf yourself if you want to:

He speaks the truth.
That's it, no more mailing lists on a Sunday morning for me..
--
Andy
--- In m..., Paul Curtis wrote:
>
>
> On 31 Jul 2011, at 14:45, Andy Warner wrote:
>
> > On Sun, Jul 31, 2011 at 2:25 AM, Jim wrote:
> >
> >> **
> >>
> >>
> >> I have spent a lot of time trying to get printf() linked to
> >> my low-level output-to-uart routines, and failed at several
> >> [...]
> >> to "Enable Support for GCC extensions" in order to do what I
> >> wanted.
> >>
> >> [...]
> >> #define printf(...) sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
> >>
> > You should change that to:
> >
> > #define printf(...) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
> > Or some people may even suggest:
> >
> > #define printf(...) if (1) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
> >
> > so that the sprintf() and MyPuts() appear as a single block. Consider
> > the case where the pre-existing code is:
> >
> > if (foo)
> > printf("Hello World!);
>
> This will not work as you expect. Extending your example:
>
> if (foo)
> printf("it's foo\n");
> else
> printf("it's not foo");
>
> That will not work as you expect. I'll leave you to figure out why.
>
> The best way to do this is simply to implement printf yourself if you want to:
>
> static char buf[128];
>
> int printf(char *format, )
> {
> va_list va;
> int n;
> va_start(va, format);
> n = vsprintf(buf, format, va); // ... or something more elegant
> " do your output using but"
> va_end(ap);
> return n;
> }
>
> -- Paul.
>

Paul, I like you suggestion of "roll your own". As soon as I get
a chance I will take a stab at implementing this.

Thanks,

Jim

Jim,

printf (and all other ouptunt lib code) is using __putchar() at the lowest
level. No need to write a custom printf.

The prototype for it is int __putchar(int ch);

Just create your own __putchar in your code.

int __putchar(int ch)
{
while(!(IFG2 & UCA0TXIFG));
UCA0TXBUF = ch;
return ch;
}

Matthias

"Jim" :

> --- In m..., Paul Curtis wrote:
>> On 31 Jul 2011, at 14:45, Andy Warner wrote:
>>
>> > On Sun, Jul 31, 2011 at 2:25 AM, Jim wrote:
>> >
>> >> **
>> >>
>> >>
>> >> I have spent a lot of time trying to get printf() linked to
>> >> my low-level output-to-uart routines, and failed at several
>> >> [...]
>> >> to "Enable Support for GCC extensions" in order to do what I
>> >> wanted.
>> >>
>> >> [...]
>> >> #define printf(...) sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
>> >>
>> > You should change that to:
>> >
>> > #define printf(...) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
>> > Or some people may even suggest:
>> >
>> > #define printf(...) if (1) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
}
>> >
>> > so that the sprintf() and MyPuts() appear as a single block. Consider
>> > the case where the pre-existing code is:
>> >
>> > if (foo)
>> > printf("Hello World!);
>>
>> This will not work as you expect. Extending your example:
>>
>> if (foo)
>> printf("it's foo\n");
>> else
>> printf("it's not foo");
>>
>> That will not work as you expect. I'll leave you to figure out why.
>>
>> The best way to do this is simply to implement printf yourself if you
wan
> t to:
>>
>> static char buf[128];
>>
>> int printf(char *format, )
>> {
>> va_list va;
>> int n;
>> va_start(va, format);
>> n = vsprintf(buf, format, va); // ... or something more elegant
>> " do your output using but"
>> va_end(ap);
>> return n;
>> }
>>
>> -- Paul.
>> Paul, I like you suggestion of "roll your own". As soon as I get
> a chance I will take a stab at implementing this.
>
> Thanks,
>
> Jim
>
>
I don't believe this is true for CCS.

Regards,

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
SolderCore running Defender... http://www.vimeo.com/25709426

> -----Original Message-----
> From: m... [mailto:m...] On Behalf
> Of Matthias Weingart
> Sent: 01 August 2011 09:49
> To: m...
> Subject: [msp430] Re: printf to UART - Revisited - CCSv4
>
> Jim,
>
> printf (and all other ouptunt lib code) is using __putchar() at the
> lowest level. No need to write a custom printf.
>
> The prototype for it is int __putchar(int ch);
>
> Just create your own __putchar in your code.
>
> int __putchar(int ch)
> {
> while(!(IFG2 & UCA0TXIFG));
> UCA0TXBUF = ch;
> return ch;
> }
>
> Matthias
>
> "Jim" :
>
> >
> >
> >
> >
> > --- In m..., Paul Curtis wrote:
> >>
> >>
> >> On 31 Jul 2011, at 14:45, Andy Warner wrote:
> >>
> >> > On Sun, Jul 31, 2011 at 2:25 AM, Jim wrote:
> >> >
> >> >> **
> >> >>
> >> >>
> >> >> I have spent a lot of time trying to get printf() linked to my
> >> >> low-level output-to-uart routines, and failed at several [...] to
> >> >> "Enable Support for GCC extensions" in order to do what I wanted.
> >> >>
> >> >> [...]
> >> >> #define printf(...) sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
> >> >>
> >> > You should change that to:
> >> >
> >> > #define printf(...) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
> Or
> >> > some people may even suggest:
> >> >
> >> > #define printf(...) if (1) { sprintf(pbuf, __VA_ARGS__);
> >> > MyPuts(pbuf)
> }
> >> >
> >> > so that the sprintf() and MyPuts() appear as a single block.
> >> > Consider the case where the pre-existing code is:
> >> >
> >> > if (foo)
> >> > printf("Hello World!);
> >>
> >> This will not work as you expect. Extending your example:
> >>
> >> if (foo)
> >> printf("it's foo\n");
> >> else
> >> printf("it's not foo");
> >>
> >> That will not work as you expect. I'll leave you to figure out why.
> >>
> >> The best way to do this is simply to implement printf yourself if
> you
> wan
> > t to:
> >>
> >> static char buf[128];
> >>
> >> int printf(char *format, )
> >> {
> >> va_list va;
> >> int n;
> >> va_start(va, format);
> >> n = vsprintf(buf, format, va); // ... or something more elegant
> >> " do your output using but"
> >> va_end(ap);
> >> return n;
> >> }
> >>
> >> -- Paul.
> >>
> >
> > Paul, I like you suggestion of "roll your own". As soon as I get a
> > chance I will take a stab at implementing this.
> >
> > Thanks,
> >
> > Jim
> >
> >
> >
> >
> >
> >
> >
> >
For those following this thread who'd like to see what I arrived
at, here's my code. This is a complete, runnable program, which
was compiled and tested with CCSv4.2.4.00032, for MSP430F2618
with RS232 level shifters for connecting UART0 to a terminal.
I followed Paul Curtis' suggestion and, pretty much, his code
template, to build my own printf replacement. See uart_printf().

Thanks, again, Paul.

Jim Smith

// ***** Begin uart_printf.c ********************************

//****************************************************************************
// MSP430x26x Demo - USCI_A0, Ultra-Low Pwr UART 1200 Echo ISR, 32kHz ACLK
//
// Simple program to get low-level character and string output to UART working,
// specifically: MyPutchar() and MyPuts(). Ultimate goal is to interface these
// to printf(), or create a uart_printf() routine, using TI's CCSv4 Compiler.
// ACLK = BRCLK = LFXT1 = 32768Hz, MCLK = SMCLK = DCO ~8.0MHz
// Baud rate divider with 32768Hz XTAL @1200 = 32768Hz/1200 = 27.31
// ******* An external watch crystal is required on XIN XOUT for ACLK *******
//
// MSP430F261x/241x
// -----------------
// /|\| XIN|-
// | | | 32kHz
// --|RST XOUT|-
// | |
// | P3.4/UCA0TXD|------------>
// | | 1200 - 7E1
// | P3.5/UCA0RXD|<------------
//
// Started with, and modified TI example MSP430x261x_uscia0_uart_03.c
// Jim Smith
// July 30, 2011
// Built with CCS Version: 4.2.4
//****************************************************************************
#include
#include
#include "msp430x26x.h"

#define PBUFSIZ 128
char pbuf[PBUFSIZ];
char ch = 'A';
int i = 325;
float j = 234.5678;

//----- MyPutchar() ----------------------
int MyPutchar(int c)
{
while(!(IFG2 & UCA0TXIFG));
UCA0TXBUF = c;
return (c);
} // End MyPutchar()

//----- MyPuts() -------------------------
int MyPuts(char *str)
{
register int i = 0;
while(str[i]) // insert in-line code for MyPutchar(), instead of a call
{
while(!(IFG2 & UCA0TXIFG));
UCA0TXBUF = str[i++];
}
return (i); // return number of chars sent
} // End MyPuts()

//----- uart_printf() --------------------
int uart_printf(char *format, ...) // same format and arguments as printf
{
va_list ap; // Argument pointer
int count; // will hold num chars sent
va_start(ap, format); // Point to the first arg
count = vsnprintf(pbuf, PBUFSIZ, format, ap); // number of chars in pbuf
if( count > 0 ) // if no error, but might be truncated
count = MyPuts(pbuf); // send pbuf string to uart
va_end(ap); // cleanup
return count; // return num chars, or -1 if error
} // End uart_printf() ***Note: vsnprintf is used to prevent buffer overrun***

//----- MAIN fuction ---------------------
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
//----- Setup the UART ---------------
P3OUT &= ~(BIT4+BIT5); // From TI example, is this necessary?
P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= (UCSSEL_1 + UCBRKIE); // CLK = ACLK, BRK int enabled
UCA0BR0 = 27; // 1200 baud: 32768/1200 = 27.31
UCA0BR1 = 0; //
UCA0MCTL = UCBRS_2; // Modulation UCBRSx = 2 (UG pg 15-30)
UCA0CTL0 |= (UCPEN | UCPAR | UC7BIT ); // Parity Enable, Even, 7-bit
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt

//----- Sign-on ----------------------
// Insert some delay for everything to stabilize
for (i = 0; i < 15; i++) { // 15 rollovers, 1.1 mHz is about 1 sec delay
__delay_cycles(65535);
} // This delay cleared up garbage when output "Hello, World!", below.

// i should be 15, because of its use in for-loop, above.
MyPuts("\r\n\
Hello, World!\r\n");
uart_printf("\
This is just to prove MyPutchar(), MyPuts() and uart_printf() actually work.\r\n");

uart_printf( "\r\n\
char: %c\r\n\
Integer: %d\r\n\
float: %1.4f\r\n", ch, i, j);
// printf("Hello");
//----- MAIN's 'forever' loop --------
// The UART0 interrupt echos incoming characters
while (1)
{
__bis_SR_register( LPM3_bits + GIE); // Enter LPMx, interrupts enabled
__no_operation(); // For using a BreakPoint
__no_operation();
} // End of main's "forever" loop
} // End of main()

//----- UCIA0 RX Interrupt ---------------
#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
char temp;
temp = ( UCA0RXBUF // Get the incoming char in temp,
& 0x7F ); // Strip off parity bit
while(!(IFG2 & UCA0TXIFG));
UCA0TXBUF = temp; // Echo the character
// Inbuf[nxtchar++] = temp; // Could add char to Inbuf
// if (temp == CMD_terminator)
// {
// set flag // for main() to process later
// __low_power_mode_off_on_exit(); // Exit LPMx
// }
} // End of USCIAB0RX_isr
//----

//***** End uart_printf.c **********************************

--- In m..., "Jim" wrote:
>
>
>
>
>
> --- In m..., Paul Curtis wrote:
> >
> >
> > On 31 Jul 2011, at 14:45, Andy Warner wrote:
> >
> > > On Sun, Jul 31, 2011 at 2:25 AM, Jim wrote:
> > >
> > >> **
> > >>
> > >>
> > >> I have spent a lot of time trying to get printf() linked to
> > >> my low-level output-to-uart routines, and failed at several
> > >> [...]
> > >> to "Enable Support for GCC extensions" in order to do what I
> > >> wanted.
> > >>
> > >> [...]
> > >> #define printf(...) sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf)
> > >>
> > > You should change that to:
> > >
> > > #define printf(...) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
> > > Or some people may even suggest:
> > >
> > > #define printf(...) if (1) { sprintf(pbuf, __VA_ARGS__); MyPuts(pbuf) }
> > >
> > > so that the sprintf() and MyPuts() appear as a single block. Consider
> > > the case where the pre-existing code is:
> > >
> > > if (foo)
> > > printf("Hello World!);
> >
> > This will not work as you expect. Extending your example:
> >
> > if (foo)
> > printf("it's foo\n");
> > else
> > printf("it's not foo");
> >
> > That will not work as you expect. I'll leave you to figure out why.
> >
> > The best way to do this is simply to implement printf yourself if you want to:
> >
> > static char buf[128];
> >
> > int printf(char *format, )
> > {
> > va_list va;
> > int n;
> > va_start(va, format);
> > n = vsprintf(buf, format, va); // ... or something more elegant
> > " do your output using but"
> > va_end(ap);
> > return n;
> > }
> >
> > -- Paul.
> >
>
> Paul, I like you suggestion of "roll your own". As soon as I get
> a chance I will take a stab at implementing this.
>
> Thanks,
>
> Jim
>