Uruchomienie GUI na płytce STM32F746GDISCO

| Prezentacje firmowe Mikrokontrolery i IoT

Zestaw uruchomieniowy STM32F746G-DISCO jest jednym z bardziej rozbudowanych zestawów startowych firmy ST. Mocny procesor, duży wyświetlacz i spora liczba różnych interfejsów sprzętowych pozwalają wykorzystać tę płytę zarówno do testowania oprogramowania, jak i do budowy unikatowych, w pełni funkcjonalnych urządzeń. W artykule pokażę, jak uruchomić system grafiki i jak połączyć ten system z własnym oprogramowaniem.

Uruchomienie GUI na płytce STM32F746GDISCO

Na płycie STM32F746G-DISCO producent zamontował dużą liczbę interfejsów i dodatkowych układów rozszerzających jej możliwości. Najważniejsze z punktu widzenia użytkownika cechy oraz parametry to:

  • mikrokontroler STM32F746NGH6 z 1 MB pamięci Flash, 320 kB pamięci RAM, z rdzeniem Cortex-M7 taktowanym zegarem o maksymalnej częstotliwości 216 MHz;
  • ekran LCD-TFT 4,3 cala o rozdzielczości 480×272 px z pojemnościowym panelem dotykowym i maksymalną głębią koloru 24 bity na piksel;
  • 128-Mbitowa pamięć Flash Quad-SPI;
  • 128-Mbitowa pamięć SDRAM, z czego dla użytkownika dostępne 64 MB;
  • 2 miniaturowe mikrofony typu MEMS;
  • kodek audio ze wzmacniaczem mocy;interfejsy:
    - USB OTG HS,
    - USB OTG FS,
    - Ethernet,
    - karty microSD,
    - SPDIF RCA,
    - kamery;
  • złącze zgodne z Arduino Rev. 3 (zasilanie i poziomy logiczne 3,3 V);
  • zintegrowany z płytą programator ST-LINK/V2-1;
  • zasilanie +5 V z 4 niezależnych wejść (z 2 USB, gniazda programatora, dodatkowego złącza zasilania) przełączanych ustawieniem zwory.
 
Fotografia 1. Płytka STM32F746G-DISCO, widok strony frontowej
 
Fotografia 2. Płytka STM32F746G-DISCO, widok strony tylnej

Fotografie 1 i 2 prezentują płytkę a dodatkowo naniesione oznaczenia wskazują usytuowanie najważniejszych elementów: 1-wyświetlacz, 2-mikrofony MEMS, 3-złącze bezpośredniego zasilania +5 V, 4-gniazdo zintegrowanego z płytą programatora, 5-USB OTG FS, 6-USB OTG HS, 7-złącze ethernet, 8-wejście i wyjście sygnałów audio, 9-wejście SPDIF, 10-gniazdo do podłączenia kamery, 11-gniazdo karty microSD, 12-złącze zgodne z płytkami Arduino. Dokładny opis części sprzętowej płytki wraz ze schematami ideowymi można znaleźć w podręczniku użytkownika http://bit.ly/31wcS5N.

Dedykowane środowiska graficzne

Zamontowany na płycie wyświetlacz może posłużyć jako wygodny interfejs graficzny dla aplikacji użytkownika. Należy jednak zadbać o przeprowadzenie prawidłowej inicjacji wyświetlacza, obsłużyć wyświetlanie zaprojektowanych ekranów i zapewnić współpracę między tym, co będzie widać, a działaniem programu użytkownika. Z lektury dokumentu poświęconego opisowi wymagań niezbędnych do sprzęgnięcia ze sobą interfejsu kontrolera i dołączonego wyświetlacza wynika, że nie jest to zadanie łatwe http://bit.ly/2XHIZgF.

Dostępne są dwie biblioteki graficzne, które bardzo ułatwiają pracę z wyświetlaczem. Są to TouchGFX i StemWin, rozpowszechniane bezpłatnie i w różnym stopniu zintegrowane z pozostałą infrastrukturą programistyczną dla kontrolerów STM.

STemWin

Biblioteka ta daje:

  • niskopoziomowy interfejs do komunikacji z wyświetlaczem, w tym procedury inicjacyjne i obsługę wymiany danych pomiędzy kontrolerem a wyświetlaczem i układem obsługującym funkcje dotyku;
  • ułatwienia przy tworzeniu wyświetlanych obiektów graficznych takich jak przyciski, napisy, kursory itp., obsługę przezroczystości, wielu warstw;
  • standardowe procedury API do sterowania i komunikacji pomiędzy oprogramowaniem użytkownika a biblioteką

