STM32F0Discovery: jak zacząć

W artykule przedstawiamy krok-po-kroku kroki niezbędne do szybkiego rozpoczęcia pracy z zestawem STM32F0Discovery, a także prosty projekt przygotowany w środowisku programistycznym ?Vision firmy Keil/ARM. Przykładowa aplikacja obsługuje przycisk i dwie diody LED zastosowane na płytce zestawu.

Przed przystąpieniem do pracy ze środowiskiem IDE ważnym jest aby mieć zainstalowany w systemie sterownik programatora ST-LINK/V2. Jeżeli nie był on wcześniej instalowany to należy pobrać ze strony producenta w zakładce Design support plik ST-LINK/V2 USB driver for Windows 7, Vista and XP i zainstalować go.

Środowisko programistyczne ?Vision można pobrać ze strony producenta. W tym celu na stronie głównej należy przejść do sekcji Download, wybrać opcję Product Downloads i spośród czterech realizacji oprogramowania wybrać wersję MDK-ARM przeznaczoną dla mikrokontrolerów z rdzeniem ARM Cortex-M. Następnie należy wypełnić formularz i kliknąć przycisk Submit po czym pojawi się link do pobrania oprogramowania. Po pobraniu i zainstalowaniu środowiska przystąpimy do utworzenia projektu prostej aplikacji obsługującej dwie diody i przycisk jakie są dostępne na płytce STM32F0Discovery.

 

Film ilustrujący działanie zestawu STM32F0Discovery z programem przykładowym, opisanym w artykule

 

 

Projekt programistyczny

Nowy projekt tworzymy wybierając z menu Project->New uVision Project… i po pojawieniu się okienka Create New Project wybieramy katalog w którym będzie zapisany plik projektu. Przykładowo, plik projektu można zapisać w katalogu STM32F0_SimpleApp\Project, natomiast pliki źródłowe można umieszczać w katalogu STM32F0_SimpleApp\Application. Po zapisaniu pojawi się okienko wyboru urządzenia docelowego Select Device for Target i należy tutaj wybrać mikrokontroler ST->STM32F051R8 jaki znajduje się na płytce STM32F0Discovery. Klikamy OK i po pojawieniu się pytania czy dodać plik startowy startup_stm32f0xx.s  do projektu wybieramy Tak. Standardowo plik będzie się znajdował w katalogu gdzie jest zapisany plik projektu.

Na płytce STM32F0Discovery znajduje się wbudowany programator ST-LINK/V2 dlatego informujemy środowisko ?Keil, że dany projekt będzie z niego korzystał. Z głównego okna programu wywołujemy okienko Options for Target (rysunek 1) w którym znajdują się dwie zakładki: Debug oraz Utilities. W pierwszej zaznaczamy radio button Use i z rozwijanej listy wybieramy ST-Link (Deprecated Version) (rysunek 2). Jeżeli przy próbie wejścia w tryb Debug pojawi się komunikat Unknown target connected to należy sprawdzić czy jest wybrany protokół SWD w okienku STLink Setup wywoływany przyciskiem Settings w tejże zakładce Debug obok wybranego wcześniej interfejsu ST-Link.

 

Rys. 1. Ikona do wywołania okienka Options for Target

Rys. 1. Ikona do wywołania okienka Options for Target

 

Rys. 2. Przykładowa konfiguracja w zakładce Debug

Rys. 2. Przykładowa konfiguracja w zakładce Debug

 

W drugiej zakładce zaznaczamy Use Target Driver for Flash Programming i z listy rozwijanej wybieramy ST-Link (Deprecated Version) (rysunek 3).

 

Rys. 3. Przykładowa konfiguracja w zakładce Utilities

Rys. 3. Przykładowa konfiguracja w zakładce Utilities

 

Kolejnym ważnym krokiem jest pobranie kodów źródłowych obsługi rdzenia i peryferii, które znacząco ułatwiają pisanie programów końcowych. Na stronie producenta zestawu w zakładce Design support należy odszukać plik archiwalny, który nazywa się STM32F0 Discovery kit firmware package, including 21 examples and preconfigured projects for 4 different IDEs. Po pobraniu i rozpakowaniu archiwum należy skopiować katalog STM32F0xx_StdPeriph_Driver z katalogu Libraries oraz katalog STM32F0-Discoveryz katalogu Utilities i umieścić je w katalogu plików źródłowych tworzonego projektu SimpleApp/Application. Tworzymy również tutaj nowe katalogi o nazwach CMSIS oraz User. Do katalogu CMSIS kopiujemy pliki core_cm0.hcore_cmInstr.c  oraz core_cmFunc.c z katalogu Libraries\CMSIS\Include, pliki stm32f0xx.h i system_stm32f0xx.h z katalogu Libraries\CMSIS\ST\STM32F0xx\Include, oraz plik system_stm32f0xx.c z katalogu system_stm32f0xx.c.

