MicrocontrollerMicros

Yield Function, Printable Class and Mapping Arrays : Useful But Unknown Features from Arduino Core

Arduino core, the source code of Arduino API functions and classes, has three useful features that can be used effectively. As the Arduino core documentation doesn’t mention them (at least until the time of publishing this micro-blog), these features are not well-known for arduino developers. Let’s discuss each feature of them one by one.

Printable Class : How to Make Any Object Printable

First of all, print() and println() methods which are used in objects like Serial instance from HardwareSerial class are originally inherited from a class called Print (it not a direct inheritance but through Stream class which is inherited by HardwareSerial). To make these two methods capable of printing any object from a new class, the main Print class inherits another class called Printable which consists of only one public method called printTo(). This method is virtual, thus every new class inherits Printable, defined by developer, can have its own definition of the method. Review the inheritance and virtual function concepts from GeeksforGeeks tutorials.

class Printable
{
  public:
    virtual size_t printTo(Print& p) const = 0;
};

On the other hand, the Print class has a special overloaded version for print() and println() methods which use the printTo() method.
size_t Print::print(const Printable& x)
{
  return x.printTo(*this);
}
size_t Print::println(const Printable& x)
{
  size_t n = print(x);
  n += println();
  return n;
}

To sum up, the following demo sketch makes the usage of printable clear.

class foo : public Printable{
  public:
  foo::foo(char f1,char f2)
  {
    __bar += f1;
    __bar += f2;
  }
  size_t printTo(Print& p) const{
  return p.print(__bar);
  }
  private:
  String __bar;
};
void setup() {
 
  // put your setup code here, to run once:
  foo chrlnk('A','T');
  Serial.begin(9600);
  Serial.println(chrlnk);
}
void loop() {
} 

Printable class Arduino example

It’s also useful to know that IPAddress.h uses the same trick to print the IP address in IPAddress.cpp.

Yield Function: A Function that Keeps Running While Arduino in a Delay

While browsing the Arduino core source files, I found a weird file called hooks.c with very few lines of code inside.

static void __empty() {
    // Empty
}
void yield(void) __attribute__ ((weak, alias("__empty")));

Reading the comments included in the file, it seems that the weak function yield() is intended to be used for scheduling aspects. By weak we mean that it can be redefined in another source file. However,for AVR based Arduino board this function is not used except for one place; inside the delay() function in wiring.c source file .
void delay(unsigned long ms)
{
    uint32_t start = micros();
    while (ms > 0) {
        yield();
        while ( ms > 0 && (micros() - start) >= 1000) {
            ms--;
            start += 1000;
        }
    }
}

A useful usage of yield() is to be redefined in the main application code with some sensitive operation while the Arduino makes nothing except for waiting the delay to end, or even implementing some simple scheduler.

Mapping Arrays: Arrays that Map The Arduino Pins to According Physical Ones

Arduino team simplifys the way to access the MCU ports/GPIO by defining arrays in the flash memory (PROGMEM) to store permanently a map between the arduino pin number and the according physical pin number in the port register and the according port address. These arrays can be found in the  pins_arduino.h header file.

const uint16_t PROGMEM port_to_input_PGM[] = {
    NOT_A_PORT,
    NOT_A_PORT,
    (uint16_t) &PINB,
    (uint16_t) &PINC,
    (uint16_t) &PIND,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
    PD, /* 0 */
    PD,
    PD,
    PD,
    PD,
    PD,
    PD,
    PD,
    PB, /* 8 */
    PB,
    PB,
    PB,
    PB,
    PB,
    PC, /* 14 */
    PC,
    PC,
    PC,
    PC,
    PC,
};

Arduino.h file defines some macros to access these arrays stored in flash via  pgm_read_word.
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )

Now, each function needs to access these registers can simply call the mapping macros. I.e. pinMode, digitalWrite, (name yours), ..etc.

Yahya Tawil

Embedded Hardware Engineer interested in open hardware and was born in the same year as Linux. Yahya is the editor-in-chief of Atadiat and believes in the importance of sharing free, practical, spam-free and high quality written content with others. His experience with Embedded Systems includes developing firmware with bare-metal C and Arduino, designing PCB&schematic and content creation.

4 Comments

  1. Many thanks for this very helpful post, now my sketch folder has a new folder called USEFUL_TRICKS.

    I want to know better how to add a Printable (by inheredit it) to my two oled libraries ESPFastSSD1331 and ESPFastSSD1351 and a ILI9341 TFT library ESPFastILI934X, I already see it on Adafruit library, but when I compile your code for ESP8266 the compiler return this error:
    Printable:5:5: error: extra qualification ‘foo::’ on member ‘foo’ [-fpermissive]
    5 | foo::foo(char f1, char f2) {
    | ^~~
    exit status 1
    extra qualification ‘foo::’ on member ‘foo’ [-fpermissive]

    I suppose that foo::foo is a class costructor, iv’ve already uset it on all my libraries, even a destructor, but in header files.
    Please, can you explain me that is wrong here and do because wont compile?
    Many thanks man 😀

  2. Ok, after a web search I’ve found the error, I changed:

    foo::foo(char f1,char f2)
    to
    foo(char f1,char f2)

    inside a class and now compile and execute it.
    As on my libraries the :: need to be outside a class, I use it in .cpp files, so this is a typo error?

    On my libraries I’ve some functions that print text on the screen, these load fonts from Fonts.h header file, the most used is a void ESPFastILI9341::drawText(uint16_t x, uint16_t y, const char *pString, uint8_t Size, uint16_t Color) eg. in TFT library, please can you explain how to implement a Print(const char *pString, uint8_t Size, uint16_t Color) to print text on the current screen position?
    I suppose that I need to manage X and Y inside a function by adding X (eg. 8 pixels) every character and when I reach the end of line increase Y accordly, right?
    To implement a Printabe function, in the costructor I add this:
    class ESPFastILI9341 : public Printable {
    but is not clear here how to manage it inside a function Print(const char *pString, uint8_t Size, uint16_t Color),
    and outside a function, need to add a size_t printTo(Print p) const function?

    Many thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to top button