Biblioteka jest uniwersalna, przystosowana do kontrolerów i wyświetlaczy różnego typu. Dostępna nieodpłatnie do użycia z kontrolerami STM i dostarczana w formie plików nagłówkowych oraz wstępnie skompilowanych plików źródłowych, które trzeba dołączyć do swojego projektu. Jest też częściowo zintegrowana z flagowym narzędziem ST, czyli STM32CubeMX, graficznym narzędziem do konfiguracji i automatycznego generowania szkieletu kodu inicjującego. Dzięki temu większość pracy związanej z dołączaniem biblioteki do programu użytkownika może przeprowadzić STM32CubeMX.

Wygenerowanie szkieletu programu z dołączoną biblioteką STemWin

Teraz opiszę kolejne kroki, które trzeba wykonać aby wygenerować szkielet kodu z dołączoną biblioteką STemWin. Projekt będzie przeznaczony dla płyty STM32F746G-DISCO z zamontowanym wyświetlaczem o rozdzielczości 480×272 px. Jako narzędzie posłuży STM32CubeMX w wersji 5.2.0 z firmware Package STM32Cube FW_ F7 v.1.15.0. Przykładowy projekt zostanie wygenerowany dla IDE SW4STM32. Szkielet oprogramowania będzie przystosowany do pracy pod nadzorem FreeRtos: darmowego systemu operacyjnego czasu rzeczywistego dla urządzeń wbudowanych.

  1. Inicjacja projektu, wybór typu płyty -> Board Selector: STM32F746G-DISCO

  2. Start Project -> Initialize all peripherals with their default mode: YES
    Powstanie projekt ze wstępnymi ustawieniami dla płyty STM-32F746G-DISCO. Oznacza to, że udostępniona do konfiguracji zostaje spora liczba różnych interfejsów w tym i te, które nie będą używane. Niektóre więc można pozamykać, czyli ustawić opcję Disabled np. dla interfejsu

    Pinout & Configuration -> Connectivity -> ETH -> Mode: Disable To przyśpieszy start płyty po każdym resecie. Innych nie należy ruszać, bo są istotne dla prawidłowego działania funkcji graficznych:

    Categories -> System Core
    Categories -> Computing
    Categories -> Connectivity -> FMC
    Categories -> Connectivity -> USART1
    Categories -> Connectivity -> I2C3
    Categories -> Connectivity -> QUADSPI
    Categories -> Multimedia
    Categories -> Middleware -> FREERTOS

    Ustawienia zegarów systemowych można pozostawić bez zmian.

  3. Należy podać nazwę projektu, ścieżkę dostępu:
    Project Manager -> Project Name: wpisz swoją nazwę projektu
    Project Manager -> Project Location: wpisz katalog docelowy projektu
    Project Manager -> Application Structure: Advanced
    Project Manager -> Tolchain/IDE: SW4STM32, Generate under root: [v]
    Project Manager -> Firmware Package Name a nd Version: STM-32Cube FW_F7 V1.15.0

  4. Należy kliknąć -> File -> Save Project

  5. Wybór środowiska graficznego:
    Pinout & Configuration -> Middleware -> Graphics -> Graphics Framework: StemWin, Display Interface: Display Parallel Interface using LTDC
    Configuration -> Parameter Settings -> Physical Display Size X size: 480, Y size: 272
    Configuration -> Parameter Settings -> Frame Buffer -> Layer0 Color Conversion: GUICC_M565
    Configuration -> Parameter Settings -> GUI Parameters -> GUI RGB Ordering: ABGR
    Configuration -> Platform Settings -> LCD Reset pin XRES: PI12

  6. GENERATE CODE
    Code Generation -> Open Project

    W tym momencie mamy wygenerowane pliki projektu dla środowiska SW4STM32. Do projektu zostały automatycznie dołączone pliki biblioteki STemWin. Po wczytaniu plików projektu do środowiska SW4STM32 można przystąpić do kompilacji. Klikamy kolejno:

    1. Project -> Clean
    2. Project -> Build All
    3. Run -> Run As…

    Po zaprogramowaniu płytki STM32F746G-DISCO, na czarnym tle powinien wyświetlić się napis: Hello world! Automatycznie wygenerowany kod aplikacji graficznej umieszczony jest w pliku Project Explorer -> nazwa twojego projektu -> STemWin -> App -> GUI_App.c w funkcji: GRAPHICS_MainTask(void).

