Určitě už se opakuji, ale timery na STM32 jsou senzační. Timer Link je toho důkazem. Jedná se o systém vnitřního propojování timerů a já myslím, že dozrál čas abychom ho zlehka nakousli. Samotný systém je velice jednoduchý, komplexní jsou až jeho aplikace. Už jste si asi všimli že některé timery mají vnitřní TRGO výstup (viz TIM2 na obrázku níže). Které timery mají TRGO nelze paušálně říct, záleží to totiž na konkrétním čipu. Typicky jsou to TIM1,2,3,4,5,8,9. Tyto timery mohou sloužit jako "mastery". Na TRGO výstup lze přivést signál z různých událostí. Například od přetečení nebo od spuštění/povolení timeru. Dále lze vyvést signál při restartu timeru (neřešme zatím co to je) nebo při compare události. V podstatě jde o všechny významné události, které v timeru mohou nastat. Tento TRGO signál je pak přiveden k ostatním timerům na vstupy ITR0 až ITR3 (ne každý timer je má). Při vhodné konfiguraci lze pak některý z ITRx signálů vybrat jako tzv TRGI a přivést do trigger controlleru, který s ním může naložit různými způsoby. Může tento signál přímo čítat do counteru (TRGI se tedy stává "clockem"), může signálem resetovat timer nebo ho spustit/povolit a nebo ho využívat jako "gate". V režimu "gate" timer čítá jen pokud je na TRGI log.1.
Jistě cítíte potenciál tohoto systému. Hravě můžete spojit dva 16bit timery za sebe (přetečení jednoho jako clock druhého) a vytvořit si tak 32bit timer. Nebo spojit dva 32bit timery do 64bitového. Lze také "PWM" signálem z jednoho timeru blokovat/gatovat jiný timer a vytvářet tím "přerušovaný" signál. Můžete timery synchronizovat (spuštění jednoho timeru skrze timer-link spustí další timery) a mnoho dalšího. Poslední věc kterou potřebujete vědět je jak jsou mezi sebou TRGO a ITRx propojeny. O tom vypovídá skupina tabulek z datasheetu. Já jsem si pro ukázku vzal tabulky z STM32F401RE.
Pro názornost vám jeden řádek rozklíčuji. Dejme tomu že nastavuji TIM5 a zajímalo by mě se kterými timery je spojen. V levém sloupci (Slave timer) si najdu TIM5 a vidím že na jeho signál ITR0 je připojen TRGO z TIM2, na ITR1 má přiveden TRGO z TIM3 a na ITR2 vede TRGO z TIM4. To je vše. TIM5 tedy není spojen s TIM1 (oproti některým dalším timerům). Zajímavý je ještě TIM9, který má na ITR2 a ITR3 připojen signál z compare jednotky TIM10 respektive TIM11 (ten je použitelný typicky pro "gatování/blokování" clocku pro TIM9).
Ještě než se pustíme do nějakého příkladu, podíváme se na funkce sloužící ke konfiguraci Timer Linku. V SPL knihovnách jsou to tyto
V LL API slouží ke stejnému účelu tyto funkce:
To by pro začátek mělo stačit a my se vrhneme na první příklad.
Představte si situaci kdy potřebujete generovat synchronní PWM signál na víc jak 4 kanálech. To nelze rozumně realizovat jedním timerem. Pomocí Timer Linku lze ale spustit synchronizovaně více timerů a lze tak podle čipu vytvořit 12-20 synchronizovaných PWM. My si ukážeme jak synchronizovat tři timery - TIM2,TIM3 a TIM5. Ukázka bude na STM32F401RE a přenést ji jako šablonu půjde na libovolné STM. Abychom mohli demonstrovat funkci spustíme si PWM na TIM2_CH1 (PA0), TIM5_CH2 (PA1) a TIM3_CH1 (PA6). Předpokládám že konfiguraci PWM už máte zvládnutou, takže se budu zabývat pouze synchronizací. Jako master využijeme TIM2 a jako TRGO mu zvolíme "Enable" signál. Na TRGO tedy přijde impulz v okamžiku spuštění TIM2. Oběma "slave" timerům (TIM3 a TIM5) vybereme příslušý ITRx (pro TIM5 je to ITR0 a pro TIM3 ITR1) a jako reakci na příchozí signál zvolíme "trigger" - tedy spuštění timeru. Celá akce bude vypadat tak že jakmile spustíme TIM2, projde signál po TRGO-TRGI spojení a spustí i oba "slave" timery. Z toho logicky plyne že TIM3 ani TIM5 ručně nespouštíme (funkci TIM_Cmd() nevolejte !) a TIM2 musíme spustit až po kompletní konfiguraci obou "slave" timerů. Stojí za to připomenou že je slušné nejprve konfigurovat "master" timer a jeho TRGO a teprve pak "slave" timery připojit k ITRx. V opačném případě hrozí že "slave" timer připojíte k TRGO na které ještě není nic namapované (a kdo ví co tam tedy je). Celou ukázku napsanou s pomocí SPL knihoven můžete stáhnout zde: a_timerlink.c. Konfiguraci timer-linku si můžete prohlédnout v úryvku ze zdrojového kódu.
/* Timery jsou nakonfigurované, ale ne spuštěné */ // nejprve nastavíme signál na TRGO výstup u "masteru" TIM_SelectOutputTrigger(TIM2,TIM_TRGOSource_Enable); // poté vybereme zdroj TRGI signálu slave obvodům (TIM5 a TIM3) // a nakonfigurujeme jak mají s ním mají naložit (spustit se) TIM_SelectInputTrigger(TIM5,TIM_TS_ITR0); // input ITR0 (TRGO z TIM2) TIM_SelectSlaveMode(TIM5,TIM_SlaveMode_Trigger); // s příchodem ITR spustit/povolit timer TIM_SelectInputTrigger(TIM3,TIM_TS_ITR1); // input ITR1 (TRGO z TIM2) TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Trigger); // s příchodem ITR spustit/povolit timer // nakonec spustíme master timer a je hotovo. TIM_Cmd(TIM2, ENABLE);
Výsledek pokusu si můžete prohlédnout na následujícím osilogramu (obr 1). Frekvenci/periodu (50Hz/20ms) a šířky pulzů jsem volil tak aby odpovídaly signálům pro řízení servo motorů. Na TIM2_CH1 (PA0) by měl být pulz široký 1ms, na TIM5_CH2 (PA1) 1.2ms a na TIM3_CH1 (PA6) 1.5ms. Všimněte si také, že strop i prescaler všech čítačů je shodný. Bez toho by PWM nebylo synchronní. Přirozeně vám ale nikdo nebrání tyto hodnoty volit dle vašich potřeb. Můžete třeba některému PWM signálu zvolit dvojnásobnou frekvenci a nebo je libovolně rozfázovat (jako na obr.2) tím, že před spuštěním před-plníte hodnoty čítačů (TIMx->CNT registr).
Home
Vx.xx 23.7.2017
By Michal Dudka (m.dudka@seznam.cz)