Hi guys
Just a short one.... do you use the build-in printf function, or have you done your own ?
I'm afraid that if I use printf it will take up all my space :/ (never tried it)
Hi guys
Just a short one.... do you use the build-in printf function, or have you done your own ?
I'm afraid that if I use printf it will take up all my space :/ (never tried it)
Some compilers have a small printf option.
I use WinAVR with the gcc compiler
Your compiler provides some fully debugged standard library functions. Why not use them?
I note that your smallest MCU is 16kB. Quite honestly, you can use as much printf() or floating point as you want.
There is no way that you would get much on your Tiny13. By the time you have a software UART or USI, you will have not much flash left.
Printf() comes in several flavours. The full shebang (with f-p) may take 4kB. ImageCraft will probably take a lot more.
David.
currently I'm developing on a mega48 (4KB)
but I only need some easy way to send small strings and numbers... right now I push every char into the buffer one by one :(
could any maybe link to a code example I could copy so its running using printf and so ?
Think actually the problem is that I'm a little scared for using others code :/
found this example in the gcc avr-libc stdio
#includestatic int uart_putchar(char c, FILE *stream); static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); static int uart_putchar(char c, FILE *stream) { if (c == '\n') uart_putchar('\r', stream); loop_until_bit_is_set(UCSRA, UDRE); UDR = c; return 0; } int main(void) { init_uart(); stdout = &mystdout; printf("Hello, world!\n"); return 0; }
But as far as I can see I should still make my own interrupt driven send and recieve rutines right ?
And what does
FILE
stand for ?
For strings and integers I'll typically use my own code.
Okay I implemented it now...
went from 1460 bytes up to 1630
when I wrote
printf("Test streng!\n");
Ooooh! A Cheap Shot at the imagecraft compiler! Now I'll need to compile a program with all 3 printf options to measure the size diffs.
//file printftst.c #include#include #include int putchar(char c){ return c; } /* void main(void){ //no printf 137 bytes puts("test"); } void main(void){ //small printf 1910 bytes printf("test"); } void main(void){ //med printf 4626 bytes printf("test"); } void main(void){ //big printf 9709 bytes printf("test"); } */ #include long seconds; char tmpstr[6]; void main(void){ //smallest prog to do printf("sec: % u \n ",seconds); takes 890 bytes with ltoa, 716 with ultoa puts("sec: "); ultoa(tmpstr,seconds,10); puts(tmpstr); putchar('\n'); }
Is there anyway to come around using 1500 bytes "just" for printing this string where "seconds" is a 32bit variable ?
printf ("sec: % u \n ", seconds);
Why not just use ultoa() ?
I'm really lost right now to be hornets :-/
It gives a really good overview the reply from bobgardner
And indianajones11 I dont know ultao() :/
'unsigned long to ascii'. Its in stdlib.h
And indianajones11 I dont know ultoa()
http://www.nongnu.org/avr-libc/u...
You need to get familiar with the library functions since you use Avr-Libc . :wink:
uint32_t biggie = 1234567895; void main(void){ char buffer[11]; // 32 bits is 4 billion+ MAX, so it takes 10 elements and the NULL. ultoa( biggie, buffer, 10); // now use buffer in whatever uart_string(), or LCD_string() code.
Looks like it :)
Think I started on a bad leg years back when I first programmed an AVR :(
Got an idea off that standard stuff was WRONG and DANGEROUS to use :/
Think actually the problem is that I'm a little scared for using others code
Think I started on a bad leg years back when I first programmed an AVRGot an idea off that standard stuff was WRONG and DANGEROUS to use
FILE is a file pointer.
Use the standard printf. If your program turns out to be too big THEN worry about it. You can download the soucre for avr-libc printf() and pare it down to the minimum you need, which will probably still be better than trying to write your own...
(Note that if you're using an ATmega48, you have a range of hardware upgrade options that may be easier than struggling to minimize your code size.)
westfw gives good advice.
Also, you'll also want to read the avrlibc manual since it has quite a lot of discussion about this. There are several variations on printf with some being much larger than others.
Smiley
Maybe I got dum-dum advice back then.. but it got me started by making my own code, where I learned the hard way to setup registers and so on :)
Maybe I got dum-dum advice back then.. but it got me started by making my own code, where I learned the hard way to setup registers and so on :)
Forget about registers and any knowledge of ASM.
Study the documentation of your Standard Library. Note that these exist for your PC, washing machine, ... too.
Occasionally you might miss the odd trick. If you find something will not fit in your mega16, ask.
A typical 'slip' is someone using pow() to produce 2 to the power of 13.
You will run into size problems with modest mega48 programs. Buy a mega328.
If you plan to sell a million mega48 products, and cannot fit into 4kB. For a modest percentage of your profits, I will squeeze it for you.
David.
I will take it all to me, and try to use the libc better and a lot more form today ! :)
And what doesFILEstand for ?
Now I'll need to compile a program with all 3 printf options to measure the size diffs.
//file printftst.c #include#include int uart_putc(char c, FILE *unused) { #ifdef __AVR_ATmega168__ while (!(UCSR0A & (1<<UDRE0))); UDR0 = c; #else while (!(UCSRA & (1<<UDRE))); UDR = c; #endif return 0; } FILE uart_str = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE); int main(void){ //no printf 316 bytes, printf-std 1650 bytes, prinf-min 1270 bytes, printf-flt 3190 bytes stdout = &uart_str; printf("test"); } /* #include long seconds; char tmpstr[6]; int main(void){ //smallest prog to do printf("sec: % u \n ",seconds); takes 668 bytes with ltoa, 638 with ultoa stdout = &uart_str; puts("sec: "); ultoa(seconds,tmpstr, 10); puts(tmpstr); putchar('\n'); } */
As it's possibly tricky to spot the results in there. Just to reiterate:
no printf - that is just puts() 316 bytes,
printf-min 1270 bytes,
printf-std 1650 bytes,
printf-flt 3190 bytes
And for the other program:
668 bytes with ltoa,
638 with ultoa
If you think it's acceptable that for printf float support it takes just short of 10K in your compiler then I guess that's fine but you can hardly complain if people call it inefficient and bloaty.
And this is a nice succint one page readable demo of how to use printf with gcc. Lets put a keyword in it that we can remember so we can seach for it like 'rumpelstiltskin'?
Then for completeness I'll mention the example in the user manual that actually explains my code:
http://www.nongnu.org/avr-libc/u...
In particular:
http://www.nongnu.org/avr-libc/e...
http://www.nongnu.org/avr-libc/e...
OK, one more question along this subject Cliff.... is it possible to use FILE now to open, read write and close files on an sd card for example? In other words, a file system module for a stand alone mini operating system? I guess a command line interpreter would be a next step?
is it possible to use FILE now to open, read write and close files on an sd card for example? In other words, a file system module for a stand alone mini operating system?
The standard streams stdin, stdout, and stderr are provided, but contrary to the C standard, since avr-libc has no knowledge about applicable devices, these streams are not already pre-initialized at application startup. Also, since there is no notion of "file" whatsoever to avr-libc, there is no function fopen() that could be used to associate a stream to some device. (See note 1.) Instead, the function fdevopen() is provided to associate a stream to a device, where the device needs to provide a function to send a character, to receive a character, or both. There is no differentiation between "text" and "binary" streams inside avr-libc. Character \n is sent literally down to the device's put() function. If the device requires a carriage return (\r) character to be sent before the linefeed, its put() routine must implement this
no printf - that is just puts() 316 bytes,
printf-min 1270 bytes,
printf-std 1650 bytes,
printf-flt 3190 bytes
CodeVision 2.03.9
putsf 150 int,width 820 long,width 1070 long,width,precision 1472 float,width,precision 3924
The big PROBLEM with most printf implementations is that they are not re-entrant. I have direct experience with this in the AVR world with ImageCraft and CodeVision. ( Not sure about AVR-GCC.)I have experienced it in other micro "C" environments as well.
So, once you get a lot of interrupt activity and ISR traffic going in your program, the printf output will get jerky, start skipping characters and sending garbage to the terminal. In general, simple and quick ISR's (like e.g. a 10 milli-sec Timer Tick ) don't seem to bother printf, but the more complex the ISRs get, and the greater their time-rate,the more likely you are to provoke problems.
In some cases I have gotten a little relief by writing a more robust putchar in assembler and pushing all registers on entry and popping them on exit, but I believe most of the problem is in printf itself.
In a number of instances I have found a small note in the C user manuals or help about the re-entrancy problem, so read carefully!
The big PROBLEM with most printf implementations is that they are not re-entrant.
The big PROBLEM with most printf implementations is that they are not re-entrant.
I see absolutely no problem on it, since you need printf only, if you want to display something.
And writing to the LCD or UART was not reentrant also.
Every device, which need a stream of data, can not be accessed by another source.
The stream must be closed first to give access to another task.
Peter
Clawson,
Neither. No RTOS involved, no printf's in ISRs.
The situation was pPrintf statements in the main line code. ISR(s) running frequently with complex operations, but no printf's or multiple accesses to the pertinent UART.
Something in the ISR(s) is disturbing something to do with the printf execution. Maybe a specific register, maybe some helper variables, who knows since the source code for printf is not supplied. I know I have bumped into this a few times with different compilers. And I know I have read that printf is non-re-entrant for a few specific compilers in the compiler's own documentation. But, it may be that the printf function is not required to be re-entrant in ANSI-C. Maybe one of the AVR Freak C Experts will know the answer to this.
The situation was pPrintf statements in the main line code. ISR(s) running frequently with complex operations, but no printf's or multiple accesses to the pertinent UART.
Something in the ISR(s) is disturbing something to do with the printf execution.
(note that printf() (in GCC) is fairly unusual in that it may use the T bit which is, I think, the only use of it in AVR-LibC - perhaps you had some Asm ISR code using T?)
I know I have bumped into this a few times with different compilers.
I have a number of very busy apps with continual interrupt-driven ADC conversions (so an interrupt every 100-200us), several timers firing interrupts, and multiple USART channels so an ISR every 100-200us. A few times a second the display refresh will typically invoke several sprintf(). Surely some of these are interrupted; probably most of them. Yet my system is stable--with MY toolchain.
Lee
theusch,
Don't panic, the sky is NOT falling. And I doubt that any printf anomaly could make even a small section of it fall.
By other compilers I meant other non-AVR compilers. E.g. 8051, 68322, 80186, 68HC11, etc. that I have worked with in the past few decades. I did not run into the problem in each compiler, but in a few of them. I got "beat up" enough (in terms of lost time, mental anquish, etc) trying to analyse the problem, that I am now wary of printf misbehavior masquerading as a self-inflicted program bug.
At some point in time I came across a description of the "printf re-entrancy syndrome" (my phrase) which seemed to describe the same class of symptoms I was seeing in the few times I had encountered it.
I know what re-entrancy is. And the problem here is not that you are calling printf from two different streams, but rather that because printf was not written to be re-entrant, it has the potential to get itself in trouble when you interrupt it in certain ways. Again, since I/we do not have the source code for the printf routines (in the majority of instances), it's not possible to perform a standard code walk-thru to determine where the "problem" may lie.
I am not saying that every C compiler has this problem. I have only had the problem a handful of times myself and I have advised others who experienced the problem in their own projects.
What I am doing is presenting my experience to the group in case someone runs into a similar instance of it. And to comment on the OP's statement that he didn't (or shouldn't) trust built-in C functions. My take on that is if I don't have source code or a really thorough description of the function's operation and implementation, I maintain a degree of skepticism. I agree, my level of trust is dependent on the reputation & pedigree of the compiler.
That all sounds like mumbo-jumbo to me.
I see no reason why any interrupt should break a foreground function. (Unless you are doing something very foolish in the ISR() ).
Depending on your memory model, you can run fairly short of SRAM. Again, you need to be pretty foolish in the first place. If your compiler reports you have used less than 80% of SRAM, you should be pretty safe.
CodeVision does a stack analysis for you.
avr-gcc does not, but the percentage usage is a good clue.
So perhaps Chuck can give us a real-life example.
David.
I know what re-entrancy is. And the problem here is not that you are calling printf from two different streams, but rather that because printf was not written to be re-entrant, it has the potential to get itself in trouble when you interrupt it in certain ways
Wait a minute... so you're defining re-entrancy as the ability of dealing with interrupts in the middle of a function? That's not re-entrancy. Any interrupt rtn that changes the behaviour of the code it interrupted in unwanted ways is buggy.
Re-entrancy is the capability of correctly processing i.e. a printf inside an interrupt routine that has just interrupted a printf right in the middle. If that holds true for i.e. a printf, then your printf is said to be re-entrant.
Two important rules:
1. you do not call printf() or any big function from inside an ISR(). period.
2. you do not re-enable interrupts inside an ISR()
Of course you will occasionally need to call small external functions. These must be re-entrant because they could be already running in the foreground.
If you can guarantee that your non-reentrant function is never called reentrantly, you will be fine.
David.