Myślę, że źle jest próbować debugować projekt oparty na mikrokontrolerze printf()
.
Rozumiem, że nie masz predefiniowanego miejsca na wyjście i że może zużywać cenne szpilki. Jednocześnie widziałem, jak ludzie używają pinu UART TX do wysyłania do terminala IDE za pomocą niestandardowego DEBUG_PRINT()
makra.
printf
, oczywiście, cały kod potrzebny do implementacjiprintf
zostanie połączony z plikiem wykonywalnym. Ale to dlatego, że kod go używał, a nie z powodu nagłówka.Odpowiedzi:
Mogę wymyślić kilka wad korzystania z printf (). Należy pamiętać, że „system osadzony” może wahać się od czegoś z kilkoma setkami bajtów pamięci programu do w pełni wyposażonego systemu QNX RTOS montowanego w szafie rack z gigabajtami pamięci RAM i terabajtami pamięci nieulotnej.
Do przesłania danych potrzebne jest miejsce. Być może masz już w systemie port debugowania lub programowania, a może nie. Jeśli nie (lub ten, który masz, nie działa), nie jest to bardzo przydatne.
To nie jest lekka funkcja we wszystkich kontekstach. To może być wielka sprawa, jeśli masz mikrokontroler z zaledwie kilkoma K pamięci, ponieważ łączenie w printf może samo z siebie pochłonąć 4K. Jeśli masz mikrokontroler 32 K lub 256 K, prawdopodobnie nie jest to problem, nie mówiąc już o dużym systemie osadzonym.
Jest mało lub nie ma sensu znajdowanie pewnych problemów związanych z alokacją pamięci lub przerwaniami i może zmienić zachowanie programu, gdy instrukcje są dołączone lub nie.
Jest to dość bezużyteczne w przypadku rzeczy wrażliwych na czas. Lepiej byłoby z analizatorem logicznym i oscyloskopem lub analizatorem protokołów, a nawet symulatorem.
Jeśli masz duży program i musisz wielokrotnie kompilować, zmieniając instrukcje printf i zmieniając je, możesz stracić dużo czasu.
Po co jest dobry - to szybki sposób na wyprowadzenie danych w wstępnie sformatowany sposób, który każdy programista C wie, jak korzystać - zero krzywej uczenia się. Jeśli chcesz wyrzucić matrycę dla filtru Kalmana, który debugujesz, może być miło wypluć ją w formacie, w którym MATLAB mógłby ją odczytać. Z pewnością lepiej niż przeglądać lokalizacje pamięci RAM pojedynczo w debugerze lub emulatorze .
Nie sądzę, aby była to bezużyteczna strzała w kołczanie, ale powinna być używana oszczędnie, wraz z gdb lub innymi debuggerami, emulatorami, analizatorami logicznymi, oscyloskopami, narzędziami do analizy kodu statycznego, narzędziami do pokrywania kodu i tak dalej.
źródło
printf()
implementacji nie jest bezpieczna dla wątków (tj. Nie wymaga ponownej rejestracji), co nie jest zabójcą transakcji, ale jest czymś, o czym należy pamiętać, używając jej w środowisku wielowątkowym.Oprócz niektórych innych dokładnych odpowiedzi, wysyłanie danych do portu z szeregowymi prędkościami transmisji może być wręcz powolne w stosunku do czasu pętli i mieć wpływ na sposób, w jaki pozostała część programu działa (podobnie jak DOWOLNY debugowanie proces).
Jak mówili inni ludzie, nie ma nic „złego” w używaniu tej techniki, ale ma ona, podobnie jak wiele innych technik debugowania, swoje ograniczenia. Tak długo, jak znasz i potrafisz sobie poradzić z tymi ograniczeniami, może być to bardzo dogodna okazja, aby pomóc ci poprawić kod.
Systemy wbudowane mają pewien stopień nieprzezroczystości, co generalnie sprawia, że debugowanie jest trochę problemem.
źródło
Istnieją dwa główne problemy, na które napotkasz podczas próby użycia
printf
na mikrokontrolerze.Po pierwsze, może być problem z umieszczeniem wyjścia w odpowiednim porcie. Nie zawsze. Ale niektóre platformy są trudniejsze niż inne. Niektóre pliki konfiguracyjne mogą być słabo udokumentowane i konieczne może być wiele eksperymentów.
Drugi to pamięć. Pełna
printf
biblioteka może być DUŻA. Czasami nie potrzebujesz wszystkich specyfikatorów formatu i mogą być dostępne specjalne wersje. Na przykładstdio.h
dostarczone przez AVR zawiera trzy różneprintf
rozmiary i funkcje o różnych rozmiarach.Miałem instancję, w której nie było dostępnej biblioteki i miałem minimalną pamięć. Więc nie miałem wyboru, jak użyć niestandardowego makra. Ale użycie
printf
lub nie jest tak naprawdę jednym z tych, które pasują do twoich wymagań.źródło
Aby dodać do tego, co Spehro Pefhany mówił o „rzeczach wrażliwych na czas”: weźmy przykład. Załóżmy, że masz żyroskop, z którego wbudowany system wykonuje 1000 pomiarów na sekundę. Chcesz debugować te pomiary, więc musisz je wydrukować. Problem: wydrukowanie ich powoduje, że system jest zbyt zajęty, aby odczytać 1000 pomiarów na sekundę, co powoduje przepełnienie bufora żyroskopu, co powoduje odczyt (i wydruk) uszkodzonych danych. I tak, drukując dane, uszkodziłeś dane, co sprawia, że myślisz, że istnieje błąd w odczycie danych, a może nie. Tak zwany heisenbug.
źródło
Głównym powodem braku debugowania za pomocą printf () jest to, że jest on zwykle nieefektywny, nieodpowiedni i niepotrzebny.
Nieefektywne: printf () i kin używają dużo pamięci flash i pamięci RAM w stosunku do tego, co jest dostępne na małym mikrokontrolerze, ale większa nieefektywność polega na rzeczywistym debugowaniu. Zmiana rejestrowanych danych wymaga ponownej kompilacji i przeprogramowania celu, co spowalnia proces. Wykorzystuje również UART, którego można by użyć do wykonywania użytecznej pracy.
Nieodpowiednie: Istnieje tylko tyle szczegółów, które można przesłać przez łącze szeregowe. Jeśli program się zawiesi, nie wiesz dokładnie gdzie, tylko ostatnie zakończone wyjście.
Niepotrzebne: wiele mikrokontrolerów można zdalnie debugować. JTAG lub zastrzeżone protokoły mogą być używane do zatrzymywania procesora, podglądania rejestrów i pamięci RAM, a nawet zmiany stanu działającego procesora bez konieczności ponownej kompilacji. Dlatego debuggery są ogólnie lepszym sposobem debugowania niż instrukcje drukowania, nawet na komputerze PC z dużą ilością miejsca i mocy.
Szkoda, że najpopularniejsza platforma mikrokontrolera dla początkujących, Arduino, nie ma debugera. AVR obsługuje zdalne debugowanie, ale protokół debugWIRE Atmela jest zastrzeżony i nieudokumentowany. Możesz użyć oficjalnej tablicy deweloperów do debugowania z GDB, ale jeśli tak, prawdopodobnie nie martwisz się już Arduino.
źródło
printf () nie działa samodzielnie. Wywołuje wiele innych funkcji, a jeśli masz mało miejsca na stosie, możesz go wcale nie użyć do debugowania problemów zbliżonych do limitu stosu. W zależności od kompilatora i mikrokontrolera ciąg formatu może również zostać umieszczony w pamięci, a nie odwołany z pamięci flash. Można to znacznie zsumować, jeśli wkleisz kod za pomocą instrukcji printf. Jest to duży problem w środowisku Arduino - początkujący używający dziesiątek lub setek instrukcji printf nagle wpadają w pozornie przypadkowe problemy, ponieważ nadpisują swoje stosy stosem.
źródło
Nawet jeśli ktoś chce wyrzucić dane na jakąś konsolę rejestrującą,
printf
funkcja na ogół nie jest zbyt dobrym sposobem na zrobienie tego, ponieważ musi zbadać przekazany ciąg formatu i parsować go w czasie wykonywania; nawet jeśli kod nigdy nie używa żadnego specyfikatora formatu innego niż%04X
, kontroler zazwyczaj będzie musiał zawrzeć cały kod, który byłby wymagany do parsowania dowolnych ciągów formatu. W zależności od używanego kontrolera użycie kodu może być o wiele bardziej wydajne:Na niektórych mikrokontrolerach PIC
log_hexi32(l)
prawdopodobnie wziąłby 9 instrukcji i mógłby zająć 17 (jeślil
znajduje się w drugim banku), podczas gdylog_hexi32p(&l)
zająłby 2. Samalog_hexi32p
funkcja mogłaby być napisana na około 14 instrukcji, więc zwróciłaby się za dwukrotne wywołanie .źródło
Jeden punkt, o którym żadna z pozostałych odpowiedzi nie wspomniała: W podstawowej mikro (IE jest tylko pętla główna () i być może kilka ISR działa w dowolnym momencie, a nie wielowątkowy system operacyjny), jeśli zawiesza się / zatrzymuje / dostaje utknąwszy w pętli, funkcja drukowania po prostu się nie wydarzy .
Ponadto ludzie powiedzieli „nie używaj printf” lub „stdio.h zajmuje dużo miejsca”, ale nie dali wiele alternatywy - embedded.kyle wspomina o uproszczonych alternatywach i jest to dokładnie to, czym prawdopodobnie powinieneś być robi to oczywiście na podstawowym systemie wbudowanym. Podstawową procedurą wypychania kilku znaków z UART może być kilka bajtów kodu.
źródło