Języki programowania w systemach wbudowanych

Języki programowania w systemach wbudowanych

Ogromna większość współczesnych urządzeń elektronicznych zawiera układy programowalne. Mikrokontrolery, procesory, SoC, SoM, FPGA… wszystkie one mają jedną wspólną cechę – do działania potrzebują oprogramowania. Za tworzenie tego kodu odpowiedzialni są programiści systemów wbudowanych. Ten dział elektroniki ewoluuje w takim tempie, jakie nieznane jest innym dziedzinom. Technologie z zakresu oprogramowania wbudowanego zmieniają się niemal z każdą nową rodziną/architekturą układów programowalnych.

W szybko zmieniającym się świecie software’u nauka nie kończy się nigdy. Dobry programista embedded, aby nadążyć za technologicznymi trendami, musi ciągle się szkolić. Od czego jednak ma zacząć młody programista, który dopiero stawia pierwsze kroki w świecie systemów wbudowanych? W artykule przyjrzymy się dwóm kluczowym obszarom tego sektora i postaramy się powiedzieć o językach programowania w systemach wbudowanych.

Czy C musi przejść na emeryturę?

Język programowania C jest bez wątpienia jednym z najpopularniejszych języków w całej historii informatyki. Przyczyn tego jest wiele i wykraczają one poza zakres tego artykułu, dlatego po prostu skupimy się na wynikach badań dotyczących popularności tego języka programowania.
W czasie ostatnich 20 lat język C uznawany był nieprzerwanie za jeden z dwóch najpopularniejszych języków programowania na świecie (rysunek 1) w rankingu TIOBE Programming Index. Jest to również najpopularniejszy język wśród twórców systemów wbudowanych i jest używany w prawie 80% wszystkich projektów wbudowanych.

Rysunek 1. Ranking języków TIOBE Programming Community Index na przestrzeni ostatnich 20 lat. Widać doskonale, że C zawsze był jednym z dwóch wiodących języków

Język C wprowadzony został na początku lat 70. XX wieku. Po raz pierwszy publicznie zaprezentowano go w 1972 roku, co oznacza, że niedawno świętował swoje pięćdziesięciolecie. Czy po pół wieku użytkowania tego języka nadszedł może czas, aby programiści systemów wbudowanych przeszli na bardziej nowoczesny język? Czy nadszedł czas, aby język C przeszedł na emeryturę?

Pokusa, aby zrezygnować z C i przejść na bardziej nowoczesny język programowania, jest stosunkowo duża z kilku powodów. Po pierwsze, początkujący inżynierowie, często bardzo poszukiwani przez firmy technologiczne, mają niewielkie lub żadne doświadczenie z programowaniem w C. Dodatkowo, współcześnie programy nauczania na uniwersytetach i politechnikach koncentrują się na nauczaniu nowszych języków, takich jak Python czy C++. Zdobycie doświadczenia w zakresie programowania w C może w związku z tym wymagać znacznych inwestycji finansowych i czasowych, a umiejętnością tą interesuje się niewiele firm, szczególnie poza sektorem oprogramowania embedded. Po drugie, choć bardzo popularny, język programowania C jest generalnie przestarzały. Język ten nie obsługuje nowoczesnych koncepcji programowania, takich jak klasy i dziedziczenie. Jeśli porównamy zestawy funkcji współczesnych języków, takich jak C++, Python i Rust, język C mocno od nich odstaje. Oczywiście C cały czas ewoluuje, ale ostatni raz dodano nowe funkcje do standardu C w 2011 roku, a wersja standardu z 2017 roku (zwana C17 lub C18) zawierała tylko poprawki techniczne i wyjaśnienia. Kolejna wersja standardu najpewniej ukaże się w 2023 roku (C23) ale nic nie zapowiada, aby dodano do niej jakieś przełomowe funkcjonalności.

Zatem wycofywanie C nadal wygląda kusząco, jednak odejście od tego języka wiąże się z kilkoma problemami. Po pierwsze – C to świetny język dla aplikacji proceduralnych niskiego poziomu, które działają blisko sprzętu. Co w zasadzie doskonale opisuje sektor oprogramowania wbudowanego. Język C jest kompaktowy i bardzo wydajny. Dodatkowo, starsi inżynierowie są mocno zakorzenieni w tym języku. Są w punkcie, w którym używają tego języka od dziesięcioleci i nie są realnie zainteresowani nauką nowego języka. Tak samo wiele starszych bibliotek i dużo starszego kodu używa języka C. Nie można ich tak po prostu porzucić, a koszty przeniesienia starszego kodu byłby po prostu zbyt duże do zaakceptowania.