Funkcje interfejsu dotykowego

Teraz trzeba dodać do projektu pliki, które umożliwią kontrolowanie interfejsu dotykowego wyświetlacza. Posłużą do tego pliki BSP z firmware package, który trzeba ściągnąć ze strony firmy ST. Na potrzeby tego opisu posługiwałem się firmware oznaczonym jako STM32Cube_FW_F7_V1.15.0.

Należy dodać sterowniki funkcji interfejsu dotykowego:

  1. W drzewie projektu IDE SW4STM32 należy utworzyć dodatkowe foldery Project Explorer -> nazwa twojego projektu -> Drivers -> prawy przycisk myszy -> New -> Folder: BSP

  2. W podobny sposób w utworzonym folderze BSP należy utworzyć podfoldery inc i src.

  3. Należy przekopiować z plików firmware package do utworzonych podfolderów: z...\STM32Cube_FW_F7_V1.15.0\Drivers\BSP\STM32746G-Discovery\
    stm32746g_discovery_sdram.c
    stm32746g_discovery_ts.c
    stm32746g_discovery.c
    do Project Explorer -> nazwa twojego projektu -> Drivers -> BSP -> src

    z ...\STM32Cube_FW_F7_V1.15.0\Drivers\BSP\STM32746G-Discovery\
    stm32746g_discovery_sdram.h
    stm32746g_discovery_ts.h
    stm32746g_discovery.h
    do Project Explorer -> nazwa twojego projektu -> Drivers -> BSP -> inc

  4. W drzewie projektu IDE SW4STM32 należy utworzyć dodatkowy folder Project Explorer -> nazwa twojego projektu -> Drivers -> prawy przycisk myszy -> New -> Folder: Components

  5. Przekopiować z plików firmware package do utworzonego podfolderu: z ...\STM32Cube_FW_F7_V1.15.0\Drivers\BSP\Components\ folder ft5336 do Project Explorer -> nazwa twojego projektu -> Drivers -> Components

  6. W drzewie projektu IDE SW4STM32 należy utworzyć dodatkowy folder Project Explorer -> nazwa twojego projektu -> Drivers -> Components, prawy przycisk myszy -> New -> Folder: Common

  7. Należy przekopiować z plików firmware package do utworzonego podfolderu: z ...\STM32Cube_FW_F7_V1.15.0\Drivers\BSP\Components\Common\ts.h do Project Explorer -> nazwa twojego projektu -> Drivers -> Components\Common\

  8. Ostatecznie w drzewie projektu IDE w folderze Drivers powinna powstać taka struktura z nowo dodanymi folderami i plikami:
    /Drivers
    	/BSP
    		/inc
    			stm32746g_discovery_sdram.h
    			stm32746g_discovery_ts.h
    			stm32746g_discovery.h
    				
    		/src
    			stm32746g_discovery_sdram.c
    			stm32746g_discovery_ts.c
    			stm32746g_discovery.c
    	/CMSIS
    	/Components
    		/Common
    			ts.h
    			/ft5336
    				ft5336.c
    				ft5336.h
    	/STM32F7xxHAL_Driver
    		​
  9. Na koniec należy dodać ścieżek dostępu do nowo utworzonych folderów: File -> Properties -> C/C++ Build -> Settings -> MCU GCC Compiler -> Includes: Add…
    Drivers\BSP
    Drivers\BSP\inc
    Drivers\BSP\src
    Drivers\Components
    Drivers\Components\Common
    Drivers\Components\ft5336

    Jeżeli próbna kompilacja zakończy się bez błędów, oznacza to, że jak dotąd wszystko zostało zrobione prawidłowo.

Dodanie własnego ekranu

Teraz przechodzimy do zaprojektowania wyglądu ekranu, który będzie się pojawiał na wyświetlaczu. Najwygodniej uprościć sobie pracę i posłużyć się gotowym narzędziem, będzie to GUIBuilder.exe. Jest to graficzny program do projektowania treści wyświetlacza i generowania plików .c, które można łatwo dołączyć do projektu. GUIBuilder.exe znajduje się w firmware package w podkatalogu: ...\ STM32Cube_FW_F7_V1.15.0\Middlewares\ST\STemWin\Software\

 
Rysunek 1. Okno programu GUIBuilder

