Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.
Pokazywanie postów oznaczonych etykietą JTAG. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą JTAG. Pokaż wszystkie posty

niedziela, 23 stycznia 2011

JTAG, a może … interfejs PDI?


Autor: Tmf
Redakcja: Dondu

W poprzednim artykule pokazałem korzyści płynące z zastosowania interfejsu JTAG, trochę pomijając jego wady.

A jakie wady JTAG posiada? Nie są one duże, ale na trzy warto zwrócić uwagę:
  • nie wszystkie AVRy posiadają JTAG. Nie jest to problemem, gdyż zazwyczaj program pisze się i tak na „większym” procku, potem otrzymany kod przenosi się na procesor docelowy. Ma to kilka zalet – przede wszystkim wygodne debuggowanie kodu, co ma związek z możliwością wykorzystania JTAGa i możliwość lepszego doboru procesora docelowego – w końcu wiemy już jakie zasoby będą wykorzystane i dokładnie wiemy ile jest potrzebne pamięci FLASH i SRAM.
  • interfejs ten wymaga kilku sygnałów (TMS, TDO, TCK, TMS), które są współdzielone z pinami IO procesora. W efekcie, jeśli odblokowany jest interfejs JTAG to nie możemy używać współdzielonych pinów IO i vice versa.
  • kolejna wada wynika z wielkości złącza – jak pokazałem w poprzednim artykule typowe złącze JTAG ma 10 pinów, a więc jest spore. Oczywiście osoby korzystające z elementów przewlekanych powiedzą – żaden problem. Lecz co raz częściej stosujemy małe elementy do montażu powierzchniowego, przy których złącze JTAG ma monstrualne rozmiary.

Oczywiście możemy wykorzystać złącze typu „gold pin” o rozstawie np. 50 milsów, które jest znacznie mniejsze, ale możemy także zrezygnować z JTAGa, bez rezygnowania z możliwości jakie daje.


PDI, czyli prostsze jest lepsze


Czytelnicy moich książek już spotkali się z interfejsem PDI. Co to takiego? Tym razem sama nazwa (The Program and Debug Interface) już nam dużo mówi – jest to interfejs programowania i debuggowania. W interfejs ten wyposażone są nowsze procesory firmy Atmel – XMEGA. Umożliwia on zarówno programowanie układów, jak i ich debuggowanie, oferując takie same możliwości jak interfejs JTAG.

Posiada on więc wszystkie zalety interfejsu JTAG, lecz do jego realizacji potrzebujemy tylko dwóch pinów IO – RESET oraz PDI. I tu dobra wiadomość. RESET zwykle nie jest wykorzystywany jako pin IO, w związku z tym nie ma problemu z jego wykorzystaniem do realizacji interfejsu PDI.

Drugi wymagany pin – PDI jest zazwyczaj również oddzielnym wyprowadzeniem procesora (aczkolwiek nie zawsze), niedostępnym w roli zwykłego pinu IO. Stad też interfejs ten nie koliduje z pinami IO, w efekcie jego użycie nie blokuje nam części portu mikrokontrolera, tak jak to było w przypadku JTAG. A nawet jeśli koliduje – to tracimy tylko jeden pin IO, a nie cztery.

Interfejs ten jest też elektrycznie prostszy w realizacji:


Interfejs PDI - Złącze, wyprowadzenia sygnałów.
Złącze PDI


Jak widzimy wykorzystuje on 6-pinową wtyczkę – identyczną z nowym standardem gniazda ISP proponowanym przez Atmela. Dzięki temu, jeśli dysponujemy nowym programatorem, np. AVRISP MkII ten sam kabelek możemy wykorzystać do programowania układów poprzez interfejs ISP (starsze mikrokontrolery firmy Atmel), jak i przez PDI (mikrokontrolery XMEGA). Wyboru interfejsu dokonuje się programowo – a nawet to nie jest potrzebne, gdyż, po wyborze w Atmel Studio używanego procesora, IDE samo przełącza programator we wspierany przez procesor tryb programowania.

Zaletą PDI jest prostota – wykorzystujemy tylko 4 przewody:
  • PDI_DATA (PDI), 
  • PDI_CLK (RESET), 
  • Vcc,
  • GND.