W pobranym pliku archiwalnym znajdują się również przykładowe projekty przedstawiające możliwości zestawu. Kody źródłowe jednego z nich zostaną wykorzystane do budowy prostej aplikacji. Z katalogu Project\Demonstration do naszego katalogu User kopiujemy pliki: main.c, main.h, stm32f0xx_conf.h, stm32f0xx_it.c oraz stm32f0xx_it.h. Pierwsze dwa pliki zawierają odpowiednio algorytm końcowy działania aplikacji oraz definicje. Kolejny plik zawiera informację jakie elementy biblioteki StdPeriph włączyć do kompilacji projektu. Ostatnie dwa pliki opisują jak mają być obsługiwane przerwania.

W oknie plików projektu Project programu głównego klikamy prawym przyciskiem myszy na najwyższym elemencie struktury plików ze standardową nazwą Target 1 i z wywołanego menu kontekstowego wybieramy Add group… po czym podajemy nazwę grupy User. W podobny sposób tworzymy grupy: STM32F0_Discovery, STM32F0xx_StdPeriph_Driver oraz CMSIS. Warto również zmienić nazwę grupy do której został dodany plik startowy z rozszerzeniem .s na MDK-ARM. Następnie klikając po kolei na utworzonych grupach i wywołując menu kontekstowe wybieramy opcję Add Files to Group… i dodajemy pliki źródłowe w taki sposób jak to przedstawiono na rysunku 4.

 

Rys. 4. Struktura plików projektu

Rys. 4. Struktura plików projektu

 

W trakcie kompilacji projektu potrzebne są ścieżki dostępu do poszczególnych plików źródłowych dlatego w okienku Options for Target w zakładce C/C++ klikamy na przycisk obok Include Paths (rysunek 5) i dodajemy je (rysunek 6). Oprócz tego w polu Define należy wpisać USE_STDPERIPH_DRIVER.

 

Rys. 5. Zakładka C/C++

Rys. 5. Zakładka konfiguracyjna C/C++

 

Rys. 6. Okno Include Paths

Rys. 6. Okno Include Paths

 

Teraz można skompilować projekt przechodząc do menu Project->Build Target lub wcisnąć na klawiaturze klawisz F7. Jeżeli wszystko jest w porządku to w okienku Build Output powinien się pojawić następujący komunikat:

Aby zobaczyć efekt działania aplikacji należy podłączyć płytkę STM32F0Discovery do portu USB oraz wejść w tryb debugowania (rysunek 7) i uruchomić wykonywanie programu (rysunek 8). Aby zatrzymać wykonywanie się programu należy wcisnąć przycisk po prawej stronie obok przycisku Start, a przycisk po lewej stronie zeruje układ.

 

Rys. 7. Ikona wejścia w tryb Debug

Rys. 7. Ikona wejścia w tryb Debug

 

Rys. 8. Ikona inicjująca uruchomienie programu

Rys. 8. Ikona inicjująca uruchomienie programu

 

Przykładowa aplikacja

Elementy jakie znajdują się na płytce zestawu i jakie zostaną wykorzystane w prostej aplikacji to (fotografia 9):

  • zielona dioda LD3 podłączona do wyprowadzenia mikrokontrolera PC9,
  • niebieska dioda LD4 podłączona do wyprowadzenia mikrokontrolera PC8,
  • przycisk USER podłączony do wyprowadzenia mikrokontrolera PA0.

 

Fot. 9. Rozmieszczenie na płytce STM32F0Discovery elementów wykorzystanych w przykładowym projekcie

Fot. 9. Rozmieszczenie na płytce STM32F0Discovery elementów wykorzystanych w przykładowym projekcie

 

Według schematu elektrycznego (rysunek 10) aby włączyć LED należy podać logiczną jedynkę na wyprowadzenie GPIO (skonfigurowane jako wyjście), do którego jest ona podłączona, natomiast aby ją zgasić należy podać na tę linię logiczne zero. Przycisk USER jest podłączony do linii PA0, a pomiędzy nim, a ujemnym biegunem źródła zasilania znajduje się rezystor. Jest to więc układ typu pull-down, dlatego stan niski odczytany na wejściu linii PA0 oznacza, że przycisk nie jest wciśnięty.

 

Rys. 10. Schemat podłączenia LED i przycisku do linii GPIO mikrokontrolera

Rys. 10. Schemat podłączenia LED i przycisku do linii GPIO mikrokontrolera

 

Funkcje pomocnicze zdefiniowane w pliku stm32f0_discovery.c

Plik stm32f0_discovery.h zawiera kilka definicji stałych wykorzystywanych w programie:

W pliku stm32f0_discovery.c znajdują się definicje sześciu pomocnych funkcji do pracy z diodami i przyciskiem:

