Keith Packard
2018-09-21 00:46:22 UTC
I build embedded systems with limited RAM; ARM cortex M0-M4 parts with
as little as 4kB of RAM and 32kB of ROM. With these tiny systems, the
traditional newlib stdio implementation can't be used as it requires
more memory than I have available. I suspect I'm not alone and wanted to
share what I'm using. Here's a link to my current git repository with
the code:
https://keithp.com/cgit/newlib.git/
I looked at the stdio implementation in the AVR libc:
https://www.nongnu.org/avr-libc/
and found that it's architecture was a good match for my
requirements. RAM required for a simple stdin/stdout console app is as
little as 16 bytes. And it doesn't use malloc, which means I can do
fully static memory allocation.
A FILE structure contains a tiny amount of state along with function
pointers to get and/or put a single character. There's no internal
buffering, and not a lot of nested function calls, which is nice in
reducing stack usage.
I've also used the libc included with SDCC, and that is even smaller but
it doesn't support multiple FILEs at all, which makes it usable only for
applications with stdin/stdout as their only use of stdio.
The code as provided by AVR libc has a bunch of AVR assembly code and
dependence on AVR data types -- the AVR environment provides only 32-bit
floats, and makes 'double' an alias for that type. I've replaced the
assembly code with C code and extended it to support 64-bit floats for
both printf and scanf. I've also included a few tests to check printf
and scanf to make sure they work correctly. Those can be built natively
so that the library can be tested without needing a separate target
machine.
To build this library, I've constructed a parallel build system using
meson so that I didn't need to change the existing autotools build
system. This has a nice advantage of speeding up building the library.
Configuring the build takes less than 20 seconds. Compiling 20
variations of the library for different embedded ARM configurations
takes about 5 minutes on my low-power laptop.
I've been upstreaming the changes I'm making in the core newlib sources
so that all of the stdio and meson changes simply add new files.
I've packaged the resulting arm-none-eabi library for Debian and it's
sitting in the 'new' queue at this point. Eventually it will become part
of a Debian distribution and may become the default library for use by
the arm-none-eabi toolchain if that makes sense.
I'd love to hear from others interested in using newlib in these smaller
systems and whether it might make sense to merge these changes into the
main newlib repository.
as little as 4kB of RAM and 32kB of ROM. With these tiny systems, the
traditional newlib stdio implementation can't be used as it requires
more memory than I have available. I suspect I'm not alone and wanted to
share what I'm using. Here's a link to my current git repository with
the code:
https://keithp.com/cgit/newlib.git/
I looked at the stdio implementation in the AVR libc:
https://www.nongnu.org/avr-libc/
and found that it's architecture was a good match for my
requirements. RAM required for a simple stdin/stdout console app is as
little as 16 bytes. And it doesn't use malloc, which means I can do
fully static memory allocation.
A FILE structure contains a tiny amount of state along with function
pointers to get and/or put a single character. There's no internal
buffering, and not a lot of nested function calls, which is nice in
reducing stack usage.
I've also used the libc included with SDCC, and that is even smaller but
it doesn't support multiple FILEs at all, which makes it usable only for
applications with stdin/stdout as their only use of stdio.
The code as provided by AVR libc has a bunch of AVR assembly code and
dependence on AVR data types -- the AVR environment provides only 32-bit
floats, and makes 'double' an alias for that type. I've replaced the
assembly code with C code and extended it to support 64-bit floats for
both printf and scanf. I've also included a few tests to check printf
and scanf to make sure they work correctly. Those can be built natively
so that the library can be tested without needing a separate target
machine.
To build this library, I've constructed a parallel build system using
meson so that I didn't need to change the existing autotools build
system. This has a nice advantage of speeding up building the library.
Configuring the build takes less than 20 seconds. Compiling 20
variations of the library for different embedded ARM configurations
takes about 5 minutes on my low-power laptop.
I've been upstreaming the changes I'm making in the core newlib sources
so that all of the stdio and meson changes simply add new files.
I've packaged the resulting arm-none-eabi library for Debian and it's
sitting in the 'new' queue at this point. Eventually it will become part
of a Debian distribution and may become the default library for use by
the arm-none-eabi toolchain if that makes sense.
I'd love to hear from others interested in using newlib in these smaller
systems and whether it might make sense to merge these changes into the
main newlib repository.
--
-keith
-keith