Precyzyjne opóźnienia w połączeniu z trybami oszczędzania energii w STM32, część 2

Spójrzmy ponownie na rysunek 1. Do wejścia dzielnika AHB podłączony jest sygnał SYSCLK. Może to być sygnał 8 MHz z wewnętrznego oscylatora RC HSI (tak dzieje się po włączeniu zasilania, po resecie lub po wyjściu z trybu głębokiego uśpienia), sygnał HSE z oscylatora kwarcowego lub sygnał PLLCLK z wyjścia PLL1. Do wejścia PLL1 można dołączyć sygnał HSI podzielony przez 2 lub sygnał z wyjścia dzielnika częstotliwości PREDIV1. Do wejścia dzielnika PREDIV1 można dołączyć sygnał HSE lub sygnał PLL2CLK z wyjścia PLL2. Do wejścia PLL2 podłączony jest sygnał HSE przez dzielnik PREDIV2. Dobierając wartości współczynników podziału i mnożniki PLL, możemy uzyskać szereg różnych częstotliwości HCLK taktowania rdzenia.
W omawianym przykładzie zakładamy, że oscylator kwarcowy HSE ma częstotliwość 5, 10, 15, 20 lub 25 MHz. Sygnał z tego oscylatora przez dzielnik PREDIV2 jest podawany na wejście PLL2. Wartość dzielnika dobieramy tak, aby na wejściu PLL2 mieć zawsze sygnał o częstotliwości 5 MHz. Mnożnik PLL2MUL ustawiamy na 8, zatem na wyjściu PLL2 uzyskujemy sygnał PLL2CLK o częstotliwości 40 MHz. Sygnał ten podajemy na wejście dzielnika PREDIV1, który ustawiamy na 5. Zatem na wyjściu dzielnika PREDIV1 mamy sygnał o częstotliwości 8 MHz, który podajemy na wejście PLL1. Dobierając mnożnik PLLMUL spośród wartości 6, 7, 8 lub 9, uzyskujemy na wyjściu PLL1 sygnał PLLCLK o częstotliwości odpowiednio 48, 56, 64 lub 72 MHz, który podajemy na wejście dzielnika AHB. Ustawiając wartość tego dzielnika na 1, 2 lub 4, uzyskujemy pożądaną częstotliwość sygnału HCLK.
Omawiany przykład napisany jest na mikrokontroler STM32F107, który należy do linii zorientowanej na komunikację (ang. connectivity line). Używamy Standard Peripheral Library. Podczas kompilacji wszystkich plików źródłowych przykładu oraz plików bibliotecznych muszą być zdefiniowane stałe preprocesora STM32F10X_CL i USE_STDPERIPH_DRIVER. Stałe te należy wyspecyfikować w konfiguracji projektu lub w wierszu poleceń kompilatora. Analogicznie powinna też zostać zdefiniowana wartość stałej HSE_VALUE, która oznacza częstotliwość podłączonego do mikrokontrolera kwarcu w Hz. Przyjęta konfiguracja sygnałów taktujących dopuszcza częstotliwości kwarcu będące wielokrotnościami 5 MHz. Taka sama wartość tej stałej musi być użyta podczas kompilowania Standard Peripheral Library. Należy dodać, że jeśli nie zdefiniujemy tej stałej, to przy zdefiniowanej stałej STM32F10X_CL domyślna wartość częstotliwości wynosi 25000000 Hz. Taki właśnie kwarc jest zamontowany na „motylu”, na którym testowany był omawiany przykład. Należy też zwrócić uwagę, że w wersjach biblioteki starszych niż 3.2.0 stała ta nazywała się HSE_Value. Trzeba wtedy przed pierwszym użyciem stałej HSE_VALUE dodać definicję:

Program i układ testowy

Układ testowy przedstawiony jest na rysunku 2 (zestaw STM32Butterfly lub STM32Butterfly2). Używamy dwóch diod świecących. LED1 wykorzystujemy do informowania o poprawnym lub niepoprawnym zakończeniu konfigurowania mikrokontrolera lub do sygnalizacji, że mikrokontroler jest w stanie aktywnym. LED2 sygnalizuje, że mikrokontroler jest w trakcie obsługi przerwania, które jest zgłaszane narastającym zboczem na wyprowadzeniu PA0 za pomocą przycisku SW. Pozwala to testować wybudzanie z trybów uśpienia i zatrzymania w celu obsłużenia przerwania. Po jego obsłużeniu mikrokontroler powinien ponownie zasnąć. Czas opóźnienia nie powinien
zależeć od ilości zgłoszonych i obsłużonych w jego trakcie przerwań. Przycisk SW ma jeszcze jedną funkcję. Wyprowadzenie PA0 skonfigurowaliśmy tak, aby narastające zbocze na nim wyprowadzało mikrokontroler z trybu czuwania. Wyjście FREQ służy do pomiaru czasu opóźnień poprzez pomiar częstotliwości generowanego na nim przebiegu.

Rys. 2. Układ testowy

Rys. 2. Układ testowy

List. 6. Sygnatury funkcji obsługujących wyjścia, umieszczone w pliku out.h

Sygnatury funkcji obsługujących wyjścia przedstawiono na listingu 6. Funkcje te są standardowe i dlatego nie zamieszczono ich szczegółowej implementacji. Funkcja OutConfigure konfiguruje porty wyjściowe. Wyprowadzenia LED i FREQ konfigurujemy jako wyjścia przeciwsobne (ang. push-pull). Wyjścia LED konfigurujemy dla maksymalnej częstotliwości 2 MHz, a wyjście FREQ – 50 MHz. Funkcje LED1on, LED1off, LED2on i LED2off, zgodnie z nazwami, włączają lub wyłączają odpowiednią LED. Funkcja FREQon ustawia wysoki poziom na wyjściu FREQ, a funkcja FREQoff – poziom niski. Funkcja Error gasi LED1, a potem wykonuje podaną jako argument liczbę mignięć LED1, po czym odczekuje dłuższą chwilę. Funkcja ta sygnalizuje błędy w połączeniu z makrem error_check. Makro to wywołujemy, aby sprawdzić, czy jakaś funkcja zakończyła się poprawnie. Jako pierwszy argument tego makra umieszczamy wywołanie funkcji, która zwraca zero przy poprawnym zakończeniu, a wartość ujemną, gdy wystąpi błąd. Jako drugi argument podajemy numer błędu – liczbę mignięć LED1. Przykładowo:

Sygnatura funkcji KeyConfigure konfigurującej wyprowadzenie, do którego podłączono przycisk jest przedstawiona na listingu 7.

List. 7. Sygnatura funkcji konfigurującej przycisk, umieszczona w pliku key.h

Jej implementacja zamieszczona jest na listingu 8. Znajduje się tam też procedura obsługi przerwania EXTI0_IRQHandler, która symuluje wykonywanie jakichś obliczeń za pomocą funkcji Delay.

List. 8. Implementacja obsługi przycisku, umieszczona w pliku key.c

O autorze