Zacznijmy od końca, czyli Vcc i GND. Wykorzystując ISP zawsze łączyliśmy GND programatora i programowanego układu (chyba, że dysponujemy programatorem z optoizolacją, co zdarza się niezmiernie rzadko). Natomiast połączenie Vcc było opcjonalne – zazwyczaj służyło możliwości zasilania programowanego układu z programatora.

W przypadku PDI Vcc programatora i programowanego układu musimy połączyć zawsze. Dlaczego? Dlatego, że programowany mikrokontroler (na razie jest to jakiś AVR z rodziny XMEGA) może pracować z napięciem 1,6-3,6 V. Aby programator mógł dostosować poziomy napięć do wymogów programowanego układu musi wiedzieć jakie napięcie w nim panuje – stąd też musimy podłączyć Vcc.

Pamiętaj, że programator pracujący w trybie PDI nigdy nie zasila programowanego układu – Vcc służy tylko do pomiaru napięcia w układzie.


Oprócz zasilania musimy jeszcze podłączyć linie samego interfejsu tak jak to pokazano na rysunku:



Programator PDI
Programator PDI



Tu też musimy zwrócić uwagę na parę rzeczy. Przede wszystkim powinniśmy zrezygnować z rezystora podciągającego RESET do Vcc. Rezystor ten nie jest potrzebny (procesor ma własne, o wiele lepsze układy monitorowania RESET), a jeśli się uprzemy go wstawić to powinien mieć on rezystancję >10 kΩ. Jeśli będzie miał mniejszą to niektóre debuggery (AVR Dragon) będą odmawiały współpracy.

Rzeczą, której absolutnie powinniśmy unikać to wszelkich kondensatorów obciążających linię RESET i PDI_DATA. Uniemożliwią one poprawną komunikację z procesorem.

Jak wspomniałem, układy XMEGA posiadają o wiele bardziej rozbudowane układy monitorowania sygnału RESET, stąd też zamiast stosować różne, znane z wcześniejszych AVRów sztuczki, lepiej poprawnie skonfigurować dostępne w nich układy monitorujące. Taka konfiguracja zazwyczaj nie jest potrzebna, gdyż ustawienia fabryczne są optymalne w większości zastosowań.

Musimy też pamiętać, o tym, aby sygnał RESET nie rozprowadzić jako sygnał zerowania do innych układów na płytce. PDI wykorzystując RESET by je okresowo inicjalizował, w efekcie debuggowanie procesora byłoby co prawda możliwe, ale ciągłe resety pozostałych urządzeń uniemożliwiłyby w praktyce debuggowanie w układzie.

Ponieważ wykorzystujemy tylko 4 sygnały, stąd też możemy użyć w programowanym układzie gniazda 4-pinowego, które jest jeszcze mniejsze. Ja w praktyce, jeśli mam naprawdę mało miejsca w ogóle nie używam gniazda, lecz robię 4 punkty stykowe na PCB – takie punkty można też wyprowadzić w postaci pasków (coś na kształt złącza krawędziowego) na brzeg płytki – grubość standardowego laminatu odpowiada rozstępowi pinów na listwie goldpin, można ją więc nasunąć na płytkę uzyskując w miarę pewny kontakt. Mniej więcej zasadę tą ilustruje poniższy rysunek:



Interfejs PDI - Zącze krawędziowe.
Zącze krawędziowe


I to wszystko. Nie pozostaje nic innego jak zacząć korzystać z nowego, prostego i szybkiego interfejsu. W tym celu jeśli posiadamy programator kompatybilny z Atmel Studio wybieramy okienko programowania i wybieramy interfejs PDI:



Programowanie za pomocą interfejsu PDI.
Programowanie via PDI


Warto zaznaczyć, że musiałem dokonać wyboru PDI, gdyż użyty mikrokontroler ATxmega256A3BU posiada zarówno interfejs JTAG, jak i PDI. Gdyby posiadał tylko PDI – wybór dokonałby się automatycznie. Jak widzimy po wybraniu interfejsu możemy bez problemu nawiązać połączenie z procesorem.

