EmbeddedRelated.com
Forums
Memfault Beyond the Launch

printf to UART - Revisited - CCSv4

Started by Jim July 31, 2011
Customizable printf, but no possibility to override putchar() in CCS?
I like my Crossworks. :-)

M.

"Paul Curtis" :

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

Beginning Microcontrollers with the MSP430

Hint: If you are getting this via email, chances are that the
default font is variable width, making program source listings
difficult -- just go to the yahoogroups site to read the original
message and select "Fixed width font" to view the message in a
more pleasing manner. You may copy and paste from there, as well.

Jim Smith

--- In m..., "Jim" wrote:
>
>
>
> 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
>

There is a way to implement your own printf() without an extra buffer:
extern int _printfi_nofloat(char const **_format, va_list _ap,
void *_op, int (*_outc)(char c, void *op),
int (*_outs)(char *s, void *op));

void Debug_putc( uint8_t c )
{
// send character directly to UART or send it to a buffer
// to decouple character output
}

void Debug_puts( const char *s )
{
while ( *s != '\0') {
Debug_putc( (uint8_t)*(s++) );
}
} // Debug_puts
static int _outc( char c, void *_op )
{
Debug_putc( (uint8_t)c );
return 1;
} // _outc
static int _outs( char *s, void *_op )
{
size_t len = strlen( s );
Debug_puts( s );
return (int)len;
} // _outs
void Debug_printf( const char *fmt, ... )
{
va_list _ap;

va_start( _ap, fmt );
_printfi_nofloat( &fmt, _ap, NULL, _outc, _outs);
va_end( _ap );
} // Debug_printf
Hardy
Thanks for the input. I tried implementing this approach, early on, and ran
into all kinds
of problems. Your code looks to be very straightforward and complete,
however, so I may go
back and have another go at this. I think the CCS library terminology is
"_printfi_nf", and
I'm not sure it is accessible outside the library, so may need to redo the
library (which
I'd most certainly like to avoid). I wanted the full floating point
capability, so I tried
"_printfi", instead, but never got it all fully working. Now that I've
reviewed, and
hopefully, have a better understanding of the use of pointers ( '*' ) and
address ( '&' ),
as well as your code (below) to guide me, I might have a better chance of
success. I will
post results if I attempt and succeed with this approach.

Jim Smith

-----Original Message-----
From: Hardy Griech [mailto:n...@mardys.de]
Sent: Tuesday, August 02, 2011 3:07 PM
To: m...
Cc: Jim
Subject: Re: [msp430] Re: printf to UART - Revisited - CCSv4

There is a way to implement your own printf() without an extra buffer:

extern int _printfi_nofloat(char const **_format, va_list _ap,
void *_op, int (*_outc)(char c, void *op),
int (*_outs)(char *s, void *op));

void Debug_putc( uint8_t c )
{
// send character directly to UART or send it to a buffer
// to decouple character output
}

void Debug_puts( const char *s )
{
while ( *s != '\0') {
Debug_putc( (uint8_t)*(s++) );
}
} // Debug_puts

static int _outc( char c, void *_op )
{
Debug_putc( (uint8_t)c );
return 1;
} // _outc

static int _outs( char *s, void *_op )
{
size_t len = strlen( s );
Debug_puts( s );
return (int)len;
} // _outs

void Debug_printf( const char *fmt, ... )
{
va_list _ap;

va_start( _ap, fmt );
_printfi_nofloat( &fmt, _ap, NULL, _outc, _outs);
va_end( _ap );
} // Debug_printf

Hardy

On 02.08.2011 23:21, Jim Smith wrote:
:
> back and have another go at this. I think the CCS library terminology is
> "_printfi_nf", and
:

in rtssrc.zip/SHARED/_printfi.c the functions are declared as follows:

#if !defined(NOFLOAT) && !defined(MINIMAL)
extern int _printfi(char **_format, va_list _ap, void *_op,
int (*_outc)(char, void *), int (*_outs)(char *,
void *));
#elif defined(NOFLOAT)
extern int _printfi_nofloat(char **_format, va_list _ap, void *_op,
int (*_outc)(char, void *), int (*_outs)(char *,
void *));
#elif defined(MINIMAL)
extern int _printfi_minimal(char **_format, va_list _ap, void *_op,
int (*_outc)(char, void *), int (*_outs)(char *,
void *));
#endif

Unfortunately I cannot remember how I stumbled into the prototypes some
years ago. Nevertheless it is working for me (with buffering and some
other features...).

Hardy
--- In m..., Hardy Griech wrote:
:
>
> in rtssrc.zip/SHARED/_printfi.c the functions are declared as follows:
>
> #if !defined(NOFLOAT) && !defined(MINIMAL)
> extern int _printfi(char **_format, va_list _ap, void *_op,
> int (*_outc)(char, void *), int (*_outs)(char *,
> void *));
> #elif defined(NOFLOAT)
> extern int _printfi_nofloat(char **_format, va_list _ap, void *_op,
> int (*_outc)(char, void *), int (*_outs)(char *,
> void *));
> #elif defined(MINIMAL)
> extern int _printfi_minimal(char **_format, va_list _ap, void *_op,
> int (*_outc)(char, void *), int (*_outs)(char *,
> void *));
> #endif
>
> Unfortunately I cannot remember how I stumbled into the prototypes some
> years ago. Nevertheless it is working for me (with buffering and some
> other features...).
>
> Hardy
>
:

Yes, you are correct, I don't know how I came up with
"_printfi_nf", and the functions ARE declared for access.

Thanks, I'm still learning! Over the years, I've moved from
assembler to compiler to full IDE for development. Thank
goodness we have fast machines for development, now! The size
and complexity of development software requires it! On the
other hand, development has gotten much easier! I started
with a ROM assembler running on a 6502 (AIM-65) with two
audio tape machines to handle the multi-pass assembler. Each
pass of the assembler required playing the source in on one
tape machine and writing results on the other. You can guess
what happens if any glitch comes along! I can remember
patching HEX code in the wee hours to avoid a new assembly.
I graduated from that to a 6502 cross-assembler running on
a floppy-based CPM machine. At the time, a real joy! I
could never have imagined or dreamed of the stuff we now
have to work with, all the peripherals, memory, etc..
built-in to the CPU chip, along with wonderful debugging!

Enough reminiscing. Thanks for your help.

Jim Smith

I have followed the suggestion of Hardy Griech and used his prototypes to

come up with a printf replacement: uart_printf(). As promised, I am
including

my working code as an attachment. Maybe that will preserve the formatting.

I liked Hardy's approach because it allowed getting rid of a declared RAM

buffer, and the possibility of buffer overrun.

I made only minor changes/additions to Hardy's prototypes. Instead of

Debug_printf(), I used uart_printf() because I need to output formatted text

and numbers, including floating point, over a UART link, both for data

transmission and for user interface. The Debug name just didn't seem

appropriate. I also used _printfi() instead of _printfi_nofloat(),

because I wanted the full floating point capability.

This working code was compiled by CCSv4 and downloaded to hardware using
TI's

MSP430 USB Debug-Interface. The hardware is a MSP430F2618, socket-mounted

On a 64-bit MSP-TS430PM64 board, to which I have added a RS232 Level

Shifter, to interface to a terminal.

Thanks, Hardy. And thanks to all the others who have made helpful
suggestions.

I have learned a lot from being a member of and monitoring this MSP430 Group

for several years. I always like to see the code: how others did things! I

hope that others may benefit from this, as well.

Jim Smith



Well, attaching a zip file to an email reply didn't work, so here is my little test program (source) for uart_printf(). If you are reading this on the http://tech.groups.yahoo.com/group/msp430/messages site, on the upper-right, under 'Show Message Info', select 'Use Fixed Width Font' to get proper formatting of the code below. Now, you can cut and paste the code into your editor, if you like.

Jim Smith

//***** Begin uart_printf_3.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, and interfaced to printf() (or its replacement), using TI's
// CCSv4 Compiler/IDE.
// 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
// Aug 2, 2011
// Built with CCS Version: 4.2.4
//************************************************************************
#include
#include
#include
#include
#include "msp430x26x.h"

char ch = 'A';
int i = 325;
float j = 234.5678;
//----- Code from Hardy Griech, pretty-much verbatim ---------------------
// js used _printfi() instead of _printfi_nofloat(), ie full floating
// point. This requires '--printf_support=full' when linking. You may
// select this in the CCS IDE by: r-click on your project name ->
// C/C++ Build -> Library Function Assumptions -> choose full as level
// of printf support. Do it for both Debug & Release Builds.

//extern int _printfi_nofloat(char const **_format, va_list _ap,
extern int _printfi(char const **_format, va_list _ap, // js changed
void *_op, int (*_outc)(char c, void *op),
int (*_outs)(char *s, void *op));

void uart_putc( uint8_t c )
{
// send character directly to UART or send it to a buffer
// to decouple character output
while(!(IFG2 & UCA0TXIFG)); // js added
UCA0TXBUF = c; // js added
}
void uart_puts( const char *s )
{
while ( *s != '\0') {
uart_putc( (uint8_t)*(s++) );
}
} // uart_puts
static int _outc( char c, void *_op )
{
uart_putc( (uint8_t)c );
return 1;
} // _outc
static int _outs( char *s, void *_op )
{
size_t len = strlen( s );
uart_puts( s );
return (int)len;
} // _outs
void uart_printf( const char *fmt, ... ) {
va_list _ap;

va_start( _ap, fmt );
// _printfi_nofloat( &fmt, _ap, NULL, _outc, _outs);
_printfi( &fmt, _ap, NULL, _outc, _outs); // js changed
va_end( _ap );
} // uart_printf
//----- End code from Hardy Griech ---

//----- 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, 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.
uart_puts("\r\nHello, World!\r\n");
uart_printf("\
This is just to prove uart_putc(), uart_puts() and uart_printf() work.\r\n\n\
char: %c\r\n\
Integer: %d\r\n\
float: %1.4f\r\n", ch, i, j);

//----- MAIN's 'forever' loop ----
// The UART0 interrupt echos incoming characters
while (1)
{
__bis_SR_register( LPM3_bits + GIE); // Enter LPMx, ints 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 & 0x7F ); // Strip off parity bit in temp
while(!(IFG2 & UCA0TXIFG));
UCA0TXBUF = temp; // Echo the character
} // End of USCIAB0RX_isr

//***** End uart_printf_3.c **************************************

--- In m..., "Jim Smith" wrote:
>
> I have followed the suggestion of Hardy Griech and used his prototypes to
>
> come up with a printf replacement: uart_printf(). As promised, I am
> including
>
> my working code as an attachment. Maybe that will preserve the formatting.

On 08/02/2011 08:14 PM, Jim wrote:

> and complexity of development software requires it! On the
> other hand, development has gotten much easier! I started
> with a ROM assembler running on a 6502 (AIM-65) with two

I still have the AIM65 (and a Z80STK & a Z80 hardware emulator
sitting on my desk to demostrate the old days :-) ). While things
have gotten complex, things are also easier and we have new methods
of programming complex things (OOP, multi-core/CPU/computer, SAS,
etc.). Of course programming in 2k is a lot easier now. :-)

