Hi, I'm trying to hook newlib's printf into my STR912's UART. I've replaced the syscall.c functions (_write_r, _open_r, etc) just fine, but I can't figure out what function calls them. I'm using newlib-1.16.0. printf( "test\r\n") calls _putc_r, which I haven't overridden, and expects a valid rentrancy structure. Calling fprintf( "test\r\n") calls _fwrite_r, which I also haven't overriden. What printf-like function calls _write_r? Alternatively, how can I provide and initialize a reentrancy struct (I think it's called __REENT or _false_ptr, so that the rentrant functions stop causing data abort exceptions due to a bad rentrancy pointer? I suppose I could go in and really hack up newlib, but that seems like a really bad way to solve the problem. What do other people do? I'd really like to use fprintf and fscanf, etc, so I can redirect I/O to the UART, SD card, LCD, etc, depending on the file pointer. Thanks!
I would expect printf to call _write_r, if it is not doing that you have something wrong - the abort exception is also a give-away! ;-) Bill Gatliff is probably the greatest expert of such things; here are a couple of articles by him on porting Newlib: http://www.embedded.com/story/OEG20020103S0073 http://neptune.billgatliff.com/newlib.html Clifford
Michael Okincha wrote: > Hi, > > I'm trying to hook newlib's printf into my STR912's UART. I've replaced > the syscall.c functions (_write_r, _open_r, etc) just fine, but I can't > figure out what function calls them. I'm using newlib-1.16.0. > > printf( "test\r\n") calls _putc_r, which I haven't overridden, and > expects a valid rentrancy structure. Calling fprintf( "test\r\n") calls > _fwrite_r, which I also haven't overriden. I'm not an expert in this but AFAIK the mentioned functions are implemented in the newlib and there is not need to override them. They all should finally call the write-syscall. > What printf-like function calls _write_r? All that use a explicit or implicit (i.e. stdout) file-handle should. Did you continue stepping though the source? How did you notice that the write-syscall never gets called? > Alternatively, how can I provide and initialize a reentrancy struct (I > think it's called __REENT or _false_ptr, so that the rentrant functions > stop causing data abort exceptions due to a bad rentrancy pointer? I don't know enough about reentrancy in the newlib. Clifford already suggested some sources for information. Also look into the newlib-lpc source-code and into the libsysbase-code from devkitpro. There is also a newlib mailinglist where the developers read, they most probably can answer any question. > I suppose I could go in and really hack up newlib, but that seems like a > really bad way to solve the problem. What do other people do? "Hack" might not be needed. Do you know how the used newlib has been configured. Do you use an older version of Yagarto or a self-compiled toolchain? > I'd really like to use fprintf and fscanf, etc, so I can redirect I/O to > the UART, SD card, LCD, etc, depending on the file pointer. newlib-lpc from Aeolus and libsysbase/libfat from DivkitPro/DevkitARM show how this can be implemented.
Hello Michael, >"Hack" might not be needed. Do you know how the used newlib has been >configured. Do you use an older version of Yagarto or a self-compiled >toolchain? The new version of YAGARTO (29.03.2009) was build to support newlib with reentrant stubs. If you use here the printf function, you must implement some stubs by yourself, e.g: _sbrk_r, _fstat_r, _isatty_r, _close_r, _lseek_r, _write_r, _read_r An example implementation can be found in my syscalls.c too. Best regards, Michael
Hi All, Thanks for the input. I did finally track this down. It turns out I wasn't initializing the pre-initialized RAM structures, like _impure_ptr or impure_data. I gutted my startup.s to the bare minimum when debugging and interrupt issue, inlcuding the code that copied the .data code from ROM to RAM. That explains why it didn't work even when I declared my own impure_data structure. Reinstating the .data copy code fixed everything. One thing I might suggest is either including with the Yagarto tools or building for yourself is the debug version of the libraries. It was very hard to debug this until I compiled my own newlib, which included all the C source in the debug files. I do see the problem with scanf & printf. The binary file became huge as soon as I added printf. Now to explore things like iprintf and other, smaller libs. Thanks all! Mike
Michael Okincha wrote: > I gutted my startup.s to the bare minimum when debugging and interrupt > issue, inlcuding the code that copied the .data code from ROM to RAM. > That explains why it didn't work even when I declared my own impure_data > structure. Reinstating the .data copy code fixed everything. I would suggest that you gutted it to less than the bare minimum. Static initialisation is an essential part of the C runtime environment set-up. Without it, no static variable with an initialisation expression will get initialised, which will probably cause a great many bugs. The zero initialisation is also essential for correct initialisation of statics without initialisers (just in case you removed that too). The 'bare minimum' would be: * Set initial stack pointer * Zero un-initialised statics * Initialise statics * Call static constructors (C++) * Jump to main. > > I do see the problem with scanf & printf. The binary file became huge > as soon as I added printf. Now to explore things like iprintf and > other, smaller libs. > Note also that formatted I/O requires a significant amount of stack space (about 4K in my experience) just to get out of bed. Removing floating point support may help lean it down. You have to rebuild Newlib to do that. Using alternatives may be preferable. Clifford
Hello, My system cannot call _write_r too, although I did the 'bare minimum'. The routine return back after called _sfvwrite_r, but never touch _write_r, any idea? I modified the _write_r only in syscalls.c from yagarto and reserved 8k for user stack + heap. It should be enough, I think.
Tim Choi wrote: > any idea? > From the information provided... no. If it did not get as far as your stub, then I would suspect your application code. But without seeing it who can tell?
Hi, Can someone provide a basic explanation for me - and possibly other newbies. The Yagarto web site provides the syscalls.c code and this works when i link it with the program that uses sprintf. The code also runs on the embedded evaluation kit. What i do not understand is that the syscalls.c seems to be a workaround since the following was written by Michael Fischer :: >The new version of YAGARTO (29.03.2009) was build to support >newlib with reentrant stubs. >If you use here the printf function, you must implement >some stubs by yourself, e.g: >_sbrk_r, _fstat_r, _isatty_r, _close_r, _lseek_r, _write_r, _read_r >An example implementation can be found in my syscalls.c too. In my program sprintf did not work until i linked syscalls.c, and from what Michael has written you need to implement your own stubs. So why does one have to implement ones own stubs ?. if the syscalls.c stubs work ? Does this mean that sprintf works how i have used it at the moment, and yet may not work later if i added extra code to the program ? What should the stubs look like to ensure that the sprintf works in all cases ?. Is this the requirements of embedded programming, every part of the C language and the way the compiler implements it must be understood in detail ?. Thanks. Regards, Richard.
Richard Shadbolt wrote: > > So why does one have to implement ones own stubs ?. if the syscalls.c > stubs work ? > Because the compiler does not know what your hardware looks like, or what physical devices you will choose to be stdout, stdin and stderr, or whether or not you have a file-system or other devices that will be supported by the standard library I/O. > Does this mean that sprintf works how i have used it at the moment, and > yet may not work later if i added extra code to the program ? > sprintf() does not need any syscall stubs because its output device is RAM. Parts of stdio access a physical device need stubs to be implemented. printf() is an example of a call that needs device support (stdout). fprintf() may access output streams other than stdout and stderr, and you may wish to support that. For example you might have a file system, or multiple serial ports that you want to access with stdio. In addition to I/O devices, dynamic memory allocation also requires sbrk to be implemented because the compiler does not know know where your free memory is or how much you have. > Is this the requirements of embedded programming, every part of the C > language and the way the compiler implements it must be understood in > detail ?. > If you are using a hardware platform for which the board support work has already been done by someone else, and that meets your requirement (and its usage license allows it) you may use it as a black-box to a large extent. Commercial vendors such as IAR and Kiel provide out-of-the-box support for a large range of micro-controllers and COTS boards. If you are using your own hardware a little more work may be required to support it. If you are using a microprocessor or microcontroller not already directly supported, you do need to know what your are doing with both the toolchain and the hardware. In the case of GCC for ARM, the compiler only knows about the ARM core. You need to provide run-time start up code to initialise at least the CPU clock and memory devices (which are not defined by the ARM core itself), as well as the C library support stubs. Check out the "ARM-GCC development resources" sticky thread at the top of this forum for more information. The "Building bare-metal ARM with GNU" link is especially relevant. Clifford
Hi Clifford, Thanks for the explanations, has helped a great deal in understanding this new area. I appreciate the time you have spent in answering the questions. Thanks. Regards, Richard.
Hi, After traced the code, I found my "printf("Hello World....") just move the string to the memory somewhere (becase the buffer size is bigger than len of string?) and then finish the printf job and return back. Did I miss to do something to zero the buffer size? From the source, if the buffer size become zero, it will call _write_r immediately...... BRs.
Hello, I found the root cause. My string was bufferred. I need to send a "\n" (e.g. printf("Hello World....\n")) or even flush the buffer driectly (i.e.: fflush(stdout)) to force the library function to call _write_r. Tim.
Tim Choi wrote:
> I found the root cause. My string was bufferred. I need to send a "\n"
As I suggested, posting your code would have helped.
Tim Choi wrote:
> I found the root cause. My string was bufferred. I need to send a "\n"
That is old, but anyway...
Solution is call of
setbuf(stdin, NULL);
setbuf(stdout, NULL);
before first call of i/o functions
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.