Czy to oznacza, że branża systemów wbudowanych utknęła z C? Jest to pewien dylemat. Branża powinna wycofywać C, oraz stosować bardziej nowoczesne języki i techniki, ale czas i koszty tych zmian oraz ilość istniejącego starszego kodu, który trzeba utrzymywać, często przeszkadzają w wycofaniu się ze stosowania tego języka.

Istnieje zatem potrzeba implementowania bardziej nowoczesnych technik, a jednocześnie potrzeba zatrzymania korzyści, jakie daje stosowanie C, może skutecznie zniechęcić do używania jednego dominującego języka i zmusza branżę do polegania na wielu językach w tworzeniu oprogramowania embedded.

Używanie innych języków do uzupełniania C już teraz ma miejsce. W tabeli 1 został pokazany ranking kilku języków w indeksie TIOBE. W przeszłości w informatyce dominował jeden lub dwa języki. Obecnie wszystkie cztery najlepsze języki mają zastosowanie na poziomie około 10%. Oczywiście, dotyczy to całego sektora IT, a nie tylko urządzeń wbudowanych, jednak wskazuje to na koniec pojedynczych dominujących języków. Zamiast tego programiści stosują teraz kilka języków, aby osiągnąć swoje cele projektowe.

Jakie są alternatywy dla C?

Oprócz znanych od dawna języków, będących alternatywami dla C, takimi jak MicroPython, C++ czy Basic, pojawia się wiele nowych, które stosowane są w systemach wbudowanych. Go, Rust i ParaSail to trzy języki, które pojawiły się około 15 lat temu. Każdy z nich prezentuje własne podejście do zarządzania złożonością przy jednoczesnym wspieraniu równoległości. Ten aspekt jest niezwykle istotny, jako że wiele obecnych aplikacji wbudowanych działa na sprzęcie wielordzeniowym, co w naturalny sposób umożliwia wprowadzanie równoległości działania kodu.

Język programowania Go

Go, któremu patronuje Google, to pomysł Roba Pika i jego kolegów z Google. Rob pracował w Bell Labs we wczesnych czasach Unixa i C, a Go pod wieloma względami dziedziczy tradycję prostoty i mocy języka C. W przeciwieństwie do C, zarządzanie pamięcią zostało przejęte przez środowisko uruchomieniowe Go poprzez ogólne podejście do wyrzucania elementów bezużytecznych, ale podobnie jak w C, nadal potrzebna jest ostrożność w wielu obszarach, aby zapewnić ogólne bezpieczeństwo programu.

Go ma kilka niezwykłych funkcji. To, czy deklaracja zostanie wyeksportowana, zależy od tego, czy jej nazwa zaczyna się od dużej litery (zgodnie z definicją Unicode). Jeśli deklaracja jest deklaracją na poziomie pakietu lub jest deklaracją pola lub metody, to, jeśli nazwa zaczyna się od dużej litery, deklaracja jest widoczna poza bieżącym pakietem. Każdy plik źródłowy Go zaczyna się od specyfikacji pakietu, który definiuje. Jeden plik źródłowy może importować deklaracje z innego, określając ścieżkę do pliku zawierającego deklaracje, ale w kodzie importującym odniesienia do eksportowanych deklaracji importowanego kodu są przy użyciu nazwy pakietu importowanego pliku, która nie musi być zgodna z nazwą pakietu importowanego pliku. Oczywiście w realnych projektach zwykle wdrażana jest jakaś standardowa konwencja nazewnictwa, która łączy nazwy plików źródłowych i nazwy pakietów.

W Go nie ma niezainicjowanych zmiennych. Jeśli zmienna nie jest jawnie zainicjowana podczas deklarowania, jest domyślnie inicjowana na zero (swojego typu), gdzie każdy typ ma odpowiednio zdefiniowane zero, zwykle albo zerową wartość liczbową, albo zerową (null) wartość wskaźnika, lub jakiś inny obiekt. W przypadku struktur i bardziej złożonych typów, inicjowane są one w stanie, w którym wszystkie komponenty mają wartość umownie uznaną za zerową.

Język programowania Rust

Język Rust powstał pierwotnie, jako osobisty projekt jednego z inżynierów z Mozilla Research – Graydona Hoare. Obecnie jego rozwój jest sponsorowany przez Mozillę i stał się swojego rodzaju przedsięwzięciem badawczym. Rust został zaprojektowany, by uporać się ze złożonością budowania komponentów nowoczesnego oprogramowania zorientowanego na przeglądarkę. Język ten opracowano do kontroli nowoczesnego, rozproszonego, wielordzeniowego środowiska sprzętowego.

