Rożne

Optymalizacja kodu w mikrokontrolerach

Autor: Laura McKinney
Data Utworzenia: 4 Kwiecień 2021
Data Aktualizacji: 16 Móc 2024
Anonim
Optymalizacje w C++ i wyniki wyzwania wydajnego kodu [webinar]
Wideo: Optymalizacje w C++ i wyniki wyzwania wydajnego kodu [webinar]

Zawartość

Autor zakończył swój ostatni projekt inżynierski z mikrokontrolerów dsPic, uzyskując obszerny wgląd w te urządzenia.

Kod w języku C mikrokontrolera może wymagać optymalizacji w niektórych zaawansowanych aplikacjach. Ta optymalizacja kodu jest praktykowana w celu zredukowania dwóch kluczowych rzeczy:

  1. Rozmiar kodu: Mikrokontrolery mogą przechowywać ograniczone dane i instrukcje ze względu na ograniczony rozmiar pamięci RAM. Dlatego kod należy zoptymalizować, aby dostępne instrukcje i pamięć danych mogły być wykorzystane w najbardziej efektywny sposób.
  2. Czas wykonania kodu: Mikrokontrolery to urządzenia sekwencyjne, które wykonują jedną instrukcję na raz. Każda instrukcja asemblera wymaga pewnej liczby cykli zegara, aby się wykonać. Dlatego kod musi być zoptymalizowany, aby zapewnić, że wykonuje wymagane zadanie w jak najmniejszej liczbie cykli zegarowych lub instrukcji montażu. Im mniej cykli zegara używa kod, tym szybciej działa. Oznacza to, że aplikacje mogą działać szybciej, ponieważ czasy przetwarzania są zminimalizowane.

W tym artykule przedstawiono porady i wskazówki, które można zastosować, aby zmniejszyć rozmiar i czas wykonania kodu mikrokontrolera.


W stosownych przypadkach do zademonstrowania przykładów zostanie użyte środowisko programistyczne MplabX firmy Microchip.

Jak eksperymentalnie mierzyć czas wykonania kodu

Aby dowiedzieć się, ile czasu zajmuje wykonanie kodu w czasie rzeczywistym, należy zmierzyć to eksperymentalnie. Analizator logiczny może być wygodnie użyty do pomiaru czasu wykonania kodu, a osoby zainteresowane mogą zapytać mnie o ten proces na e-mail. Poza tym:

  • Niektóre kompilatory mają możliwość zliczania cykli zegara, które zużywa kod.
  • Niektóre debuggery, na przykład ICD 3 firmy microchip, mogą bezpośrednio mierzyć czas wykonania za pomocą stopera.

1. Poznaj moc obliczeniową i rozmiar pamięci swojego mikrokontrolera

Nie zawsze częstotliwość zegara (MHz) daje prawdziwy obraz szybkości przetwarzania mikrokontrolera, bardziej realistyczną miarą jest MIPS (mega instrukcje na sekundę) lub liczba instrukcji, które MCU może wykonać w ciągu sekundy.

Mikrokontrolery zwykle mieszczą się w zakresie od 60–70 MIPS w kategorii high-end do 20 MIPS 8-bitowych AVR. Mikrokontroler o wysokim MIPS prawdopodobnie będzie droższy niż urządzenie z niższej półki, więc tutaj masz kompromis między kosztem a szybkością przetwarzania.


Mikrokontrolery mają oddzielną pamięć do przechowywania danych i kodu programu. Rozmiar obu z nich można znaleźć w arkuszu danych. Możesz potrzebować MCU z większym rozmiarem pamięci, jeśli twój kod jest znacznie duży.

2. Wybór zmiennych do optymalizacji rozmiaru kodu

Mikrokontrolery mają ograniczoną pamięć danych, zwykle w zakresie od 1 do 4 KB. W takim przypadku warto wybrać najbardziej odpowiedni typ zmiennej zgodnie z oczekiwanym zakresem przechowywanej daty. Poniższa tabela podsumowuje te zmienne:

Podsumowanie zmiennych używanych w języku C.

Typ zmiennejRozmiar w bajtachZasięg

bool

1

Tylko 0 lub 1

zwęglać

1


-128 do 127

int

2

-32 768 do 32767

unsigned int

2

Od 0 do 65 535

długo

4

-2 147 483 648 do 2 147 483 647

pływak

4

Dokładne do 6 miejsc po przecinku

podwójnie

8

Dokładne do 15 miejsc po przecinku

długie podwójne

10

Dokładne do 19 miejsc po przecinku

