DocBohn / CowPi_stdio

A library to interface with the Arduino serial monitor using familiar stdio functions.
Apache License 2.0
0 stars 0 forks source link

CowPi_stdio Library

GitHub Release GitHub License

Arduino Library PlatformIO Registry

See also CowPi

What the CowPi_stdio library has to offer

This library brings FILE streams to the Arduino toolchain. Specifically, the library defines stdout and stdin file streams to use the USB connection to a host computer. Doing so brings printf and scanf, familiar to any C programmer, to Arduino boards. The library also provides FILE streams for assorted display modules, allowing programmers to use fprintf to send text to the display modules

What the CowPi_stdio library will have to offer

Our plans for upcoming releases include:

How to use the CowPi_stdio library

See the documentation for details. The short version, assuming you're using C++ (to include Arduino's .ino files) is:

Enabling/Disabling Memory-Expensive Display Modules

While the library is written for run-time configuration, there are some portions that you may wish to eliminate at compile-time to reduce the memory used. You can do so by passing compile-time arguments that are discussed below:

Matrix Font

The dot matrix font defined in the library is sizable indeed. Removing the dot matrix font will eliminate a little over 2KB -- on AVR devices, this savings will be in flash memory; on ARM devices, this savings will be in RAM

Morse Code Font

The Morse Code font defined in the library is smaller than the dot matrix font but large enough to consider excluding. Removing the Morse Code font will eliminate a little over 1KB -- on AVR devices, this savings will be in flash memory; on ARM devices, this savings will be in RAM

Timed Displays

There are some displays that update based on a timer, such as the scrolling 7-segment display, the LED matrix display, and the Morse Code display. Passing the compiler argument -DNO_TIMED_DISPLAYS will disable these displays and will elimate 880 bytes from flash memory. This argument is not the default on any microcontrollers.

Which displays are disabled

If you attempt to configure a disabled display module, then the FILE * variable that add_display_module() returns will be NULL, the same as would happen for any other configuration error.

Status

MCU printf/scanf SPI bitbang SPI hardware I2C bitbang I2C hardware Buffer Timer Notes
ATmega328P โœ… โœ… โœ… โœ… โœ… uses registers I2C code works fine on actual hardware but not in simulator (bitbang I2C works for both)
ATmega2560 โœ… โœ… โœ… โœ… โœ… uses registers I2C code works fine on actual hardware but not in simulator (bitbang I2C works for both)
ATmega4809 โœ… โ‡ โŒ โ‡ โŒ โŒ
nRF52840 โŒ โ‡ โŒ โ‡ โŒ โ‡ Locks up USB -- problem with waiting for Serial?
RP2040 (Arduino framework) โœ… โœ… โŒ โœ… โŒ uses mbed::Ticker Still need to resolve floating point conversions
SAM D21 โœ… โ‡ โŒ โ‡ โŒ โŒ Still need to resolve floating point conversions
Display Module AVR megaAVR MBED SAMD
8-digit, 7-segment display (MAX7219, 5V) โœ… โ‡ โœ… โ‡
8-digit, 7-segment scrolling display (MAX7219, 5V) โœ… โŒ โœ… โŒ
8x8 LED matrix scrolling display (MAX7219, 5V) โœ… โŒ โœ… โŒ
16x2 LCD character display (HD44780, 5V; some devices support 3.3V) โœ… โ‡ โœ… โ‡
20x4 LCD character display (HD44780, 5V; some devices support 3.3V) โœ… โ‡ โœ… โ‡
128x64 OLED matrix display (SSD1306, 3.3V or 5V) โŒ โŒ โŒ โŒ
128x32 OLED matrix display (SSD1306, 3.3V or 5V) โŒ โŒ โŒ โŒ
Morse Code LED (no serial adapter necessary) โœ… โŒ โœ… โŒ

(MBED tested on Raspberry Pi Pico but not on Arduino Nano 33 BLE)

Tested on...

The tradeoffs

Advantage of using printf

Being able to print using a format string with conversion specifiers is much more convenient than using the Arduino Serial.print and Serial.println functions. Even without specifying alignment and padding, as soon as you combine constant text with a variable, printf becomes easier to use than a chain of Serial.print/println calls. (But, of course, you have all the conversion specifier goodness, including alignment and padding. Well, almost all -- see the note below about limitations.)

Disadvantage of using printf

Using printf will increase the size of your executable by about 1.2KB over simply using Serial.print and Serial.println, about the same as if you were to combine snprintf with Serial.println.

For example, on an Arduino Nano,

void setup(void) {
    Serial.begin(9600);
    int a = 3, b = 7;
    Serial.print(a);
    Serial.print(" + ");
    Serial.print(b);
    Serial.print(" = ");
    Serial.println(a + b);
}

void loop(void) {
}

uses 1814 bytes of Flash memory and 196 bytes of SRAM, whereas,

#include <CowPi_stdio.h>

void setup(void) {
    cowpi_stdio_setup(9600);
    int a = 3, b = 7;
    printf("%d + %d = %d\n", a, b, a + b);
}

void loop(void) {
}

uses 3054 bytes of Flash memory and 218 bytes of SRAM.

Neither advantage nor disadvantage

Limitations

The only limitations are inherited from the avr-libc (for AVR) and the newlib (for ARM) libraries. The one you will most likely notice is floating point conversions, which can be overcome. There are other limitations that cannot be.

Floating point conversions

Like most microcontroller environments, the default implementation does not support floating point conversions (except for Raspberry Pi Pico). Instead, the output will be ? on AVR architectures. On ARM (SAMD) architectures, the output is an unprintable character.

Another implementation is available that will support floating point conversions.

Other limitations

About the name

Some of the code in the CowPi_stdio library was once part of the CowPi library, which was designed to work with Cow Pi development boards. The code in the CowPi_stdio library will work in projects that do not use a Cow Pi development board, but we preserve the "CowPi" part of the name as a nod to its origins, and also to distinguish it from the stdio portion of libc. The "stdio" part of the name is because it makes available to AVR architectures two of the most-commonly used functions from stdio.h and makes it possible for coders to use stdio functions to work with display modules for both AVR and ARM architectures.

Why Cow Pi?

Because it's punny.

No, I mean, -Pi is typically used as a suffix for circuits that use a Raspberry Pi instead of an Arduino.

Typically, yes, but Cowduino isn't very punny, is it? Besides, it also works with the Raspberry Pi Pico.

An abbreviated pre-history

Some of the code in the CowPi_stdio library was once part of the CowPi library, which was designed to work with Cow Pi development boards, designed for class assignments at the hardware/software interface. Version 0.3 of the CowPi library saw many improvements, including being able to use printf() and scanf() with a serial terminal and abstractions for controlling MAX7219- and HH44780-based display modules. Plans for v0.5 included abstractions for SSD1306-based display modules and to further abstract the display modules by creating file streams for them that can be used with fprintf(). (The fprintf() code is in CowPi_stdio; the SSD1306 code will probably be in CowPi_stdio v0.7.) As we were making initial forays into what this display code would look like, we realized that the code that controls the displays depends on the displays but not on any of the other hardware on the Cow Pi development board, and we realized that it might be useful for projects that don't use the Cow Pi development board.

And so we separated the display code out from the rest of the CowPi library.