ISR Contexts in Embedded C and C++ — Selecting the correct function at compile time

Interrupt handling is an important part of embedded systems development: it allows separating application logic from peripheral interfacing, while removing the need for polling and allowing real-time operations of peripherals.

With interrupt handling in mind, the library may add functionality that requires different implementation while inside an interrupt context. Alternatively, a library function may require checks and calls when running outside an interrupt.

The rule of thumb for interrupt handling is the faster, the better. This usually rules out automatic context detection at runtime. So, library writers generate two versions of the same function, optimizing for the context where they’re executed.

One example of an API that extensively uses of this technique is FreeRTOS’s API. We can take its Timer API as an example, which provides many pairs of these functions:

  • xTimerStart / xTimerStartFromISR
  • xTimerStop / xTimerStopFromISR
  • xTimerChangePeriod / xTimerChangePeriodFromISR
  • xTimerReset / xTimerResetFromISR
  • xTimerPendFunctionCall / xTimerPendFunctionCallFromISR

But this approach has some issues:

  • A user depends on an IDE or documentation to know if a FromISR function even exists
  • If a free function does not have the FromISR suffix, does it mean it’s interrupt-safe or not?
    • Do we really expect a programmer to access documentation to verify if a call is valid in a specific context?

It’s 2021, we can do better than that. In this article, we’ll explore 4 ways of improving an interface like that with C++.

But wait, there’s more: for those who won’t/can’t use C++, we’ll also see 2 ways of doing this with C!

Continue Reading...

Using C++20's concepts as a CRTP alternative: a viable replacement?

A few months ago, a user asked on Reddit “How suitable are concepts for use as a replacement for CRTP interfaces?”. The main conclusion of the discussion was that concepts were designed to constrain, not for what CRTP is used.

But what is CRTP used for? CRTP (Curiously Recurring Template Pattern) is a way of providing compile-time polymorphism through inheritance. It’s commonly used to extend functionality of a derived class, using some required implementation details provided by it. The main idea behind CRTP is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 1. We have a Base class template that utilizes a Derived template parameter
template<typename Derived>
struct Base {
// 2. We also have a public interface that our derived class wants to provide
auto public_behavior(){
// 3. We can safely cast the this pointer to the Derived class
auto& self = *static_cast<Derived*>(this);

// 4. We then use the required provided behavior from the base class, and give our base behavior
return do_something(self.provided_behavior());
}

};

// 5. We can have a derived class that inherits from Base, using itself as template parameter.
// Notice it uses public inheritance, since we want to provide a public interface
struct MyDerived : Base<MyDerived> {
// 6. And then we provide the interface that the base class requires
auto provided_behavior() { /*...*/ }
};

// 7. We can just invoke the public behavior, and no one using it needs to know it uses CRTP.
MyDerived object;
object.public_behavior();

Code reuse can be seen as CRTP’s most important feature, as per Daisy Hollman’s “Thoughts on Curiously Recurring Template Pattern” lightning talk, since we can write the base class once, and inherit from it to implement the interface without repeating ourselves.

One real-world example of how it’s done is on the Standard library, and standardized on C++20 (which means CRTP is far from an outdated technique!): std::ranges::view_interface. With just two public member functions, we can provide a vast interface with CRTP!

But the question is: can we emulate the behavior of CRTP without using inheritance?

Let’s go to the point: the short answer is yes, but there are some caveats. So, let’s explore an example and verify some issues we can encounter:

Continue Reading...

The evolution of constexpr: compile-time lookup tables in C++

Lookup tables (LUTs) are an important resource for systems programming. They are the embodiment of the time-space tradeoff: precomputing results allow faster computation, up to O(1)!

My background: I’m a modern C++ enthusiast and a embedded systems developer. Recently, I had to implement two CRC tables, with different parameters. Instead of hard coding the tables, I went for my favorite kind of approach: computed at compile time. As the codebase was in C++11, it reminded me how far we’ve come.

So, in this article, we’ll review how to implement compile-time lookup tables in C++, for every Standard C++ published so far: C++98, C++03, C++11, C++14, C++17 and C++20. We’ll focus on the evolution of constexpr, but we’ll also see important additions to the language, such as auto and library functionality.

Note: for this article, we’ll only consider features available on each Standard, even if some of the library features were possible to implement in previous versions of C++.

🔗C++98/03: The Dark Ages

Before modern C++, we did not have ways of compute constant expressions with the own language.

All we had for this task was exactly what C has:

Continue Reading...

Forwarding References? Forwardable References! (or: don't use std::forward just because you can)

Forwarding references are a somewhat controversial topic, starting from their name. When working with them, we’ve been taught to use std::forward. After all, it’s in their name!

In this article, we’ll see when using std::forward is not only detrimental, it’s plain wrong.

If you’re already tired of reading introductions on rvalue references, move semantics and perfect forwarding, skip to the end.

🔗rvalue references and move semantics

Since C++11, we have the difference between lvalue and rvalue references:

1
2
3
4
5
// A function with an lvalue reference parameter
void lvalue_function(type& reference);

// A function with an rvalue reference parameter
void rvalue_function(type&& reference);

With them, we can implement something similar to std::unique_ptr, which only became possible in C++11:

Continue Reading...