Przykład:

  • Jeśli mają zostać dodane dwie zmienne X i Y, a wynik ma być przechowywany w Z, ale oczekuje się, że wartość Z będzie większa niż 65 535 po dodaniu, wówczas Z można zadeklarować jako długie, a X i Y można zadeklarować jako bez znaku int, wartości X i Y również nie powinny być ujemne. Pozwoli to zaoszczędzić 04 bajtów w pamięci danych, które w innym przypadku zostałyby wykorzystane, gdyby wszystkie zmienne były zadeklarowane jako długie.
  • Dwie zmienne X i Y, których wartości mają być liczbami całkowitymi, mają być podzielone, ale wynik dzielenia może dać ułamek dziesiętny, wtedy X i Y można zadeklarować jako int, a wynik można zadeklarować jako zmiennoprzecinkowy lub podwójny w zależności od wymagana precyzja.

Wybór typu danych może mieć kluczowe znaczenie przy deklarowaniu tablic zawierających dużą liczbę elementów.

3. Wybór zmiennych do optymalizacji czasu wykonania kodu

  • Jest ustalonym faktem, że obliczenia zmiennoprzecinkowe trwają dłużej niż obliczenia stałoprzecinkowe. Nie używaj zmiennej zmiennoprzecinkowej, gdy wartość dziesiętna nie jest wymagana. Jeśli to możliwe, pracuj z liczbami całkowitymi bez znaku.
  • Zmienne lokalne są preferowane od zmiennych globalnych. Jeśli zmienna jest używana tylko w funkcji, musi być zadeklarowana w tej funkcji, ponieważ dostęp do zmiennych globalnych jest wolniejszy niż do zmiennych lokalnych.
  • 8-bitowy mikrokontroler znajdzie jedną zmienną o rozmiarze jednego bajtu, do którego jest szybszy dostęp, a 16-bitowy mikrokontroler będzie miał łatwiejszy dostęp do zmiennej 2-bajtowej ze względu na długość generowanego adresu.

4. Optymalizacja operacji arytmetycznych

Operacje arytmetyczne można optymalizować na następujące sposoby.

  1. Użyj tabel przeglądowych wstępnie obliczonych wartości zamiast obliczać sinus lub inną funkcję trygonometryczną lub jakąkolwiek inną operację, której wynik może być wcześniej znany w kodzie.
  2. W przypadku, gdy tablica przeglądowa sinus jest już przechowywana w pamięci, cosinus może być oszacowany przez przesunięcie wskaźnika tablicy o 90 stopni do przodu.
  3. Spośród czterech operacji arytmetycznych, dzielenie i mnożenie zajmują najwięcej czasu przetwarzania, w praktyce może to być rzędu setek mikrosekund w przypadku wartości zmiennoprzecinkowych.
  4. Użyj instrukcji przesunięcia bitowego zamiast dzielenia i mnożenia. Instrukcja zmiany 3 w prawo służy do podzielenia przez 23 gdzie jako instrukcja przesunięcia w lewo 1 posłuży do pomnożenia przez 21.

5. Użyj mikrokontrolera z obsługą DSP do intensywnych obliczeń

Niektóre mikrokontrolery mają jednostkę przetwarzającą DSP inną niż konwencjonalna jednostka ALU wbudowana w ich architekturę. Ten silnik DSP jest przystosowany do wykonywania obliczeń arytmetycznych bardzo szybko w najmniejszej liczbie cykli zegara (w większości przypadków jeden) wielokrotnie szybciej niż ALU.

Instrukcje, które procesor DSP może wykonać szybciej niż ALU to:

  • Instrukcje przesuwania i obracania bitu.
  • Mnożenie, dzielenie i inne operacje arytmetyczne.
  • Obliczanie sinusów i innych funkcji trygonometrycznych.
  • Wszystkie operacje DSP, takie jak FFT, DFT, splot i filtrowanie FIR.

Korzystanie z silnika DSP mikrokontrolera wymaga, aby:

  • Projekt zawiera oddzielne biblioteki DSP.
  • Nazwy funkcji różnią się od standardowych bibliotek matematycznych języka C. Dokumentację tych bibliotek i funkcji można znaleźć na stronach internetowych odpowiednich producentów.
  • Silnik DSP wykorzystuje inny typ zmiennej „ułamkowej”. Dowiedz się, jak używać zmiennych typu ułamkowego przed kontynuowaniem korzystania z funkcji biblioteki dsp.

Zauważ, że standardowe funkcje biblioteki matematycznej nie będą wywoływać silnika DSP, ponieważ są tłumaczone na instrukcje asemblera ALU.

