niedziela, 9 października 2016

[5] STM32F4 - Systick na rejestrach

W tym poście chciałbym opisać sposób konfiguracji systicka z wykorzystaniem rejestrów. Programy będą miały za zadanie generować przerwanie co określoną ilość czasu przez licznik.

[Źródło: http://www.st.com/en/evaluation-tools/stm32f4discovery.html]

Do uruchomienia Systicka wykorzystuje się funkcje SysTick_Config(). Jako jej argument podaje się zmienną w formacie uitn32_t, która określa ilość ticków zegara.

Prezentuje się ona w następujący sposób:

  1. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
  2. {
  3.   if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */
  4.   SysTick->LOAD  = ticks - 1;                                  /* set reload register */
  5.   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  6.   SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  7.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
  8.                    SysTick_CTRL_TICKINT_Msk   |
  9.                    SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  10.   return (0);                                                  /* Function successful */
  11. }

Funkcja ma dosyć bogaty zestaw wykonywanych operacji, działa ona w następujący sposób:
  • Pierwsza instrukcja ma za zadanie sprawdzić czy podana ilość impulsów nie przekracza rozdzielczość liczniki, jeśli tak, to zostaje zwrócona wartość 1 i działanie funkcji zostaje zakończone.
  • Do rejestru LOAD jest ładowana wprowadzona ilość impulsów.
  • Ustawiany jest priorytet przerwania na możliwie najniższy.
  • Wartość rejestru VAL dla licznika zostaje wyzerowana.
  • Przedostatnia linijka ma za zadanie włączyć zegar, przerwania i sam licznik.
  • Na samym końcu zwracana jest wartość 0.

Jeśli chodzi o rejestry tego timera to można wyróżnić następujące:
  • Systick Control and Status - STCTRL - podstawowe sposoby kontrolowania Systicka jak włączenie zegarów, przerwań trybu poll.
  • Systick Reload Value - STRELOAD - wartość jaka ma być wgrana gdy zostanie osiągnięte 0.
  • SysTick Current Value - STCURR - wartość aktualna wproadzona do rejestru.
  • SysTick Calibration Value - STCALIB - zawiera ilość tików dla określonego interwału czasowego.


W celu konfiguracji należy załadować wartość do SysTick Reload Value z określonymi interwałami jakie są wymagane dla zdarzeń z tego licznika. Przerwanie jest aktywowane za pomocą bitu Countflag w rejestrze kontrolnym, podczas zmiany z 1 na 0. 

Aby Systick był ustawiony na przerwania to należy wykorzystać Tickinit czyli pierwszy bit rejestru kontrolnego w stan wysoki.  Dodatkowo odpowiednie przerwanie w NVIC musi zostać włączone. Zegar jakim będzie taktowany licznik wybiera się poprzez bit 2 czyli CLKSource. Jedynka oznacza zegar systemowy, natomiast zero oznacza zewnętrzny.

Program:


Poniższy program jak już wspomniałem wcześniej ustawia odpowiednią wartość w rejestrze systicka tak aby on zapalał oraz gasił diodę co określony interwał czasowy.

  1. volatile zmienna = 0;
  2. int main(void)
  3. {
  4.     RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; //Wlaczenie zegara dla GPIOD
  5.     __DSB();                             //Odczekanie na wykonanie instrukcji
  6.    
  7.     //Konfiguracja pinu
  8.     GPIOD->MODER |= GPIO_Mode_OUT;
  9.     GPIOD->OSPEEDR |= GPIO_Speed_25MHz;
  10.     GPIOD->OTYPER |= GPIO_OType_PP;
  11.     GPIOD->PUPDR |= GPIO_PuPd_NOPULL;
  12.     SysTick_Config(16000000/4);         //Domyślna predkosc czyli HSI 16MHz przez 2.
  13.     while(1);
  14. }
  15. void SysTick_Handler(void){
  16.     if (zmienna==0)
  17.     {   zmienna++;
  18.         GPIOD->BSRRL |= 0x1000;
  19.     }
  20.     else if(zmienna==1)
  21.     {   zmienna++;
  22.         GPIOD->BSRRL |= 0x2000;
  23.     }
  24.     else if(zmienna==2)
  25.     {   zmienna++;
  26.         GPIOD->BSRRL |= 0x4000;
  27.     }
  28.     else if(zmienna==3)
  29.     {   zmienna++;
  30.         GPIOD->BSRRL |= 0x8000;
  31.     }
  32.     else
  33.     {
  34.         zmienna=0;
  35.         GPIOD->BSRRH = 0xF000;
  36.     }
  37. }

W funkcji użyto instrukcji _DSB(). Ma ona za zadanie odczekać pewien okres czasu aż zegary zostaną uruchomione (Errata dla STM32F40x str. 15). Inna metoda, którą można użyć zamiast tej wykorzystuje odczekania pewnej ilości instrukcji NOP(). Dwie takie instrukcje dla zegara AHB oraz 1 + preskaler od AHB/APB dla zegara APB. W obsłudze przerwania cyklicznie będą włączane kolejne diody aż do zapalenia wszystkich. Wtedy zostaną one wyzerowane i cykl zacznie się od początku.

Poniżej przedstawiam drugi przykład programu, gdzie systick nie działa w trybie przerwania tylko w tzw. trybie pulling.

Domyślnie Systick jest ustawiany w tryb polling, co oznacza, że należy w pętli while sprawdzać czy przerwanie zostało wygenerowane. Jest to włączane poprzez bit Countflag. Odczytywanie z tego rejestru powoduje wyczyszczenie bitu tej flagi.

  1. volatile zmienna = 0;
  2. int main(void)
  3. {
  4.     RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; //Wlaczenie zegara dla GPIOD
  5.     __DSB();                             //Odczekanie na wykonanie instrukcji
  6.    
  7.     //Konfiguracja pinu
  8.     GPIOD->MODER |= GPIO_Mode_OUT;
  9.     GPIOD->OSPEEDR |= GPIO_Speed_25MHz;
  10.     GPIOD->OTYPER |= GPIO_OType_PP;
  11.     GPIOD->PUPDR |= GPIO_PuPd_NOPULL;
  12.    
  13.     SysTick->LOAD = 8000000 - 1;
  14.     SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
  15.    
  16.     while(1){
  17.         if (zmienna==0)
  18.         {   zmienna++;
  19.             GPIOD->BSRRL |= 0x1000;
  20.         }
  21.         else if(zmienna==1)
  22.         {   zmienna++;
  23.             GPIOD->BSRRL |= 0x2000;
  24.         }
  25.         else if(zmienna==2)
  26.         {   zmienna++;
  27.             GPIOD->BSRRL |= 0x4000;
  28.         }
  29.         else if(zmienna==3)
  30.         {   zmienna++;
  31.             GPIOD->BSRRL |= 0x8000;
  32.         }  
  33.         else
  34.         {   zmienna=0;
  35.             GPIOD->BSRRH = 0xF000;
  36.         }
  37.     }
  38. }

Dokumentacja

[1] Systick Timer
[2] Errata