Co to SEGGER System Viewer?

Jest to prosty tool do “tracingu” - czyli możemy podejrzeć eventy w naszej aplikacji. Dla mnie podstawowym wykorzystaniem jest podgląd na zajętość CPU, podgląd na wywłaszczanie się tasków w RTOSie - co za tym idzie podgląd na ich czasy wykonywania.

Oczywiście to narzędzie nie jest dedykowane tylko do aplikacji opartych o jakiś RTOS - do “baremetalowych” także możemy to wykorzystać - SEGGER udostępnia bardzo dobrą dokumentację jak używać ich biliotek.

W dalszej części tekstu zamiast nazwy SEGGER SystemViewer używam skrótu SSV.

Przykład użycia tego programu można też znaleźć we wpisie numer 002.

Konfiguracja

Jak skonfigurować SSV do działania w STMkach? Zademonstruję na przykładzie projektu z wpisu o uruchomieniu FreeRTOSa na nucleo L4.

W internecie dostępna jest ogólna instrukcja do tego pod tym linkiem: link na oficjalnej stronie.

Jak uruchomić SSV:

  • uruchamiamy stronę z plikami do pobrania: https://www.segger.com/downloads/systemview/
  • pobieramy/instalujemy aplikację - aktualnie to wersja 3.10
  • pobieramy źródła do projektu - oznaczone jako “Target Source”
  • oczywiście pobieramy też dokumentacje
  • struktura pobranego archiwum jest bardzo prosta:

obr

Katalogi to:

  • “SEGGER” jest to katalog z źródłami do umieszczenia jako katalog ze źródłami, ale do includów też go trzeba podciągnąć ze względu na główny plik “.h”.
  • “Config” jest “per aplikacja” - do umieszczenia w sekcji plików konfiguracyjnych naszego projektu.
  • “Sample” zawierają dodatkowe pliki “per RTOS”, lub też “NoOS” na przykładzie FreeRTOSV10 znajdziemy tam:
    • “Config” - z dodatkowym plikiem konfiguracyjnym do przeklejenia jak wcześniejsze Configi
    • 2 pliki “luzem” do dorzucenia do źródeł
    • Katalog z Patchem - jest to zestaw modyfikacji, które trzeba wprowadzić do określonego RTOS-a, można to łatwo zrobić z terminala - o tym w osobnym wpisie

W rezultacie otrzymamy taką strukturę plików:

obr

Widzimy też co będzie problemem po kompilacji - error: conflicting types for ‘_write_r’ - aktualnie poradźmy sobie z tym w ten sposób, że dopasujmy typ w pliku od SEGGER’a aby się zgadzał z bibliotecznymi.

Po tej zmianie projekt się kompiluje - musimy uruchomić teraz wszystko w mainie przez wywołaniem OSa:

  SEGGER_SYSVIEW_Conf();
  SEGGER_SYSVIEW_Start();

  xTaskCreate( vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);
  xTaskCreate( vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);
  xTaskCreate( vTask3, "Task3", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);
  vTaskStartScheduler();

Zerknijmy jeszcze do ciała funkcji “SEGGER_SYSVIEW_Conf()” - w “_cbSendSystemDesc” możemy dodawać wektory przerwań i będą też wyświetlone w aplikacji z podpisem.

Po wgraniu nie wszystko zadziała - musimy “zaaplikować” patcha - jest to modyfikacja FreeRTOSa udostępniona przez SEGGERa, w projekcie do pobrania gotowa wersja, a więcej o patchach w innym wpisie.

Potem na końcu pliku FreeRTOSConfig.h dodajemy: #include “SEGGER_SYSVIEW_FreeRTOS.h” - bez tego nie zobaczymy taskow, jedynie moment inicjalizacji rzeczy RTOSowych.

Dalej w tym samym pliku (FreeRTOSConfig.h) dodajemy:

#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_pxTaskGetStackStart 1

Na tym etapie wszystko powinno działać, aczkolwiek w runtime pojawił się problem z zablokowaniem pracy mikrokontrolera przez funkcję uruchamiającą SSV - fix na to można znaleźć tutaj: fix na forum. Dla lepszej demonstracji działania dodałem “dummy” delaye do tasków z poprzedniego projektu, tak aby działały blokująco i symulowały ważne/długie operacje:

void dummyDelay(void)
{
    for(volatile uint32_t i = 0; i < 0xffff; i++)
    {
        i++;
    }
}

void vTask1( void * pvParameters )
{
    for (;;)
    {
        HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
        dummyDelay();
        vTaskDelay(100);
    }
}

void vTask2( void * pvParameters )
{
    for (;;)
    {
        HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
        dummyDelay();
        vTaskDelay(150);
    }
}

void vTask3( void * pvParameters )
{
    for (;;)
    {
        HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
        dummyDelay();
        vTaskDelay(160);
    }
}

Możemy uruchomić aplikację SSV. Jeśli przy uruchomieniu dostaniemy error “Target DLL …JLink_x64.dll not found !” to musimy dograć pakiet tooli do J-Linka ze strony SEGGERa - jest to tzw “J-Link Software and Documentation Pack”.

Po połączeniu widoczny jest taki efekt:

obr

Tu zbliżenie na sytuację gdy wszystkie 3 taski chcą uzyskać dostęp do rdzenia i wykorzystywany jest mechanizm roud robin:

obr

Tracowanie aplikacji - niekoniecznie z użyciem tej apki może często “uratować dupe”, ale nie traktujmy tego jako narzędzie, które zastąpi wszystkie inne - jest to kolejny młotek do skrzynki narzędziowej.

Jeszcze na szybko przyszedł mi jeszcze jeden pomysł na fajne “demo” - ustawmy 2 taski na taki sam priorytet i jeden na wyższy - więc powinien on przerwać pozostałe, a tamte 2 gdyby uruchomiły się jednocześnie - powinien zadziałać RoundRobin. I tak to wygląda:

obr

I to widać w pierwszym zaznaczeniu. W drugim mamy sytuacje, że task 1 i 2 zaznaczone są do uruchomienia, ale czekają z powodu taska numer 3 o wyższym priorytecie.

Projekt do pobrania tutaj: pobierz projekt.