poniedziałek, 9 listopada 2015

[2] STM32 M3 - Nucleo - F103RB - Taktowanie, licznik SysTick

Tym razem chciałem przedstawić sposób obsługi timerów w mikrokontrolerze z rdzeniem Cortex M3. Opiszę sposób inicjalizacji timerów oraz zastosowanie licznik SysTick jako pętli opóźniającej.

Wstęp


W tym układzie jest możliwość obsługi 7 wbudowanych timerów. Z czego do użytku typowego wykorzystuje się cztery z nich.

  • Cztery 16 bitowe timery;
  • Dwa układy czuwające (Watchdog);
  • Jeden Systick - jest to 24 bitowy licznik zliczający w dół od zadanej wartości.

Taktowanie


Układ taktowany jest z wewnętrznego oscylatora. Jego częstotliwość taktowania wynosi 8MHz. Przy korzystaniu z powielacza częstotliwości sygnał jest odpowiednio zwiększany do pożądanej wartości. Następnie ustawiamy wartość PLLMul, która przemnaża podawaną częstotliwość z HSI podzieloną przez 2. Wartość PLLMul można wybrać z przedziału od 2 do 16.



Jeśli chcemy uzyskać wartość taktowania maksymalną, jaką można otrzymać poprzez wewnętrzny oscylator, czyli 64MHz, to należy wybrać parametr PLLMul na 16 oraz AHB Prescaler na 1.

W takim przypadku otrzymamy następujące maksymalne taktowanie wszystkich linii.

  • APB1 GPIO - 32 MHz;
  • APB1 Timer - 64 MHz;
  • APB2 GPIO - 64 MHz;
  • APB2 Timer - 64 MHz;


Rys. 1.1. Taktowanie mikrokontrolera

Program 1 - Inicjalizacja SysTicka

Działanie systicka polega na zmniejszaniu wartości w kolejnych przejściach od wartości zadanej. Po przejściu układu przez 0 generowane jest przerwanie. Po wywołaniu przerwania zliczanie rozpoczyna się od nowa. Jego zadaniem jest odliczanie podanego przedziału czasu.

Konfiguracja tego licznika rozpoczyna się od podania wartości początkowej, od której nastąpi odliczanie. Od niej oraz od wartości taktowania zależy jak często będzie zgłaszane przerwanie przez licznik.

W pierwszej kolejności należy zdeklarować zmienną przechowującą wartości. Dalej następuje wybranie wartości początkowej licznika czyli co ile przerwanie będzie zgłaszane.

Przerwanie od licznika ma być zgłaszane co 1 ms czyli 1/1000 s. W związku z tym wybieramy sygnał jakim jest główny sygnał taktujący czyli 64MHz. Sygnał ten zostaje podzielony przez wartość 1000. Dzięki takiej operacji przerwanie będzie zgłaszane co 64000 takty układu.

#include "stm32f10x.h"
 
#define PinDioda GPIO_Pin_5
#define LineDioda GPIOA
#define ClockGPIOA RCC_APB2Periph_GPIOA
 
volatile uint32_t timer = 0;
 
void DelayInitial(void);
void DelayMs(uint32_t);
void SysTick_Handler(void);
void GpioInit(void);
 
int main(void)
{
 GpioInit();
 DelayInitial();
 
 while (1)
 {
  GPIO_SetBits(LineDioda, PinDioda);
  DelayMs(1000);
  GPIO_ResetBits(LineDioda, PinDioda);
  DelayMs(2000);
 }
}
 
void GpioInit(void)
{
    //inicjalizacja obiektu GPIO
    GPIO_InitTypeDef GpioInit;
 
    //Włączenie zegara dla linii GPIOA
    RCC_APB2PeriphClockCmd(ClockGPIOA, ENABLE);
 
    //Inicjalizacja pinu Dioda
    GPIO_StructInit(&GpioInit);
    //Wybranie konfigurowanego pinu
    GpioInit.GPIO_Pin = PinDioda;
    //Ustawienie pinu jak wyjście PushPull
    GpioInit.GPIO_Mode = GPIO_Mode_Out_PP;
    //Inicjalizacja linii z podanymi ustawieniami
    GPIO_Init(LineDioda, &GpioInit);
}
 
void SysTick_Handler()
{
 if(timer)
 {
  timer--;
 }
}
 
void DelayMs(uint32_t time)
{
 timer = time;
 while(timer)
 {}
}
 
void DelayInitial(void)
{
 //Ustawienie opóźnień co 1ms = 64000000 / 1000
 SysTick_Config(SystemCoreClock / 1000);
}

W przypadku gdy chcemy wywołać przerwania co 1us. Wtedy należy zmienić parametry w części DelayInit(). Wartość częstotliwości należy w takim przypadku podzielić przez 1000000. W takim przypadku przerwanie będzie wykonywane co 64 takty zegara.

void DelayInitial(void)
{
 SysTick_Config(SystemCoreClock / 1000000);
}

Systick pozwala na wykonanie bardzo dokładnej pętli opóźniającej. Dodatkowo możliwe jest jego zastosowanie w przypadkach pomiaru długości trwania stanu wysokiego np. w czujniku HCSR-04. Gdzie mierzona jest odległość czujnika od przeszkody. W takim przypadku mierzy się ilość wystąpień przerwania w czasie występowania stanu wysokiego na pinie.