Śledzenie programu na Arduino Zero Pro z GDB i openOCD

Arduino dzięki swej prostocie ma mnóstwo zalet. Osobom mającym doświadczenie z programowaniem na początku może sprawiać problem brak debugera, czyli narzędzia pozwalającego podglądać działanie programu w kontrolerze. Można podejrzeć/zmieniać wartości zmiennych, wykonywać komendy krok po kroku. Mówiąc krótko sprawdzić, czemu program nie działa jak powinien. Przy bardziej złożonych programach jest to nieoceniona pomoc.
Arduino nie dysponuje takim narzędziem. Jedyna dostępna metoda to wysyłanie komunikatów przez obiekt Serial.

Arduino Zero Pro na ratunek

Od dziś dostępny na Nettigo jest nowy model Arduino Zero Pro. Płytka ta ma na pokładzie 32 bitowy procesor ARM Cortex-M0. Nowością jest złącze do śledzenia działania programów.
Arduino Zero Pro jest wyposażony w dodatkowy układ, który przez dodatkowy port USB daje funkcjonalność debugowania bezpośrednio na płytce.

Jak zacząć śledzenie

Testy prowadziliśmy na komputerze z Linuxem, jednakże, całość oprogramowania niezbędnego do pracy jest częścią Arduino IDE, i dlatego metoda opisana powinna działać na każdym OS na którym działa Arduino IDE.

Arduino ORG

Pierwsza ważna sprawa, musimy mieć zainstalowane Arduino IDE ze strony Arduino.org a nie jak dotychczas z Arduino.cc – w tej chwili (maj 2015) tylko to IDE ma wsparcie dla Arduino Zero Pro.

Ściagamy i instalujemy Arduino IDE 1.7.3 lub nowsze. Następnie potrzebujemy, by IDE było bardziej rozgadane niż zazwyczaj, dlatego otwieramy ustawienia (Ctrl+,) i szukamy opcji Show verbose option during i zaznaczamy przy compilation.

Do testów na warsztat weźmiemy szkic Blink. Otwieramy go (menu Files/Examples/01. Basic/Blink). Arduino Zero podłączamy kablem micro USB do portu PROGRAMMING, w IDE wybieramy płytkę i port (też programming) i wgrywamy program na płytkę (Ctrl+U).

OpenOCD

Konsorcjum ARM opracowało dla procesorów Cortex-M0 standard komunikacji nazwany CMSIS (dla ciekawskich – link) i istnieje otwarte oprogramowanie obsługujący ten standard.

Pozwólcie że przedstawię – OpenOCD. Arduino IDE jest dostarczane razem z OpenOCD, dlatego nic nie trzeba instalować.

Uruchomienie OpenOCD

Mając wgrany na Arduino nasz Blink, przechodzimy do katalogu, gdzie rozpakowaliśmy Arduino IDE i wydajemy komendę (to jest jedna linia):

./hardware/tools/OpenOCD-0.9.0-dev-arduino/bin/openocd -s hardware/tools/OpenOCD-0.9.0-dev-arduino/share/openocd/scripts/ -f hardware/arduino/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg

Uruchamiasz OpenOCD. Paramter po -s wskazuje na katalog, w którym jest zestaw plików konfiguracji samego OpenOCD. Po -f jest lokalizacja pliku konfigurującego OpenOCD dla Arduino Zero. Prawidłowy rezultat powinien wyglądać tak:

Open On-Chip Debugger 0.9.0-dev-g1deebff (2015-02-06-13:06)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'cmsis-dap'
adapter speed: 500 kHz
adapter_nsrst_delay: 100
cortex_m reset_config sysresetreq
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: JTAG Supported
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : CMSIS-DAP: FW Version = 01.1F.0118
Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1
Info : DAP_SWJ Sequence (reset: 50+ '1' followed by 0)
Info : CMSIS-DAP: Interface ready
Info : clock speed 500 kHz
Info : IDCODE 0x0bc11477
Info : at91samd21g18.cpu: hardware has 4 breakpoints, 2 watchpoints

GDB

OpenOCD jest gotowe do pracy. Nasłuchuje one na portach 4444 i 3333. Do tego pierwszego możemy się podłączyć telnetem, ten drugi jest dla protokołu GDB.

GDB to otwarte oprogramowanie do śledzenia wykonywania programu (debugger). Jest również dołączone do Arduino IDE. To jest o tyle istotne, że GDB musi być skompilowane ze wsparciem dla architektury ARM.