Na rysunku 1 widać przykładowe okno z programu GUIBuilder. W górnej części okna umieszczona jest belka z dostępnymi do wyboru graficznymi elementami, które można wykorzystać w tworzonym projekcie własnego ekranu. Po wskazaniu kursorem elementu i kliknięciu prawym przyciskiem myszy element zostaje umieszczony na obszarze symulującym wyświetlacz. Jako pierwszy powinien zostać wybrany jeden z dwu elementów: Window albo FrameWin. To będą rodzice dla wszystkich pochodnych elementów wyświetlanych na wyświetlaczu. Pierwszy z nich Window, stanowi surowy podkład, dla którego można jedynie ustawić kolor. Drugi, czyli FrameWin, przypomina typowe okienko Windows z ramką, nagłówkiem i możliwością dodania bocznych suwaków przewijania.

Z lewej strony okna GUIBuildera znajdują się dodatkowe panele - z listą użytych w projekcie elementów i z ich właściwościami. Przez kliknięcie lewym przyciskiem myszy na element listy można go otworzyć do edycji - kliknięcie prawym przyciskiem na edytowany element otwiera listę dostępnych do zmiany ustawień.

Po wybraniu na belce programu opcji File -> Save (Ctr+S) projekt zostanie przekonwertowany i zapisany jako zwykły plik .c, który bezpośrednio można dodać do projektu naszego programu. Plik w każdej chwili może być ponownie wczytany do GUIBuildera i wyświetlony jako projekt graficzny do edycji.

Po pierwszym uruchomieniu GUIBuildera tworzony jest w jego katalogu plik GUIBuilder.ini. Jest w nim podana ścieżka do katalogu, w którym będą zapisywane pliki wynikowe. Zawartość pliku .ini można poddać edycji i określić własną ścieżkę dostępu do wybranego katalogu: [Settings] ProjectPath="c:\ ścieżka dostępu do wybranego katalogu \".

Na rysunku 1 widać projekt prostego okna, które będzie użyte w przykładowym projekcie dla płyty STM32F746G-DISCO. Rodzicem jest element typu Window, na którym umieszczono dwa pola tekstowe i dwa przyciski: Button1 i Button2. Po naciśnięciu każdego ma zmienić się tekst wyświetlany przez pole tekstowe Text_test. Na podstawie tego projektu program GUIBuilder generuje plik WindowDLG.c. Plik należy dodać do projektu, w tym celu klikamy: Project Explorer -> nazwa twojego projektu -> STemWin -> App:WindowDLG.c.

Uzupełnianie kodu

Na koniec trzeba wszystko razem połączyć. Wymaga to dopisania własnego kodu, zatem przechodzimy do projektu w IDE SW4STM32 i w pliku main.c. wykonujemy:

  1. Dołączenie plików nagłówkowych bibliotek - listing 1.
    Listing 1. Dołączenie plików nagłówkowych bibliotek w pliku
    main.c
    /* Private includes --------*/
    /* USER CODE BEGIN Includes */
    #include „stm32746g_discovery_ts.h”​
  2. Deklarację zmiennych globalnych do obsługi ekranu dotykowego - listing 2.
    Listing 2. Deklaracja zmiennych globalnych do obsługi ekranu
    dotykowego w pliku main.c
    /* USER CODE BEGIN PV */
    GUI_PID_STATE TS_State;
    TS_StateTypeDef ts;​

