W większości projektów najważniejszym komponentem jest mikrokontroler – i to jego można postrzegać jako głównego „prądożercę”. Na szczęście doskonale wiedzą o tym też producenci półprzewodników, dlatego od lat walczą o klienta, oferując coraz większą wydajność, coraz sprytniejsze peryferia czy też coraz mniejsze zapotrzebowanie na energię. Łatwo się w tym gąszczu ofert pogubić, a do tego noty katalogowe i strony produktów zawsze prezentują parametry danego komponentu zmierzone w najbardziej optymistycznych warunkach. Warto ponadto zastanowić się, czy lepiej byłoby wykonywać program z wolniejszym, aczkolwiek oszczędniejszym zegarem, czy jednak zwiększyć częstotliwość kosztem poboru prądu, aby szybciej skończyć zadanie i uśpić układ na dłużej. Na potrzeby porównania przyjmiemy kilka prostych założeń:
- program jest wykonywany raz na sekundę, a jego wykonanie zajmuje 2000 cykli programu;
- raz na sekundę wykonywany jest pomiar za pomocą ADC, w czasie którego mikrokontroler pozostaje uśpiony;
- do cyklicznego rozpoczynania egzekucji programu stosowany jest timer watchdog.
W ramach porównania wyliczony będzie średni pobór prądu przy napięciu zasilania 3 V lub 3,3 V (zależnie od tego, które dane są dostępne w notach) i dla różnych częstotliwości zegarowych dostępnych bez użycia zewnętrznego rezonatora. Ponieważ najwięcej doświadczenia mam z mikrokontrolerami firmy Microchip, właśnie one zostały wybrane do tych rozważań. Pobieżny przegląd not katalogowych procesorów różnych innych rodzin oraz producentów wskazuje na to, że nie ma między nimi dramatycznych różnic i w każdej rodzinie układów można znaleźć kilka dobrych alternatyw.
Microchip PIC, dsPIC/PIC24 i PIC32
Microchip od lat rozwija własną technologię XLP, nazywaną też nanoWatt. Sam spotkałem się z nią po raz pierwszy ponad dekadę temu, gdy zacząłem uczyć się programowania na układzie PIC18F45K50. Od tamtej pory zaobserwowałem spory postęp. Na przedstawiciela ośmiobitowych PICów wybrany został PIC18F27Q10, jeden z nowszych produktów z tej kategorii w ofercie Microchipa. Mikrokontroler ten oferuje bogaty zestaw rozbudowanych peryferiów, zapewniając przy tym dużą energooszczędność – nieużywane peryferia są wyłączone i nie pobierają prądu. W ramach oszczędności energii układ oferuje też rozbudowany system zegarowy oraz możliwość częściowego lub całkowitego uśpienia CPU. Producent chwali się również bardzo niskim poborem prądu: 900 nA przy 1,8 V w stanie uśpienia z aktywnym watchdogiem.
Posługując się notą katalogową, możemy policzyć średni pobór prądu przy dwóch ustawieniach zegara: LFINTOSC 31 kHz i HFINTOSC 4 MHz. Wartości poboru prądu dla obu częstotliwości trzeba odczytać z wykresów, co obarczone jest pewnym błędem. Dla LFINTOSC można przyjąć pobór 2,7 μA przy 3 V, a dla HFINTOSC będzie to już 500 μA przy 4 MHz. ADC w trakcie konwersji – gdy rdzeń pozostaje nieaktywny – pobiera 330 μA, a CPU w stanie uśpienia potrzebuje tylko 1,5 μA, wliczając w to zasilanie watchdoga. Poza poborem prądu musimy też znać czas wykonywania kodu i czas trwania konwersji ADC.
Przetwornik analogowo-cyfrowy potrzebuje 11TAD + 3TCY. TAD to czas jednego cyklu konwersji, w tym wypadku będzie to okres wewnętrznego oscylatora ADC, wynoszący typowo 2,2 μs. TCY jest natomiast czasem trwania jednej instrukcji, w przypadku LFINTOSC wynosi on 129 μs, a przy 4 MHz sięga 1 μs. Te liczby wynikają z faktu, że jedna instrukcja wykonuje się przez cztery cykle zegarowe. Musimy też doliczyć czas startu oscylatora HFINTOSC: 100 μs. Tabela 1 zawiera wyliczone czasy i pobór prądu na poszczególnych etapach pracy układu oraz uśrednione wartości natężenia prądu. Przy obliczaniu prądu uwzględniono też fakt, że zużycie go przez różne komponenty sumuje się, gdyż LFINTOSC nigdy się nie zatrzymuje (taktuje bowiem blok watchdog) i oba są używane przez ADC zależnie od ustawionej częstotliwości pracy. Średni pobór został wyliczony metodą pokazaną w poprzedniej części artykułu.
Jak widać, z wolniejszym zegarem można zaoszczędzić 28,7% energii tylko na średnim poborze prądu. To całkiem sporo, choć same wartości liczbowe wydają się znikome.
Spójrzmy teraz na układy 16-bitowe serii PIC24/dsPIC. Tutaj sytuacja nieco bardziej się komplikuje ze względu na fakt, w jak wielu spośród tych układów zdarzają się różne błędy w krzemie, czasami wpływające też na pobór prądu. Na przedstawiciela układów 16-bitowych wybrany został PIC24FJ128GC010.
Układy z tej rodziny łączą w sobie rozbudowane peryferia analogowe z wieloma możliwościami oszczędzania energii. Dodatkowo Michrochip dodał sprzętową obsługę wyświetlaczy LCD, interfejs USB i dość szybkie CPU (16 MIPS) z hardware’ową realizacją mnożenia i dzielenia w jednym cyklu. Z naszego punktu widzenia użyteczną funkcją może być bateryjne podtrzymywanie pamięci oraz modułu RTCC. Tabela 2, ukazuje średni pobór prądu w przypadku naszego przykładowego programu korzystającego zegarów 31 kHz i 2 MHz przy napięciu zasilania 3,3 V.
W opisanym przykładzie to szybszy zegar prowadzi, a różnica wynosi 19,4%. Co ważne, im dłuższy program – przy tych samych zegarach – tym bardziej zaobserwowana przewaga będzie wzrastać.
W przypadku PIC32 mamy o tyle ciekawą sytuację, że przez lata Microchip używał architektury MIPS32 – ale po akwizycji firmy Atmel przez wspomnianego producenta do jego oferty dołączyły mikrokontrolery serii SAM, a potem PIC32 z rdzeniami ARM Cortex-M23 o niższym poborze prądu. Na reprezentanta układów 32-bitowych został jednak wybrany mikrokontroler z rdzeniem MIPS32 microAptiv, PIC32MM0256GPM036. Nie jest to ani najbardziej rozbudowany mikrokontroler z całej rodziny MIPS32, ani też najszybszy – za to na pewno energooszczędny. Tabela 3 pokazuje wyniki pomiaru prądu przy napięciu zasilania 3,3 V.
Tym razem różnica okazuje się dramatyczna – użycie szybszego zegara zmniejsza średni pobór prądu 3,9 razy! Nadal jednak pobór prądu pozostaje znaczny, zwłaszcza gdy porównamy go z układami 8- i 16-bitowymi. PIC32MM0256GPM036 w naszym przykładzie pobiera 4 razy więcej energii niż PIC18F27Q10. Czytelnik może zatem zadać sobie pytanie, na co komu więcej bitów, skoro ośmiobitowiec wygrywa pod względem oszczędności energii? Odpowiedź jest prosta: wszystko zależy od założeń projektowych i programistycznych.
Więcej mocy!
W naszym przykładzie program był prosty i rzadko wykonywany. Sytuacja zmienia się wtedy, gdy wymaga on na przykład zaawansowanych obliczeń matematycznych. Programowe mnożenie i dzielenie dwóch zmiennych to relatywnie powolny proces, jeśli mikrokontroler nie zapewnia mu wsparcia sprzętowego. Nawet operacja dodawania lub odejmowania może zająć sporo cykli, gdy wykonujemy ją na liczbach 32- lub 64-bitowych, a ALU jest ośmiobitowe. W przypadku prostych programów nie stanowi to dużego problemu, jeśli jednak kod wymaga wielu różnych operacji na dużych liczbach, na przykład do przetwarzania danych o zmianach położenia i prędkości, to osiem bitów nie wystarczy.
Ale nie tylko do obliczeń przyda się szybszy i wydajniejszy układ. Niech program będzie 5 razy dłuższy – wówczas ośmiobitowy mikrokontroler z zegarem LFINOSC nie nadąży z wykonywaniem kodu. Mikrokontroler 16-bitowy z zegarem LPRC spędzi 64% czasu na wykonywaniu programu, natomiast układ MIPS32 będzie potrzebował tylko 32% czasu, dzięki zoptymalizowanej egzekucji instrukcji. W przypadku mikrokontrolera 8-bitowego nie ma wyboru – trzeba użyć szybszego zegara. Dla 16-bitowego PIC24FJ128GC010 to też będzie lepszy wybór – i to nawet oszczędniejszy niż dla PIC18F27Q10, gdyż ten drugi potrzebuje aż 22,2% więcej energii na jego wykonanie w tej samej jednostce czasu.
W naszym przykładzie wykonywaliśmy jeden pomiar ADC – a jeśli musimy wykonać ich dziesiątki, setki czy tysiące na sekundę? Albo użyć równolegle wielu różnych peryferiów? Wtedy przydać się może układ DMA – niewystępujący zbyt często w ośmiobitowcach, za to powszechnie dostępny w układach 16- i 32-bitowych. Załóżmy na przykład, iż potrzebny jest układ zasilany bateryjnie, który wykryje dźwięk lub sygnał elektryczny o określonych częstotliwościach poniżej 1 kHz. W takiej sytuacji można skonfigurować moduł ADC i moduł DMA, by moduł ADC zbierał 2048 próbek na sekundę, a moduł DMA zapisywał je w kolejnych komórkach bloku pamięci liczącego 4 kB. Po zapełnieniu jednej lub drugiej połowy bloku moduł DMA budzi CPU odpowiednim przerwaniem, a program wykonuje transformatę Fouriera na zbiorze 2048 próbek oraz identyfikuje obecność poszukiwanych częstotliwości (jeśli ich brak, wraca do stanu uśpienia), podczas gdy moduły ADC i DMA pracują dalej. Oczywiście można to zadanie zrealizować za pomocą kilku aktywnych filtrów pasmowych, ale koszt takiego rozwiązania może być zbyt wysoki. W naszym przykładzie układ ośmiobitowy, nawet z DMA, może się nie sprawdzić ze względu na liczbę potrzebnych obliczeń. Optymalnym rozwiązaniem może okazać się użycie układu z wbudowanymi funkcjami DSP. Zapewne część Czytelników zapyta, na co komu taki układ? Przykładowa odpowiedź może być dość prosta: do odróżniania pszczół od komarów. Pszczoły bzyczą z częstotliwością 250...300 Hz, trzmiele z częstotliwością 200...250 Hz, a komary w paśmie od 700 Hz do ponad 1 kHz. Inne potencjalnie zastosowanie to prosty układ mierzący aktywność mózgu, tj. wykrywający, czy użytkownik jest w stanie relaksu, czy wzmożonej aktywności. Wymyślenie kolejnych zastosowań zostawiam Czytelnikowi jako ćwiczenie wyobraźni.
Dobrym przykładem układów wymagających zarówno dużej mocy obliczeniowej, jak i oszczędnego wykonywania programu, są opaski sportowe mierzące aktywność fizyczną. Mikrokontroler musi zbierać i przetwarzać dane z wielu czujników, kompresować je oraz przechowywać w pamięci do czasu następnej synchronizacji, wyświetlać czas, licznik kroków, często też mierzyć tętno czy poziom natlenienia krwi oraz realizować dodatkowe funkcje. Jednocześnie opaska taka może mieć nieduże ogniwo litowe, które powinno wystarczać na minimum jedną dobę pracy – albo baterię, zdolną wytrzymać od kilku miesięcy do nawet roku. By uzmysłowić Czytelnikowi skalę opisywanego problemu, posłużę się przykładem opaski sportowej Amazfit Bip S: przy normalnym użytkowaniu wytrzymuje ona na jednym ładowaniu przynajmniej dwa dni, co sprawdziłem praktycznie. Opaska ta ma ogniwo litowo-polimerowe o pojemności 200 mAh. Oznacza to, że średni pobór prądu na sekundę wynosi ~1,16 μA (zatem mniej, niż wykazywały ujęte we wcześniejszych przykładach mikrokontrolery – przy realizacji znacznie większej liczby zadań, włącznie z obsługą podświetlanego wyświetlacza i optycznym pomiarem tętna co minutę).
Osiągnięto tę oszczędność przez utrzymywanie stanu uśpienia wszystkich komponentów wewnątrz opaski przez większość czasu. Jeśli pomiar tętna następowałby co 5 minut, ten monitor aktywności działałby nawet 15 dni na jednym ładowaniu, gdyż to właśnie czujnik tętna pobiera najwięcej energii: na oświetlenie skóry i naczyń krwionośnych w niej się znajdujących. Nawet tu istnieje pewna oszczędność uzyskana przez producenta samego czujnika: diody LED pracują impulsowo ze zmienną intensywnością, dostosowaną do aktualnych warunków pomiaru. Pomiar położenia i ruchu opaski też nie jest ciągły – wystarczy wykonać go 2...3 razy na sekundę. Należy przy tym pamiętać, że większość sensorów MEMS ma własne procesory realizujące funkcję integracji oraz analizy pomiarów. Wysoka specjalizacja tych układów pozwoliła producentom ograniczyć pobór prądu i zintegrować takie funkcje, jak automatyczne wykrywanie zmiany położenia czy zliczanie kroków w samym sensorze. W ten sposób główny mikrokontroler opaski może pozostawać nieaktywny przez zdecydowaną większość czasu.