Reply by Jim August 5, 20112011-08-05
Scott, take a look at the interrupt-driven input of my posting to the TI e2e site. Using that technique, you can collect the input string, saving it in an input buffer via interrupt, let the interrupt routine notify main() when the string terminator arrives, then process the string in main() (outside the interrupt), with something like:
sscanf( Inbuf, fmt, ...);.
That eliminates the input wait-loop that you mentioned.

In my example, the input interrupt routine is not putting the incoming characters into Inbuf, but is only sending a flag to main(), and main() is printing out a simple response, just to show that the technique works.

Hope this helps,
Jim Smith

--- In m..., "swhitney14" wrote:
>
> Hi Jim,
>
> Thank you for the link and the fast answer. Your example looks great, and I have been able to implement printf, putc, and puts on uartA1 on my board. I cannot imagine how much longer it would have taken without your help and that of the others in this group. The CCSv4 documentation on device drivers is simply dismal, and not having an out-of-the-box way to connect the standard I/O to an on-chip resource is nearly inexcusable. Good for IAR users, I guess.
>
> Regarding the second part of my question, has anyone come up with an equivalent solution for scanf/gets/getc? Formatted input is equally important to us, and would greatly help with generation of a more elaborate command parser for development testing and field use.
>
> I assume that similar low-level routines are available for the innards of scanf, and there may be routines that we can replace for something like _inc() and _ins(), similar to _outc() and _outs().
>
> Also, has anyone implemented a buffering scheme to provide interrupt driven transmission of output data to prevent the "busy-wait" required for something like:
>
> while(!IFG2 & UCA0TXIFG) ; // wait for room in Tx register
>
> Thanks again, Jim and Hardy!
>

Beginning Microcontrollers with the MSP430

Reply by swhitney14 August 5, 20112011-08-05
Hi Jim,

Thank you for the link and the fast answer. Your example looks great, and I have been able to implement printf, putc, and puts on uartA1 on my board. I cannot imagine how much longer it would have taken without your help and that of the others in this group. The CCSv4 documentation on device drivers is simply dismal, and not having an out-of-the-box way to connect the standard I/O to an on-chip resource is nearly inexcusable. Good for IAR users, I guess.

Regarding the second part of my question, has anyone come up with an equivalent solution for scanf/gets/getc? Formatted input is equally important to us, and would greatly help with generation of a more elaborate command parser for development testing and field use.

I assume that similar low-level routines are available for the innards of scanf, and there may be routines that we can replace for something like _inc() and _ins(), similar to _outc() and _outs().

Also, has anyone implemented a buffering scheme to provide interrupt driven transmission of output data to prevent the "busy-wait" required for something like:

while(!IFG2 & UCA0TXIFG) ; // wait for room in Tx register

Thanks again, Jim and Hardy!

Reply by Jim August 5, 20112011-08-05
Scott, see my answer to your post: http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/f/166/p/126576/453324.aspx#453324

Jim Smith
PS: I had tried (and failed, miserably) to come up with a device driver, as you mentioned below. That's when I started this thread and started getting helpful suggestions right away!

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

Reply by swhitney14 August 4, 20112011-08-04
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.
>

Reply by Neil Cherry August 3, 20112011-08-03
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
Reply by Jim August 3, 20112011-08-03
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.

Reply by Jim Smith August 3, 20112011-08-03
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



Reply by Jim August 2, 20112011-08-02
--- 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

Reply by Hardy Griech August 2, 20112011-08-02
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
Reply by Jim Smith August 2, 20112011-08-02
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