Warto zwrócić uwagę na jeszcze jedną sprawę. Jeśli procesor oprócz PDI jest także wyposażony w interfejs JTAG, to ten ostatni jest domyślnie odblokowany. W niczym nam to nie przeszkadza, lecz jak pamiętamy, piny JTAG są współdzielone z pinami IO, stąd też przy odblokowanym JTAG nie będziemy mogli wykorzystać odpowiednich pinów IO. Jeśli musimy z nich skorzystać wygodnie jest zablokować JTAG, pozostawiając odblokowany wyłącznie interfejs PDI. W tym celu przestawiamy odpowiedni fusebit:


Wyłączenie interfejsu JTAG


Aby zablokować JTAG wystarczy odhaczyć fajkę przy fusebicie JTAGEN (JTAG enable). To samo możemy oczywiście uzyskać programowo – w XMEGA mamy programowy dostęp do bitów konfiguracyjnych procesora, stąd sama aplikacja może sobie je skonfigurować wedle życzenia programisty.


Możliwości i szybkość działania


Na koniec pozostaje jeszcze porównać szybkość działania i możliwości obu interfejsów. Porównanie to jest krótkie – są one takie same. Podobnie - szybkość programowania, czy też responsywność w czasie debuggowania są praktycznie identyczne (subiektywnie wydaje mi się, że PDI jest dużo szybszy, ale nie testowałem tego zbytnio).

Po co więc stosować PDI?
Wystarczy rzucić okiem na rozpis sygnałów na poszczególnych interfejsach:


Od lewej: PDI, ISP i JTAG.

Jak widzimy PDI jest po prostu prostszy – stąd wygodniejszy w zastosowaniu go we własnych układach.


Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

wtorek, 18 stycznia 2011

JTAG, co to takiego i dlaczego warto używać?


Autor: tmf
Redakcja: Dondu

Dziadek też nie używał JTAG.
JTAG dziadka
Udzielając odpowiedzi na forach, często namawiam osoby mające problemy do używania interfejsu JTAG. Co to takiego i czemu zachęcam do jego używania? Rozwinięcie nazwy interfejsu (Joint Test Action Group) niewiele nam powie o jego możliwościach i korzyściach ze stosowana, przyjrzyjmy mu się więc bliżej od strony praktycznej.

Oczywiście można spotkać się z opiniami, że mój dziadek nie używał JTAGa i żył, ja też nie używam i żyję, więc po co mi to?

No cóż, nasi dziadkowie nie mieli też samochodów, a ich dziadkowie używali lamp naftowych. Tak się też oczywiście da, więc jeśli interesuje cię życie jaskiniowca mikrokontrolerowego, to lepiej dalej nie czytaj.


Do rzeczy ...

Interfejs JTAG umożliwia zarówno programowanie procesorów, jak i debugowanie zawartego w nich kodu, a także połączeń elektrycznych mikrokontrolera z resztą układu. Widzimy więc, że możliwości tego interfejsu są spore przez co zajmuje on drugie miejsce na liście najważniejszych kryteriów wyboru mikrokontrolerów przez producentów urządzeń. Warto więc się mu przyjrzeć bliżej.

Musimy pamiętać, że nie wszystkie mikrokontrolery AVR posiadają interfejs JTAG – posiadają go tylko „większe” mikrokontrolery ATMEGA (ATMega16, 32, 64, 128 etc.) oraz mikrokontrolery XMEGA. Te ostatnie posiadają także interfejs PDI udostępniający podobne funkcjonalności.

Inne posiadają interfejs ISP, małe ATTiny posiadają interfejs TPI, a nowsze, w tym XMEGA dodatkowo interfejs PDI, także umożliwiający debugowanie układów.

Po co więc interfejs, który nie występuje we wszystkich mikrokontrolerach?

Przede wszystkim programatory posiadające interfejs JTAG (AVR Dragon, JTAGICE, JTAGICE MkII, JTAGICEIII) są wyposażone w kilka interfejsów – obsługują zarówno JTAG, jak i PDI, ISP, itd. W efekcie przy pomocy takiego programatora możemy programować wszystkie mikrokontrolery, lecz oczywiście nie wszystkie będziemy mogli debugować (debugować można wyłącznie poprzez interfejs JTAG lub PDI).

