cancel
Showing results for 
Search instead for 
Did you mean: 

Standard C I/O

Daniel.Ribeiro
Associate II

Hi.

I'm a newcomer into the STM32 world. I'm using Atollic Studio 9.3.0 and a STM32F0 Discovery board.

I'm trying to retarget C I/O functions and I've read that one must write a _write() function ( pun NOT intended ) and that the standard library is nanolib, that uses tiny_printf().

My question is : How can I configure ( if possible ) the toolchain in order to use the standard C I/O functions, having to rewrite only fputc() and fgetc(), as I do in other toolchains I've used until now?

Thanks in advance.

7 REPLIES 7

Welcome to GNU/GCC, you're going to have to get your hands dirtier.

Most of the board/file level stuff likely lives in syscalls.c this includes the memory allocation function _sbrk along with the IO routines fputc() will layer on top of.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Daniel.Ribeiro
Associate II

Thank you for answering, Clive.

Examining the code of syscalls.c I saw neither fputc() nor fgetc().

And taking into account your words, I had a sensation that fputc(), which is a character I/O function is on top of _write(), which is a string I/O function. This seems not to make sense for me. What have I missing?

fputc() is high level "user facing" function, _write() is the "character device" low level implementation. The classic fputc()/fwrite() on PC/UNIX boxes has buffering so as to optimize the transfer to the drivers, and not block on every call.

ST has used __io_putchar() to touch the hardware, but if you want to support multiple USART, for example, this would be more readily handled in the syscalls.c or newlib_stubs.c files commonly used in embedded GNU/GCC implementations.

/*
 write
 Write a character to a file. `libc' subroutines will use this system routine for output to all files, including stdout
 Returns -1 on error or number of bytes sent
 */
int _write(int file, char *ptr, int len) {
    int n;
    switch (file) {
    case STDOUT_FILENO: /*stdout*/
    case STDERR_FILENO: /* stderr */
        for (n = 0; n < len; n++) {
                                        __io_putchar(*ptr++);
        }
        break;
    default:
        errno = EBADF;
        return -1;
    }
    return len;
}

In Keil, I'd use fputc(), but that's something where embedded platforms were the first thought, rather than the last. Again there would be the place you could use a FILE structure of your own, and implement multiple streams.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Daniel.Ribeiro
Associate II

If I was able to write my own fputc() function, it would not have buffering for writing to character I/O devices and it would have buffering for writing to string I/O devices. That's the way I use on Keil, too.

The f in fputc() is the reason we can use it to direct the output to more than one device.

I still can't see a reason for not matching the standards.

Where did these people get the idea embedded programmers are handicapped and should be 'driven'?

I'd personally prefer that things don't block waiting for chronically slow serial devices.

In OS land, the transition from User/System space is quite expensive, doing it for every character scales really badly. Most output stuff can be buffered, and flushed when an input is expected. For simplicity's sake the micro-controller with no mass-storage or OS is treating everything as characters.

>>Where did these people get the idea embedded programmers are handicapped and should be 'driven'?

Probably when they got sick of people complaining about doing X rather than Y when comes to board specific, and individual specific ways of implementing an IO layer, you'd make a polled one, they'd want interrupt driven one, give them an interrupt driven one they'd want it to toast sideways. The trick here is to have something crude and simple, and give everyone the code and access to write it however the heck they see fit.

>>If I was able to write my own...

You get to do exactly that.

But it's a toaster...

https://metro.co.uk/2014/04/08/dont-put-a-toaster-on-its-side-and-try-to-make-cheese-on-toast-warns-fire-brigade-4692167/

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Pavel A.
Evangelist III

> That's the way I use on Keil, too

So just keep using Keil for STM32F0? It is free, and its debugger is better too.

Keil even supports debug prints to the debugger, without using UART or ITM (which F0 does not have).

As to adapting syscalls.c - you can find examples on github.

-- pa

Daniel.Ribeiro
Associate II

HI, Pavel.

The reason I'd like to change to Atollic TrueStudio is that it's an interface a lot more richer and user friendly than Keil.

Keil seems not to have been much evolved in recent years.

Besides that, I've only a Demo version of Keil and I use it just to learn about a new microcontroller and make some simple tests of its peripheral devices. Its simplicity allows a quick setup and short time to operation right out of the box.

Have a nice weekend!