W zasadzie ten temat nie miał powstać, a przynajmniej nie z Mojej ręki, ale cóż... stało się. W tym szybkim kursie chciałbym przedstawić wszystkim nie tylko mikrokontrolery STM32 z rdzeniem Cortex-M0, ale też często pomijane, stąd mało znane biblioteki Low-layer Library (w skrócie zwane LL) jakie pojawiły się obok bibliotek HAL (Hardware Abstraction Layer), które zastąpiły nieco przestarzałe już biblioteki SPL (Standard Peripherial Library).
Jak dotąd tworzenie programów dla wielu mikrokontrolerów 8-bitowych było oparte na bezpośrednim odwoływaniu się do rejestrów procesora w celu skonfigurowania lub dostępu do wbudowanych peryferii. Niekiedy nawet bez wykorzystania języków wyższego poziomu, takich jak C lub nawet Basic, skupiając się na kodzie maszynowym z wykorzystaniem asebmlera. Dziś chyba nikt nie wyobraża sobie pisania kodu maszynowego dla całej aplikacji.
Sytuacja się nieco zmieniła gdy zaczęły na rynek wchodzić nieco bardziej rozbudowane mikrokontrolery: pierwsze jednostki z rdzeniami ARM, Atmel Xmega, STM32 Cortex-M3. Szybko zorientowano się, że pisanie kodu w języku maszynowym lub bezpośrednio z wykorzystaniem odwołań do rejestrów stało się nieco nieefektywne. Zaczęły pojawiać się namiastki lub gotowe, pełne biblioteki programistyczne. Dla mikrokontrolerów Atmel były to np. biblioteki ASF (Advanced Software Framework), dla STM32 zaś wspomniane już biblioteki SPL.
Biblioteki te ewoluowały i dla układów STM32, w związku z pojawieniem się nowych układów w rodzinie, szybko wprowadzono w życie ideę bibliotek HAL. Miały one na celu ujednolicenie tworzenia programu dla każdego mikrokontrolera STM32, tak by kod był jak najbardziej przenośny i niuanse związane z inną budową wewnętrzną poszczególnych mikrokontrolerów ukryć właśnie w treści bibliotek, tak by programista widział te same, dobrze znane mu funkcje.
Przy okazji tworzenia bibliotek HAL, inżynierowie z ST przygotowali też inną bardzo ciekawą gałąź bibliotek zwanych Low-layer Library. Stanowi ona część bibliotek HAL i gdyby narysować to na grafie to stoi ona niżej i odnosi się bezpośrednio do sprzętu. Dzięki temu nie mamy aż tak dużego poziomu abstrakcji jak w bibliotekach HAL, ale również nie odwołujemy się bezpośrednio do oceanu rejestrów i bitów w nich umieszczonych. Wszystko robią za nas biblioteki LL za pomocą prostych makr, struktur i zaledwie kilku funkcji, których nazwy mówią nam już więcej co dana funkcja lub makro robi.
Właśnie tym chciałbym się zająć w tym szybkim kursie.
Środowisko
Na początek, aby wogóle zacząć należy sobie przygotować odpowiednie środowisko. Dla mikrokontrolerów STM32 powstało ich kilkanaście. Moim zdaniem najważniejsze z nich to:
- Keil ARM-MDK, który w wersji Lite dla podstawowych procesorów jest bezpłatny. Ograniczeniem jest tu ilość generowanego kodu, która wynosi 32kB. Oprócz tego jest też specjalna wersja MDK for STM32L0 and STM32F0 dla układów STM32 z rdzeniem Cortex-M0(+).
- Atollic TrueStudio, który od wersji 9.0 jest całkowicie bezpłatny ale nie obsługuje już innych procesorów poza STM32. Wszystko dlatego, że projekt został przejęty przez ST. ST obecnie zaleca używanie TrueStudio jako podstawowego środowiska.
- AC6 System Workbench for STM32 (SW4STM32), który przed przejęciem TrueStudio przez ST miał szansę stać się domyślnym środowiskiem i był przez ST wspierany.
Ja wybrałem SW4STM32 z kilku powodów. Po pierwsze, pozwala w miarę szybko rozpocząć pracę nad kodem bo samo proponuję i w dużym stopniu konfiguruje wykorzystanie biblotek SPL (jeśli są dostępne) lub HAL-LL. Ot, zaznaczamy odpowiednią opcję i biblioteki automatycznie są dołączane do projektu. Po drugie, mimo Moich prób nie udało mi się zmusić TrueStudio by korzystało z bibliotek HAL-LL bez tworzenia zalążku projektu przez specjalne narzędzie STM32CubeMX. Pomimo umieszczenia odpowiednich plików i ustawień we właściwych miejscach, kompilacja zawsze kończyła się błędami z brakiem dostępu do pewnych symboli. (Rozwiązano. Patrz niżej). Po trzecie, jest i było w pełni darmowe, i widać, że nadal się rozwija, choć brak wsparcia ze strony ST daje się już we znaki.
Oczywiście osoby znające ekosystem Eclipse lub Visual Studio jak swoją własną kieszeń mogą sobie samemu złożyć całe środowisko instalując potrzebne wtyczki i pobrać odpowiednie biblioteki.
Uwaga! SW4STM32 nie będzie działać w systemie Windows XP.
Instalacja
SW4STM32 możemy pobrać - po zalogowaniu - ze strony http://www.openstm32.org/Downloading%2B ... Binstaller Należy tylko wybrać odpowiedni instalator w zależności od tego jaki posiadamy system operacyjny. Piszę te słowa na komputerze z Windows 7 x64 więc wybiorę instalator "install_sw4stm32_win_64bits-v2.5.exe"
Przed instalacją należy się upewnić czy w systemie jest zainstalowana Java JRE. Bez tego instalator się nie uruchomi, ani też środowisko oparte na Eclipse nie będzie działać.
Proces instalacji jest dość prosty. Uruchamiamy instalator, akceptujemy licencję. Następnie wybieramy docelowy folder instalacji. Domyślnie będzie to "C:\Ac6\SystemWorkbench" i możemy to tak zostawić, z uwagi na mechanizmy ochrony systemów Windows.
Następnie program poprosi o wskazanie które składniki ma zainstalować. Jeśli już mamy w systemie zainstalowane wcześniej sterowniki do programatora ST-Link to możemy odznaczyć tą drugą opcję. Jeśli nie to zostawiamy tak jak jest.
Na koniec zostaje tylko wybór gdzie mają pojawić się ikony programu. Po kilku minutach ta część instalacji się zakończy i będzie można po raz pierwszy uruchomić środowisko by dokończyć proces jego tworzenia.
Podczas pierwszego uruchomienia program poprosi o wskazanie miejsca gdzie będzie przechowywał nasze projekty, tzw. workspace. W zasadzie lokalizacja może być dowolna, byle byśmy mieli pełne prawa dostępu. Ja wybrałem sobie zdecydowanie złą lokalizację w folderze "C:\Ac6\Workspace", ale na tym komputerze nie mam innego dysku i nie chciałem robić większego bałaganu. Taka lokalizacja spowoduje, że przy usuwaniu programu będziemy musieli uważać by nie skasować sobie całego dorobku razem z programem. Zatem jeśli macie inną możliwość skorzystajcie z niej.
Warto też zaznaczyć opcję poniżej by program ustawił ją jako domyślną i więcej nie pytał o wskazanie miejsca przechowywania projektów. Gdybyście chcieli przygotować kilka przestrzeni roboczych, np. jedną na gotowe projekty, a drugą na testowe to nie zaznaczajcie tej opcji. Będziecie mogli wybierać z jaką przestrzenią roboczą chcecie w danej sesji pracować.
Po kliknięciu OK program zostanie uruchomiony i od razu przystąpi do pobrania i instalacji minimalnego zestawu potrzebnych wtyczek. Po zakończeniu tej operacji okno Welcome możemy już zamknąć, gdyż nie będzie potrzebne.
Pierwsze co powinniśmy zrobić to przejść do menu Help -> Check for Updates, by sprawdzić czy nie ma aktualizacji od czasu wydania naszego instalatora. Jeśli są to pozwalamy je zainstalować. Teraz przechodzimy do Help -> Install new sofware bo chciałbym byście zainstalowali sobie jeszcze wtyczkę STM32CubeMX, która może okazać się przydatna.
Kierujemy przeglądarkę na adres https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-configurators-and-code-generators/stm32cubemx.html i przechodzimy do sekcji TOOLS AND SOFTWARE klikamy na STSW-STM32095. Program przeniesie nas na inną stronę i tam na końcu strony w tabeli klikamy Get Software. Po zalogowaniu lub podaniu danych witryna udostępni nam link do odpowiedniego pliku w tabeli pod przyciskiem Download. Pobieramy archiwum ZIP, ale nie rozpakowujemy go!
Wracamy do System Workbench i w otwartym wcześniej oknie Install klikamy Add..., następnie w następnym oknie Archive.... Wybieramy pobrany plik "en.stsw-stm32095.zip" i OK. Teraz na liście powinno się dać zaznaczyć STM32CubeMX_Eclipse_Plugin. Po zaznaczeniu klikany dwa razy Next i po zaakceptowaniu licencji Finish. Po zainstalowaniu wtyczki restartujemy program.
Po ponownym uruchomieniu przechodzimy do menu Window -> Perspective -> Open perspective -> Other... i wybieramy STM32CubeMX. Jeśli wszystko zrobiliśmy dobrze to powinna się pokazać zakładka z STM32CubeMX.
Tam przechodzimy do Help -> Manage embeeded software packages. Dzięki niej zainstalujemy sobie już wcześniej biblioteki HAL-LL dla naszej docelowej rodziny STM32F0. Rozwijamy tą sekcję i zaznaczamy najnowszą paczkę.
Jeśli ktoś planuje też tworzenie kodu dla pozostałych lub innych rodzin to może od razu zaznaczyć więcej pakietów do instalacji. Teraz klikamy Install Now i czekamy aż proces się zakończy, po czym klikamy Close.
Pierwszy program
Teraz czas na to co tygrysy lubią najbardziej. "Napiszemy" pierwszy program, by sprawdzić czy wszystko działa. Aby wrócić do edycji kodu przełączamy perspektywę w prawym górnym rogu okna za pomocą ikony zaznaczonej na czerwono.
Na chwilę obecną Moją platformą docelową będzie płytka Nucleo z procesorem STM32F072RB. Choć założenie jest takie, by jednak stworzyć naszą µGeek-ową płytkę ewaluacyjną i na bazować na niej. Również, by nie przedłużać tej części nie będę się teraz wgłębiał w szczegóły i pokażę jak utworzyć projekt, skompilować go i uruchomić. Dzięki temu będziemy wiedzieli czy całość działa jak należy.
Wybieramy File -> New -> C Project. Otworzy się okno kreatora gdzie podamy wymagane informacje. Nazwę projektu wpiszę sobie "TUT01_01" - pierwszy program, pierwszej części - i jako typ projektu wybiorę Ac6 STM32 MCU Project. W następnym kroku zostawię wszystko tak jak jest. Teraz pora na wybór platformy docelowej. Mimo, że mam płytkę Nucleo i jest ona na liście w zakładce Board to przełączę się na zakładkę MCU i tam z listy wybiorę STM32F072RBTx, bo taki jest użyty na płytce. Chodzi o to, by podczas tworzenia projektu nie zostały dodane dodatkowe funkcje związane z tymi płytkami, bo są nam zbędne.
Pora teraz na ostatni, decydujący krok. Ponieważ chcemy użyć bibliotek HAL-LL to wybieramy je za pomocą przełącznika. Ponieważ odpowiednie pliki już pobraliśmy podczas konfigurowania STM32CubeMX to powinniśmy zauważyć tekst "Firmware xxx has been found.". Gdybyśmy tych plików nie mieli to program zaproponowałby pobranie ich udostępniając przycisk Download target firmware. Na razie resztę ustawień pozostawiamy tak jak jest i klikamy Finish.
W oknie Project Explorer powinien się pojawić nasz projekt. Rozwijamy go by była widoczna zawartość gałęzi "src" i tam mamy już dostępny plik "main.c". Klikamy na niego by otworzył się w edytorze obok. Na razie jest to podstawowy szablon jego zawartości z funkcja main() i pustą pętlą główną for(;;). Zaznaczamy wszystko i kasujemy, by zastąpić to naszym przykładowym kodem:
Code: Select all
/**
******************************************************************************
* @file main.c
* @author Ac6
* @version V1.0
* @date 01-December-2013
* @brief Default main function.
******************************************************************************
*/
#include "stm32f0xx.h"
#include "stm32f0xx_ll_bus.h"
#include "stm32f0xx_ll_cortex.h"
#include "stm32f0xx_ll_utils.h"
#include "stm32f0xx_ll_gpio.h"
int main(void)
{
/* konfigurujemy SysTick by można użyc funkcji opóźniającej */
/* domyślnie procesor w pełni pracuje na częstotliwosci 8MHz!! */
LL_Init1msTick(8000000);
/* włączamy zegar dla GPIOA */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
/* definiujemy strukturę konfiguracji portu GPIO */
LL_GPIO_InitTypeDef gpio;
/* i wypełniamy ją potrzebnymi danymi */
gpio.Pin = LL_GPIO_PIN_5;
gpio.Mode = LL_GPIO_MODE_OUTPUT;
gpio.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
/* teraz przekazujemy gotową konfigurację */
LL_GPIO_Init(GPIOA, &gpio);
for(;;){
/* ustawiamy stan wysoki na PA5 i czekamy sekundę */
LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_5);
LL_mDelay(1000);
/* ustawiamy stan niski na PA5 i czekamy sekundę */
LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_5);
LL_mDelay(1000);
}
}
Edytor wykaże w nim ok. 10 błędów, ale to normalne, gdyż jeszcze nie wie, że będziemy używać bibliotek LL zamiast HAL. Przechodzimy do Project -> Properites i w sekcji C/C++ Build zaznaczamy Settings. Tam na otwartej zakładce odnajdujemy sekcję Preprocesor. Zamieniamy symbol "USE_HAL_DRIVER" na "USE_FULL_LL_DRIVER" by uaktywniły się odpowiednie fragmenty w plikach nagłówkowych biblioteki.
Klikamy na Apply i poniżej na OK. Teraz wszystkie błędy powinny już zniknąć. Możemy spróbować skompilować nasz program. Klikamy na pasku narzędzi ikonę młotka - polecenie Build. Po pozytywnym zakończeniu operacji w dolnym oknie w zakładce Console powinniśmy zobaczyć raport z kompilacji z tabelą zajętości i wiadomość "<godzina> Build Finished (took <czas>)".
Teraz pozostało tylko wgrać nasz program do podłączonej płytki Nucleo. W tym celu odnajdujemy przycisk strzałeczki w okrągłym zielonym kółku - polecenie Run. Program zapyta nas jeszcze jaki typ aplikacji chcemy uruchomić. Wybieramy pierwszy od góry: "Ac6 STM32 C/C++ Application". Rozpocznie się proces wgrywania kodu za pomocą wbudowanego w płytkę Nucleo programatora ST-LINK. Dioda programatora zamiga na zielono i po chwili nasz program rozpocznie migać zieloną diodą połączoną z pinem PA5, co sekundę. To oznacza, że program został skompilowany poprawnie i wszystko działa jak należy.
W następnej części rozłożymy nasz pierwszy program na części pierwsze i poznamy co tam tak naprawdę się dzieje, i po co tyle linii kodu by to działało. Jak ktoś nie chce czekać na pełen opis to niech spojrzy na komentarze w kodzie.
Fin