Drugim powodem jest sposób w jaki możemy tworzyć aplikacje. Nawet tworząc aplikację na ATMega8, która nie posiada JTAG, nic nie stoi na przeszkodzie, aby wykorzystać płytę rozwojową z ATMega128 i potem przenieść gotowy i sprawdzony kod na ATMega8. Takie postępowanie jest nawet łatwiejsze w przypadku rodziny XMEGA – ze względu na zgodność nazw rejestrów i budowę układów peryferyjnych. Dzięki temu piszemy sobie wygodnie program, na „dużym” mikrokontrolerze, debugujemy go, a po zakończeniu prac po prostu rekompilujemy na urządzenie docelowe. Nawet jeśli w efekcie będziemy musieli wprowadzić jakieś poprawki do kodu, to jego pisanie będzie znacznie ułatwione, dzięki możliwości debugowania kodu.


Interfejs

Sam interfejs elektryczny JTAG jest niezwykle prosty. Składa się on zaledwie z kilku sygnałów (z których nie wszystkie są potrzebne):
  • TDI (ang. Test Data In) – wejście danych,
  • TDO (ang. Test Data Out) – wyjście danych,
  • TCK (ang. Test Clock) – wejście sygnału zegarowego,
  • TMS (ang. Test Mode Select) – wybór trybu pracy,
  • TRST (ang. Test Reset) – zerowanie (opcjonalne).


Oprócz tego istnieje kilka innych sygnałów, które należy podłączyć. Widok gniazda JTAG pokazuje poniższy rysunek:

Złącze JTAG
Złącze JTAG

Oczywiście obowiązkowo należy połączyć masy programowanego układu i programatora (sygnały GND). Podłączenie Vcc jest opcjonalne, umożliwia ono zasilanie programowanego układu z programatora. Zazwyczaj programator ma w tym celu dodatkową zworkę, należy jednak pamiętać, że wydajność prądowa programatora jest niewielka i zwykle ograniczona do 200-300 mA. Należy bezwzględnie pamiętać o podłączeniu pinu nazwanego VREF. Co to takiego? Jest to pin umożliwiający programatorowi określenie napięcia z jakim pracuje programowany układ. Z tego pinu zasilane są bufory wyjściowe programatora, zapewniające konwersję poziomów logicznych – zwykle programator potrafi pracować z urządzeniami zasilanymi napięciami w zakresie 1,6-5 V. W układzie VREF należy podłączyć do Vcc – napięcia zasilającego debuggowany procesor.

Pozostałe sygnały (TMD, TDO, TDI, TCK) należy połączyć z odpowiednimi pinami procesora (o tych samych nazwach), opcjonalnie należy podłączyć także sygnał NSRST do pinu RESET mikrokontrolera – połączenie to nie jest konieczne, ale zalecane.

Pamiętaj, że jeśli mikrokontroler posiada JTAG, to jest on sprzedawany z odblokowanym interfejsem. Ponieważ JTAG przejmuje kontrolę nad odpowiednimi pinami IO procesora, program nie może zmienić ich stanu i ich kontrolować do czasu zablokowania interfejsu JTAG (za pomocą odpowiedniego fusebitu lub rejestru IO).

Dla rodziny ATMega JTAG zajmuje zwykle część pinów portu C mikrokontrolera – jeśli ci one nie działają to przyczyną jest właśnie domyślnie odblokowany JTAG. Więcej na ten temat przeczytasz w artykule: Pułapki AVR: JTAG blokuje piny portu

I to wszystko – jak widzimy sama wtyczka JTAG jest 10-pinowa, analogicznie jak stara wtyczka ISP, stąd też nie zajmuje ona więcej miejsca na PCB niż zwykłe gniazdo ISP.



Daisy chain

JTAG ma jeszcze jedną zaletę, o której często się zapomina. Pisałem o tym w swojej książce „Język C dla mikrokontrolerów AVR. Od podstaw do zaawansowanych aplikacji” więc tu tylko krótko o tym. Interfejs JTAG umożliwia łączenie szeregowe układów posiadających taki interfejs.