--
Linux Home Automation Neil Cherry n...@linuxha.com
http://www.linuxha.com/ Main site
http://linuxha.blogspot.com/ My HA Blog
Author of: Linux Smart Homes For Dummies
Jim,

This looks like terrific work, and thanks to you and to Hardy. I have been trying to find out how to actually install a device driver using CCSv4, and the documentation is pretty useless. The manual only talks about writing open(), close(), read(), write(), rename(), unlink(), and then installing the new device driver using add_device(). Sounds great, but I cannot find any decent examples of connecting a serial port in this manner. At least your method provides a reasonable alternative.

On the flip side, have you or anyone else in the group written some code to implement an equivalent of scanf() for UART input? Formatted I/O in both directions is essential for the project I am working on, so any pointers are greatly appreciated!

Also, it would be helpful to have the transmit interrupt handler installed, so that busy-wait loops for the transmit buffer to become empty could be avoided. In many embedded "super-loop" applications, having to sit in a busy-wait for any extended period of time is going to negatively impact overall system performance.

I plan to try your posted solution on the printf() side, and also am looking forward to hearing about possible scanf() implementations for a UART. I have asked this question on the TI E2E board, but no luck so far...

Scott

--- In m..., "Jim" wrote:
>
> Well, attaching a zip file to an email reply didn't work, so here is my little test program (source) for uart_printf(). If you are reading this on the http://tech.groups.yahoo.com/group/msp430/messages site, on the upper-right, under 'Show Message Info', select 'Use Fixed Width Font' to get proper formatting of the code below. Now, you can cut and paste the code into your editor, if you like.
>
> Jim Smith
>
> //***** Begin uart_printf_3.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, and interfaced to printf() (or its replacement), using TI's
> // CCSv4 Compiler/IDE.
> // 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
> // Aug 2, 2011
> // Built with CCS Version: 4.2.4
> //************************************************************************
> #include
> #include
> #include
> #include
> #include "msp430x26x.h"
>
> char ch = 'A';
> int i = 325;
> float j = 234.5678;
> //----- Code from Hardy Griech, pretty-much verbatim ---------------------
> // js used _printfi() instead of _printfi_nofloat(), ie full floating
> // point. This requires '--printf_support=full' when linking. You may
> // select this in the CCS IDE by: r-click on your project name ->
> // C/C++ Build -> Library Function Assumptions -> choose full as level
> // of printf support. Do it for both Debug & Release Builds.
>
> //extern int _printfi_nofloat(char const **_format, va_list _ap,
> extern int _printfi(char const **_format, va_list _ap, // js changed
> void *_op, int (*_outc)(char c, void *op),
> int (*_outs)(char *s, void *op));
>
> void uart_putc( uint8_t c )
> {
> // send character directly to UART or send it to a buffer
> // to decouple character output
> while(!(IFG2 & UCA0TXIFG)); // js added
> UCA0TXBUF = c; // js added
> }
> void uart_puts( const char *s )
> {
> while ( *s != '\0') {
> uart_putc( (uint8_t)*(s++) );
> }
> } // uart_puts
> static int _outc( char c, void *_op )
> {
> uart_putc( (uint8_t)c );
> return 1;
> } // _outc
> static int _outs( char *s, void *_op )
> {
> size_t len = strlen( s );
> uart_puts( s );
> return (int)len;
> } // _outs
> void uart_printf( const char *fmt, ... ) {
> va_list _ap;
>
> va_start( _ap, fmt );
> // _printfi_nofloat( &fmt, _ap, NULL, _outc, _outs);
> _printfi( &fmt, _ap, NULL, _outc, _outs); // js changed
> va_end( _ap );
> } // uart_printf
> //----- End code from Hardy Griech ---
>
> //----- 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, 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.
> uart_puts("\r\nHello, World!\r\n");
> uart_printf("\
> This is just to prove uart_putc(), uart_puts() and uart_printf() work.\r\n\n\
> char: %c\r\n\
> Integer: %d\r\n\
> float: %1.4f\r\n", ch, i, j);
>
> //----- MAIN's 'forever' loop ----
> // The UART0 interrupt echos incoming characters
> while (1)
> {
> __bis_SR_register( LPM3_bits + GIE); // Enter LPMx, ints 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 & 0x7F ); // Strip off parity bit in temp
> while(!(IFG2 & UCA0TXIFG));
> UCA0TXBUF = temp; // Echo the character
> } // End of USCIAB0RX_isr
>
> //***** End uart_printf_3.c **************************************
>
> --- In m..., "Jim Smith" wrote:
> >
> > I have followed the suggestion of Hardy Griech and used his prototypes to
> >
> > come up with a printf replacement: uart_printf(). As promised, I am
> > including
> >
> > my working code as an attachment. Maybe that will preserve the formatting.
>


Memfault Beyond the Launch