Przydatne biblioteki C++ STM32

C++ w systemach embedded otwiera całą gamę nowych możliwości. Poprawne użycie nowoczesnych konstrukcji języka i biblioteki standardowej pozwala ułatwić i przyspieszyć naszą pracę. Niestety większość popularnych bibliotek C++ nie jest tworzona z myślą o systemach embedded. Czasami taka biblioteka mimo wszystko u nas zadziała, jednak nie zawsze mamy tyle szczęścia. Nawet wykorzystanie dużej części STL może być problematyczne ze względu na dynamiczną alokację pamięci. Istnieją jednak biblioteki stworzone właśnie z myślą o mikrokontrolerach. W tym wpisie przybliżę kilka z nich, szczególnie pod kątem użycia w STM32.

Dlaczego warto pisać w C++

Zanim przejdę do opisu konkretnych bibliotek, odpowiem na pytanie po co w ogóle przesiadać się z czystego C. C++, a szczególnie jego nowe standardy, ma kilka istotnych zalet:

  • Redukcja duplikacji dzięki klasom i templatom.
  • Możliwość uniknięcia typowych błędów ze wskaźnikami dzięki referencjom i smart pointerom.
  • RAII ułatwia kontrolę czasu życia zasobów.
  • Dokładniejsze sprawdzanie typów i niejawnych rzutowań.
  • Rozbudowana biblioteka standardowa zawierająca implementacje struktur danych i algorytmów.

Dzięki tym funkcjom można po prostu tworzyć lepszy kod. Co więcej nie musi się to wcale wiązać ze spadkiem wydajności końcowej aplikacji.

Jak pokazują badania – C od wielu lat niepodzielnie króluje jako główny język systemów embedded. Jednak będzie się to powoli zmieniać. Mikrokontrolery mają coraz więcej RAM i FLASH. Programy muszą realizować coraz bardziej skomplikowane zadania. Dlatego bardziej zaawansowane języki jak C++ to przyszłość branży. Społeczności związane z C++, ale i innymi językami jak np. Rust, czy Go wykonują niesamowitą pracę w celu ich popularyzacji w systemach embedded.

Ograniczenia C++ w embedded

Decydując się na użycie C++ w embedded, musimy zdawać sobie sprawę, czego nie powinniśmy robić. Głównym ograniczeniem jest wykorzystanie heapa – a więc operatory new/delete, ewentualnie malloc/free. W embedded najlepiej, jakbyśmy w ogóle go nie używali. Korzystanie z dynamicznej alokacji pamięci jest niedeterministyczne, powoduje fragmentację i do efektywnego działania wymaga wykorzystania dużo większego obszaru pamięci niż jest rzeczywiście potrzebny. Więcej o problemach z heapem można przeczytać w tym artykule. Inne problemy niespotykane w tradycyjnych aplikacjach to brak wsparcia systemu operacyjnego, czy brak obsługi wyjątków.

To tyle tytułem wstępu, pora przejść do właściwej części, czyli bibliotek C++ na STM32.

Biblioteki do obsługi peryferiów

Headery pisane w C zawierające definicje wszystkich rejestrów procesora oraz ich pól bitowych są nieodłącznym elementem każdej biblioteki dla mikrokontrolerów. Jej użycie skutkuje powstaniem charakterystycznego kodu pełnego dziwnych symboli nie mających sensu jeżeli na bieżąco nie sprawdzamy wszystkiego z datasheetem. C++ oferuje tutaj obiecującą alternatywę. Można użyć biblioteki, która wychwyci podczas kompilacji wpisanie wartości na nieodpowiednim bicie, czy użycie stałej związanej z innym rejestrem. Jest kilka dostępnych bibliotek tego typu.

Kvasir

Ta biblioteka najbardziej przypadła mi do gustu. Wygląda na dosyć prostą w użyciu i mamy od razu wszystko, czego potrzebujemy łącznie z gotowymi headerami dla wielu modeli procesorów różnych rodzin i producentów. Biblioteka oparta jest na templatach, a poszczególne headery mogą być generowane z plików konfiguracyjnych. Jest napisana w standardzie C++11. Autorem Kvasir jest Odin Holmes, którego można było zobaczyć na Codedive i 4Developers. Jeżeli wystartuję z jakimś nowym projektem to będzie prawdopodobnie mój wybór nr 1.

Modm