Jeśli więc w budowanym systemie mamy np. dwa mikrokontrolery z interfejsem JTAG, do tego pamięć z takim interfejsem lub inny układ, to nie musimy wyprowadzać kilku złącz JTAG. Po prostu łączymy je szeregowo, w ten sposób, że sygnał TDO doprowadzamy do wejścia TDI kolejnego układu itd.

W ten sposób tworzymy łańcuszek układów. Pozostałe sygnały prowadzimy równolegle (TMS, TCK). Dzięki temu przy pomocy jednego złącza mamy dostęp do wszystkich układów na płytce. Wystarczy tylko znać ich względne położenie w łańcuchu.


Programowanie z użyciem JTAG

Pierwszą rzeczą do której wykorzystamy JTAG jest programowanie układu docelowego. Tu malkontenci mogą powiedzieć, po co – mogę sobie zaprogramować przy pomocy ukochanego USBAsp. Prawda, mogą :-)

Jednak programowanie przy pomocy JTAG ma parę zalet:
  • jest szybsze. Zdecydowanie szybsze niż przy pomocy USBasp, ale także ogólnie szybsze niż w trybie ISP. Dla procesorów posiadających niewiele pamięci różnice są bez znaczenia, ale dla procesorów posiadających 64-256 kB FLASH różnice mogą sięgać minut!
  • w trybie JTAG da się programować mikrokontroler także z niewłaściwie ustawionymi fusebitami (znany problem „zablokowałem mikrokontroler”). Ponieważ JTAG używa sygnału TCK do taktowania układów wewnątrz mikrokontrolera, konfiguracja zegara wybrana przy pomocy fusebitów jest bez znaczenia. W ten sposób można sobie odblokować zablokowany mikrokontroler. Oczywiście wybierając rodzinę XMEGA raz na zawsze rozwiązujemy problem zablokowanego procesora – w tej rodzinie źródło zegara wybiera się programowo.


Programowanie z wykorzystaniem JTAG wygląda praktycznie tak samo, jak z wykorzystaniem ISP, czy PDI:


JTAG - Programowanie za pomocą pliku elf.
Programowanie za pomocą pliku elf


Warto zwrócić uwagę, że programuję MCU z użyciem pliku elf a nie HEX (nie trzeba generować plików hex i eep co skraca czas kompilacji). Oczywiście mamy również możliwość zmiany z poziomu Atmel Studio fusebitów i innych parametrów mikrokontrolera.

Jeśli korzystamy z trybu daisy chain to należy wcześniej skonfigurować narzędzie:


JTAG - AVR Dragon - Konfiguracja Daisy chain.
Konfiguracja Daisy chain

Na powyższym przykładzie nasz mikrokontroler jest podłączony jako drugie urządzenie w łańcuchu, a po nim są kolejne dwa urządzenia. Jednak w większości przypadków, szczególnie w warunkach amatorskich takiej konfiguracji nie wykorzystujemy, stąd też nie ma potrzeby konfigurowania interfejsu – wystarczy zaznaczenie domyślnej opcji „Target device in not part of a JTAG daisy chain”.


Debugowanie programu

Największe zalety JTAGa ujawniają się w czasie debugowania programu. Ponieważ sam temat debugowania jest szeroki i być może omówimy go w kolejnych artykułach (jeśli będzie takie zapotrzebowanie) tu pokażę tylko kilka marchewek. Co nam daje debugger sprzętowy? Oto jego krótkie możliwości:
  • zakładanie pułapek – po natrafieniu na nie program zostanie przerwany (ale możliwe jest wznowienie jego pracy),
  • podgląd wartości zmiennych w programie oraz rejestrów mikrokontrolera,
  • podgląd zawartości pamięci FLASH, EEPROM i SRAM mikrokontrolera,
  • modyfikacja zmiennych i pamięci, a następnie wznowienie pracy programu z nowymi wartościami,
  • możliwość wykonywania krokowego programu – w tym trybie wykonywane są pojedyncze instrukcje programu (instrukcje języka C lub asemblera),
  •  możemy także wykonywać całe bloki instrukcji, np. funkcje, po wykonaniu, których program jest wstrzymywany i możemy przeanalizować jakie zaszły zmiany.