Pierwsza funkcja przyjmuje jako argument wartość LED3 (liczba 0) albo LED4 (liczba 1), włącza sygnał zegarowy w obu przypadkach taktujący układ PORTC, który jest podłączony do szyny AHB, konfiguruje wyprowadzenie (PC8 lub PC9) na wyjście typu push-pull bez wewnętrznych rezystorów podciągających i do pracy z maksymalną częstotliwością 50 MHz:

Druga funkcja wykorzystuje rejestr BSRR do ustawiania w stan wysoki określonych linii portu. Tutaj pod nazwą GPIO_PIN[Led] kryje się wartość GPIO_Pin_8 lub GPIO_Pin_9 (które są zdefiniowane jawnie w pliku stm32f0xx_gpio.h):

Funkcja wyłączająca diodę jest podobna do poprzedniej, ale wykorzystuje rejestr BRR do zerowania określonej linii portu:

Funkcja zmieniająca stan diody na przeciwny operuje na rejestrze danych wyjściowych ODR. Pobiera ona zawartość tego rejestru, wykonuje na niej operację XOR z wartością GPIO_Pin_8 lub GPIO_Pin_9 i zapisuje z powrotem do rejestru ODR:

Linia do której podłączony jest przycisk konfigurowana jest w funkcji STM_EVAL_PBInit() do której należy przekazać 2 argumenty. Pierwszy określa jaki przycisk będzie konfigurowany, a że na płytce jest dostępny tylko jeden przycisk do zastosowania w aplikacji to wystarczy przekazać stałą BUTTON_USER, albo liczbę 0. Drugi argument mówi czy linia będzie tylko skonfigurowana (BUTTON_MODE_GPIO) czy również będzie skonfigurowane przerwanie od zmiany jej stanu (BUTTON_USER_EXTI). W programie głównym wykorzystano pierwszą opcję bez wykorzystania przerwań, a linia PA0 jest konfigurowana jako wejście bez rezystorów podciągających, gdyż taki znajduje się już na płytce. Listing funkcji jest następujący:

Ostatnia funkcja z dostępnych w omawianym pliku pobiera stan linii PA0 i zwraca wartość SET (przycisk włączony) lub RESET (przycisk wyłączony):

Program główny

Algorytm działania programu głównego jest następujący:

  • po podłączeniu układu do portu USB komputera zaczyna migać zielona dioda LED z częstotliwością 2,5 Hz,
  • jeżeli zostanie wciśnięty przycisk USER i przytrzymany aż do zapalenia się niebieskiej diody LED to zielona dioda zacznie migać szybciej, z częstotliwością 5 Hz,
  • ponowne wciśnięcie i przytrzymanie przycisku USER do ponownego zapalenia się niebieskiej diody powoduje, że zielona dioda zostanie wyłączona,
  • kolejne wciśnięcia przycisku powodują powtórzenie powyższych działań.

Listing funkcji main() z pliku main.c przedstawiono poniżej:

Odliczanie czasu 1 ms jest realizowane przez systemowy timer SysTick, który domyślnie zlicza kolejne takty sygnału zegarowego HCLK do zadanej przez użytkownika wartości, a po przekroczeniu jej zeruje licznik i generuje zdarzenie, które skutkuje pojawieniem się przerwania i wywołaniem funkcji obsługi przerwania SysTick_Handler(), której zawartość może być modyfikowana w pliku SysTick_Handler(). Częstotliwość sygnału HCLK wynosi 48 MHz – szczegóły znajdują się w pliku system_stm32f0xx.c.

Na początku funkcji main() jest deklarowana zmienna RCC_Clocks, która jest przekazywana jako argument do funkcji RCC_GetClocksFreq(). Jest to potrzebne do pobrania informacji o częstotliwościach poszczególnych zegarów w systemie, a w danym przypadku interesuje nas częstotliwość zegara HCLK, która zostanie podzielona przez 1000 i przekazana do funkcji SysTick_Config(). Oznacza to w danym konkretnym przypadku, że jeżeli wartość pola HCLK_Frequency podzielimy przez 1000 to otrzymamy 48,000 i po przekazaniu jej do powyższej funkcji SysTick będzie zliczał 48,000 impulsów sygnału zegarowego HCLK po czym wygeneruje przerwanie. Podczas działania programu przerwanie to będzie generowane przez cały czas co 1 ms.

Wywołanie funkcji Delay() z argumentem w jednostkach 1 ms powoduje zapisanie do zmiennej TimingDelay wartości tego argumentu oraz oczekiwanie w pętli while() dopóki zmienna ta jest różna od 0:

Zmienna TimingDelay jest dekrementowana (jeżeli jest różna od zera) w funkcji TimingDelay_Decrement() wywoływanej co 1 ms z funkcji obsługi przerwania od SysTick:

Jan Szemiet

Do pobrania