6. Praca z przerwaniami

Używaj przerwań do wykonywania określonych funkcji, takich jak:

  • Czytanie wartości ADC.
  • Wysyłanie i odbieranie z UART.
  • Aktualizacja rejestrów cyklu pracy PWM.
  • Komunikacja CAN lub I2C.

Przerwania będą obsługiwać te funkcje szybciej w porównaniu z wykonywaniem ich w głównej części za pomocą wywołania funkcji lub kodu wbudowanego.

Przerwania będą również wyzwalane tylko wtedy, gdy jest to wymagane, podczas gdy kod zostanie zakodowany w treści głównej, kod będzie wykonywany w każdej iteracji pętli while (1).

7. Użyj najlepszych dostępnych kompilatorów

Kompilatory mogą automatycznie implementować niektóre z optymalizacji omówionych powyżej podczas tłumaczenia kodu z języka C na język asemblera, jeśli są odpowiednio skonfigurowane. Poszukaj opcji optymalizacji w swoim kompilatorze i, jeśli to możliwe, zaktualizuj kompilatory do profesjonalnych wersji, ponieważ są one bardziej wydajnymi optymalizatorami kodu.

8. Inteligentnie używaj instrukcji warunkowych

  • Używając serii instrukcji if-else, najpierw zachowaj najbardziej prawdopodobny warunek. W ten sposób MCU nie będzie musiało przeszukiwać wszystkich warunków po znalezieniu prawdziwego stanu.
  • Instrukcja switch-case jest zwykle szybsza niż if-else.
  • Użyj zagnieżdżonych instrukcji if-else zamiast serii instrukcji. Blok if-else zawierający wiele instrukcji można podzielić na mniejsze podgałęzie w celu optymalizacji pod kątem najgorszego (ostatniego) warunku.

9. Użyj funkcji wbudowanych

Funkcje, które mają być użyte w kodzie tylko raz, można zadeklarować jako statyczne. Spowoduje to, że kompilator zoptymalizuje tę funkcję do funkcji wbudowanej, a zatem żaden kod asemblera nie zostanie przetłumaczony dla wywołania funkcji.

  • Funkcję można zadeklarować w tekście, używając wraz z nią słowa kluczowego „static”.

10. Użyj zdekrementowanych pętli

Zmniejszona pętla wygeneruje mniej kodu asemblera w porównaniu z przyrostową pętlą.

Dzieje się tak, ponieważ w pętli przyrostowej potrzebna jest instrukcja porównania, aby porównać indeks pętli z maksymalną wartością w każdej pętli, aby sprawdzić, czy indeks pętli osiąga maksymalną wartość. Wręcz przeciwnie, w pętli dekrementacji to porównanie nie jest już potrzebne, ponieważ zmniejszony wynik indeksu pętli ustawi flagę zerową w SREG, jeśli osiągnie zero.

Biorąc pod uwagę, że pętla musi iterować sto razy, zmniejszenie jednej instrukcji z pętli pozwoli uniknąć jej wykonania sto razy, więc wpływ będzie prawdopodobnie bardziej znaczący, gdy pętla będzie musiała powtarzać wiele razy.

Podsumowanie

Te wskazówki mogą być pomocne, ale ich prawdziwe zastosowanie i moc zależy od umiejętności programisty i poleceń, które ma na swoim kodzie. Pamiętaj, że rozmiar programu nie zawsze determinuje czas wykonania, niektóre instrukcje mogą zużywać więcej cykli zegara niż inne, więc po raz kolejny umiejętności programu muszą odegrać swoją rolę.

Ten artykuł jest dokładny i zgodny z najlepszą wiedzą autora. Treści służą wyłącznie do celów informacyjnych lub rozrywkowych i nie zastępują osobistych porad ani profesjonalnych porad w kwestiach biznesowych, finansowych, prawnych lub technicznych.

Fascynujące Posty

Wybór Strony

Jak wydrukować Hello World w Swift
Komputery

Jak wydrukować Hello World w Swift

Doświadczony admini trator / inżynier y temów z ponad 10-letnim doświadczeniem w zarządzaniu infra trukturą erwerową i operacjami centrów danych. wift to język programowania opracowany przez...
Co to jest Mukbang?
Internet

Co to jest Mukbang?

Rachelle je t pi arką internetową od ponad dziewięciu lat i lubi pi ać o celebrytach, technologii, telewizji, grach wideo i prawdziwej zbrodni.Tradycyjnie Mukbang to wideo, w którym o oba zjada d...