Zobaczmy jak to wygląda na prostym przykładzie. Na poniższym rysunku pokazałem fragment programu, na którym wykonanie zostało wstrzymane. Instrukcja, na której program został wstrzymany zaznaczona jest żółtą linią:

Przykład debugowania programu w Atmel Studio.
Debug

Jak widzimy program zatrzymał się na instrukcji for. W trakcie wstrzymania jego wykonania w okienku Locals można podglądnąć wartość lokalnych zmiennych w programie, w pokazanym przykładzie zmiennych tmpmenuitem, bmp_height, bmp_width itd.

Oczywiście możemy nie tylko podglądać te zmienne, ale jeśli chcemy możemy w każdej chwili ich wartość zmienić – umożliwia to łatwe przetestowanie fragmentu kodu dla zadanych wartości początkowych. Kolejne instrukcje możemy wykonywać pojedynczo naciskając klawisz F11.

Jeśli natrafimy na funkcję to automatycznie „wskoczymy” w jej ciało, dzięki temu będziemy mogli prześledzić jej wykonanie. Jeśli taka możliwość nas nie interesuje możemy od razu wykonać całą funkcję (np. na naszym przykładzie funkcją jest Menu_GetMenuRows()) naciskając klawisz F10.

Możemy też wykonać program do instrukcji oznaczonej przez bieżącą pozycję kursora naciskając Ctrl+F10. Opcje te są także dostępne w Atmel Studio w menu Debug. W każdej chwili możemy wznowić działanie programu naciskając F5. W takiej sytuacji program będzie normalnie wykonywany aż do chwili, kiedy go nie przerwiemy (Ctrl+F5) lub nie natrafi on na pułapkę (breakpoint).

No właśnie, a jak wygląda zastawianie pułapek? Nic prostszego, wystarczy na interesującej nas linii programu nacisnąć klawisz F9 (Debug/Toggle Breakpoint) i już. Jeśli procesor wykonując program natrafi na pułapkę, zawiesi swoje działanie, a Atmel Studio pokaże nam jego stan w chwili natrafienia na zastawioną pułapkę. Widzimy to na kolejnym zrzucie:


Przykład debugowania programu w Atmel Studio. Breakpoint (pułapka).
Breakpoint


Pułapka została zastawiona na linii uint8_t no=Menu_GetMenuItemsNo(); Wykonanie programu zostało przerwane a my możemy sobie sprawdzić co się w programie dzieje, analizując zawartość zmiennych. Akurat debuggowana funkcja jest odpowiedzialna za przeskok do kolejnej pozycji menu, przed jej wykonaniem postanowiłem sprawdzić wartość zmiennych menuindex i no – określających numer pozycji menu i liczbę pozycji. Oczywiście możemy łatwo sprawdzić dowolną zmienną, wpisując ją w oknie Watch – jedyny warunek – zmienna ta musi być w zasięgu widoczności bieżącego fragmentu kodu. Tu reguły widoczności są identyczne jak w języku C – jeśli dana zmienna jest widoczna w danym fragmencie kodu, to możemy jej zawartość podglądnąć.

Od tej reguły istnieją wyjątki związane z faktem, że kompilator mocno optymalizuje kod, usuwając niepotrzebne zmienne. Takich zoptymalizowanych zmiennych, ponieważ nie istnieją w kodzie wynikowym, nie możemy podglądać.

Ktoś powie – ok, fajnie, ale przecież w innym artykule pokazaliście, że to samo można osiągnąć stosując symulator w Atmel Studio. To prawda, posługiwanie się debuggerem sprzętowym daje mniej więcej takie same możliwości jak symulacja. Jak zwykle różnice tkwią w szczegółach.

Musimy pamiętać, że symulator symuluje wyłącznie działanie procesora, natomiast w rzeczywistym układzie stan procesora zależy nie tylko od programu, ale także od jego otoczenia – pozostałych układów elektronicznych znajdujących się na płytce. Symulator oczywiście ich bezpośrednio nie symuluje (ale można tego typu funkcjonalność w pewnym stopniu do niego dodać), natomiast debugger sprzętowy umożliwia śledzenie pracy programu w rzeczywistym układzie. W efekcie te dwie metody debuggowania doskonale się uzupełniają. Ale to nie wszystko. Popatrzmy na kolejny zrzut ekranu:


