zeke 693 Posted February 22, 2011 Share Posted February 22, 2011 I'm faced with the challenge of getting printf() working on my MSP430F5438 experimenter's board. My mentor tells me that I should modify fputc() for my needs. My intuition tells me to roll my own routines. If you had the need to redirect STDIO to a hardware serial port on the msp430, would you: A. Follow Harman's advice as posted here? B. Follow Michael Barr's advice as posted here? What do you think? Quote Link to post Share on other sites
JMLB 24 Posted February 23, 2011 Share Posted February 23, 2011 On my Arm, when I got my printf to work, I simply created a c file and put this in it struct __FILE { int handle; // Add whatever you need here }; FILE __stdout; FILE __stdin; /*=============================================== * fputc *=================================================*/ int fputc(int ch, FILE *f) { return (SendChar(ch)); } SendChar is the function I used to send a byte to the serial port. Quote Link to post Share on other sites
thenutbunny 0 Posted February 23, 2011 Share Posted February 23, 2011 If you are not getting all the formating abilities of printf/scanf, I can't see a reason to implement them, you can just write your own routines preferably with a circular buffer implementation(I just skimmed the text but as I understand, Michael Barr says this.) and name them whatever you like. But if the reason for wanting printf is formating purposes than you should go as Harman says. If you ask my opinion: printf/scanf formatting is not so suitable for uart, I did write my own routines in the past with support for different configurations(by implementing handlers) and advanced formating with start and stop frames and such. Quote Link to post Share on other sites
thanhtran 10 Posted February 24, 2011 Share Posted February 24, 2011 I've tried similar thing (i.e implement put_char()) and enable cut down version printf in CCS, but when I tried to use it, I had problem with not enough memory on the 22F74 (1K RAM). Couldn't figure out how to solve it, but then I was able to find this "tiny printf" which worked well http://www.sparetimelabs.com/tinyprintf/index.html -Thanh bluehash and zeke 2 Quote Link to post Share on other sites
GeekDoc 226 Posted February 24, 2011 Share Posted February 24, 2011 ...but then I was able to find this "tiny printf" which worked well ...memory footprint...of about 1.4 kb. Ouch! The built-in stdio library only took 1.3kb when I tried to use sprintf(). I'm pretty sure using printf() from stdio would require less. :? Quote Link to post Share on other sites
zeke 693 Posted February 24, 2011 Author Share Posted February 24, 2011 In the last couple of days, I have collected some primo information on this topic and I thought I should post links so others could benefit. 1. how to point printf to UART on MSP430F1232 2. Help! CCS4.0 with MSP430F2252 has Trouble with 32 bit (Long) Data. 3. IAR AppNote 430-03 4. Tips for using printf 5. Printf support in compiler 6. printf on msp430 Today, I was able to successfully test the solution presented at link 2 but it took a lot of flash space. MSP430: Program loaded. Code Size - Text: 3024 bytes Data: 774 bytes Good thing the F5438 has a lot of flash. There is one more method that I would like to try. It's a combination of link 6 and some ideas my mentor had. Stay tuned. jsolarski 1 Quote Link to post Share on other sites
JMLB 24 Posted February 24, 2011 Share Posted February 24, 2011 some times you need to implement the C library for your microcontroller. Quote Link to post Share on other sites
thanhtran 10 Posted February 24, 2011 Share Posted February 24, 2011 ...but then I was able to find this "tiny printf" which worked well ...memory footprint...of about 1.4 kb. Ouch! The built-in stdio library only took 1.3kb when I tried to use sprintf(). I'm pretty sure using printf() from stdio would require less. :? Have you actually tried it? I didn't have problem with the code size. I have problem with the memory foot print (RAM) when I was trying to use it. As soon as I have a call to "printf" in my code, the linker couldn't find memory for it. I have written some basic printing functions in both assembly (for Microchip PIC), and in C (for MSP430), but there they were far from ease of use and speed of coding when using some thing like printf. -Thanh Quote Link to post Share on other sites
zeke 693 Posted February 25, 2011 Author Share Posted February 25, 2011 Last night, I tried the C I/O method as described here: Tips for using printf but the code bloated to 6K flash and almost 1500 bytes of ram. The worst problem was that it couldn't handle (long ints) at all. Ultimately, I had the best success with the method described here: Help! CCS4.0 with MSP430F2252 has Trouble with 32 bit (Long) Data. It does everything that I need right now. The bonus is a smaller memory footprint than the TI method. Quote Link to post Share on other sites
zeke 693 Posted March 2, 2011 Author Share Posted March 2, 2011 I just wanted to follow up and say that if you need the printf() function then this routine will be your best bet, in my opinion. Help! CCS4.0 with MSP430F2252 has Trouble with 32 bit (Long) Data. For long term storage, I post the message that contains the code here: Posted by Bin replied on 30 Dec 2009 1:55 PM Verified by Bin Verified Answer Prodigy80 Points Good inspiration. I casted all numbers with (long int) when calling printf() and it works! I think it is acceptable. A warning (is also an explanation) is written into the printf() comment section. See following source code. The printf() is ok to use now. Everyone is free to use and modify the source code below and I assume no responsibility. /*------------------------------------------------------------------- DESCRIPTION: Send one char in TX buffer, if it is not busy. Wait until not busy. INPUTS: One char. OUTPUTS: Send all the char in TX buffer. RETURNS: None. ---------------------------------------------------------------------*/ // Modify this routine so that it points to YOUR UART (zeke) void putChar(unsigned char byte) { while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready? UCA0TXBUF = byte; // Load Tx register that clear UCA0TXIFG } /*------------------------------------------------------------------- DESCRIPTION: Move numbers of lines up in the HyperTerminal. INPUTS: None. OUTPUTS: Line up to TX buffer. RETURNS: None. ---------------------------------------------------------------------*/ void linesUp(unsigned char lines) { unsigned char i; for (i = 0; i < lines; ++i) { putChar(0x1b); putChar(0x5b); putChar(0x41); } } /*------------------------------------------------------------------- DESCRIPTION: Send out charater strings with defined width, justification and padding. Width = 0 or width < string length means unlimited width. Normal padding is space and left justification, but it can pad '0' or pad to the right side, depending on pad value. pad justification padding char bxxxxxx00 left ' ' bxxxxxx1x right ' ' or '0' bxxxxxxx1 left or right '0' INPUTS: Valid string and special charater in form of "\n" for example refered by pointer *string. Output field width. Justification and padding flag pad. OUTPUTS: Sent formated string to com port output. RETURNS: Total of chars sent. ---------------------------------------------------------------------*/ #define PAD_RIGHT 0x01 #define PAD_ZERO 0x02 int prints(char *string, unsigned char width, unsigned char pad) { int pc = 0; unsigned char padchar = ' '; // The pading char is space normally if (width > 0) // If output width is defined { unsigned char len = 0; char *ptr; for (ptr = string; *ptr; ++ptr) ++len; // Calculate string length and put it in len if (len >= width) width = 0; // If string is longer than width, then width is not applicable define as zero else width -= len; // Else redefine width as padding spaces if (pad & PAD_ZERO) padchar = '0'; // If padding char is zero, then get padchar as zero ready instead of original space } if (!(pad & PAD_RIGHT)) // If not right padding - left justification { for (; width > 0; --width) // If ther is padding width. Output padding char as '0' or ' '. { putChar (padchar); ++pc; } } for (; *string ; ++string) // Output the full string { putChar (*string); ++pc; } for (; width > 0; --width) { // Write padding char to the right if normal left justification putChar (padchar); ++pc; } return pc; // Return the output char number } /*------------------------------------------------------------------- * DESCRIPTION: Print 32 bit signed interger in dec or hex. In specific * width, padding and justification using prints(). Use 12 byte buffer * which is enough for 32 bit int. * INPUTS: Up to 32 byte signed interger i. Counting base: 10 or 16. * Sign flag sg. Output string width. padding and justification flag. * Leter base for number conversion. * OUTPUTS: Sent formated interger as string to com port output. * RETURNS: Total of chars sent. ---------------------------------------------------------------------*/ #define PRINT_BUF_LEN 12 int printi(long int i, unsigned char b, unsigned char sg, unsigned char width, unsigned char pad, unsigned char letbase) { char print_buf[PRINT_BUF_LEN]; // Interger as string array char *s; char neg = 0; unsigned long int t; unsigned long int u = i; int pc = 0; if (i == 0) // If output char is 0, then just output it with padding and width. { print_buf[0] = '0'; print_buf[1] = '\0'; // Always remenber to put string end return prints(print_buf, width, pad); //Print out zero and done. } if (sg && (b == 10) && (i < 0)) // If it is a negative int, then record the '-' and number as positive { neg = 1; u = -i; } s = print_buf + PRINT_BUF_LEN-1; // Point s to the end of the output buffer and put a null there. *s = '\0'; while (u) // Convert the positive int to string with whatever counting base, dec, or hex. { t = u % b; if( t >= 10 ) t += letbase - '0' - 10; *--s = t + '0'; u /= b; } if (neg) { // If it is a negative number if( width && (pad & PAD_ZERO) ) { // If there is width, right justified and pad with zero, output negative sign. putChar ('-'); ++pc; --width; } else *--s = '-'; // Otherwise put the '-' to string buffer. } return pc + prints (s, width, pad); // Output the string buffer and return the output counter. } /*------------------------------------------------------------------- * DESCRIPTION: short form of printf. Print argument strings with mixed * varables (string or interger)inside formated. * INPUTS: Argument string pointer. * OUTPUTS: print out the argument with style using prints() and printi(). * RETURNS: Total of chars sent. * Warning!!! varables and constant numbers even 0, must casted with * (long int)in printf(), if it is going to print out using * format "u", "d", "X" and "x"! Or the complier will assigned * 16-bit for data smaller than 16 bit and the argument pointer * will fetch a wrong 32-bit data and the argument point * increament will be in wrong size. * Limitations: 1) It treats all interger as 32 bit data only. * 2) No floating point data presentation. * 3) Has left/right alignment with 0 padding. * 4) Has format code "s", "d", "X", "x", "u" and "c" only. ---------------------------------------------------------------------*/ int printf(char *format, ...) { int width, pad; int pc = 0; char scr[2]; va_list args; va_start(args, format); for (; *format != 0; ++format) { if (*format == '%') { ++format; width = pad = 0; if (*format == '\0') break; if (*format == '%') goto out; if (*format == '-') { ++format; pad = PAD_RIGHT; } while (*format == '0') { ++format; pad |= PAD_ZERO; } for ( ; *format >= '0' && *format <= '9'; ++format) { width *= 10; width += *format - '0'; } if( *format == 's' ) { char *s = (char *)va_arg( args, int ); pc += prints (s?s:"(null)", width, pad); continue; } if( *format == 'd' ) { pc += printi (va_arg( args, long int ), 10, 1, width, pad, 'a'); continue; } if( *format == 'x' ) { pc += printi (va_arg( args, long int ), 16, 0, width, pad, 'a'); continue; } if( *format == 'X' ) { pc += printi (va_arg( args, long int ), 16, 0, width, pad, 'A'); continue; } if( *format == 'u' ) { pc += printi (va_arg( args, long int ), 10, 0, width, pad, 'a'); continue; } if( *format == 'c' ) { // char are converted to int then pushed on the stack scr[0] = (char)va_arg( args, int ); scr[1] = '\0'; pc += prints (scr, width, pad); continue; } } else { out: putChar(*format); ++pc; } } va_end( args ); return pc; } /* Test printf() below */ main { char *ptr = "Hello world!"; char *np = 0; long int i = 5; int bs = sizeof(long int)*8; // Bit to shift long int mi = ((long int)1 << (bs-1)) + 1; // Maximum negative number printf("%s\n", ptr); printf("printf test\n"); printf("%s is null pointer\n", np); printf("%d = 5\n", (long int)i); printf("%d = - max int\n", mi); printf("Long int 123456789 print out is %u", (long int)123456789); printf("\nmi in hex is %x\n", (long int)mi); printf("bs in dec is %u\n", (long int)bs); printf("char %c = 'a'\n", 'a'); printf("hex %x = ff\n", (long int)0xff); printf("hex %02x = 00\n", (long int)0); printf("signed %d = unsigned %u = hex %x\n", (long int)-32767, (long int)-32767, (long int)-32767); printf("signed %d = unsigned %u = hex %x\n", (long int)-3, (long int)-3, (long int)-3); printf("%d %s(s)%", (long int)0, "message"); printf("\n"); printf("%d %s(s) with %%\n", (long int)0, "message"); printf("justif: \"%-10s\"\n", "left"); printf("justif: \"%10s\"\n", "right"); printf(" 3: %04d zero padded\n", (long int)3); printf(" 3: %-4d left justif.\n", (long int)3); printf(" 3: %4d right justif.\n", (long int)3); printf("-3: %04d zero padded\n", (long int)-3); printf("-3: %-4d left justif.\n", (long int)-3); printf("-3: %4d right justif.\n\n\n", (long int)-3); } Result: Hello world! printf test (null) is null pointer 5 = 5 -2147483647 = - max int Long int 123456789 print out is 123456789 mi in hex is 80000001 bs in dec is 32 char a = 'a' hex ff = ff hex 00 = 00 signed -32767 = unsigned 4294934529 = hex ffff8001 signed -3 = unsigned 4294967293 = hex fffffffd 0 message(s) 0 message(s) with % justif: "left " justif: " right" 3: 0003 zero padded 3: 3 left justif. 3: 3 right justif. -3: -003 zero padded -3: -3 left justif. -3: -3 right justif. To use this code, modify the Putchar() function so that it points to your UART. To verify it works, run the sample main() routine and compare the output to what is posted here. @Bin, wherever you are, Thank you! bluehash and GeekDoc 2 Quote Link to post Share on other sites
bluehash 1,581 Posted March 2, 2011 Share Posted March 2, 2011 Zeke, could you repost this to Codevault. If not, I can go ahead and do it. This looks like a nice resource. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.