Tenhle díl jsem napsal na základě problémů kolegy, který se snažil pomocí časovače donutit mcu k pravidelnému vykonávání nějakého programu. Snad tedy připojené demo a moje povídání pomůže v realizaci tohoto nápadu i ostatním.




Úvodem

Při požadavku na pravidelné vykonávání nějakého kódu je asi nejjednodušším řešením využít časovače a nějaké jeho události. Tuto událost využít jako podklad pro vyvolání přerušení a kód, který budeme chtít pravidelně vykonávat umístíme do handleru přerušení. Událostí, které mohou časovače generovat je celá řada. Nejjednodušším je událost TIM_IT_Update, což je událost vyvolaná v okamžiku znovunaplnění hodnoty čítače inicializační hodnotou. Pochopitelně že časovač můžeme využít i mnohem komplikovaněji - časovače též mohou sloužit ke generování několika různých PWM signálů (každý ve svém compare/capture kanále). Takže například časovač TIM2 má 4 kanály a proto můžeme nastavit různé střídy pro jednotlivé kanály, čímž dostaneme až 4 různé časy pro tento časovač. Dosažení nastavené hodnoty pro první kanál vyvolá událost TIM_IT_CC1 a obdobně pro druhý kanál TIM_IT_CC2, atd. Tudíž za cenu mírného zesložitění programu (odchytáváme 4 události a musíme vždy nastavovat nově hodnotu Compare pro daný kanál) můžeme jedním časovačem vytvořit až 4 pravidelně se opakující časy. Dobrý příklad na tento složitější způsob poskytuje STMicroelectronics ve svých demoexamplech fe firmware k STM32F4Discovery kitu (naleznete jej pod názvem TIM_TimeBase v Peripherial_Examples.
Nicméně, pokud nemáme nějakou moc složitou aplikaci, tak nemusíme využití čítače tak komplikovat a využijeme ten jednodušší, výše popsaný způsob.


Přerušení pomocí TIM_IT_Update

Jako časovač si zvolíme třeba časovač č. 2. Jak se můžete přesvědčit v datasheetu k STM32F405 (kap. 2.2.20, Tabulka 3), tak TIM2 patří mezi obecně použitelné časovače, které mají 32-bitový čítač a maximální rychlost hodin pro tento časovač je 84 MHz. Jinými slovy řečeno nejkratší událost, kterou tímto časovačem můžeme změřit je cca 11,9 ns a pak můžeme měřit násobky tohoto času až do hodnoty 11,9ns * 2^32 = 51,13 s (použil jsem 2^32, protože máme 32-bitový časovač).
Pro naše potřeby nám toto časové rozpětí stačí. Kdybychom potřebovali měřit delší časy, tak musíme použít předděličku čítače, která dělí kmitočet hodin přicházejících do čítače. Protože předdělička je 16-ti bitová, tak si dobu můžeme prodloužit maximálně na 51,13 * 65536 = 3350892 s, jinými slovy řečeno, na pěkně dlouhou dobu.

/* Set the prescaler value */
PrescalerValue = (uint16_t) (0);


Jako další věc se vrhneme na Reference Manual pro STM32F4, konkrétně tedy RM0090. A podíváme se na kapitolu 14.2 pojednávající o obecných čítačích a ověříme si, že tam skutečně je napsáno že můžeme využít ke generování přerušení. Může Vám to připadat jako trivialita, ale je dobré se o podrobnostech vnitřku HW raději přesvědčit předem. Tudíž můžeme pokračovat a nastavíme si timer. Začneme tím, že si pustíme hodiny.

 /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);


Pak nastavíme vlastní hodnoty pro čítač.

 /* budeme odmerovat cas 1s, pak Perioda =  1/11,9ns = 84000000 */
  Perioda = 84000000;

  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = Perioda;
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);


Pochopitelně že si můžete vyzkoušet jinou dobu. Dále si nastavíme nested vektor přerušení.

 /* Set the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);


Protože v tomto jednoduchém příkladu máme jen jedno přerušení, tak se nemusíme zatěžovat jeho prioritami. V opačném případě se pak musíme zamyslet, zda nemáme některé přerušení tak významné, aby mělo přednost před ostatními - pokud ano, tak mu nastavíme NIŽŠÍ prioritu (tedy významnější) a je vykonáno přednostně před přerušeními s vyšší prioritou. Podrobně jsme to probírali v kapitole věnovaným přerušením u STM32VL Discovery kitu.

Tak a konfiguraci máme celou hotovou. Ještě vše povolíme aby čítač čítal a přerušení se generovala.

 /* TIM Interrupts enable */
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

  /* TIM2 enable counter */
  TIM_Cmd(TIM2, ENABLE);


Nyní nám zbývá napsat handler pro přerušení. Tedy ten kód programu, který se vykoná po okamžiku vzniku námi vybrané události. Handler dáváme dle zvykových pravidel do souboru stm32f4xx_it.c. Handler nám stačí primitivní, jen změníme stav svitu zelené LED.

void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    STM_EVAL_LEDToggle(LED4);
  }
}


Tedy zjistíme zda událost vyvolaná čítačem 2 je ta naše (TIM_IT_Update) a pokud ano, tak začneme provádět náš kód. Nesmíme zapomenout vymazat příznak této události pomocí TIM_ClearITPendingBit(TIM2, TIM_IT_Update);.

A to je opravdu vše, nic složitého a krásně to funguje, jak se můžete přesvědčit. Nezávisle na jiné činnosti v hlavní smyčce (z demonstračních důvodů je tam blikání LED5 po stisku USER tlačítka) LED4 tvrdohlavě mění svůj stav každou sekundu.


Závěr

Využití časovačů podobným způsobem a využití DMA je hlavní změna, kterou se programátoři 8-mi bitových mcu musí naučit chápat a využívat. Na ARM není dobré se dívat jako na statický systém, kde vykonání každé operace trvá předem známou dobu. Lépe je řešit systém jako sadu úloh, které probíhají nezávisle na sobě - lineární programování se pomalu se zvyšující se složitostí obvodů začíná blížit víceúlohovému jednoduchému operačnímu systému.


Odkazy

Projekt v pravém korálovém studiu 3.1.0 k tomuto dílu si můžete stáhnout zde.
Popis STM32F4 Discovery kitu odkaz
Homepage kitu na webu ST odkaz
Databrief ke kitu odkaz
User Manual 1472 ke kitu odkaz
Getting Started odkaz
Datasheet k mcu na kitu odkaz
Reference Manual RM0090 k mcu na kitu odkaz

Začínáme s STM32F4 kitem 1. odkaz (vývojové prostředí, atd.)
Začínáme s STM32F4 kitem 2. odkaz (USB Úvod)
Začínáme s STM32F4 kitem 3. odkaz (USB Enumerace)
Začínáme s STM32F4 kitem 4. odkaz (USB Virtual COM port)
Modifikce USB HID pro STM32F103 odkaz
Začínáme s STM32F4 kitem 5. odkaz (označení portů, alternativní funkce)
Začínáme s STM32F4 kitem 6. odkaz (VGA monitor)
Začínáme s STM32F4 kitem 7. odkaz (USB HID)
Začínáme s STM32F4 kitem 7b. odkaz (Doplněk k HID - senzory)
Začínáme s STM32F4 kitem 8. odkaz (PC aplikace k USB HID)
Začínáme s STM32F4 kitem 9. odkaz (USB Bulk transport)
Začínáme s STM32F4 kitem 10. odkaz (Micro-Xplorer)