Następnie uzupełniamy kod w plikach związanych z GUI (wyświetlanym ekranem). Pliki znajdujące się w katalogu projektu Project Explorer -> nazwa twojego projektu -> STemWin -> App

  1. Uzupełniamy kod w GUI_App.h zawartością z listingu 3:
    Listing 3. Uzupełnienie w pliku GUI_App.h
    #include „stm32746g_discovery_ts.h”
    #include „stm32746g_discovery_sdram.h”
    #include „WM.h”
    #include „DIALOG.h”
    WM_HWIN CreateWindow(void);
    extern GUI_PID_STATE TS_State;
    extern TS_StateTypeDef ts;​
    W tym miejscu potrzebna jest mała uwaga. Uzupełnienie w ten sposób pliku GUI_App.h jest jak najbardziej dopuszczalne i będzie działać. Jednak w momencie uruchomienia STM32CubeMX i powtórnego wygenerowania szkieletu kodu, plik GUI_App.h zostanie wygenerowany ponownie a wprowadzone zmiany nie zostaną zachowane. Są dwa rozwiązania: albo każdorazowo po generowaniu kodu przez STM32CubeMX będziemy dopisywać podane wyżej zmiany w pliku GUI_App.h, albo umieścimy je na początku sekcji /* USER CODE BEGIN GRAPHICS_MainTask */ w pliku GUI_App.c. Drugie rozwiązanie jest mniej eleganckie, ale będzie działało.

  2. Teraz należy dopisać fragment kodu powodujący wyświetlenie zaprojektowanego ekranu i włączenie opcji dotyku dla klawiszy Button1 i Button2. Należy wprowadzić zmiany w GUI_App.c, jak na listingu 4.
    Listing 4. Zmiany w pliku GUI_App.c
    /* USER CODE BEGIN GRAPHICS_MainTask */
    /* User can implement his graphic application here */
    /* Hello Word example */
    // GUI_Clear();
    // GUI_SetColor(GUI_WHITE);
    // GUI_SetFont(&GUI_Font32_1);
    // GUI_DispStringAt(„Hello world!”, (LCD_GetXSize()-150)/2, (LCD_GetYSize()-20)/2);
    
     GUI_Delay(100);
     BSP_SDRAM_Init();
     BSP_TS_Init(LCD_GetXSize(), LCD_GetYSize());
    
     CreateWindow(); //wyświetlenie ekranu
     GUI_Delay(500);
     
     while(1)
     {
         BSP_TS_GetState(&ts); //Pobranie stanu
         if (ts.touchDetected) //Wykrycie dotyku
         {
             TS_State.Pressed = ts.touchDetected;
             TS_State.y = ts.touchY[0];
             TS_State.x = ts.touchX[0];
             GUI_PID_StoreState(&TS_State); //Przekazanie stanu
         }
         else //Brak dotknięcia
         {
             TS_State.Pressed = 0;
             TS_State.y = -1;
             TS_State.x = -1;
             GUI_PID_StoreState(&TS_State); //Przekazanie stanu
         }
         GUI_Delay(100);
     }
    /* USER CODE END GRAPHICS_MainTask */​

     

  3. Na koniec należy dodać kod wykonywany po naciśnięciu któregoś z klawiszy. W tym przykładzie będzie zmieniana treść pola tekstowego Text_test. Zmiany w pliku WindowDLG.c jak na listingu 5.

    Listing 5. Zmiany w pliku WindowDLG.c
     switch(Id) {
           case ID_BUTTON_0: // Notifications sent by ‘Button1’
           switch(NCode) {
                    case WM_NOTIFICATION_CLICKED:
                    // USER START (Optionally insert code for reacting on notification message)
                    hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_1);
                    TEXT_SetTextColor(hItem, GUI_MAKE_COLOR(0x008000FF));
                    TEXT_SetText(hItem, „nacisniety przycisk Button1”);
                    //reakcja na naciśnięcie BUTTON1
                    // USER END
                    break;
                    case WM_NOTIFICATION_RELEASED:
                    // USER START (Optionally insert code for reacting on notification message)
                    // USER END
                    break;
                    // USER START (Optionally insert additional code for further notification
                    // handling)
                    // USER END
                } break;
           case ID_BUTTON_1: // Notifications sent by ‘Button2’
           switch(NCode) {
                    case WM_NOTIFICATION_CLICKED:
                    // USER START (Optionally insert code for reacting on notification message)
                    hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_1);
                    TEXT_SetTextColor(hItem, GUI_MAKE_COLOR(0x00803000));
                    TEXT_SetText(hItem, „a teraz nacisniety Button2”);
                    //reakcja na naciśnięcie BUTTON2
                    // USER END
                    break;
                    case WM_NOTIFICATION_RELEASED:
                    // USER START (Optionally insert code for reacting on notification message)
                    // USER END
                    break;
                    // USER START (Optionally insert additional code for further notification
                    //handling)
                    // USER END
           } break;
           // USER START (Optionally insert additional code for further Ids)
           // USER END
     } break;
     // USER START (Optionally insert additional message handling)
     // USER END​

To już wszystko. Po kompilacji i wgraniu programu do mikrokontrolera na płycie STM32F746G-DISCO po chwili na wyświetlaczu powinien pojawić się ekran taki jaki zaprojektowaliśmy w GUIBuilderze. Przyciskanie obydwu klawiszy powinno wpływać na treść wyświetlanego napisu.

Ryszard Szymaniak

Zobacz również