Atmel Studio JTAG - debugowanie stanu portów.
IO View

Co na nim widzimy? Przede wszystkim kod asemblerowy pokazanego wcześniej programu. Dzięki temu możemy podglądając wykonanie programu i zobaczyć w jaki sposób kompilator przetłumaczył kod C na asembler oraz możemy wykonywać kolejne instrukcje asemblera. Ze względu na działanie optymalizatora czasami kod C jest przez kompilator bardzo modyfikowany, co utrudnia jego śledzenie. Stąd też przejście do okna disassemblera znacznie ułatwia śledzenie kodu i czasami jest wygodniejsze niż śledzenie kodu w oknie kodu C. Ale nie to jest tu najważniejsze.

Spójrzmy na prawą stronę naszego zrzutu, do okna zatytułowanego IO View. I tu właśnie widać całą potęgę debuggera sprzętowego. Na bieżąco mamy podgląd na wszystkie układy peryferyjne procesora i ich rejestry! Dla przykładu na zrzucie pokazano stan rejestrów układu USARTD) – po rozwinięciu odpowiedniej pozycji możemy uzyskać skrócony, szybki podgląd na stan tego układu peryferyjnego (łącznie z opisem słownym pól konfiguracyjnych):


Widok IO


Poniżej mamy pokazany stan każdego z jego rejestrów oraz poszczególnych bitów konfiguracyjnych. Jeśli więc konfigurujesz jakiś układ peryferyjny i chcesz sprawdzić czy napisany kod robi to poprawnie (uzyskujesz zamierzony efekt) to wystarczy podglądnąć jego rejestry po  wykonaniu kodu odpowiedzialnego za jego konfigurację.

W tym zakresie debugger sprzętowy umożliwia nam uzyskanie tego samego co symulator. Lecz jak zwykle jest różnica. Dla układów peryferyjnych będących wyjściami procesora generalnie w symulatorze uzyskamy to samo. Lecz jeśli jakiś układ zależy od sygnałów doprowadzonych do procesora?

Oczywiście w takiej sytuacji stan układu peryferyjnego nie da się w pełni zasymulować. Przykładem może być rejestr wejściowy portu IO – bity tego rejestru zależą od stanu panującego na wejściach procesora, a nie bezpośrednio od kodu programu! I tu zbliżamy się do kolejnej wspaniałej cechy debuggera sprzętowego…


Debugowanie połączeń elektrycznych na PCB

Tak samo jak w przypadku zmiennych możemy nie tylko podglądać stan rejestrów IO procesora, ale także możemy ich wartość zmieniać. W ten sposób w trakcie działania programu możemy zmieniać konfigurację układów peryferyjnych! A co jeśli zmiana konfiguracji wpłynie na stan wyjść procesora? Tak będzie np. jeśli zmienimy stan rejestru wyjściowego portu – zmiana jego stanu natychmiast wpłynie na poziom logiczny panujący na odpowiednim pinie IO! I to jest właśnie kolejna fantastyczna cecha debuggera sprzętowego.

Lutując układy, szczególnie o gęstszym rastrze nie sposób nie popełnić błędów – np. podczas lutowania możemy doprowadzić do przypadkowego połączenia sąsiednich pinów:


Płytka PCB - Zwarcie między pinami.
Zwarcie między pinami

Czasami tego typu błędy są łatwe do wykrycia, lecz często odstępy pomiędzy pinami są mniejsze niż 0,5 mm – nie zawsze takie mostki cynowe znajdziemy. Co więcej trawiąc płytki w domu (ale także jeśli je zamawiamy) może się zdarzyć sytuacja w której dochodzi do nieprawidłowego połączenia sąsiednich ścieżek, lub wręcz odwrotnie, w wyniku podtrawienia dochodzi do przerwania ciągłości ścieżki:


Płytka PCB - Uszkodzona ścieżka.
PCB - Uszkodzona ścieżka

