Debugowanie programu poprzez łącze szeregowe.¶
Któregoś dnia na dział gdzie byłem kierownikiem przyszedł szef innej firmy ze swoimi dwoma „programistami” embedded. Ujęcie słowa programiści w cudzysłów nie jest przypadkowe. Akurat pisałem oprogramowanie (Kierownik działu nie tylko papierki przetwarza, lecz również uczy, projektuje i rozwija oprogramowanie). Obaj „programiści” popatrzyli na monitory podpięte do komputera i zszokowało Ich to co zobaczyli. W terminalu na ekranie wyskakiwały mi napisy którędy przeszedł właśnie program. W terminalu wyświetlało się w którym pliku, której linii i jakiej funkcji był program. Co pewien czas pojawiały się napisy typu „do shutdown, lcd power off, lcd power on, etc.: Nie wspomniawszy o wyświetleniu całej konfiguracji urządzenie wejścia/wyjścia czy sygnalizacji wejścia do przerwania.
FileName:LineNumber NazwaFunkcji FileName:LineNumber NazwaFunkcji FileName:LineNumber NazwaFunkcji
Zszokowani patrzyli i nie mogli uwierzyć w to co widzieli, a sztuczka nie jest trudna do realizacji za to bardzo przydatna. Poniżej przedstawiłem jak to zrobić.
#define debugtrace() dbg_printf(„nr%s %u %s ,__FILE__,__LINE__,__FUNCTION__)
Za pomocą tej linijki kodu wstawione checkpointy informowały mnie przez które miejsce w programie właśnie przeszedł kontroler. Oczywiście dbg_printf jest odpowiednikiem zwykłego printf, lecz za pomocą zmiany makra można go wyłączyć w programie docelowym gdzie nie zostanie wkompilowany. W przedstawionej makrodefinicji najważniejszą cześć stanowi użycie definicji dostarczanych przez kompilator.
__FILE__ zwraca nazwę kompilowanego pliku;
__LINE__ zwraca bieżącą linię kompilowanego pliku;
__FUNCTION__ zwraca nazwę kompilowanej funkcj;
Podstawowy debug oparty jest na połączeniu szeregowym RS232/RS485/USB CDC/ lub poprzez interfejs SWI. Jeśli posiadamy interfejs SPI<->USB przekierować na SPI. wystarczy napisać sobie prostą funkcę printgdzie zapis możemy przekirować do dowolnego interfejsu lub wykorzystać standardową funkcję printf z dopisanym uchwytem do dowolnego interfejsu za pomocą którego skomunikujemy urządzenie z komputerem PC. Wybór na interfejs szeregowy wynika z tego, iż najłatwiej wtedy przekierować komunikaty do gotowego terminala na PC.
Zanim zaczniemy pisać jakiekolwiek oprogramowanie musimy zapewnić sobie możliwość śledzenia kodu.
- Kiedyś zaczynało się od pisania prostego transferu RS232 najczęściej w postaci programowej
obsługi transferu. Gdy udało się przesłać znaki po RS232 można było sprawdzić stan urządzeń(rejestrów sterujących)
Kolejnym krokiem było pisanie oprogramowania obsługi sprzętowej transmisji.
Następnie implementowało się transmisję z obsługą przerwań
Obecnie można zaimplementować na wielu kontrolerach transmisję z wykorzystaniem DMA.
- Ostatnim krokiem jest napisanie całych funkcji wyświetlania stanu urządzeń.
jak i monitorów pozwalających śledzić krokowo oprogramowanie.
Te reguły rozwoju podstawy dla rozwoju oprogramowania generalnie się nie zmieniły. Tym nie mniej pojawiły się układy debugerów, które z jednej strony ułatwiają odpluskwiane programów a z drugiej powodują nowe problemy. Okazuje się, że są sytuacje w których interfejs JTAG też zawodzi. Wtedy ratuje sytuację tylko takie „surowe” śledzenie w starym stylu. Pierwszy raz „naciąłem” się na problemy z JTAG-iem JTAG-MK2, który w pewnych sytuacjach „gubił” śledzenie gdyż oprogramowanie po stronie PC nie było w stanie przewidzieć gdzie postawić breakpoint-y aby uchwycić miejsce, do którego przejdzie mikrokontroler. Dzieje się tak dlatego, iż wbudowany układ śledzenie kontrolera ma ograniczoną liczbę pułapek adresowych, dzięki którym następuje zatrzymanie pracy kontrolera i umożliwienie odczytu stanu kontrolera. Niezależnie od kontrolera i interfejsu wcześniej, czy później traficie na ten problem. Ja ponownie trafiłem na niego w przypadku kontrolerów ARM cortex-M.
Nie każdy kontroler ma możliwość napisania monitora do śledzenia pracy krokowej. Tym nie mniej jest możliwość ominięcia tego problemu poprzez napisanie monitora, który może wykonać pojedynczy rozkaz i zwrócić stan kontrolera a całe zobrazowanie stanu kontrolera wykonać w dodatkowym programie na komputerze PC. Dlaczego mamy wykonywać rozkazy bezpośrednio na ukłądzie docelowym a stan kontrolera obrazować na PC? Przecież można od razu napisać emulator kontrolera. Nie jest tak różowo jak by się mogło wydawać. Producent kontrolera też popełnia błędy. Błędy konstrukcyjne kontrolera czasem po wykryciu pojawiają się w erreatach wydawanych przez producenta. Czasem zostają wykryte dopiero przez użytkownika. Emulator kontrolera może się zachowywać inaczej niż kontroler. Osobiście wykryłem dwa nieopisane przez producenta błędy w mikrokontrolerach, lub jego bibliotekach dostarczanych przez producenta. Jeden sprzętowy błąd w AT89C52 i jeden w bibliotece dla mikrokontrolera STM32, który obecnie używam najczęściej.
Aby dać pewną podstawę do „surowego” śledzenia softu, poniżej załączam kod od bardzo starej wersji biblioteki do debugu softweru.