poniedziałek, 30 listopada 2015

[8] STM32 M3 - Nucleo - F103RB - Oszczędzanie energii

W tym poście chciałbym opisać możliwe tryby oszczędzania energii w mikrokontrolerach z rdzeniem Cortex M3.

Wstęp


Obecnie od nowych urządzeń wymaga się jak najniższego poboru prądu dotyczy to nie tylko korzyści środowiskowych ale i dłuższego czasu działania takich układów na baterii.

Pierwsza z dostępnych opcji dotyczy całkowitego wyłączenia nie wykorzystywanych układów peryferyjnych, lub ich chwilowego wyłączenia, jeśli nie są one w danej chwili wykorzystywane. Kolejnym sposobem jest obniżenie taktowania układów. Pozwoli to zmniejszyć pobór prądu tych układów. 


Poniżej przedstawiam przykładową tabelkę z dokumentacji przedstawiającą pobór prądu dla działania programu z pamięci Flash. Można na niej zaobserwować znaczące zmniejszenie poboru prądu dla niższych częstotliwości. Tak samo prezentuje się sytuacja dla pozostałych układów. Ważnym parametrem jest także temperatura pracy układu. Im jest ona większa tym pobór prądu też ulega zwiększeniu. Nie jest to jednak aż tak odczuwalne.

Rys. 1.1. Pobór prądu

Oprócz możliwości doboru częstotliwości pracy, na stałe bądź dynamicznie, istnieje też możliwość wykorzystywanie trybów oszczędzania energii, takich jak: uśpienie, głębokie uśpienie, zatrzymanie bądź czuwanie.

Tryb uśpienia


Tryb uśpienia charakteryzuje się tym, że dla niego zostaje utrzymane zasilanie głównego rdzenia, natomiast taktowanie zostaje całkowicie wyłączone.
Ustawienie tej funkcji jest możliwe dzięki funkcji NVIC_SystemLPConfig. Możliwe są trzy opcje wejścia w stan uśpienia podstawowy NVIC_LP_SEVONPEND, wejście po zakończeniu obsługi konkretnego układu NVIC_LP_SLEEPONEXIT oraz wejście w stan głębokiego uśpienia, które jest dostępne tylko z drugiego z wymienionych trybów NVIC_LP_SLEEPDEEP.

Funkcja w bibliotece prezentuje się następująco:

void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_NVIC_LP(LowPowerMode));
  assert_param(IS_FUNCTIONAL_STATE(NewState));  
 
  if (NewState != DISABLE)
  {
    SCB->SCR |= LowPowerMode;
  }
  else
  {
    SCB->SCR &= (uint32_t)(~(uint32_t)LowPowerMode);
  }
}

Jako pierwszy argument należy podać jeden z trybów wymienionych powyżej, jako drugi natomiast włączenie bądź wyłączenie wybranej opcji (Enable lub Disable).

Aby wejść w ten tryb należy wywołać makro __WFI(), którego zadaniem jest wejście w stan uśpienia po czym następuje oczekiwanie na pojawienie się przerwania. Makro __WFE() działa tak samo z tą różnicą, że oczekuje ono na zdarzenie. Przedstawione makra pozwalają na wybudzenie z trybu uśpienia, po takim wybudzeniu nie wracają one z powrotem do tego trybu.

Druga opcja tzn. NVIC_LP_SLEEPONEXIT powoduje, jak już wspomniałem wcześniej, wejście układu w tryb uśpienia po wykonaniu przerwania. Makra pozwalają na uśpienie, nawet jeśli nie wywołano przerwania. 

Ostatnia trzecia opcja czyli tryb głębokiego uśpienia dodatkowo wyłącza także pętle PLL. Dzięki temu następuje całkowite wyłączenie układów peryferyjnych. W tym trybie jest najdłuższy okres przechodzenia do normalnej pracy. 

Tryb zatrzymania


Ten tryb pozwala na wyłączenie sygnałów taktujących, szyn systemowych i układów peryferyjnych. Włączone natomiast zostaje zasilanie do układów taktujących, zegar czasu rzeczywistego oraz układ czuwający watchdog. Ten tryb pozwala także na ograniczenie poboru układu stabilizatora napięcia do 1,8V.  
Funkcja z jakiej należy skorzystać wygląda następująco:

Wywołąnie tego trybu następuje poprzez wywołanie funkcji zamieszczonej powyżej z następującymi parametrami:

PWR_EnterSTOPMode(PWR_Regular_LowPower, PWR_STOPEntry_WFE);

Po wyjściu z tego trybu należy pamiętać o ponownej konfiguracji wszystkich zegarów, ponieważ zostają one całkowicie wyłączone i wymagają ponownej inicjalizacji.

Tryb czuwania


W tym trybie zostają wyłączone sygnały taktujące rdzeń, szyny systemowe, układy peryferyjne, zasilanie rdzenia oraz zasilanie układów peryferyjnych. Włączone natomiast zostają układy czuwające, RTC oraz rejestry chronione. Wywołanie tego trybu następuje poprzez funkcję umieszczoną poniżej. 

void PWR_EnterSTANDBYMode(void)
{
  /* Clear Wake-up flag */
  PWR->CR |= PWR_CR_CWUF;
  /* Select STANDBY mode */
  PWR->CR |= PWR_CR_PDDS;
  /* Set SLEEPDEEP bit of Cortex System Control Register */
  SCB->SCR |= SCB_SCR_SLEEPDEEP;
/* This option is used to ensure that store operations are completed */
#if defined ( __CC_ARM   )
  __force_stores();
#endif
  /* Request Wait For Interrupt */
  __WFI();
}

Wybudzenie z tego trybu jest inicjalizowane przez wyzerowanie układu, alarm wywołany zegarem czasu rzeczywistego, przepełnienie układu czuwającego bądź zbocze narastające wywołane na pinie WKUP czyli PA0.

Krótki opis działania wszystkich trybów został także umieszczony w nocie katalogowej w punkcie 2.3.12.

Na końcu przedstawiłem tabelę na której przedstawiono pobór prądu dla trybu zatrzymania oraz czuwania. Można nie niej zaobserwować dokładne różnice pomiędzy poszczególnymi trybami działania.

Rys. 1.2. Tabela poboru prądu dla różnych trybów działania