No i chyba najczęstsza sytuacja – tzw. zimny lut. Pozornie wszystko jest ok, jednak zła spoina nie zapewnia połączenia elektrycznego. Poszukiwanie tego typu błędów bywa naprawdę uciążliwe. Czy JTAG może nam w tym pomóc? Zazwyczaj tak. Dlaczego? Jak pamiętamy możemy z poziomu Atmel Studio debugując program zmieniać stan układów peryferyjnych, w tym rejestrów portów IO – w efekcie możemy łatwo klikając myszką zmieniać stan wszystkich wyjść IO procesora.

W efekcie, jeśli podejrzewamy zwarcie dwóch pinów IO to wystarczy zmienić stan jednego i sprawdzić czy jednocześnie nie zmienił się stan drugiego (oczywiście musimy go wcześniej skonfigurować jako wejście – np. klikając myszą na odpowiednie bity rejestru DIR). Możemy też wymusić stan pinu IO a następnie miernikiem sprawdzić czy stosowne napięcie panuje na wejściu układu, którym przy pomocy danego pinu sterujemy. W ten sposób możemy naprawdę szybko znaleźć nieprawidłowe połączenia.

Technika ta jest wygodna jeszcze w jednej sytuacji. Wyobraźmy sobie, że łączymy z MCU np. wyświetlacz LCD. Nawet popularny wyświetlacz alfanumeryczny wymaga w tym celu 6-7 połączeń, co więcej odpowiednie piny IO procesora musimy doprowadzić do odpowiednich wejść LCD. O pomyłkę nietrudno, wystarczy pomylić dwa przewody i już nasz układ nie działa. Początkujący (chociaż nie tylko początkujący) elektronicy zarzekają się, że 100-razy sprawdzili poprawność połączeń, a układ nie działa. Magia? Być może… lecz tu z pomocą ponownie może nam przyjść JTAG/PDI. Wystarczy zmienić stan kolejnych pinów IO i sprawdzić, czy stan spodziewanych wejść LCD również ulega zmianie. W ten sposób szybko zidentyfikujemy problem.


Prawdy i mity – czyli JTAG jest drogi

Mam nadzieję, że udało mi się pokazać istotne zalety JTAG/PDI, pozostaje jeszcze drażliwa kwestia – ceny. Na grupach zwykle przeciwnicy debuggerów sprzętowych piszą, że cena JTAGa jest wysoka i jest on w związku z tym niedostępny dla hobbystów.

Nic bardziej błędnego. Tego typu programatory/debuggery można kupić już za kilkanaście złotych. Oczywiście w tej cenie nie dostaniemy nic rewelacyjnego – możemy kupić (lub sami zbudować) debugger JTAGICE współpracujący wyłącznie z AVR Studio 4.19 i wcześniejszymi, umożliwiający debuggowanie w układzie procesorów ATMega. Nie jest to wiele, lecz dla osób zajmujących się wyłącznie starszymi AVRami ciągle jest to atrakcyjna propozycja.

A co z osobami doceniającymi zalety Atmel Studio lub pracującymi z XMEGA? Tu niestety musimy wydać nieco więcej. Naprawdę świetnym programatorem/Debuggerem jest AVR Dragon – jego cena to ok. 240-250 zł. Nie jest to mało, ale jest on wart każdej wydanej złotówki – umożliwia on programowanie wszystkich układów AVR, w tym AVR32 przez wszystkie możliwe interfejsy, oraz… oczywiście sprzętowe debuggowanie układów, które mają taką możliwość.

Czy jest to dużo? Z pewnością jest to istotna pozycja w budżecie, lecz wydatek naprawdę szybko się zwraca i z całą odpowiedzialnością mogę ten debugger polecić. Osoby posiadające większą gotówkę mogą zakupić JTAGICE3 (nie wnosi on w stosunku do Dragonia praktycznie nic poza plastikową obudową), a dla fascynatów JTAGICE MkII, którego cena moim zdaniem jest mocno przesadzona.

Oczywiście zawsze możemy zapolować na okazje i ewentualnie spróbować zdobyć te układy po naprawdę dobrych cenach na różnych szkoleniach organizowanych przez firmę Atmel. Niestety Polska jest traktowana sieroco (wina Atmela, czy dystrybutora na Polskę, który się nie stara?), więc na dobre okazje możemy zapolować u naszych zachodnich sąsiadów :-)


Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.