Skip to content

mhx/libembedded

Repository files navigation

Codacy Badge

libembedded - Modern C++ for Embedded Systems

This library will hopefully, over time, become a collection of useful, modern C++ abstractions, with a particular focus on being useful in the context of embedded systems.

The goal for this library is to provide abstractions that

  • work nicely without exceptions and RTTI enabled,

  • work nicely without dynamic memory allocation and

  • require only C++11 compliant compilers.

What's inside

A polymorphic function wrapper with in-place storage

embedded::function is loosely modeled after std::function and inspired by both SG14's inplace_function and folly::Function. It requires no dynamic memory allocation, but, contrary to etl::delegate, is able to wrap lambdas and other function objects as long as they fit into the in-place storage.

A circular buffer adapter

The circular_buffer_adapter template allows the construction of circular buffers on top of a arbitrary, and possibly persistent, memory. This means that you can easily build circular buffers on top of EEPROM sections.

Variable length integers

embedded::varint implements encoding and decoding of interger values to and from byte streams, using as few bytes as possible, and independent of byte order.

Type traits

A few type traits have been back-ported from later C++ standards. More will be added on-demand.

An experimental compile-time IIR filter design library

This library (in embedded/signal) can be used to directly design IIR filters in C++ code without any run-time overhead. This is currently in experimental state as the interface isn't yet settled and there's quite a few things that are still missing. However, you can do things like:

constexpr auto design =
    iirfilter<>(1000.0).lowpass(chebyshev1<8>(3.0), 40.0).sos<float>();

auto filter = design.instance();

for (;;) {
    output(filter(input()));
}

This will design an 8th-order Chebyshev Type I low-pass filter with 3 dB of passband ripple, a sample rate of 1 kHz and a cutoff frequency of 40 Hz. All filter coefficients will be determined at compile-time and the run-time filter code is extremely efficient. For example, this is the full ARM assembly for the above code, but using a second-order filter:

process():
        push            {r3, lr}
        vpush.64        {d8, d9, d10}
        vldr.32         s17, .L5
        vldr.32         s20, .L5+4
        vldr.32         s19, .L5+8
        vmov.f32        s16, s17
        vldr.32         s18, .L5+12
.L2:
        bl              input()
        vmul.f32        s13, s0, s20
        vmov.f32        s15, s0
        vldr.32         s12, .L5+16
        vadd.f32        s14, s16, s13
        vmul.f32        s16, s14, s18
        vmls.f32        s13, s14, s12
        vmov.f32        s0, s14
        vnmls.f32       s16, s15, s19
        vadd.f32        s16, s16, s17
        vmov.f32        s17, s13
        bl              output(float)
        b               .L2
.L5:
        .word   0
        .word   1005574271
        .word   1013962879
        .word   -1075339548
        .word   1062851613

The library is also able to build fixed-point arithmetic filters if a suitable fixed-point implementation is provided (e.g. fpm).

You can find examples in the examples directory of the repo.

Experimental compile-time math library

This is primarily used by the compile-time filter design library and currently only contains the minimum functionality needed to implement the filter design. It does contain things like constexpr functions (provided either via libstdc++'s non-standard builtins or via the gcem library), constexpr complex numbers and constexpr vectors.