Podobnie jak Go, w Rust zdecydowano się uprościć zarządzanie pamięcią, wbudowując wyrzucanie elementów bezużytecznych (garbage collector) w język. W przeciwieństwie do Go, w Rust zdecydowano się ograniczyć jego działanie do stert poszczególnych zadań i przyjąć unikalną politykę własności danych, które mogą być wymieniane między zadaniami. Oznacza to, że dane, które mogą być współdzielone między zadaniami, są widoczne tylko dla jednego z nich w danym momencie i tylko za pośrednictwem jednego wskaźnika na raz (stąd wskaźnik będący właścicielem). Eliminuje to możliwość powstawania hazardów w pracy w systemach wielowątkowych i eliminuje potrzebę odśmiecania pamięci dla globalnego stosu wymiany danych. Po odrzuceniu wskaźnika będącego właścicielem, pamięć wyznaczona przez ten wskaźnik może zostać natychmiast odzyskana – więc żadne śmieci nie gromadzą się na globalnej stercie wymiany danych.

Język programowania ParaSail

Język ParaSail firmy AdaCore wspiera równoległość o krok dalej niż Go czy Rust, traktując wszystkie oceny wyrażeń w języku, jako w założeniu równoległe, jednocześnie obejmując swoją konstrukcją pełne bezpieczeństwo typowania zmiennych i ochronę przed wystąpieniem hazardów. Zamiast zwiększać złożoność, aby to osiągnąć, wyraźnym celem twórców ParaSail było osiągnięcie bezpieczeństwa i zrównoleglenia operacji poprzez uproszczenie języka. Niektóre funkcje pominięte w ParaSail obejmują:

  • brak wskaźników,
  • brak zmiennych globalnych,
  • brak obsługi wyjątków w czasie wykonywania,
  • brak jawnych wątków, jawnego blokowania ani sygnalizacji,
  • brak jawnej sterty, co przekłada się na brak konieczności odśmiecania pamięci,
  • brak aliasingu parametrów.

Kluczowe narzędzia programistów

W Manifeście Agile czytamy, że „Dochodzimy do tego, by bardziej cenić jednostki i interakcje niż procesy i narzędzi”.. Zwykle okazuje się, że programiści (nie tylko systemów wbudowanych) nie tylko kochają swoje narzędzia, ale mają wręcz na ich punkcie obsesję. Często zadawanym pytaniem w tych kręgach jest: „Jakiego narzędzia użyłeś do tego”.. Blogi i filmy, które omawiają narzędzia, wydają się być znacznie częstsze i lepiej zrealizowane niż te, które objaśniają procesy, umiejętności korzystania z języka itp. Programiści są bardzo często zainteresowani narzędziami, co rodzi interesujące pytania. W dalszej części artykułu omawiamy pewne obszary, gdzie często stosowane są pomocne narzędzia dla programistów, jednak – intencjonalnie – nie wymieniamy ich z nazwy. Każdy programista preferować może inne narzędzia, to kwestia bardzo subiektywna. Ponadto dynamika zmian w tym sektorze jest ogromna, a chcemy, by ten artykuł zachował aktualność dłużej, niż przez rok czy dwa...

Jakie jest najważniejsze narzędzie dostępne dla programistów systemów wbudowanych?

To pytanie może mieć tyle odpowiedzi, ilu jest programistów embedded. Na ogół otrzymamy na nie odpowiedź: „To zależy”.. Każdy napotyka inne wyzwania, wykorzystuje inne środowiska, które mogą radykalnie zmieniać to, jakie narzędzia są mu potrzebne i jakie są dla niego najbardziej pomocne. Istnieją jednak trzy obszary – triada oprogramowania wbudowanego – w których odpowiednie narzędzia mogą pomóc zespołom odnieść sukces, pod warunkiem, że pamiętają one, że narzędzia te nie są najważniejsze.

Architektura i projektowanie oprogramowania

Architektura oprogramowania ma kluczowe znaczenie dla każdego systemu wbudowanego. System taki musi być skalowalny, elastyczny i nadawać się do wielokrotnego użytku. Architektura oprogramowania to tak jakby plan działania tego oprogramowania. Dlatego korzystanie z narzędzi do tworzenia tego planu ma kluczowe znaczenie dla programistów i zarządzających procesem tworzenia oprogramowania.

Narzędzia do projektowania architektury oprogramowania mogą obejmować zarówno narzędzia, w których architektura jest tworzona w języku UML, jak i narzędzia, które mogą pozwolić na modelowanie systemu czy jego symulację. Narzędzia te mogą być darmowe lub open-source, komercyjne, a nawet opracowane wewnętrznie przez zespół – często stosuje się tutaj oprogramowanie napisane np. w Pythonie lub innych współczesnych językach. Tutaj główne zagadnienie polega na znalezieniu narzędzi, które pozwolą na opracowanie, przetestowanie, a nawet i wdrożenie czystej i przejrzystej architektury, tak, by zminimalizować czas poświęcony później na samo opracowanie oprogramowania dla systemu wbudowanego.