By móc śledzić program potrzebujemy pliku w formacie ELF z programem i informacjami opisującymi jego strukturę.
Plik taki powstaje podczas kompilacji kodu i jest przechowywany w tymczasowym katalogu. By uzyskać plik, jeszcze raz skompilujemy program, tym razem tylko weryfikacja (Ctrl+R). W jednej z ostatnich linii pojawi się ścieżka do pliku z rozszerzeniem .elf.

Poglądowy obrazek (zwróć uwagę, że konsola została przesunięta w prawo. bo linie się nie zawijają automatycznie):
image

Uruchamiamy GDB, w katalogu gdzie jest arduino IDE wydajemy komendę:

./hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/arm-none-eabi-gdb -d examples/01.Basics/Blink/

Katalog podany po opcji -d jest miejscem, gdzie GDB będzie szukało kodu naszego programu, by móc wyświetlać nam informacje o wykonywanym kodzie w przyjazny dla nas sposób. Po uruchomieniu GDB powinniśmy otrzymać linię poleceń tego programu.

GNU gdb (GNU Tools for ARM Embedded Processors (Arduino build)) 7.6.0.20140228-cvs
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
.
(gdb) 

Ninejszy artykuł nie jest instrukcją jak korzystać z GDB, pokażę tylko niezbędne rzeczy by rozpocząć śledzenie programu na Arduino.

Teraz poinformujemy GDB gdzie znajdzie skompilowany program, który będziemy śledzić:

(gdb) file /tmp/build4557814640826011475.tmp/Blink.cpp.elf
Reading symbols from /tmp/build4557814640826011475.tmp/Blink.cpp.elf...done.
(gdb) 

Komenda file służy do podania ścieżki do tego pliku, ścieżka to ta skopiowana z konsoli Arduino IDE.

GDB musimy powiedzieć, że nasz program jest wykonywany gdzie indziej:

(gdb) target remote localhost:3333
Remote debugging using localhost:3333
0x00000000 in ?? ()
(gdb) 

Teraz jesteśmy gotowi przejąć kontrolę nad programem, spójrzcie na ten zapis sesji z GDB:

(gdb) monitor reset halt
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x21000000 pc: 0x000028b8 msp: 0x20002c08
(gdb) monitor reset init
target state: halted
target halted due to debug-request, current mode: Thread 
xPSR: 0x21000000 pc: 0x000028b8 msp: 0x20002c08
(gdb) l loop
19    // initialize digital pin 13 as an output.
20    pinMode(13, OUTPUT);
21  }
22  
23  // the loop function runs over and over again forever
24  void loop() {
25    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
26    delay(1000);              // wait for a second
27    digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
28    delay(1000);              // wait for a second
(gdb) b 25
Breakpoint 1 at 0x4120: file Blink.ino, line 25.
(gdb) cont
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, loop () at Blink.ino:25
25    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
(gdb) c
Continuing.

Breakpoint 1, loop () at Blink.ino:25
25    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
(gdb) 

I tak monitor reset halt wysyła komendę do zdalnego urządzenia, aby zatrzymało wykonywanie programu (po wydaniu tej komendy dioda na Arduino Zero przestaje migać). monitor reset init przywraca procesor do stanu ‘zerowego’ tak by rozpocząć pracę na nowo.

l loop wyświetla nam kod funkcji loop (dlatego potrzebowaliśmy wskazać GDB, gdzie jest katalog z naszym szkicem). Polecenie b 25 ustawia punkt przerwania wykonywania w linii 25, a polecenie cont wznawia (a ponieważ wykonaliśmy monitor reset init to rozpocznie działanie od początku) wykonywanie programu na Arduino.

Jednak nim zapali się dioda, to procesor dotrze do linii 25, której kod ma właśnie zaświecić tę diodę i debugger zatrzyma wykonywanie programu. Kolejne polecenie c to skrót od cont wznowi działanie programu. Wykona się pełen cykl, dioda się zaświeci na sekundę, zgaśnie i procesor znowu dotrze do lini 25 i zatrzyma wykonywanie programu.

Co dalej?

To była bardzo prosta demonstracja jak korzystać z możliwości, jakie otwiera przed Wami Arduino Zero Pro. Osoby mające doświadczenie z GDB mogą już śmiało zamówić Zero. Pozostałych zachęcamy do prób, bo GDB warto opanować, ten krótki film pokaże Wam, jak wyglądało debugowanie Blinka na żywo.

Gdy działa już GDB nie ma problemu, by skorzystać z graficznego interfejsu, jakie istnieją do tego programu. Na przykład DDD (tym razem musicie doinstalować ten program, nie jest on częścię Arduino IDE)

By go uruchomić, trzeba tylko wskazać mu właściwą wersję GDB (tą z Arduino IDE):

ddd --debugger "hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/arm-none-eabi-gdb -d examples/01.Basics/Blink/"