Permalink
Fetching contributors…
Cannot retrieve contributors at this time
164 lines (128 sloc) 5.54 KB

ETL

Build Status

C++1x Embedded Template Library for Atmel AVR 8-bit and Espressif ESP 32-bit microcontrollers.

ETL is a header only template library geared towards the size and performance constraints of embedded applications. Its main objective is to take advantage of the efficiency of generic programming and to produce the fastest possible binaries.

ETL provides compile-time abstractions whose strongly typed definitions can leverage high-level information and relations about the mcu's peripherals.

For example, type information about the PORT to which belongs a given PIN makes compile-time optimization of PORT manipulation possible.

template <typename PinRed, typename PinGreen, typename PinBlue>
class RGBLed {
  enum class bitColor : uint8_t { Red=1<<0, Green=1<<1, Blue=1<<2 };
public:
  void SetColor(uint8_t color) const {
     if (color & bitColor::Red) pinRed::Set(); else pinRed::Clear();
     if (color & bitColor::Green) pinGreen::Set(); else pinGreen::Clear();
     if (color & bitColor::Blue) pinBlue::Set(); else pinBlue::Clear();
    }    
};

If we create an RGBLed object connected to pins D7, B0 and B1 and call SetColor :

RGBLed<PinD7, PinB0, PinB1> myLed;

myLed.SetColor(0b101);

the compiler will produce the following assembly code :

5f 9a    sbi 0x0b, 7         ; 2 cycles
28 98    cbi 0x05, 0         ; 2 cycles
29 9a    sbi 0x05, 1         ; 2 cycles

And if another RGBLed is connected to pins B2, B3 and B4 :

RGBLed<PinB2, PinB3, PinB4> myLed2;

myLed2.SetColor(0b101);

almost the same output will be produced :

sbi 0x05, 2         ; 2 cycles
cbi 0x05, 3         ; 2 cycles
sbi 0x05, 4         ; 2 cycles

For this second RGBLed, a good hand-optimization would have used a global PORTB manipulation considering the fact that all pins belong to the same PORTB. This optimization can easily be performed programmatically by testing at compile-time if the pins belong to a same port, using the std::is_same traits class.

template <typename PinRed, typename PinGreen, typename PinBlue>
class RGBLed {
public:
  void SetColor(uint8_t color) const {
    if (std::is_same<pinRed::Port, pinGreen::Port>::value &&
        std::is_same<pinRed::Port, pinBlue::Port>::value) {
      pinRed::Port::ChangeBits(pinRed::bitmask() | pinGreen::bitmask() | pinBlue::bitmask(), 
                                (color & bitColor::Red ? pinRed::bitmask() : 0) + 
                                (color & bitColor::Green ? pinGreen::bitmask() : 0) +
                                (color & bitColor::Blue ? pinBlue::bitmask() : 0));
    }      
    else {
     if (color & bitColor::Red)   pinRed::Set();    else pinRed::Clear();
     if (color & bitColor::Green) pinGreen::Set();  else pinGreen::Clear();
     if (color & bitColor::Blue)  pinBlue::Set();   else pinBlue::Clear();
    }      
  }
};

which now produces this code when all the pins belong to the same PORT, providing a +50% acceleration :

85 b1    in r24, 0x05        ; 1 cycle
8c 77    andi r24, 0x7c      ; 1 cycle
86 60    ori r24, 0x06       ; 1 cycle 
85 b9    out 0x05, r24       ; 1 cycle

C++21 Support

  • std::string_view::starts_width/end_width

C++17 Support

  • std::string_view string-like objects with resources in Flash memory and no freestore allocations
  • std::...\_v traits std::is_const_v, std::is_same_v, std::is_object_v, std::is_pod_v, ...

C++14 Support

  • std::integer_sequence

C++11 Support

  • std::move, std::forward needed for xvalue support, move semantics and perfect forwading
  • std::unique_ptr, std::make_unique
  • <array>
  • <bitset>
  • <cstddef>
  • <exception>
  • <functional>
  • <iterator>
  • <initializer_list>
  • <type_traits>
  • <utility>

Using ETL in an Atmel Studio 7 project

  1. Create a new C++ project :
  • 'File' -> 'New Project' -> 'GCC C++ Executable Project'
  • Select your target device
  1. Configure the project to use C++14 : In 'Project' -> 'Project properties' -> 'Toolchain' -> 'AVR/GNU C++ Compiler' -> 'Miscellaneous' add -std=c++14 in the 'Other flags:' field.

  2. Add ETL include path in your configuration : In 'Project' -> 'Project properties' -> 'Toolchain' -> 'AVR/GNU C++ Compiler' -> 'General'

    • add "C:\your_path\ETL\include" in the 'Default Include Paths:' field.*

    • Add "C:\your_path\ETL\libstd\include" unless your toolchain has already a C++ standard library.

      *(where your_path is the actual location of the ETL library).

  3. Add #include <etl.h> in your cpp file. You can now use new, delete, new[], delete[] and placement new operators. The free store manager provides you additional functions :

  etl::FreeStore::GetMemorySize()  
  etl::FreeStore::GetMemoryFragmentation()  
  etl::Freestore::GetFreeMemory()

An optional freestore trace log can be activated by defining ETL_FREESTORE_LOG_DEPTH with the requested log depth (3 bytes are used per log so a 64 log depth will consume 192 bytes of SRAM) :

  #define ETL_FREESTORE_LOG_DEPTH 64
  #include <etl.h>

This defines three public variables in :

  uint8_t etl::FreeStore::FreeStoreDebugTrace::log_counter;       // number of logged operations
  Operation etl::FreeStore::FreeStoreDebugTrace::log_operation[]  // logged operations
  void* etl::FreeStore::FreeStoreDebugTrace::log_address[]        // logged addresses