Poczytałem sobie trochę o tej bibliotece i niesamowicie mi się spodobała. Podobnie jak poprzednio mamy templaty opakowujące rejestry i dodające static asserty. Biblioteki są generowane na podstawie plików konfiguracyjnych ściąganych ze stron producentów. Na przykład STM32 ściąga bibliotekę Cube MX i z javowych binarek wyciąga informacje o poszczególnych pinach i peryferiach. Dzięki temu ma nawet takie informacje jak możliwe alternatywne funkcje każdego pinu, czy do których kanałów DMA można podłączyć dane peryferia. Niestety kiedy ją ściągnąłem i się pobawiłem, okazało się, że nie jest tak różowo. Mamy skrypty do automatycznej generacji, ale działają tylko na Linuxie i MacOs. Brak wsparcia dla Windowsa. Próbowałem nawet trochę się pobawić i uruchomić ten proces. Nawet sporą część konfiguracji udało mi się przejść, ale ostatecznie poległem. Biblioteka wykorzystuje C++17, co może być minusem jeśli w swoich projektach używamy starszego standardu.

Xpcc

Starszy brat Modm. Działa z C++14 i wykorzystuje w dużej części te same toole do generacji. Wygenerowanie biblioteki na Windowsie prawdopodobnie także będzie dużym wyzwaniem. Nie ma też nigdzie dostępnego outputu z wygenerowanymi headerami.

libstm32pp

Ta biblioteka jest dużo mniej rozbudowana niż poprzednie. Została napisana pod C++11. Poza mechanizmem do wpisywania wartości do rejestrów posiada gotowe funkcje typu GPIOpin::setMode. W przeciwieństwie do poprzednich, biblioteka nie jest generowana na podstawie żadnej konfiguracji. Wszystko prawdopodobnie było dodane przez autora ręcznie. Na githubie można znaleźć kilka podobnych projektów np. stm32plus, czy stm32tpl.

Inne biblioteki

ETLCPP

Jest to biblioteka zastępująca STL i posiadająca implementacje popularnych struktur i algorytmów z biblioteki standardowej, które nie wykorzystują heapa. Została ona stworzona specjalnie z myślą o Embedded. Mamy więc vector, array,  set, iteratory itp. Dokumentacja jest dostępna na stronie projektu. Biblioteka wykorzystuje standard C++03. Jeżeli ruszę z nowym projektem, na pewno będę chciał ją wypróbować.

type_safe

Biblioteka wyłapująca niejawne konwersje między podstawowymi typami np. między intami signed i unsigned. Dodatkowo umożliwia tworzenie własnych typów, dla których można definiować dozwolone operacje. Dokładniejszy opis jest dostępny na stronie autora. Biblioteka na pewno jest przydatna do systemów safety-critical, gdzie staramy się unikać wszelkich niejawnych konwersji.

NamedType

Podobna biblioteka do poprzedniej – też umożliwia wykrywanie podczas kompilacji błędów konwersji między typami. Jednak jej głównym zadaniem jest tworzenie jawnych typów takich jak np. wysokość, czy długość. Dzięki temu możemy uniknąć błedów choćby przy przekazywaniu parametrów do funkcji – zamiast wielu argumentów typu int możemy je nazwać na przykład width, height.

debug_assert

Biblioteka do obsługi assertów lepsza niż standardowe assert.h. Mamy tu kilka dodatkowych opcji takich jak poziomy asercji, czy moduły. Dzięki temu możemy włączać/wyłączać asserty dla interesujących nas części kodu.

Systemy operacyjne

Distortos

RTOS napisany w C++11, który wygląda bardzo ciekawie. Został napisany głównie z myślą o STM32 i zawiera wszystkie potrzebne funkcjonalności takie jak priorytety tasków, mutexy, semafory czy kolejki. Autorem jest FreddieChopin, który na swojej stronie ma dużo innych ciekawych narzędzi takich jak skompilowane pod windowsa wersje debuggera OpenOCD, czy bleeding-edge-toolchain. Distortos również ląduje na mojej liście do użycia w kolejnym projekcie.

QP State Machines

Na koniec taka ciekawostka – framework na systemy embedded oparty o maszyny stanu. Umożliwia on pisanie softu korzystając z reactive programming. Workflow wygląda tak, że najpierw opisujemy nasz system za pomocą diagramów UML z maszynami stanu, a następnie generujemy z tego kod.

 

1 Comment

  1. Dzięki za wzmiankę o distortos, choć trochę szkoda, że dopiero na przedostatnim miejscu <:

    Jeśli użyjesz go w jakimś projekcie, to koniecznie daj znać. W projekcie obecnie bardzo sporo się zmienia, miejmy nadzieję że na lepsze, choć chwilowo są to głównie zmiany dotyczące magicznych generatorów kodu. Na udoskonalanie samych mechanizmów RTOSa (a lista potrzebnych zmian którą sobie zapisałem jest naprawdę długa) wciąż brak czasu…

1 Pingback

  1. Pingback: C++ bez exceptionów - ucgosu.pl

Dodaj komentarz

Your email address will not be published.

*

© 2018 ucgosu.pl

Theme by Anders NorénUp ↑