Agile, DevOps i procesy

Bez względu na to, jak duży lub mały jest zespół, w którym tworzymy oprogramowanie, potrzebne jest stoswanie procesów zapewniających spójność i wysoką jakość opracowywanego oprogramowania. Zespoły programistów embedded podchodzą do tego bardzo różnie, od grup, które rozprowadzają kod jak na dzikim zachodzie po zespoły zdyscyplinowane i zorientowane na zwinne procesy. Z biegiem czasu to zespoły, które wdrożyły odpowiednie procesy, odniosły największe sukcesy.

Obecnie dostępnych jest wiele doskonałych narzędzi, które mogą pomóc zespołom w zarządzaniu ich codziennymi działaniami. Niektóre narzędzia będą się różnić w zależności od tego, czy stosuje się metodologię Agile, a nawet w zależności od konkretnej wdrożonej metodologii. Na przykład niektóre narzędzia umożliwiają wykorzystanie Test-Driven Development (TDD, gdzie tworzenie oprogramowania jest sterowane testami), czy Continuous Integration / Continuous Deployment (CI/CD – ciągła integracja/ciągłe wdrażanie, proces, w którym oprogramowanie jest po każdej, drobnej zmianie, integrowane i testowane).

Narzędzia procesowe nieustannie się zmieniają i ewoluują. W ciągu ostatnich kilku lat narzędzia do zarządzania projektami stały się bardziej stabilne, co nie zmienia faktu, że wszystkie narzędzia, które umożliwiają CI/CD czy DevOpsing, napędzają dalsze zmiany w zakresie paradygmatów tworzenia oprogramowania.

Rozwój oprogramowania

Narzędzia do tworzenia oprogramowania to te, którymi programiści są zwykle najbardziej zainteresowani. Narzędzia te umożliwiają edycję, kompilację, testowanie i analizę kodu. Istnieje duży nacisk ze strony programistów na korzystanie z narzędzi open-source. Dostępne są bardzo świetne i mogące zapewnić wiele wartości narzędzia, jednak na ogół otwarte i darmowe narzędzia mają pewne ograniczenia. Narzędzia komercyjne z kolei mogą poważnie zaszkodzić naszemu portfelowi, ale mogą też zwiększyć elastyczność i wygodę programowania, dzięki czemu w pewnym momencie inwestycje zwracają się (lub też nie – wszystko zależy od rachunku kosztów i zysków).

Należy pamiętać, że narzędzia związane z tworzeniem oprogramowania nieustannie się zmieniają. Jeśli spojrzymy na narzędzia, które były używane kilka lat temu i porównamy je z obecnymi, to widać, że nawet połowa z nich się zmieniła. Stopień wymiany narzędzi może nawet bardziej postępować, a zbliżające się technologie narzędzi programistycznych korzystających z uczenia maszynowego tylko przyspieszą tempo tej wymiany.

Podsumowanie

Narzędzia, z których, na co dzień korzystają zespoły zajmujące się tworzeniem rozwiązań wbudowanych, nieustannie się zmieniają i ewoluują. Mimo swojej dominacji, język C powoli ustępuje innym językom, a główną przyczyną niewielkiego tempa tych zmian jest przyzwyczajenie branży i ogrom pracy, potrzebnej do zmiany języka, przepisania bibliotek itd.

W zakresie stosowanych narzędzi zmiany są o wiele szybsze, szczególnie, że ich rozwój napędzany jest przez cały sektor IT. Narzędzie o kluczowym znaczeniu dla programistów dzisiaj prawdopodobnie zostaną odrzucone za kilka lat na rzecz nowszego narzędzia oferującego niższe koszty, krótszy czas wprowadzania na rynek lub wyższy zwrot z inwestycji dla firmy. To, które narzędzie jest w danym momencie najważniejsze, będzie zależeć głównie od własnych przyzwyczajeń, potrzeb i konkretnego zadania, jakie stawiane jest przed programistą. Z pewnością jednak, wszystkie narzędzia, wspierające zwinny rozwój oprogramowania, będą coraz istotniejsze, również w sektorze oprogramowania wbudowanego.

Nikodem Czechowski, EP

Bibliografia

Artykuł ukazał się w
Elektronika Praktyczna
czerwiec 2023
Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik grudzień 2024

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio listopad - grudzień 2024

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka, Podzespoły, Aplikacje listopad - grudzień 2024

Automatyka, Podzespoły, Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna grudzień 2024

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich styczeń 2025

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów